求助: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();
}
我也遇到了这样的问题。
我猥琐的解决办法有3个,
1.mpu6050读取数据时将电机睡眠,读取完后再唤醒电机。
2.分别在2个单片机上单独工作,然后数据传输给电机的主板,这样就互不干扰了。
3.不读取陀螺仪的数据,只使用加速度计的数据。 解决没啊,是不是独立供电就好了啊
你的那个去零点漂移是什么啊
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-4-10 09:51
void Angle_Calcu(void) { //计算当前倾角
Angle_ax = (ax-955)/263; //去除零点偏移955,//±2g //163 ...
我也想问,估计作者也不知道 大家这个问题解决了吗我现在和楼主遇到了一样得问题
页:
[1]