幻的结界 发表于 2017-3-29 16:49:16

求助:Arduino自平衡小车电机一驱动就不能继续读mpu6050数据

背景:arduino uno r3,mpu6050用i2c,l298n驱动,蓝牙从,直流减速电机,电源18650两节实际电压8v左右一路供arduino一路升压供驱动

出现问题:调试过程中会出现电机突然停在某个转速上不再更新,期间角度输出不再更新;经过一段时间的折腾烧芯片之类的现在问题变严重,电机一转就读不了mpu6050数据。情况类似 http://www.geek-workshop.com/thread-1548-1-1.html

自己折腾期间成果如下:
确定在软件中的具体停止运行的语句位置:
   循环中主控芯片读取当前倾角传感器模块获得的姿态信息

确定出错条件:
   未给电机驱动供电时,正常读取
   电机供电但PWM值给定较小,电机未能正常转动时,正常读取
   电机供电且给定PWM值较大,电机正常转动后,
                           较低转速下可以正常读取几秒,高转速下无法读取

目前已排除如下原因:
   由于驱动与主控模块使用同一电源产生的电压干扰
   MPU6050运行时受电机电磁干扰
   Arduino主控模块电路存在问题导致的IIC总线受阻

有没有大神有遇到这个问题恳切地希望指导一二~

程序如下:
////////////基于Arduino的两轮自平衡机器人 ////////////
#include "Wire.h"   //Wire库
#include "I2Cdev.h"   //IIC总线
#include "MPU6050.h"//加速度计和陀螺仪传感器

int Encoder_left =2;//中断0,用于左轮转速测量
int C_left =4;
int Encoder_right= 3; //中断1,用于右轮转速测量
int C_right =5;
int E_left =10;       //左轮控制及输出
int M_left =8;
int M_left2 =9;
int E_right =11;      //右轮控制及输出
int M_right =12;
int M_right2 =13;

int PWM_left =0;      //左轮PWM输出值
int PWM_right =0;   //右轮PWM输出值

int count_left =0;    //左轮转速
int count_right =0;   //右轮转速

MPU6050 accelgyro;
int16_t ax, ay, az, gx, gy, gz;
float Angle_ax;       //由加速度计算的倾斜角度
float Gyro_gy;      //由Y轴陀螺仪计算得到的角速度
float Angle;          //小车倾斜角度
float Setpoint =-2; //小车直立平衡倾角

char val = 'Z';       //蓝牙遥控信号暂存
int Speed_need =0;
int Turn_need =0;
float speeds,speeds_filter, positions;
float diff_speeds,diff_speeds_all;

float K =0.95;//一阶互补滤波系数
float dt =0.005;
float Kp =25, Kd =0.5, Ksp =0, Ksi =Ksp/200;
int Output =0;

void Code_left() { //左轮编码器计数中断程序   
if (digitalRead(Encoder_left) == LOW) {   
    if (digitalRead(C_left) == LOW)      count_left--;
    else   count_left++;
}
else {
    if (digitalRead(C_left) == LOW)      count_left++;
    else   count_left--;
}
}

void Code_right() { //右轮编码器计数中断程序   
if (digitalRead(Encoder_right) == LOW) {
    if (digitalRead(C_right) == LOW)   count_right++;
    else   count_right--;
}
else {
    if (digitalRead(C_right) == LOW)   count_right--;
    else   count_right++;
}
}

void setup() {
   Wire.begin();
   Serial.begin(115200);
   accelgyro.initialize(); //MPU6050初始化
   delay(100);

   pinMode(E_left, OUTPUT);pinMode(M_left, OUTPUT);pinMode(M_left2, OUTPUT);//左轮控制引脚
   pinMode(E_right, OUTPUT); pinMode(M_right, OUTPUT); pinMode(M_right2, OUTPUT); //右轮控制引脚
   pinMode(6, OUTPUT);digitalWrite(6,HIGH);             //电机编码器正极
   pinMode(7, OUTPUT);digitalWrite(7,HIGH);
   pinMode(Encoder_left, INPUT);pinMode(C_left, INPUT); //编码器信号读取
   pinMode(Encoder_right, INPUT); pinMode(C_right, INPUT);

   attachInterrupt(0, Code_left, CHANGE); attachInterrupt(1, Code_right, CHANGE); //利用跳变沿进入中断程序测速
}

void SetMotorVoltage(int LeftVol, int RightVol) { //电机控制
    if(LeftVol >= 0)
    {digitalWrite(M_left,HIGH);
   digitalWrite(M_left2,LOW);}
    else
    {digitalWrite(M_left,LOW);
   digitalWrite(M_left2,HIGH);
   LeftVol = -LeftVol;}
    if(RightVol >= 0)
    {digitalWrite(M_right,HIGH);
   digitalWrite(M_right2,LOW);}
    else
    {digitalWrite(M_right,LOW);
   digitalWrite(M_right2,HIGH);
   RightVol = -RightVol;}
   
    if(LeftVol > 255){LeftVol = 250;}//防止PWM值超过255
    if(RightVol > 255) {RightVol = 250;} //防止PWM值超过255
   
    analogWrite(E_left,LeftVol);
    analogWrite(E_right,RightVol);
}

