ANDOON 发表于 2013-6-9 18:24:30

ARDUINO+MPU6050+步进电机的自平衡小车

本帖最后由 ANDOON 于 2013-6-9 20:12 编辑

先亮出我的程序,参看大神们的:

/*****************====================================********************/
//**************** 一阶互补滤波+ PID+ MPU6050********************/
//************************************************************************//
#include <Wire.h>
#include <i2cdev.h>
#include <MPU6050.h>
#include <AFMotor.h>
//*********************************************************/
//*********************************************************/
MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;

//********************************************************/
//*************************L293D**************************/
// two stepper motors one on each port
AF_Stepper motor1(200, 1);//LEFT
AF_Stepper motor2(200, 2);//RIGHT

#define Gry_offset 296//陀螺仪X轴的静态飘移。
#define Gyr_Gain -0.00763//由陀螺仪X轴读数转换为角速度值,=1/131 敏感比例因子131、65.5、32.8、16.4 LSB/s,向前方向与X轴为反方向,故乘以-1
#define ACC_Gain 0.000061//由读数转换为加速度值,=1/16384Sensitivity Scale Factor 16384、8192、4096、2048 LSB/g
#define pi 3.1415926
#define K 0.715//一阶互补滤波权重取值,不知由来,可更改。

/********** 互补滤波器参数 *********/
unsigned long now ;
unsigned long preTime = 0;
float angleG = 0;

/*********** PID控制器参数 *********/
unsigned long lastTime;         // 前次时间
float ITerm, lastInput;    // 积分项、前次输入
float Output = 0.0;      // PID输出值
float LOutput,ROutput;

float LSpeed_Need=0.0,RSpeed_Need=0.0;// 转弯设置

void setup(){
Wire.begin();
Serial.begin(38400);
accelgyro.initialize();//MPU6050初始化。
motor1.setSpeed(10);
motor2.setSpeed(10);
}
void loop(){
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得正值
ANGLE_1();                                                //一阶互补滤波后的输出倾斜角度
if (abs(angleA)<45) {// 角度小于45度 运行程序
      PIDD();                                             //PID控制器
      DISTAN();                                        //左右电机步进距离输出
}
   else {      // 角度大于45度 停止PWM输出
      motor1.release();
          motor2.release();
      }
   Serial.print(angleG); Serial.print("\t");
   Serial.println(Output);
}

