找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9489|回复: 19
打印 上一主题 下一主题
收起左侧

[宁静清幽的平衡小车进程帖]

[复制链接]
跳转到指定楼层
楼主
本帖最后由 宁静清幽 于 2016-2-5 11:24 编辑

组装晒图
来几发小车照片,晒一晒
小车主控板正面照片




小车主控板反面照片


主控板给我的感觉:板子质量杠杠的,焊工也是棒棒哒,没有什么质量问题


小车底盘反面照片



全身照片


感觉小车帅帅哒
基础实验
  
1.      Keil工程模板的建立

2.      LED指示灯实验

这两个实验就放一块了,Keil工程模板的建立在图中了,不知道这样算不算完成,好多文件还没有写呢,做以后的实验再补充。

LED指示灯实验主函数代码在下图就不再贴出来了



all_header.h的代码如下
  1. #ifndef __all_head_
  2. #define __all_head_

  3. #include "STC15W4Kxx.h"
  4. #include <intrins.h>
  5. #include "Delay.h"

  6. #endif
复制代码


Delay.h的代码和all_header.h的代码格式一样,也不贴啦。
还是贴一下吧。
  1. #ifndef __Delay_
  2. #define __Dealy_
  3. #include <intrins.h>
  4. void Delay300ms();                //@20.000MHz
  5. #endif
复制代码
在贴一下Delay.c的代码吧!
  1. #include "Delay.h"
  2. void Delay300ms()                //@20.000MHz
  3. {
  4.         unsigned char i, j, k;
  5.         _nop_();
  6.         _nop_();
  7.         i = 23;
  8.         j = 205;
  9.         k = 120;
  10.         do
  11.         {
  12.                 do
  13.                 {
  14.                         while (--k);
  15.                 } while (--j);
  16.         } while (--i);
  17. }
复制代码
最后来张效果图

打死我,我也不会说这个程序里面控制的两个LED,但是只有一个亮。这个问题实在是无关紧要啦

3.      UART串口通讯实验

还是先上个效果图


写好程序编译,在左侧选好单片机型号,串口号,用的是内部时钟,填好IRC频率,为了方便通信嘛,就选的11.0592M。
在右侧最下面的蓝色框中,选好串口好,波特率,无校验位,停止位1位。上面两个蓝色框就是效果图了
对了,还得用安卓数据线把小车和电脑连起来,装上CP2102的驱动。
再上代码
主函数main代码:
  1. #include "all_header.h"

  2. void main()
  3. {        
  4.         Uart1Init();
  5.         EA=1;
  6.                 while(1);
  7. }
  8. void UART1() interrupt 4 using 1
  9. {
  10.         unsigned char date;
  11.         if (RI)
  12.         {        
  13.                 RI=0;
  14.                 date=SBUF;
  15.                 UART1SendByte(date);
  16.         }
  17.         if (TI)
  18.         {
  19.                 TI=0;
  20.         }
  21. }
复制代码

all_header.h头文件代码:
  1. #ifndef __all_head_
  2. #define __all_head_


  3. #include "STC15W4Kxx.h"
  4. #include <intrins.h>
  5. //#include "Delay.h"
  6. #include "UART1.h"

  7. #endif
复制代码
UART1.h代码:
  1. #ifndef _UART_H_  
  2. #define _UART_H_  

  3. #include "STC15W4Kxx.h"

  4. void Uart1Init(void);
  5. void UART1SendByte(unsigned char TxD1);

  6. #endif  
复制代码
UART1.c代码:
  1. #include "UART1.h"

  2. void Uart1Init(void)                //115200bps@11.0592MHz
  3. {
  4.         SCON = 0x50;                //8位数据,可变波特率
  5.         AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
  6.         AUXR |= 0x04;                //定时器2时钟为Fosc,即1T
  7.         T2L = 0xE8;                //设定定时初值
  8.         T2H = 0xFF;                //设定定时初值
  9.         AUXR |= 0x10;                //启动定时器2
  10. }


  11. void UART1SendByte(unsigned char TxD1)  
  12. {   
  13.     SBUF=TxD1;  
  14.     while(TI == 0);
  15.     TI=0;   
  16. }
复制代码

串口通信实验就算是完成了

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:94185 发表于 2016-2-5 18:05 来自手机 | 只看该作者
666
回复

使用道具 举报