void Angle_Calcu(void) { //计算当前倾角
    Angle_ax = (ax-955)/263; //去除零点偏移955,//±2g //16384*0.92*3.14/180 //弧度转换为度
    Gyro_gy = -(gy-239)/131; //去除零点偏移239,//±250°/s //131 //负号为方向处理
    Angle = K*(Angle+Gyro_gy*dt)+(1-K)*Angle_ax; //一阶互补滤波
    Serial.print(millis());Serial.print("\t");Serial.println(Angle);                                                                                                   
}

void PWM_Calcu(void) { //计算输出PWM值
if (abs(Angle-Setpoint) > 30) { //角度大于30度时停止PWM输出速度积分清零
      SetMotorVoltage(0,0);
      positions = 0;
      }
else {      
      diff_speeds = (count_left - count_right)*0.5; //求得两轮速度差用于直行时的转向调整
      diff_speeds_all += diff_speeds;
      speeds = (count_left + count_right)*0.5;
      speeds_filter = 0.8*speeds_filter+0.2*speeds; //一阶互补滤波
      positions += speeds_filter;
      positions -= Speed_need;
      positions = constrain(positions, -200, 200);//抗积分饱和

      count_left = 0;                               //编码器测得速度清零
      count_right = 0;

      Output = Kp*(Angle-Setpoint)+Kd*Gyro_gy - (Ksp*speeds_filter+Ksi*positions); //角度环负反馈和速度环正反馈输出叠加
      Serial.println(Output);

      if(Turn_need == 0) { //转向环负反馈输出叠加及转向控制
      PWM_left = Output+diff_speeds_all;
      PWM_right = Output-diff_speeds_all;
      }
      else {
      PWM_left = Output+Turn_need;
      PWM_right = Output-Turn_need;
      }

      SetMotorVoltage(PWM_left,PWM_right);
      }
}

void loop() {
   if (Serial.available() > 0) //读蓝牙指令
   {
   val = Serial.read();
   if   (val=='A') {Speed_need=10;Turn_need=0;   Serial.println(val);} //前进
   else if(val=='B') {Speed_need=-10; Turn_need=0;   Serial.println(val);} //后退
   else if(val=='C') {Speed_need=0;   Turn_need=30;Serial.println(val);} //左转
   else if(val=='D') {Speed_need=0;   Turn_need=-30; Serial.println(val);} //右转
   else if(val=='Z') {Speed_need=0;   Turn_need=0;   Serial.println(val);} //直立
   else if(val=='E') {Kp+=1;   val = 'Z'; Serial.print("Kp="); Serial.println(Kp);}
   else if(val=='F') {Kp-=1;   val = 'Z'; Serial.print("Kp="); Serial.println(Kp);}
   else if(val=='G') {Kd+=0.01;val = 'Z'; Serial.print("Kd="); Serial.println(Kd);}
   else if(val=='H') {Kd-=0.01;val = 'Z'; Serial.print("Kd="); Serial.println(Kd);}
   else if(val=='I') {Ksp+=10; val = 'Z'; Serial.print("Ksp=");Serial.println(Ksp);}
   else if(val=='J') {Ksp-=10; val = 'Z'; Serial.print("Ksp=");Serial.println(Ksp);}
   }   
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //读MPU6050数据
    Angle_Calcu();
    PWM_Calcu();   
}





IceWater 发表于 2017-4-5 16:25:51

我也遇到了这样的问题。
我猥琐的解决办法有3个,
1.mpu6050读取数据时将电机睡眠,读取完后再唤醒电机。
2.分别在2个单片机上单独工作,然后数据传输给电机的主板,这样就互不干扰了。
3.不读取陀螺仪的数据,只使用加速度计的数据。

靳靳 发表于 2017-4-10 08:27:37

解决没啊,是不是独立供电就好了啊

靳靳 发表于 2017-4-10 09:50:56

你的那个去零点漂移是什么啊

靳靳 发表于 2017-4-10 09:51:42

void Angle_Calcu(void) { //计算当前倾角
    Angle_ax = (ax-955)/263; //去除零点偏移955,//±2g //16384*0.92*3.14/180 //弧度转换为度
    Gyro_gy = -(gy-239)/131; //去除零点偏移239,//±250°/s //131 //负号为方向处理
    Angle = K*(Angle+Gyro_gy*dt)+(1-K)*Angle_ax; //一阶互补滤波
    Serial.print(millis());Serial.print("\t");Serial.println(Angle);
那个955和239怎么确定的啊????????

mayunzhi 发表于 2017-9-16 18:35:59

靳靳 发表于 2017-4-10 09:51
void Angle_Calcu(void) { //计算当前倾角
    Angle_ax = (ax-955)/263; //去除零点偏移955,//±2g //163 ...

我也想问,估计作者也不知道

lzj110108718 发表于 2020-6-23 11:49:15

大家这个问题解决了吗我现在和楼主遇到了一样得问题
页: [1]
查看完整版本: 求助:Arduino自平衡小车电机一驱动就不能继续读mpu6050数据