//*********************************************************************/
//*************angleG= 一阶互补滤波后的输出倾斜角度(o)**********************/
void ANGLE_1()
{
now = millis();//当前时间(ms)
float dt = (now - preTime) / 1000.0;//微分时间(s)
preTime = now;//上一次采样时间(ms)                                                            
float gx_revised = gx + Gry_offset;//陀螺仪x轴静态时修正后的角速度读数,向前为负值
float omega= Gyr_Gain* gx_revised;//陀螺仪,转换为向前的角速度(o/s),Gyr_Gain取负,故负负得正
float angle_dt = omega * dt;//角度的单次积分值
//angleG+= angle_dt;//陀螺仪,积分获得角度值
angleG+= (Gyr_Gain * (gx + Gry_offset)) * dt;
float A= K/ (K+ dt);//陀螺仪的权值
angleG= A* (angleG+ omega* dt)+ (1-A)* angleA;//一阶互补滤波后的输出角度(o)
}
//************************PID控制器*************************************/
//*************步进电机根据倾斜程度调整输出距离***************************/
//************左电机输出距离LOutput**************************************/
//************右电机输出距离ROutput**************************************/
//********************************************************************/
void PIDD(){
   

}
//**********************左右电机步进距离输出******************************/
//***************************************************************/
void DISTAN(){
    stepper1.setMaxSpeed(300.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(LOutput);
   
    stepper2.setMaxSpeed(300.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(ROutput);
   
    stepper1.run();
    stepper2.run();
}

望大神们帮忙修改PID控制和步进电机控制程序,小弟谢谢了。

ANDOON 发表于 2013-6-9 18:25:46

电机驱动是L293D模块。

学慧放弃 发表于 2013-6-9 19:29:05

那平衡怎么和前进结合的???

FoieDEEEE_仲敬 发表于 2013-6-9 19:35:03

很复杂啊,看不懂==。
把这些东西弄成一个库该多好

ANDOON 发表于 2013-6-9 19:39:32

学慧放弃 发表于 2013-6-9 19:29 static/image/common/back.gif
那平衡怎么和前进结合的???

//************************PID控制器*************************************/
//*************步进电机根据倾斜程度调整输出步进距离***************************/
//************左电机输出距离LOutput**************************************/
//************右电机输出距离ROutput**************************************/
   //********************************************************************/
void PIDD(){
   

}
//**********************左右电机步进距离输出******************************/
//***************************************************************/
void DISTAN(){
   stepper1.setMaxSpeed(300.0);
   stepper1.setAcceleration(100.0);
   stepper1.moveTo(LOutput);
   
    stepper2.setMaxSpeed(300.0);
   stepper2.setAcceleration(100.0);
   stepper2.moveTo(ROutput);
   
    stepper1.run();
   stepper2.run();
}

学慧放弃 发表于 2013-6-9 19:47:20

ANDOON 发表于 2013-6-9 19:39 static/image/common/back.gif
//************************PID控制器*************************************/
//*************步进电机 ...

喔,你那小车平衡性能好不???不是说陀螺仪算法还是有很大误差吗??

ANDOON 发表于 2013-6-9 19:58:01

学慧放弃 发表于 2013-6-9 19:47 static/image/common/back.gif
喔,你那小车平衡性能好不???不是说陀螺仪算法还是有很大误差吗??

误差不大。。不会控制它平衡,不会算应该让小车步进多少,才能平衡。

学慧放弃 发表于 2013-6-9 21:05:04

ANDOON 发表于 2013-6-9 19:58 static/image/common/back.gif
误差不大。。不会控制它平衡,不会算应该让小车步进多少,才能平衡。

你可以参考德国四轴的算法看看

L╃→煌/xin 发表于 2013-8-17 16:24:47

步进电机做不了平衡车吧?

ANDOON 发表于 2013-9-1 21:38:47

L╃→煌/xin 发表于 2013-8-17 16:24 static/image/common/back.gif
步进电机做不了平衡车吧?

基于Cortex-M4与步进电机下两轮自平衡小车的移动控制
http://www.amobbs.com/thread-5531409-1-1.html

dalywan 发表于 2013-9-1 22:40:12

同感,我也觉得步进电机跑起来真的很慢啊。

tangmao48 发表于 2013-9-1 23:16:39

第一次见到有人用步进电机做平衡车

ANDOON 发表于 2013-9-2 13:04:13

本帖最后由 ANDOON 于 2013-9-2 13:07 编辑

/*****************====================================********************/
//**************** 一阶互补滤波+ PID+ MPU6050********************/
//************************************************************************//
#include <Wire.h>
#include <i2cdev.h>
#include <MPU6050.h>
//*********************************************************/
//*********************************************************/
MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;

//********************************************************/
//*************************MOTOR**************************/
// Define two steppers and the pins they will use
int dirPin_1 = 8;
int stepperPin_1 = 9;
int dirPin_2 = 6;
int stepperPin_2 = 7;


#define Gry_offset 296//陀螺仪X轴的静态飘移。
#define Gyr_Gain -0.00763//由陀螺仪X轴读数转换为角速度值,=1/131 敏感比例因子131、65.5、32.8、16.4 LSB/s,向前方向与X轴为反方向,故乘以-1
#define ACC_Gain 0.000061//由读数转换为加速度值,=1/16384Sensitivity Scale Factor 16384、8192、4096、2048 LSB/g
#define pi 3.1415926
#define K 0.715//一阶互补滤波权重取值,不知由来,可更改。

/********** 互补滤波器参数 *********/
unsigned long now ;
unsigned long preTime = 0;
float angleG = 0;

/*********** PID控制器参数 *********/
unsigned long lastTime = 0;         // 前次时间
float ITerm = 0.0, lastInput = 0.0;    // 积分项、前次输入
float Output = 0.0;      // PID输出值
float LOutput,ROutput;

float LSpeed_Need=0.0,RSpeed_Need=0.0;// 转弯设置

void setup(){
Wire.begin();
Serial.begin(38400);
accelgyro.initialize();//MPU6050初始化。
pinMode(dirPin_1, OUTPUT);
pinMode(stepperPin_1, OUTPUT);
pinMode(dirPin_2, OUTPUT);
pinMode(stepperPin_2, OUTPUT);
}
void loop(){
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得正值
now = millis();//当前时间(ms)
float dt = (now - preTime) / 1000.0;//微分时间(s)
preTime = now;//上一次采样时间(ms)                                                            
float gx_revised = gx + Gry_offset;//陀螺仪x轴静态时修正后的角速度读数,向前为负值
float omega= Gyr_Gain* gx_revised;//陀螺仪,转换为向前的角速度(o/s),Gyr_Gain取负,故负负得正
float angle_dt = omega * dt;//角度的单次积分值
//angleG+= angle_dt;//陀螺仪,积分获得角度值
angleG+= (Gyr_Gain * (gx + Gry_offset)) * dt;
float A= K/ (K+ dt);//陀螺仪的权值
angleG= A* (angleG+ omega* dt)+ (1-A)* angleA;//一阶互补滤波后的输出角度(o)
//********************************************************************
//*********************************************************************
if (abs(angleG)<45) {    // 角度小于45度 运行程序
      
      PIDD();
      PWMB();
   }
   Serial.print(angleG); Serial.print("\t");
   Serial.println(Output);
}
//*********************************************************************/
//********************************************************************/
/**********=================PID控制器====================*************/
//********************************************************************/
void PIDD(){
    now = millis();                                       // 当前时间(ms)
    float TimeChange = (now - lastTime) / 1000.0;               // 采样时间(s)
    float Kp = 10.0, Ki = 0.23, Kd = 0.0;                  // 比例系数、积分系数、微分系数
    float SampleTime = 0.1;                                 // 采样时间(s)
    float Setpoint =-2.0;                                  // 设定目标值(degree)
    //float outMin = -400.0, outMax = +400.0;                   // 输出上限、输出下限
    if(TimeChange >= SampleTime) {                              // 到达预定采样时间时
      float Input = angleG;                              // 输入赋值
      float error = Setpoint - Input;                     // 偏差值
      ITerm+= (Ki * error * TimeChange);                      // 计算积分项
       // ITerm = constrain(ITerm, outMin, outMax);         // 限定值域
      float DTerm = Kd * (Input - lastInput) / TimeChange;    // 计算微分项
      Output = Kp * error + ITerm + DTerm;                // 计算输出值
       // Output = constrain(Output, outMin, outMax);         // 限定值域
      LOutput=Output+RSpeed_Need;                         //左电机
      ROutput=Output-RSpeed_Need;                         //右电机
      lastInput = Input;                                  // 记录输入值
      lastTime = now;                                     // 记录本次时间
    }
}
//**********************PWM调速输出******************************/
//***************************************************************/
void PWMB(){
if(Output > 0){
    step_forwards(Output);
}
if (Output < 0){
    step_backwards(abs(Output));
}
}
//**********************电机运转控制******************************/
//***************************************************************/
void step_forwards(int speeds){
    digitalWrite(dirPin_1,0);
    digitalWrite(dirPin_2,1);
   
    digitalWrite(stepperPin_1, HIGH);
    digitalWrite(stepperPin_2, HIGH);
    delayMicroseconds(speeds);
    digitalWrite(stepperPin_1, LOW);
    digitalWrite(stepperPin_2, LOW);
    delayMicroseconds(speeds);
}
void step_backwards(int speeds){
    digitalWrite(dirPin_1,1);
    digitalWrite(dirPin_2,0);
   
    digitalWrite(stepperPin_1, HIGH);
    digitalWrite(stepperPin_2, HIGH);
    delayMicroseconds(speeds);
    digitalWrite(stepperPin_1, LOW);
    digitalWrite(stepperPin_2, LOW);
    delayMicroseconds(speeds);
}最终能够稳定站立的程序,使用LV8731驱动步进电机,L293输出电流太小,容易热。

ANDOON 发表于 2013-9-2 13:08:33

dalywan 发表于 2013-9-1 22:40 static/image/common/back.gif
同感,我也觉得步进电机跑起来真的很慢啊。

基于Cortex-M4与步进电机下两轮自平衡小车的移动控制
http://www.amobbs.com/thread-5531409-1-1.html

ANDOON 发表于 2013-9-2 13:08:54

tangmao48 发表于 2013-9-1 23:16 static/image/common/back.gif
第一次见到有人用步进电机做平衡车

基于Cortex-M4与步进电机下两轮自平衡小车的移动控制
http://www.amobbs.com/thread-5531409-1-1.html
页: [1] 2
查看完整版本: ARDUINO+MPU6050+步进电机的自平衡小车