极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 20699|回复: 7

两轮自平衡小车

[复制链接]
发表于 2011-10-17 21:30:23 | 显示全部楼层 |阅读模式
  1. //两轮自平衡小车

  2. //IDG330 Mannual, 2mv= 1度/s 的角速率,ad读数1024,3.3v,那么每读数对应 3.223mV,所以每读数对应3.223/2/180*PI= 0.028123弧度/秒
  3. static const double SEMICIRCLE_ARC = 57.29578; /*半圆对应的弧度值*/
  4. static const double GYRO_OPERATOR = 0.028123; /*AD读取的陀螺仪数值对应的弧度算子*/

  5. /*kalman*/
  6. static const double C_0 = 1;
  7. static const double Q_angle=0.001, Q_gyro=0.003, R_angle=0.5, dt=0.005;//注意:dt的取值为kalman滤波器采样时间
  8. double P[2][2] = {{ 1, 0 },
  9.                   { 0, 1 }};
  10. double Pdot[4] ={ 0,0,0,0};
  11. double q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;
  12. double angle, angle_dot;

  13. /*sensor*/
  14. double sensorPort[6] = { 0, 1, 2, 3, 4, 5};/*传感器地址,电路决定.accZ,gyroX, AD1, AD2, AD3, AD4*/
  15. double sensorValue[6];/*传感器的返回值*/

  16. /*传感器零点 0:Z轴(平行轴) 1:陀螺仪中点*/
  17. double sensorZero[2] = {499,505};
  18. double sensorAdjusted[2];/*传感器的返回值重整*/
  19. //double provAngle;

  20. /*moto*/
  21. int E1 = 6;
  22. int E2 = 9;
  23. int M1 = 7;
  24. int M2 = 8;
  25. double deadAreaCompensation1 = 45,deadAreaCompensation2 = 35;

  26. /*balance*/
  27. double RATE[4] = { 0,0,0,0};/*公式中的4个变量*/
  28. double K[4] = { 60.45, 1.27, 125, 0.75};/*公式中的4个常量*/
  29. double K_AD[4] = { 1, 1, 1, 1};/*公式中的4个常量*/
  30. double wheel_ls[7];/*左轮:0:编码器 1:位移(position) 2:position_dot 3:position_dot_filter 4:speedNeed 5:turnNeed 6:speedOutPut */
  31. double wheel_rs[7];/*右轮:0:编码器 1:位移(position) 2:position_dot 3:position_dot_filter 4:speedNeed 5:turnNeed 6:speedOutPut */

  32. double Torque;/*扭矩*/
  33. unsigned int count,count2;
  34. boolean OK=false;//这个是误差达到一定程度后的系统关闭开关.
  35. int bf,X,Y;//从无线端发来的命令

  36. /*kalman*/
  37. /*angle_m:经过atan2(ax,ay)方法计算的偏角,弧度值
  38. gyro_m:经过初步减去零点的陀螺仪角速度值,弧度值
  39. */
  40. void Kalman_Filter(double angle_m,double gyro_m)
  41. {
  42. angle+=(gyro_m-q_bias) * dt;
  43. angle_err = angle_m - angle;
  44. Pdot[0]=Q_angle - P[0][1] - P[1][0];
  45. Pdot[1]=- P[1][1];
  46. Pdot[2]=- P[1][1];
  47. Pdot[3]=Q_gyro;
  48. P[0][0] += Pdot[0] * dt;
  49. P[0][1] += Pdot[1] * dt;
  50. P[1][0] += Pdot[2] * dt;
  51. P[1][1] += Pdot[3] * dt;
  52. PCt_0 = C_0 * P[0][0];
  53. PCt_1 = C_0 * P[1][0];
  54. E = R_angle + C_0 * PCt_0;
  55. K_0 = PCt_0 / E;
  56. K_1 = PCt_1 / E;
  57. t_0 = PCt_0;
  58. t_1 = C_0 * P[0][1];
  59. P[0][0] -= K_0 * t_0;
  60. P[0][1] -= K_0 * t_1;
  61. P[1][0] -= K_1 * t_0;
  62. P[1][1] -= K_1 * t_1;
  63. angle        += K_0 * angle_err;
  64. q_bias += K_1 * angle_err;
  65. angle_dot = gyro_m-q_bias;//也许应该用last_angle-angle
  66. }

  67. void do_balance() {

  68. sensorValue[0] = analogRead(sensorPort[0]);//Z轴加速度
  69. sensorValue[1] = analogRead(sensorPort[1]);//X轴旋转(陀螺)
  70. sensorValue[2] = analogRead(sensorPort[2]);//旋钮1
  71. sensorValue[3] = analogRead(sensorPort[3]);//旋钮2
  72. sensorValue[4] = analogRead(sensorPort[4]);//旋钮3
  73. sensorValue[5] = analogRead(sensorPort[5]);//旋钮4

  74. //算出整理过的零点值
  75. sensorAdjusted[0] = sensorValue[0] - sensorZero[0];
  76. if(abs(sensorAdjusted[0]) > 70)//如果倾斜到一定程度,就停机
  77. {
  78.     OK = false;
  79. sensorAdjusted[0] =sensorAdjusted[0]>0, 70,-70;
  80. }
  81. sensorAdjusted[1] = sensorZero[1] - sensorValue[1];/*减去初始零点*/


  82. /*根据可变电阻改变K的倍数*/
  83. //deadAreaCompensation = (sensorValue[4]+1)/10.24;
  84. //K_AD[0] = (sensorValue[2]+1)/256;//102.4;/*值在0.001~10之间变化.在AD=100的时候接近1 */
  85. //K_AD[1] = (sensorValue[3]+1)/256;//102.4;
  86. //K_AD[2] = (sensorValue[4]+1)/256;//102.4;
  87. //K_AD[3] = (sensorValue[5]+1)/256;//102.4;

  88. /*根据上一周期Torqu的值统计轮子转动积分*/
  89. wheel_ls[2] = Torque > 0, wheel_ls[0],-wheel_ls[0];
  90. wheel_rs[2] = Torque > 0, wheel_rs[0],-wheel_rs[0];
  91. wheel_ls[0] = wheel_rs[0] = 0;
  92. /*************** balance *********************************************/

  93. /*小车初始状态*/
  94. {
  95.     if(!OK)
  96.     {
  97.       if(abs(sensorAdjusted[0]) <= 3)//小车被推倒平衡位置后才启动电机
  98.       {
  99.         count=0;
  100.         OK = true;
  101.       }
  102.       for(int i = 0; i <7;i++)
  103.       {
  104.         wheel_ls[i] = 0;
  105.         wheel_rs[i] = 0;
  106.       }
  107.     }
  108. }

  109. /*balance*/
  110. {
  111.     /*GYRO_OPERATOR = 0.028123 AD读取的陀螺仪数值对应的弧度算子*/
  112.     Kalman_Filter(atan2(sensorAdjusted[0], sqrt(10000-sensorAdjusted[0]*sensorAdjusted[0])), sensorAdjusted[1] * GYRO_OPERATOR);//10000:因为只有一轴加速度计,所以虚拟一个斜边   

  113. RATE[0] = angle * SEMICIRCLE_ARC;//SEMICIRCLE_ARC=57.29578; /*半圆对应的弧度值*/
  114.     RATE[1] = angle_dot * SEMICIRCLE_ARC;
  115. }

  116. /*计算速度 double wheel_ls[8]; 0:编码器累加 1:位移(position) 2:position_dot 3:速度(position_dot_filter) 4:speedNeed 5:turnNeed 6:speedOutPut
  117. */
  118. {
  119.     wheel_ls[3] *= 0.95;              /*车轮速度滤波,wheel_ls[3] : position_dot_filter*/
  120.     wheel_ls[3] += wheel_ls[2]*0.05; /*wheel_ls[2] : position_dot*/
  121.     wheel_ls[1] += wheel_ls[3];       /*wheel_ls[1] : position*/
  122.     wheel_ls[1] += wheel_ls[4];       /*wheel_ls[4] : speedNeed*/
  123.     wheel_ls[1] = max(-50, wheel_ls[1]);
  124.     wheel_ls[1] = min(50, wheel_ls[1]);

  125.     RATE[2] = wheel_ls[3];//速度--滤波过了
  126.     RATE[3] = wheel_ls[1];//位置
  127. }

  128. /*Torque 综合所有参数算出扭矩*/
  129. {
  130.     Torque = RATE[0] * K[0] * K_AD[0] + RATE[1] * K[1] * K_AD[1] + RATE[2] * K[2] * K_AD[2] + RATE[3] * K[3]* K_AD[3];
  131.    
  132.     //根据扭矩算轮子的命令值
  133.    wheel_ls[6] = abs(Torque)+ deadAreaCompensation1;//wheel_ls[6]:扭矩输出 deadAreaCompensation1:左轮的死区补偿
  134. wheel_ls[6] = min(255, wheel_ls[6]);//限制最大扭矩255
  135.     wheel_ls[6] = OK, wheel_ls[6],0;

  136. wheel_rs[6] = abs(Torque)+ deadAreaCompensation2;
  137.     wheel_rs[6] = min(255, wheel_rs[6]);
  138.     wheel_rs[6] = OK, wheel_rs[6],0;
  139. }

  140. if(Torque > 0)
  141. {
  142.     digitalWrite(M2, HIGH);
  143.     digitalWrite(M1, LOW);
  144. }
  145. else
  146. {
  147.     digitalWrite(M2, LOW);
  148.     digitalWrite(M1, HIGH);
  149. }
  150. analogWrite(E1, wheel_ls[6]); //PWM调速a==0-255
  151. analogWrite(E2, wheel_rs[6]);
  152. }
  153. void do_msg(){
  154. if(count%100==0)
  155. {
  156.     Serial.print("$CLEAR\r\n");
  157.     Serial.print("$GO 1 1\r\n");
  158.     Serial.print("$PRINT ");

  159.     Serial.print(wheel_ls[1]);
  160.     Serial.print(" ");
  161.     Serial.print(wheel_ls[3]);
  162.     //Serial.print(" ");
  163.     //Serial.print(RATE[2]);
  164.     //Serial.print(K[0]*K_AD[0]);
  165.     //Serial.print(" ");
  166.     //Serial.print(K[1]*K_AD[1]);
  167.     //Serial.print(" ");
  168.     Serial.print("\r\n");

  169.     Serial.print("$GO 2 1\r\n");
  170.     Serial.print("$PRINT ");
  171.     //Serial.print(K[0]*K_AD[0]);
  172.     //Serial.print(" ");
  173.     //Serial.print(K[1]*K_AD[1]);
  174.     //Serial.print(" ");
  175.     //Serial.print(K[2]*K_AD[2]);
  176.     //Serial.print(" ");
  177.     //Serial.print(K[3]*K_AD[3]);
  178.     //Serial.print(count);
  179.     Serial.print(wheel_ls[5]);
  180.     Serial.print(" ");
  181.     Serial.print(wheel_rs[5]);
  182.     //Serial.print(count);
  183.     //Serial.print(Torque);
  184.     Serial.print("\r\n");
  185. }
  186. }
  187. /***************** setup-loop *************************************************/
  188. void setup() {
  189. count=0;
  190. X=Y=8;
  191. bf=-1;
  192. //init motos
  193. for (int i = 6; i <= 9; i++) {
  194.     pinMode(i, OUTPUT);
  195. }
  196. Serial.begin(9600);//115200);
  197. analogReference(EXTERNAL); //设置模拟输入为外部参考3.3V

  198. attachInterrupt(0, blinkone, CHANGE); //设置为0号中断,中断函数blink,触发方式为RISING
  199. attachInterrupt(1, blinktwo, CHANGE); //设置为0号中断,中断函数blink,触发方式为RISING
  200. }
  201. void blinkone()//中断函数
  202. {
  203. wheel_ls[0] ++;
  204. }
  205. void blinktwo()//中断函数
  206. {
  207. wheel_rs[0] ++;
  208. }

  209. void loop() {
  210. do_balance();//计算平衡
  211. do_msg();
  212. delay(3);
  213. count++;
  214. if(count>=60000)
  215.     count=0;
  216. }
复制代码
回复

使用道具 举报

发表于 2011-11-7 17:26:17 | 显示全部楼层
你自己弄的呀!
回复 支持 反对

使用道具 举报

发表于 2011-11-11 18:16:32 | 显示全部楼层
好多地方看不懂啊……高人……………………{:soso_e179:}
回复 支持 反对

使用道具 举报

发表于 2011-12-12 22:17:41 | 显示全部楼层
又见卡尔曼滤波
回复 支持 反对

使用道具 举报

发表于 2011-12-13 10:32:08 | 显示全部楼层
期待实验视频
回复 支持 反对

使用道具 举报

发表于 2012-2-29 22:14:06 | 显示全部楼层
继续学习!
回复 支持 反对

使用道具 举报

发表于 2012-12-19 11:42:02 | 显示全部楼层
学习中……………………
回复 支持 反对

使用道具 举报

发表于 2013-12-10 23:37:56 | 显示全部楼层
这个是全部代码吗
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-26 19:36 , Processed in 0.051111 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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