☆与☆ 发表于 2014-3-4 21:35:00

求助,两轮小车~

小车用的是ARDUINO UNO+MPU6050+L289,目前再平衡状态,总是不停地抖动,下图是平衡状态角度波形图,javascript:;求大神们指点~
#include <Wire.h>         
#include <i2cdev.h>
#include <MPU6050.h>
#include <PID_v1.h>
#define Left1 10          //定义左直流电机输出
#define Left2 11          //定义左直流电机输出
#define Right1 5          //定义右直流电机输出
#define Right2 6          //定义右直流电机输出
#define drift 20          //小车角度调整范围
#define Gry_offset -72    //陀螺仪X轴的静态飘移。
#define Gyr_Gain -0.00763 //由陀螺仪X轴读数转换为角速度值(1/131)
                        //向前方向与X轴为反方向,故乘以-1
#define ACC_Gain 0.000061 //由读数转换为加速度值(1/16384)
#define pi 3.1415926      //定义PI值
//#define K 0.715         //一阶互补滤波权重取值,不知由来,可更改。
#define Q_angle 0.01      //角度数据置信度
#define Q_omega 0.0003    //角速度数据置信度
#define R_angle 0.01      //方差噪声
unsigned long preTime = 0;//定义积分初始时间
float angleG = 0;
double Klm_angle;         
float bias = 0;
float P_00 = 0, P_01 = 0, P_10 = 0, P_11 = 0;
double Setpoint, Input, Output;
double temp_kp,temp_ki,temp_kd;
MPU6050 accelgyro;         //MPU6050初始化
int16_t ax, ay, az;
int16_t gx, gy, gz;
PID myPID(&Input,&Output,&Setpoint,10,0.05,0,DIRECT);


void car_stop()            //小车停止函数
{
    analogWrite(Left1,0);      
    analogWrite(Right1,0);   
    analogWrite(Left2,0);   
    analogWrite(Right2,0);
}


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


    //卡尔曼滤波
    Klm_angle += (omega - bias) * dt;          // 先验估计
    P_00 += -(P_10 + P_01) * dt + Q_angle *dt;
    P_01 += -P_11 * dt;
    P_10 += -P_11 * dt;
    P_11 += +Q_omega * dt;                     // 先验估计误差协方差
    float K_0 = P_00 / (P_00 + R_angle);
    float K_1 = P_10 / (P_00 + R_angle);
    bias += K_1 * (angleA - Klm_angle);
    Klm_angle += K_0 * (angleA - Klm_angle);   // 后验估计
    P_00 -= K_0 * P_00;
    P_01 -= K_0 * P_01;
    P_10 -= K_1 * P_00;
    P_11 -= K_1 * P_01;                        // 后验估计误差协方差
    Serial.print(angleA);
    Serial.print(",");
    Serial.println(Klm_angle);
    //PID算法结合PWM输出
    if((Klm_angle>(Setpoint-drift))&&(Klm_angle<(Setpoint+drift)))
    {
      if((Klm_angle>Setpoint)&&(Klm_angle<(Setpoint+drift)))
      {   
            myPID.SetControllerDirection(REVERSE);
            Input=Klm_angle;   
            myPID.Compute();
            analogWrite(Left2,min(Output+150,255));      
            analogWrite(Right2,min(Output+150,255));      
            analogWrite(Left1,0);               
            analogWrite(Right1,0);                  
      }
      if((Klm_angle<Setpoint)&&(Klm_angle>(Setpoint-drift)))
      {
            myPID.SetControllerDirection(DIRECT);
            Input=Klm_angle;
            myPID.Compute();
            analogWrite(Left1,min(Output+100,255));   
            analogWrite(Right1,min(Output+100,255));      
            analogWrite(Left2,0);      
            analogWrite(Right2,0);   
      }
    }
    else
    {
      car_stop();
   }
}

shihaipeng04 发表于 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]谢啦,刚才打错了
页: [1]
查看完整版本: 求助,两轮小车~