极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 10187|回复: 3

求助,两轮小车~

[复制链接]
发表于 2014-3-4 21:35:00 | 显示全部楼层 |阅读模式
小车用的是ARDUINO UNO+MPU6050+L289,目前再平衡状态,总是不停地抖动,下图是平衡状态角度波形图,javascript:;求大神们指点~

  1. #include <Wire.h>         
  2. #include <i2cdev.h>
  3. #include <MPU6050.h>
  4. #include <PID_v1.h>
  5. #define Left1 10          //定义左直流电机输出
  6. #define Left2 11          //定义左直流电机输出
  7. #define Right1 5          //定义右直流电机输出
  8. #define Right2 6          //定义右直流电机输出
  9. #define drift 20          //小车角度调整范围
  10. #define Gry_offset -72    //陀螺仪X轴的静态飘移。
  11. #define Gyr_Gain -0.00763 //由陀螺仪X轴读数转换为角速度值(1/131)
  12.                           //向前方向与X轴为反方向,故乘以-1
  13. #define ACC_Gain 0.000061 //由读数转换为加速度值(1/16384)
  14. #define pi 3.1415926      //定义PI值
  15. //#define K 0.715           //一阶互补滤波权重取值,不知由来,可更改。
  16. #define Q_angle 0.01      //角度数据置信度
  17. #define Q_omega 0.0003    //角速度数据置信度
  18. #define R_angle 0.01      //方差噪声
  19. unsigned long preTime = 0;//定义积分初始时间
  20. float angleG = 0;
  21. double Klm_angle;         
  22. float bias = 0;
  23. float P_00 = 0, P_01 = 0, P_10 = 0, P_11 = 0;
  24. double Setpoint, Input, Output;
  25. double temp_kp,temp_ki,temp_kd;
  26. MPU6050 accelgyro;         //MPU6050初始化
  27. int16_t ax, ay, az;
  28. int16_t gx, gy, gz;
  29. PID myPID(&Input,&Output,&Setpoint,10,0.05,0,DIRECT);


  30. void car_stop()            //小车停止函数
  31. {
  32.     analogWrite(Left1,0);      
  33.     analogWrite(Right1,0);   
  34.     analogWrite(Left2,0);   
  35.     analogWrite(Right2,0);
  36. }


  37. void setup()               //主程序初始化
  38. {
  39.     Wire.begin();
  40.     Serial.begin(9600);   
  41.     accelgyro.initialize(); //MPU6050初始化。
  42.     pinMode(Left1,OUTPUT);
  43.     pinMode(Left2,OUTPUT);
  44.     pinMode(Right1,OUTPUT);
  45.     pinMode(Right2,OUTPUT);
  46.     Wire.begin();           //I2C初始化
  47.     accelgyro.testConnection();
  48.     Setpoint=-2.00;         //设置平衡角
  49.     myPID.SetSampleTime(10);
  50.     myPID.SetMode(AUTOMATIC);
  51. }
  52. void loop()
  53. {
  54.     unsigned long now = millis();            //当前时间(ms)
  55.     float dt = (now - preTime) / 500.0;      //微分时间(s)
  56.     preTime = now;                           //上一次采样时间(ms)
  57.     accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);//读取六轴数值
  58.     float Y_Accelerometer = ay * ACC_Gain;   //转换为向前的加速度(g),为负值
  59.     float Z_Accelerometer = az * ACC_Gain;   //转换为向下的加速度(g)
  60.     float angleA= atan(Y_Accelerometer/ Z_Accelerometer)* (-180)/ pi;//加速度仪,反正切获得弧度值,乘以180度/pi
  61.                                                                    //获得角度值,乘以-1得正值                                                           
  62.     float gx_revised = gx + Gry_offset;      //陀螺仪x轴静态时修正后的角速度读数,向前为负值
  63.     float omega= Gyr_Gain* gx_revised;       //陀螺仪,转换为向前的角速度(o/s),Gyr_Gain取负,故负负得正


  64.     //卡尔曼滤波
  65.     Klm_angle += (omega - bias) * dt;          // 先验估计
  66.     P_00 += -(P_10 + P_01) * dt + Q_angle *dt;
  67.     P_01 += -P_11 * dt;
  68.     P_10 += -P_11 * dt;
  69.     P_11 += +Q_omega * dt;                     // 先验估计误差协方差
  70.     float K_0 = P_00 / (P_00 + R_angle);
  71.     float K_1 = P_10 / (P_00 + R_angle);
  72.     bias += K_1 * (angleA - Klm_angle);
  73.     Klm_angle += K_0 * (angleA - Klm_angle);   // 后验估计
  74.     P_00 -= K_0 * P_00;
  75.     P_01 -= K_0 * P_01;
  76.     P_10 -= K_1 * P_00;
  77.     P_11 -= K_1 * P_01;                        // 后验估计误差协方差
  78.     Serial.print(angleA);
  79.     Serial.print(",");
  80.     Serial.println(Klm_angle);
  81.     //PID算法结合PWM输出
  82.     if((Klm_angle>(Setpoint-drift))&&(Klm_angle<(Setpoint+drift)))
  83.     {
  84.         if((Klm_angle>Setpoint)&&(Klm_angle<(Setpoint+drift)))
  85.         {   
  86.             myPID.SetControllerDirection(REVERSE);
  87.             Input=Klm_angle;   
  88.             myPID.Compute();
  89.             analogWrite(Left2,min(Output+150,255));      
  90.             analogWrite(Right2,min(Output+150,255));      
  91.             analogWrite(Left1,0);               
  92.             analogWrite(Right1,0);                  
  93.         }
  94.         if((Klm_angle<Setpoint)&&(Klm_angle>(Setpoint-drift)))
  95.         {
  96.             myPID.SetControllerDirection(DIRECT);
  97.             Input=Klm_angle;
  98.             myPID.Compute();
  99.             analogWrite(Left1,min(Output+100,255));     
  100.             analogWrite(Right1,min(Output+100,255));      
  101.             analogWrite(Left2,0);      
  102.             analogWrite(Right2,0);   
  103.         }
  104.     }
  105.     else
  106.     {
  107.       car_stop();  
  108.      }
  109. }
复制代码

本帖子中包含更多资源

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

x
回复

使用道具 举报

发表于 2014-3-4 23:51:51 | 显示全部楼层
程序没看,说下思路好了, 看来程序应该是检测陀螺仪状态,然后调整小车姿态,保持平衡。 因为机械精度问题微小的震动也可能会被检测到,再加之车子调整幅度可能比较大,所以车子会一直抖动,往复运动于左右偏差之间。

思路,增加调整姿态的阀值,减小调整姿态的幅度。 或者根据偏离程度来决定调整幅度的大小。 也就是说,偏离1度 用 相对微弱的幅度和速度调整姿态,偏离10度,就大幅度和速度的调整姿态。
回复 支持 反对

使用道具 举报

发表于 2014-3-5 16:16:41 | 显示全部楼层
i2cdev是干啥的啊  给个呗[email protected]谢啦
回复 支持 反对

使用道具 举报

发表于 2014-3-5 16:17:28 | 显示全部楼层

i2cdev是干啥的啊  给个呗[email protected]谢啦,刚才打错了
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-10 03:18 , Processed in 0.036840 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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