极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 18201|回复: 10

让你的自衡小车更快的站起来

[复制链接]
发表于 2013-4-16 10:08:58 | 显示全部楼层 |阅读模式
简单说就是先测出小车的死区,逐渐调高PWM的输出,电机开始转动时的PWM值就是小车的死区,然后在PID输出加上这个死区,这样就能更好的保持小车的稳定性。
原理分析(个人分析):以前做伺服控制时,伺服电机有一个“使能”的状态,当伺服电机上使能后,电机轴就处在一种“抱死”的状态,在自衡小车的控制信号中增加死区值,也是相当于将小车始终保持在一个“抱死”的状态,小车的稳定性也就会更高。小车还没站立起来的可以试一下。
本人的小车基本站起来的,算法就是按照官方手册里来的,纯角度控制,没用速度控制,改天上视频。

一下代码是临时版的代码,注释很烂,程序也很烂,如果觉得有参考可以看一下,否则可以直接无视,O(∩_∩)O~

  1. #include <I2Cdev.h>
  2. #include <L298N.h>
  3. #include <MPU6050.h>
  4. #include <Wire.h>
  5. #include <stdlib.h>

  6. float ax,az,gy;//get acceleration_x,acceleration_z,rotation_y
  7. long OffsetGy,OffsetSum;
  8. float OffsetAccSumX,OffsetAccSumZ,OffsetAcc;
  9. float AngleAcc,AngleRotation,AngleMerge;//angel computed by acceleration and rotation
  10. //============define variable for freescale refrence manual=========
  11. float AngleMergeLast,Tg,Pangle,Dangle,MotorDeadZone;
  12. //==================

  13. float Kp,Kd,Ki,pid_SP,pid_CV;
  14. float Err,ErrLast,ErrAfter;//PID
  15. long LastTime,NowTime,TimeSpan,SampleTime,PIDLastTime;//
  16. ////===========kalman filter parameter define============
  17. //float A,B,H,Q,R,P00,P10,X00,X10,Z,U,Kg;
  18. ////==========add serial communication=========
  19. String SerialString;
  20. boolean mark=0;
  21. char *comdata;

  22. bool blinkState=false;
  23. L298N l298n;
  24. MPU6050 mpu;


  25. void setup()
  26. {
  27.   
  28. //  SampleTime=10;
  29. //  //============initial kalman parameter======
  30. //  A=1.0;
  31. //  H=1.0;
  32. //  Q=0.003;
  33. //  R=0.01;
  34. //  P00=5.0;
  35. //  P10=0.0;
  36. //  X00=0.0;
  37. //  //===============end initial===========
  38.   Wire.begin();
  39.   Serial.begin(9600);
  40.   Serial.println("start");
  41.   mpu.initialize();
  42.   Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  43.   //compute the gyroscope offset automatic
  44.   OffsetSum=0;
  45.   for(int i=0;i<1024;i++)
  46.   {
  47.     //Serial.println(mpu.getRotationY());
  48. //    OffsetAccSumX+=mpu.getAccelerationX()/16384.00;
  49. //    OffsetAccSumZ+=mpu.getAccelerationZ()/16384.00;
  50.     OffsetSum=OffsetSum+mpu.getRotationY();
  51.     //delay(20);
  52.    }
  53.   //OffsetAcc=(-1.0)*atan2(OffsetAccSumX/200.0,OffsetAccSumZ/200.0)*180/PI;
  54.   OffsetGy=OffsetSum/1024;
  55.   pid_SP=0.0;
  56.   Kp=48.0;
  57.   Ki=12.0;
  58.   Kd=0.0;
  59.   AngleMergeLast=0.0;
  60.   Tg=0.5;
  61.   MotorDeadZone=80;
  62. }

  63. void loop()
  64. {
  65.   
  66.   NowTime=millis();
  67.   TimeSpan=NowTime-LastTime;
  68.   LastTime=NowTime;
  69.   //==============add serial communication=======
  70.   SerialString="";
  71.   while(Serial.available()>0)
  72.   {
  73.     SerialString += char(Serial.read());
  74.     delay(2);
  75.     mark=1;
  76.   }
  77.   if (mark)
  78.   {
  79.     SerialString.trim();
  80.     //int len=SerialString.length();
  81. //    int PIndex=SerialString.indexOf('P');
  82. //    int IIndex=SerialString.indexOf('I');
  83. //    int DIndex=SerialString.indexOf('D');
  84. //    int SIndex=SerialString.indexOf('S');
  85.     //int PComma=SerialString.indexOf(',');
  86.     //int IIndex=PIndex+1;
  87.    
  88.     //int IComma=SerialString.indexOf(',',IIndex);
  89.     //==============set only one parameter each time===========
  90.     String _Para="";
  91.     switch(SerialString[0])
  92.     {
  93.       case 'p':
  94.       case 'P':
  95.         _Para=SerialString.substring(1);
  96.         _Para.trim();
  97.         comdata=&_Para[0];
  98.         Kp=atof(comdata);
  99.         Dangle=atof(comdata);
  100.         
  101.         break;
  102.       case 'i':
  103.       case 'I':
  104.         _Para=SerialString.substring(1);
  105.         _Para.trim();
  106.         comdata=&_Para[0];
  107.         Ki=atof(comdata);
  108.         Pangle=atof(comdata);
  109.         
  110.         break;
  111.         
  112.       case 'm':
  113.       case 'M':
  114.         _Para=SerialString.substring(1);
  115.         _Para.trim();
  116.         comdata=&_Para[0];
  117.         //Ki=atof(comdata);
  118.         MotorDeadZone=atof(comdata);
  119.         
  120.         break;
  121.         
  122.       case 'd':
  123.       case 'D':
  124.         _Para=SerialString.substring(1);
  125.         _Para.trim();
  126.         comdata=&_Para[0];
  127.         Kd=atof(comdata);
  128.         
  129.         break;
  130.       case 's':
  131.       case 'S':
  132.         _Para=SerialString.substring(1);
  133.         _Para.trim();
  134.         comdata=&_Para[0];
  135.         pid_SP=atof(comdata);
  136.         
  137.         break;
  138.       case 't':
  139.       case 'T':
  140.         _Para=SerialString.substring(1);
  141.         _Para.trim();
  142.         comdata=&_Para[0];
  143.         Tg=atof(comdata);
  144.         
  145.         break;
  146.       default:
  147.         break;
  148.     }
  149. //    String _mkp=SerialString.substring(PComma+1,IIndex-1);
  150. //    _mkp.trim();
  151. //    comdata=&_mkp[0];
  152. //    Kp=atof(comdata);
  153. //    String _mki=SerialString.substring(IComma+1);
  154. //    _mki.trim();
  155. //    comdata=&_mki[0];
  156. //    Ki=atof(comdata);
  157.    
  158.     mark=0;
  159.   }

  160. //  //=================test kalman filter==========================
  161. //  ax=mpu.getAccelerationX()/16384.00;
  162. //  az=mpu.getAccelerationZ()/16384.00;
  163. //  AngleAcc=(-1.0)*atan2(ax,az)*180/PI;
  164. //  gy=(mpu.getRotationY()-OffsetGy)/131.00;
  165. //  AngleRotation=AngleRotation+gy*TimeSpan/1000.00;
  166. //  //=============kalman calculate============
  167. //  B=TimeSpan/1000.0;
  168. //  U=gy;
  169. //  Z=AngleAcc;
  170. //  X10=A*X00+B*U; //=======formula 1
  171. //  P10=A*P00*(1/A)+Q;//formula 2
  172. //  Kg=P10*(1/H)/(H*P10*(1/H)+R);//formula 3
  173. //  
  174. //  X00=X10+Kg*(Z-H*X10);//formula 4
  175. //  
  176. //  //P00=(1-Kg*H)*P10;//formula 5
  177. //  P00=(1-Kg*H)*P10*(1-Kg*H)+Kg*R*Kg;
  178. //  AngleMerge=X00;
  179. //  
  180. //  //================end test kalman filter======================

  181.   //MergeAngle();
  182.   MergeAngle_Freescale();
  183.   //PID();
  184.   if(1.0<AngleMerge)
  185.   {
  186.     l298n.MotorAForward(pid_CV);
  187.     l298n.MotorBForward(pid_CV);
  188.   }
  189.   else if(-1.0>AngleMerge)
  190.   {
  191.     l298n.MotorAReversal(pid_CV);
  192.     l298n.MotorBReversal(pid_CV);   
  193.   }
  194.   else
  195.   {
  196.     l298n.MotorAStop();
  197.     l298n.MotorBStop();
  198.   }
  199.   Serial.print(AngleMerge);
  200.   Serial.print(",");
  201.   Serial.print(Dangle);
  202.   Serial.print(",");
  203.   Serial.print(Pangle);
  204.   Serial.print(",");
  205.   Serial.print(pid_CV);
  206.   Serial.print(",");
  207.   Serial.print(MotorDeadZone);
  208.   Serial.print(",");
  209.   Serial.println(Tg);
  210.   delay(10);

  211. }
  212. void PID()
  213. {
  214.   //===========04-13 add sample time=============
  215.   
  216.   if((NowTime-PIDLastTime)>SampleTime)
  217.   {
  218.     PIDLastTime=NowTime;
  219.    
  220.     ErrAfter=ErrLast;
  221.     ErrLast=Err;
  222.     Err=pid_SP-abs(AngleMerge);
  223.     //Err=pid_SP-AngleMerge;
  224.     float deltOut=Kp*Err+Ki*ErrLast+Kd*ErrAfter;
  225.    
  226.     pid_CV=min(255.0,abs(pid_CV+deltOut)+MotorDeadZone);
  227.     //pid_CV=max(80,pid_CV);//limit the min PWM output
  228.   }
  229. }
  230. void MergeAngle()
  231. {
  232.   //compute AngleAcc
  233.   ax=mpu.getAccelerationX()/16384.00;
  234.   az=mpu.getAccelerationZ()/16384.00;
  235.   AngleAcc=(-1.0)*atan2(ax,az)*180/PI;
  236.   gy=(mpu.getRotationY()-OffsetGy)/131.00;
  237.   AngleRotation=AngleRotation+gy*TimeSpan/1000.00;

  238.   AngleMerge=0.9*AngleRotation+0.1*AngleAcc;
  239. }
  240. void MergeAngle_Freescale()
  241. {
  242.   ax=mpu.getAccelerationX()/16384.00;
  243.   az=mpu.getAccelerationZ()/16384.00;
  244.   AngleAcc=(-1.0)*atan2(ax,az)*180/PI;
  245.   gy=(mpu.getRotationY()-OffsetGy)/131.00;
  246.   AngleRotation=AngleRotation+gy*TimeSpan/1000.00;
  247.   
  248.   float AngleErr=AngleAcc-AngleMerge;
  249.   AngleMerge=AngleMerge+(gy+AngleErr/Tg)*TimeSpan/1000.00;

  250.   // ========this solution is from Freescale, it is effective
  251. pid_CV=abs((0-gy)*Dangle+(0-AngleMerge)*Pangle)+MotorDeadZone;
  252. pid_CV=min(255.0,pid_CV);
  253. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2013-4-16 12:10:29 | 显示全部楼层
想做个玩玩····
回复 支持 反对

使用道具 举报

发表于 2013-4-16 12:49:34 | 显示全部楼层
使用普通的玩具直流电机可以实现吗?
回复 支持 反对

使用道具 举报

发表于 2013-4-16 12:49:53 | 显示全部楼层
传感器使用的什么型号的?
回复 支持 反对

使用道具 举报

发表于 2013-4-16 13:43:45 | 显示全部楼层
maxiujun 发表于 2013-4-16 12:49
传感器使用的什么型号的?

看注释里写的是MPU6050
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-4-16 14:28:41 | 显示全部楼层
maxiujun 发表于 2013-4-16 12:49
使用普通的玩具直流电机可以实现吗?

只要扭矩和速度足够就可以(也就是功率足够大,O(∩_∩)O~)。我用的是带测速的,淘宝价格22元,搜一下就知道了。
回复 支持 反对

使用道具 举报

发表于 2013-4-22 20:57:41 来自手机 | 显示全部楼层
标记一下,爪机看的麻烦来自: Android客户端
回复 支持 反对

使用道具 举报

发表于 2013-6-29 17:50:37 | 显示全部楼层
没有<L298N.h>文件,不知能否提供。
回复 支持 反对

使用道具 举报

发表于 2013-10-10 22:55:07 | 显示全部楼层
程序是有点乱,每个人定义的名字不同,不过我的小车还不能实现蓝牙控制,有点头疼、
回复 支持 反对

使用道具 举报

发表于 2013-11-26 12:47:00 | 显示全部楼层
164335413 发表于 2013-10-10 22:55
程序是有点乱,每个人定义的名字不同,不过我的小车还不能实现蓝牙控制,有点头疼、

同求<L298N.h>文件
回复 支持 反对

使用道具 举报

发表于 2013-12-29 17:48:28 | 显示全部楼层
在学习平衡小车,,,学习楼主了
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-14 05:43 , Processed in 0.105238 second(s), 27 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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