极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 34918|回复: 7

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

[复制链接]
发表于 2017-3-29 16:49:16 | 显示全部楼层 |阅读模式
背景: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总线受阻

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

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

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

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

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

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

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

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

  34. void Code_left() { //左轮编码器计数中断程序   
  35.   if (digitalRead(Encoder_left) == LOW) {     
  36.     if (digitalRead(C_left) == LOW)      count_left--;  
  37.     else     count_left++;
  38.   }
  39.   else {
  40.     if (digitalRead(C_left) == LOW)      count_left++;
  41.     else     count_left--;
  42.   }
  43. }

  44. void Code_right() { //右轮编码器计数中断程序   
  45.   if (digitalRead(Encoder_right) == LOW) {
  46.     if (digitalRead(C_right) == LOW)     count_right++;
  47.     else     count_right--;
  48.   }
  49.   else {
  50.     if (digitalRead(C_right) == LOW)     count_right--;
  51.     else     count_right++;
  52.   }
  53. }

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

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

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

  67. void SetMotorVoltage(int LeftVol, int RightVol) { //电机控制
  68.     if(LeftVol >= 0)
  69.     {digitalWrite(M_left,HIGH);
  70.      digitalWrite(M_left2,LOW);}
  71.     else
  72.     {digitalWrite(M_left,LOW);
  73.      digitalWrite(M_left2,HIGH);
  74.      LeftVol = -LeftVol;}
  75.     if(RightVol >= 0)
  76.     {digitalWrite(M_right,HIGH);
  77.      digitalWrite(M_right2,LOW);}
  78.     else
  79.     {digitalWrite(M_right,LOW);
  80.      digitalWrite(M_right2,HIGH);
  81.      RightVol = -RightVol;}
  82.      
  83.     if(LeftVol > 255)  {LeftVol = 250;}  //防止PWM值超过255
  84.     if(RightVol > 255) {RightVol = 250;} //防止PWM值超过255
  85.    
  86.     analogWrite(E_left,LeftVol);
  87.     analogWrite(E_right,RightVol);
  88. }

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

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

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

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

  112.       if(Turn_need == 0) { //转向环负反馈输出叠加及转向控制
  113.         PWM_left = Output+diff_speeds_all;
  114.         PWM_right = Output-diff_speeds_all;
  115.         }
  116.       else {
  117.         PWM_left = Output+Turn_need;
  118.         PWM_right = Output-Turn_need;
  119.         }

  120.         SetMotorVoltage(PWM_left,PWM_right);
  121.       }
  122. }

  123. void loop() {
  124.    if (Serial.available() > 0) //读蓝牙指令
  125.    {
  126.      val = Serial.read();
  127.      if     (val=='A') {Speed_need=10;  Turn_need=0;   Serial.println(val);} //前进
  128.      else if(val=='B') {Speed_need=-10; Turn_need=0;   Serial.println(val);} //后退
  129.      else if(val=='C') {Speed_need=0;   Turn_need=30;  Serial.println(val);} //左转
  130.      else if(val=='D') {Speed_need=0;   Turn_need=-30; Serial.println(val);} //右转
  131.      else if(val=='Z') {Speed_need=0;   Turn_need=0;   Serial.println(val);} //直立
  132.      else if(val=='E') {Kp+=1;   val = 'Z'; Serial.print("Kp="); Serial.println(Kp);}
  133.      else if(val=='F') {Kp-=1;   val = 'Z'; Serial.print("Kp="); Serial.println(Kp);}
  134.      else if(val=='G') {Kd+=0.01;val = 'Z'; Serial.print("Kd="); Serial.println(Kd);}
  135.      else if(val=='H') {Kd-=0.01;val = 'Z'; Serial.print("Kd="); Serial.println(Kd);}
  136.      else if(val=='I') {Ksp+=10; val = 'Z'; Serial.print("Ksp=");Serial.println(Ksp);}
  137.      else if(val=='J') {Ksp-=10; val = 'Z'; Serial.print("Ksp=");Serial.println(Ksp);}  
  138.    }   
  139.     accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //读MPU6050数据
  140.     Angle_Calcu();
  141.     PWM_Calcu();   
  142. }
复制代码





回复

使用道具 举报

发表于 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怎么确定的啊????????
回复 支持 反对

使用道具 举报

发表于 2017-9-16 18:35:59 | 显示全部楼层
靳靳 发表于 2017-4-10 09:51
void Angle_Calcu(void) { //计算当前倾角
    Angle_ax = (ax-955)/263; //去除零点偏移955,//±2g //163 ...

我也想问,估计作者也不知道
回复 支持 反对

使用道具 举报

发表于 2020-6-23 11:49:15 | 显示全部楼层
大家这个问题解决了吗  我现在和楼主遇到了一样得问题
回复 支持 反对

使用道具 举报

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

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

Archiver|联系我们|极客工坊

GMT+8, 2024-4-19 13:09 , Processed in 0.039804 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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