板凳
ID:104166 发表于 2016-2-5 22:12 | 只看该作者
4.      PWM驱动电机实验
还是先上效果图打算传视频来着,不过不会传


先是逆时针加速再减速,后是顺时针加速再减速。
是时候上代码了
main.c:
  1. #include "all_header.h"
  2. //20MHZ
  3. void main()
  4. {        int i,temp=0;
  5.         PWMInit();
  6.         P2M0=0x02;      //芯片上电后所有与PWM相关的IO口均为高阻态
  7.         P2M1=0x00;        //将PWM2和PWM3IO 设置为强上拉(推挽)
  8.         P3M0=0x80;        //其余的P2P3口为弱上拉
  9.         P3M1=0x00;
  10.                 while(1)
  11.                 {        for(i=0;i<100;i++)//逆时针加速
  12.                         {
  13.                         temp+=200;
  14.                         PWM2T1=20000-temp;
  15.                         Delay25ms();
  16.                         }
  17.                         for(i=0;i<100;i++)//逆时针减速
  18.                         {
  19.                         temp-=200;
  20.                         PWM2T1=20000-temp;
  21.                         Delay25ms();
  22.                         }//上面的两个循环执行完后,PWM2T1=20000就不用再重新赋值了
  23.                         for(i=0;i<100;i++)//顺时针加速
  24.                         {
  25.                         temp+=200;
  26.                         PWM3T1=20000-temp;
  27.                         Delay25ms();
  28.                         }
  29.                         for(i=0;i<100;i++)//顺时针减速
  30.                         {
  31.                         temp-=200;
  32.                         PWM3T1=20000-temp;
  33.                         Delay25ms();
  34.                         }
  35.                 }
  36. }
复制代码
pwm.c:
  1. #include "PWM.h"
  2. void PWMInit()
  3. {
  4.         P_SW2|=0x80;                                    //使能访问XSFR
  5.         PWMCFG = 0x00;          //配置PWM初始化电平为低电平
  6.         PWMCKS = 0x00;          //选择PWM的时钟为Fosc/(0+1)=20M
  7.         PWMC = 20001;                //设置PWM周期 PWM频率为 PWM时钟频率(上行代码)20M/20001=1k
  8.        
  9.         PWM2T1 = 20000;                //设置PWM2第一次反转的PWM计数
  10.         PWM2T2 = 20001;                //设置PWM2第二次反转的PWM计数

  11.         PWM3T1 = 20000;                 
  12.         PWM3T2 = 20001;
  13.        
  14.         PWM2CR=0x00;                 //输出管脚为P3.7 无PWM中断,无PWM反转中断
  15.         PWM3CR=0x00;                //输出管脚为P2.1 无PWM中断,无PWM反转中断
  16.         PWMCR |= 0x03;                //使能PWM2 PWM3输出
  17.         PWMCR |= 0x80;          //使能PWM博兴发生器,PWM计数器开始计数
复制代码
就贴出这两个主要的代码吧!全部代码打包!
PWM驱动电机实验.zip (41 KB, 下载次数: 12)

回复

使用道具 举报

地板
ID:104166 发表于 2016-2-6 00:20 | 只看该作者
bjyxyc 发表于 2016-2-6 00:03
用什么型号的芯片呢

IPA15w4k61s4
回复

使用道具 举报

5#
ID:104166 发表于 2016-2-21 16:36 | 只看该作者
5.      编码器数据采集实验

先上一张速度图像(用的wps表格画的)



这是在2.5秒内加速到最大,延迟300毫秒,再在2.5秒内减速的图像,一共两个这样的过程。
如何采集速度:
电机上有霍尔编码器:电机转一圈回输出11个左右的脉冲(脉冲个数有编码器决定),通过配置单片机的定时器3和定时器4,使其对外部脉冲计数,配置定时器1使其每隔8毫秒读出脉冲来,再通过串口发给电脑,这样就采集到了速度。
配置定时器1的代码:
  1. void Timer1Init(void)                //8毫秒@20.000MHz
  2. {
  3.         AUXR &= 0xBF;                //定时器时钟12T模式
  4.         TMOD &= 0x0F;                //设置定时器模式
  5.         TL1 = 0xEB;                //设置定时初值
  6.         TH1 = 0xCB;                //设置定时初值
  7.         TF1 = 0;                //清除TF1标志
  8.         TR1 = 1;                //定时器1开始计时
  9.         ET1 = 1;                //允许定时器1中断

  10. }
复制代码
配置定时器3、4的代码:
  1. void Timer_3_4_Init(void)
  2. {

  3.   T4T3M |= 0xCC;        //允许定时器3、4运行对外部脉冲计数
  4.   IE2 &= 0x1F;        //进制定时器3、4产生中断
  5. }
复制代码

主函数MAIN和定时器1中断代码:
  1. #include "all_header.h"
  2. //20M晶振
  3. int num=0;
  4. void main()
  5. {        int i,temp=0;
  6.         PWMInit();        //PWM初始化
  7.         Uart1Init();        //串口1初始化
  8.         Timer1Init();        //定时器1初始化
  9.         Timer_3_4_Init();//定时器3 4初始化
  10.         P2M0=0x02;      //芯片上电后所有与PWM相关的IO口均为高阻态
  11.         P2M1=0x00;        //将PWM2和PWM3所在的IO口设置为强上拉(推挽)
  12.         P3M0=0x80;        //取余的P2P3口为弱上拉(准双向扣)
  13.         P3M1=0x00;
  14.         EA=1;                //允许总中断
  15.         T3L=0;
  16.         T3H=0;
  17.                 while(1)
  18.                 {        for(i=0;i<100;i++)//正传加速
  19.                         {
  20.                         temp+=200;
  21.                         PWM2T1=20000-temp;
  22.                         Delay25ms();
  23.                         }
  24.                         Delay300ms();//延迟300毫秒
  25.                         for(i=0;i<100;i++)//正传减速
  26.                         {
  27.                         temp-=200;
  28.                         PWM2T1=20000-temp;
  29.                         Delay25ms();
  30.                         }
  31.                 }
  32. }

  33. void Timer1_Int() interrupt 3
  34. {
  35.         num=(T3H<<8)+T3L; //获取脉冲个数
  36.         T4T3M&=        0x77;        //关闭定时器3、4
  37.         T3H=T3L=0;        //脉冲个数清零
  38.         T4T3M |= 0xCC;        //将定时器3、4做计数用并开启定时器3、4
  39.         UART1SendByte(num);//发送num低8位(8毫秒内最大在17左右,num的低8位计数就够)
  40. }
复制代码

实验所有代码: 编码器数据采集.zip (45.88 KB, 下载次数: 12)


回复

使用道具 举报

6#
ID:104166 发表于 2016-2-21 23:23 | 只看该作者
6.传感器数据采集实验
还是先上一张图

上图是我找了一个认为平衡时,陀螺仪输出的原始数据,可以大致认为Y轴加速度的零点漂移大约为-390,X轴角速度零点漂移大约为-17。
如何得到的这些数据:
      MPU6050是一个可以测加速度和角速度的6轴传感器(里面还有一个温度传感器),单片机通过IIC协议和MPU6050通信,配置MPU6050,定时通信读出数据,将这些数据通过串口1发送给电脑。
下面是配置MPU6050的代码:
  1. void InitMPU6050()
  2. {
  3.         Single_WriteI2C(PWR_MGMT_1, 0x00);        //正常启用
  4.         Single_WriteI2C(SMPLRT_DIV, 0x07);        //采样率 = 陀螺仪的输出率 / (1 + SMPLRT_DIV)
  5.         Single_WriteI2C(CONFIG, 0x04);                //Accelerometer:21hz 8.5ms ; Gyroscope:20hz 8.3ms
  6.         Single_WriteI2C(GYRO_CONFIG, 0x18);        //+-2000°/s
  7.         Single_WriteI2C(ACCEL_CONFIG, 0x00);        //+-2g不自检
  8. }
复制代码
读取数据的代码:

  1. int GetData(unsigned char REG_Address)
  2. {
  3.         unsigned int H;
  4.         unsigned char L;
  5.         H=Single_ReadI2C(REG_Address);
  6.         L=Single_ReadI2C(REG_Address+1);
  7.         return (H<<8)+L;   //和成数据
  8. }
复制代码
MPU6050常用寄存器:

  1. //****************************************
  2. //定义MPU6050内部寄存器地址
  3. //****************************************

  4. #define        SMPLRT_DIV                0x19        //陀螺仪采样率0x07(125Hz)
  5. #define        CONFIG                        0x1A        //低通滤波频率
  6. #define        GYRO_CONFIG                0x1B        //陀螺仪自检及测量范围
  7. #define        ACCEL_CONFIG        0x1C        //加速度自检测量范围
  8. #define        ACCEL_XOUT_H        0x3B
  9. #define        ACCEL_XOUT_L        0x3C
  10. #define        ACCEL_YOUT_H        0x3D
  11. #define        ACCEL_YOUT_L        0x3E
  12. #define        ACCEL_ZOUT_H        0x3F
  13. #define        ACCEL_ZOUT_L        0x40
  14. #define        TEMP_OUT_H                0x41
  15. #define        TEMP_OUT_L                0x42
  16. #define        GYRO_XOUT_H                0x43
  17. #define        GYRO_XOUT_L                0x44       
  18. #define        GYRO_YOUT_H                0x45
  19. #define        GYRO_YOUT_L                0x46
  20. #define        GYRO_ZOUT_H                0x47
  21. #define        GYRO_ZOUT_L                0x48
  22. #define        PWR_MGMT_1                0x6B        //电源管理 0x00正常启用
复制代码

IIC的代码就不贴啦,最后打包。

主函数MAIN代码
  1. #include "all_header.h"
  2. //20M晶振
  3. int ACCEL,GYRO;
  4. void main()
  5. {       
  6. //设置所有IO口为弱上拉
  7.         P1M0=0x00;
  8.         P1M1=0x00;
  9.         P2M0=0x00;
  10.         P2M1=0x00;
  11.         P3M0=0x00;
  12.         P3M1=0x00;
  13.         P4M0=0x00;
  14.         P4M1=0x00;
  15.         P5M0=0x00;
  16.         P5M1=0x00;
  17.         Uart1Init();        //串口1初始化
  18.         Timer1Init();        //定时器1初始化8ms中断

  19.         InitMPU6050();        //初始化MPU6050
  20.         Delay300ms();
  21.                 EA=1;        开总中断
  22.                 while(1)
  23.                 {       
  24.                 }
  25. }

  26. void Timer1_Int() interrupt 3        //定时器18ms中断
  27. {
  28.        
  29.         ACCEL=GetData(ACCEL_YOUT_H);        //读取Y轴加速度
  30.         GYRO=GetData(GYRO_XOUT_H);        //读取X轴角速度
  31.         UART1SendByte(ACCEL);                //发送加速度低八位
  32.         UART1SendByte(ACCEL>>8);        //发送加速度高八位
  33.         UART1SendByte(GYRO);
  34.         UART1SendByte(GYRO>>8);
  35. }
复制代码
本实验代码 传感器数据采集.zip (53.16 KB, 下载次数: 9)


回复

使用道具 举报

7#
ID:77578 发表于 2016-2-23 20:36 | 只看该作者
你串口助手很好啊,是什么?
回复

使用道具 举报

8#
ID:104166 发表于 2016-2-23 22:31 | 只看该作者
moyuqilin 发表于 2016-2-23 20:36
你串口助手很好啊,是什么?

为了看数据方便,就动手写了这么个不能再简陋的助手。
回复

使用道具 举报

9#
ID:104166 发表于 2016-2-24 17:09 | 只看该作者
7.      无线通讯实验(蓝牙)没有nRF24l0(不会玩,以后得鼓捣鼓捣),而且小车上有蓝牙,就用蓝牙啦
先上图


左边用的是手机蓝牙串口助手,发送的 hello world,右边在电脑串口助手接收到的。一共用了单片机上的2个串口,串口2和蓝牙相连接,串口1和电脑连接。在电脑上选好串口号和波特率校验位,停止位,烧写上程序就可以通信啦。
数据流向:手机蓝牙-->蓝牙模块-->单片机串口2-->串口1-->电脑串口助手。感觉实际上还是串口通信,蓝牙默认的波特率是115200,名称是HMSoft,喵大应该是提前设置好了,通过命令可以更改蓝牙的一些参数。
下面是代码:
串口1 、2初始化代码:

  1. void Uart1Init(void)                //115200bps@20.000MHz
  2. {
  3.         SCON = 0x50;
  4.         AUXR |= 0x01;
  5.         AUXR |= 0x04;       
  6.         T2L = 0xD5;
  7.         T2H = 0xFF;
  8.         AUXR |= 0x10;
  9.         ES=1;
  10. }
  11. void Uart2Init(void)                //115200bps@20.000MHz
  12. {
  13.         S2CON = 0x50;                //8位数据,可变波特率
  14.         AUXR |= 0x04;                //定时器2时钟为Fosc,即1T
  15.         T2L = 0xD5;                //设定定时初值
  16.         T2H = 0xFF;                //设定定时初值
  17.         AUXR |= 0x10;                //启动定时器2
  18.         IE2 |=0x01;                /允许定时器2中断
  19. }
复制代码

串口1发送数据代码:

  1. void UART1SendByte(unsigned char TxD1)  
  2. {   
  3.     SBUF=TxD1;  
  4.     while(TI == 0);//等待发送完成
  5.     TI=0;   
  6. }
复制代码

Main代码:

  1. #include "all_header.h"
  2. //20MH
  3. void main()
  4. {               

  5.         //P13 I/O口设置为弱上拉
  6.         P1M0=0x00;
  7.         P1M1=0x00;
  8.         P3M0=0x00;
  9.         P3M1=0x00;
  10.         Uart1Init();
  11.         Uart2Init();
  12.         EA=1;
  13.                 while(1);
  14. }
  15. void  Interrupt_Uart2(void) interrupt  8 using 1         //125hz
  16. {
  17.         if(S2CON & 0x01)
  18.         {
  19.                 S2CON&=~0x01;
  20.                 UART1SendByte(S2BUF);
  21.         }
  22. }
复制代码
无线通讯实验就算完成啦




闪亮.gif (667.5 KB, 下载次数: 226)

闪亮.gif

长亮.gif (311.88 KB, 下载次数: 215)

长亮.gif
回复

使用道具 举报

10#
ID:104166 发表于 2016-2-26 01:10 | 只看该作者
进阶实验:

1.     多传感器数据融合



看了喵大和网上的资料,用互补滤波进行数据融合就可以满足,但要调节好比例权重(不知道这样说有没有为题),我用的也是互补滤波。
下面就是我所观察到的实验结果:(红色线为融合后的数据,黑色线为由加速度算出的角度,纵轴的单位就是度,一个像素代表1度,我没有软件中写坐标)

图1:
图1是加速度比例权重(此图为0.1)比较大的图像,其代码为CarAngle=0.9*(CarAngle+GyroSpeed*0.008)+0.1*AccelAngle;
小车稍微有点震动,加速度就会变化,但是车体的角度并没有变化,微小的晃动是噪声,所以由加速度算出来的角度也会有很多噪声,加速度权重过大,就会掺杂更多的噪声,不能反应真实的车体角度。
图2是车体直立突然到向一个方向,待一会,然后直立,再反相倒的车体角度的图像。图中的那些突起的黑线,是转小车时突然停止产生的,车体的角度并没有那样的突变(先变大在减小),车体角度而只是增大然后突然不变,在由于加速度比例权重过大,可以看到融合后的图像(红色线)也不能真实反应车体的角度。
图2:
图2是加速度比例权重适当(此图为0.005)的数据融合图像。其代码为CarAngle=0.995*(CarAngle+GyroSpeed*0.008)+0.005*AccelAngle;

可以看到在那些黑线突起地方,红线也平滑的变化,能够反应真实的车体角度变化。
图3:
图3是车体一开始就有一定的倾斜角的情况下供电的图像(刚开始时黑色线(也就是由加速度算出的角度)能够反应车体的真是角度),进行数据融合之前没有给车体角度赋初值(就是先先将由加速度算出的角度赋给车体角度变量)就会出现这样的情况。在代码中有赋初值的注释。
图4:
图4是进行数据融合之前,给车体角度赋初值得图像,在刚开始的图像部分,黑色线被红色先覆盖了。这样无论小车在什么角度开机,总能够确保一开机融合后的角度都是正确的。
下面是MAIN代码:
  1. #include "all_header.h"
  2. //20MHz
  3. int AccelData;
  4. int GyrolData;
  5. float AccelAngle;
  6. float GyroSpeed;
  7. float CarAngle;
  8. float GyroAngle;
  9. int temp;
  10. void main()
  11. {       
  12.         //设置所有IO口为准双向口
  13.         P0M0=0x00;
  14.         P0M1=0x00;
  15.         P1M0=0x00;
  16.         P1M1=0x00;
  17.         P2M0=0x00;
  18.         P2M1=0x00;
  19.         P3M0=0x00;
  20.         P3M1=0x00;
  21.         P4M0=0x00;
  22.         P4M1=0x00;
  23.         P5M0=0x00;
  24.         P5M1=0x00;
  25.         InitMPU6050();//MPU6050初始化
  26.         Delay300ms();
  27.         Uart1Init();//串口1初始化
  28.         AccelData=GetData(ACCEL_YOUT_H);
  29.         AccelAngle=(float)(AccelData-370)/16384.0f;
  30.         //I在此先将由加速度算出的角度给CarAngle,
  31.         //来确保一开机,融合后的角度就是正确的。
  32.         CarAngle=AccelAngle*57.2957795f;
  33.         Timer1Init();//定时器1初始化
  34.         Delay300ms();
  35.         EA=1;
  36.                 while(1);
  37. }
  38. void  Interrupt_Timer1(void) interrupt  3         //125hz
  39. {
  40.         AccelData=GetData(ACCEL_YOUT_H);        //获取Y轴加速度
  41.         GyrolData=GetData(GYRO_XOUT_H);                //获取X轴角速度
  42.         AccelAngle=(float)(AccelData-370)/16384.0f;//出去零点偏移,就是你得到角度(单位是弧度)
  43.         AccelAngle=AccelAngle*57.2957795f;// 180/3.1415926535898弧度转换为度
  44.         temp=(int)AccelAngle;                //强制转换为整形量
  45.         UART1SendByte(temp);                //发低八位
  46.         UART1SendByte(temp>>8);        //发高八位
  47.         GyroSpeed=(float)(GyrolData-(-17))/16.4f;
  48.         CarAngle=0.995*(CarAngle+GyroSpeed*0.008)+0.005*AccelAngle;//互补滤波
  49.         temp=(int)CarAngle;
  50.         UART1SendByte(temp);
  51.         UART1SendByte(temp>>8);
  52. }
复制代码

实验代码: 数据融合.zip (51.21 KB, 下载次数: 7)
回复

使用道具 举报

11#
ID:94185 发表于 2016-2-27 17:47 | 只看该作者
宁静清幽 发表于 2016-2-26 01:10
进阶实验:

1.     多传感器数据融合

非常好。继续加油。把小车都学透~
回复

使用道具 举报

12#
ID:79544 发表于 2016-3-8 10:37 | 只看该作者
真是高手,佩服啊,长见识啦,谢谢分享
回复

使用道具 举报

13#
ID:104166 发表于 2016-3-9 21:35 | 只看该作者
腾飞的龙 发表于 2016-3-8 10:37
真是高手,佩服啊,长见识啦,谢谢分享

啥高手,参数调不好,上面的都是跟着喵大学的!
回复

使用道具 举报

14#
ID:104166 发表于 2016-3-24 12:55 | 只看该作者
进阶实验

2.     PID调试

关于小车PID的调试,也在网上找了好多资料,也看了喵大的角度环视频,调试经验有从网上学的也有些自己简单的体会。
原来没接触的时候也是一头雾水(毕竟不是学自控的孩子),后来在网上搜了一些资料,对这些基本概念也有了大概的了解,下面说一下我对PID的了解吧!1)我对PID的理解:PID分增量式和位置式,增量式的计算结果是在上一次的控制量基础上需要增加的量,或减少的量;位置式的每一次计算都是一个新的控制量的大小,而不是增加量,也不知道这说对不对(表达能力有限)。喵大的貌似是位置式,我的代码也是参考喵大的。PID控制一定要有反馈,要不然何谈控制(有点像废话)。PID控制就是比例P、积分I、微分控制D,这些运算是对于偏差来说的。    (1)比例运算:对偏差进行比例运算,就是偏差乘上一个系数,把这个偏差放大或缩小,对于平衡小车角度环来说,偏差角度=目标角度-当前角度,目标角度就是平衡时候的角度,就是0喽,比例控制量=偏差*比例系数,偏差大了,就是小车倾斜程度大了,我们给小车的电机大点电压,使小车加速运动,来减小偏差,从而使小车趋向平衡,同理,偏差小,给电机的电压小点,这就是比例控制,比例参数过小,小车“没劲”,不能抵消自身重力,太大的话,大幅度摇摆太厉害。
    (2)积分运算:对偏差进行积分,就是把偏差进行累加,偏差和=偏差和+偏差*积分系数;只要出现偏差,通过累加就会使偏差和变大,我们给电机的电压就要大,来使小车趋向平衡,直到偏差和为零的时候,积分这一部分对电压控制没有贡献。相对于比例参数来说,积分系数是很小的,但积分系数过小累加和变化不明显,控制也就不明显,过大,即出现了一个很小的误差,通过积分系数放大了好多,累加和也会变得很大,使系统不稳定。
    (3)微分控制:就是偏差对时间求导,得到的是偏差的变化率。对于小车的角度环来说偏差d=C-f(t);C就是我们目标角度,是一个恒定值,一般是0,f(t)是当前的角度值,偏差d对时间求导=常数C对时间求导+f(t)对时间求导,常数的导数是0,所以偏差d对时间求导相当于角度对时间求导,得到的是角速度,角速度可以直接从陀螺仪上面获取,就不用我们运算了,不过我们注意角速度的正负号。角速度的正负号代表小车像前还是向后倒下了,可以自己规定。角速度的绝对值代表小车倒下的速度,小车倒下的速度越快,我们就要给小车电机更大的电压,来抵消小车倒下,微分控制起到加快调节的作用。微分控制量=角速度*微分系数,我们把角速度乘以一个系数(也就是微分系数)就得到微分控制部分的控制量的大小了。微分系数太小也不能抵消小车的倒下,太大了会使小车小幅度高频震荡,容易烧驱动。
以上只是我的简单理解,有什么不对或者不全的地方还请大家指出,共同进步
2)调试
关于平衡车的控制,用到了两个环的控制,分别是角度环和速度环,角度环用PD,速度环用PI,在只有角度环的时候我也用过PID,以可以达到平衡,但是由于没有速度环,小车不一定跑到哪了。
写一下主要的公式:

    角度环:角度偏差d_Angle=SetAngle-CarAngle;     AngleCtrlOut=d_Angle*P_Angle+w*D_Angle;    w是角速度,在这之前还要对小车的角度进行滤波,前面的实验有过介绍,AngleCtrlOut是角度环的PWM输出
    速度环:速度偏差d_Speed=SetSpeed-CarSeed;  Car_I=Car_I+d_Speed*I_Speed;    SpeedCtrlOut=d_Speed*P_Speed+CarI;  SpeedCtrlOut是速度环的PWM输出。这些系数与单片机PWM的最大量有关系,比如单片机PWM的最大量是10000;在调角度环的时候一般是先让微分系数D_Angle=0,先只调比例系数,这样AngleCtrlOut=d_Angle*P_Angl;当偏差角度 d_Angle=10度,比例系数P_Angle=10,AngleCtrlOut才=100,小车PWM输出占PWM最大量的1%,理论上小车电机的转速为最快转速的1%(实际上达不到,也有可能死区电压都没过),这样小车没有足够的加速度来克服重力使车达到平衡。比例系数P_Angle还需要调大。但是当单片机PWM的最大量是256的时候,偏差角度 d_Angle=10度,比例系数P_Angle=10的时候,AngleCtrlOut还是=100,约占PWM最大量的39%,这个系数可能还靠点谱,所以说这些系数PWM最大量是有关系的。
    调试这些系数的过程:先调角度环,再速度环。关于反馈类型说的文邹邹点:角度环是负反馈,速度环是正反馈。说的通俗点:角度环中,偏差角度变大时,小车要控制偏差角度减小,就是让车轮朝着倒下的方向加速转。速度环中,速度变大,我们得给小车更快的速度,让小车追上自己,保持平衡。在调试的时候,可以分别调一下两个环,注意参数的正负,保证每个环,都是使车轮朝向小车倾斜的方向转就行了,在只有速度环时,手动转一个车轮,另一个车轮会慢慢转起来,最终两个车轮越转越快。
    调角度环时,一般是先让微分系数D_Angle=0,先只调比例系数,调到能使小车站起来,在平衡位置来回的摆动,再稍微增加比例系数,加入微分系数D_Angle,微分系数D_Angle从小到大。调到小车能够比较稳定的平衡,这时候,你轻推小车,小车会朝着一个方向加速跑过去,直至倒下。这个也是正常的,当然小车能接近平衡跑的越远说明参数越好,加入速度环可以解决这个问题,如果不加速度环,在角度环里面加入对偏差的积分(累加偏差),也能使小车平衡。只是对小车的速度没法控制。
    调速度环时,一般是先让积分系数I_Speed=0,先只调比例系数,由0开始增加,调到你推一下小车,小车能有足够的加速度来使小车保持平衡,这时小车新的平衡位置不再原地了,感觉小车能够很好的保持平衡之后,这时再加速度积分,加入速度积分后,小车会趋向于原地平衡
    我的理解就是这些,有什么不对或者不全的还请大家指出来,一块讨论共同学习哈。我自己感觉对于车速控制的理解还不够深,对于两个车轮速度分别控制还有待加强。
    挺感谢喵大的这个平台的,给我提供了学习平衡车基础,有机会让我这样的平衡车入门级玩家能从头到尾深刻了解平衡车的原理。给这个网站平台点个赞,给喵大的开源精神点个赞,给喵大的热心肠点个赞。
    本想弄点图片的,电池,又让我弄过放了,废了,平衡充接电池的时候,接反了一下,灯不亮了,平衡冲也出问题了。唉我勒个去,我也是被自己整无语了。在下个实验中在上图片吧。

回复

使用道具 举报

15#
ID:104166 发表于 2016-4-16 23:09 | 只看该作者
进阶实验
3.     实现平衡小车直立时处于静止状态
下面两个图片是小车静止时受到干扰后小车运动的图片

第一张图的速度环是用的PI,第张图用的是PD,可以看到第一张图中:用手推车,车会回到原来的位置;第二张图中:用手推车则不会会到原来的位置。下面是代码:

  1. Speed_Least=(float)(g_iLeftMotorPluseSigma+g_iRightMotorPluseSigma)/2.0;//获取速度

  2. g_iRightMotorPluseSigma=g_iLeftMotorPluseSigma=0;//速度清零
  3. g_fCarSpeed=Speed_Least*0.75+g_fCarSpeed*0.25;//速度滤波
  4. fDelta = g_iCarSpeedSet;//此处全局整形目标车速 g_iCarSpeedSet为零
  5. fDelta -= g_fCarSpeed;//得到速度偏差
  6. fP = fDelta*g_fcSpeed_P;//速度偏差乘上比例系数


复制代码
上面代码是两个车速度环的公共代码。

下面是第一个图片中PI速度环的代码:

  1. fI = fDelta*g_fcSpeed_I;速度偏差乘上积分系数
  2. g_fCarPosition += fI; //偏差累加,在开始初始化的时候g_fCarPosition是为零的
  3. /****************加入积分限幅*****************/
  4. if(g_fCarPosition>20000)g_fCarPosition=20000;
  5. if(g_fCarPosition<-20000)g_fCarPosition=-20000;
  6. /*********************************************/
  7. g_fSpeedCtrlOut = fP+g_fCarPosition;//速度环控制量输出
复制代码

下面是第二个图片中PD速度环的代码:

  1. fD = (fDelta-g_fcSpeedDerta)*g_fcSpeed_D;//得到速度的变化率
  2. g_fSpeedCtrlOut = fP+fD;<span style="line-height: 1.5;">//速度环控制量输出</span>
复制代码

所有代码: 所有代码.zip (144.52 KB, 下载次数: 36)
附件里的代码跟喵大的差不多,我是照着喵大的代码敲的,不过我的这个有些地方比较难看。我刚开始看喵大的代码的时候,看着也头大,后来我就先看程序名,看看这个程序的流程;看个大概了,之后再了解程序的细节,死扣每一句,之后慢慢理解了小车。

由衷感谢喵大的这个平台,让我学到了平衡小车的知识,感谢,感谢,感谢。


静止1.gif (3.48 MB, 下载次数: 144)

静止1

静止1
回复

使用道具 举报

16#
ID:102157 发表于 2016-4-21 10:47 | 只看该作者
厉害,大神,请接下我的膝盖你做了转向没?
回复

使用道具 举报

17#
ID:114829 发表于 2016-5-4 12:43 | 只看该作者
楼主能否给我一份具体的资料啊  ?
回复

使用道具 举报

18#
ID:145818 发表于 2016-11-2 22:11 | 只看该作者
不错!!!!值得学习!
回复

使用道具 举报

19#
ID:200681 发表于 2017-5-14 17:31 | 只看该作者
值得学习学习,我也在做小车,希望最后能够成功
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表