自平衡小车制作

一、介绍

1、控制输入:加速度传感器和陀螺仪测得的小车倾角。当加速度传感器水平放置时,Z轴会测量到重力加速度,大小为g。当加速度传感器倾斜时,Z轴上测量的g就会变小,根据变小之前的值和之后的值,就可以算得倾角值。

        这样一看似乎只需要加速度就可以获得小车的倾角,再对此信号进行微分便可以获得倾角速度。但在实际小车运行过程中,由于小车本身的摆动所产生的加速度会在Z轴上有分量,它叠加在上述测量信号上使得输出信号无法准确反映车模的倾角。

        为了减少运动与摆动的影响,加速度传感器安装的高度应该越低越好,但是也无法彻底消除运动与摆动的影响。因此就需要引入陀螺仪,用于测量小车倾角变化的速度,即角速度。将角速度进行积分便可以得到小车的倾角。

        由于陀螺仪输出的是小车的角速度,不会受到车体运动的影响,因此该信号中噪声很小。但是由于从陀螺仪测量的角速度值获得角度值,需要经过积分运算。如果角速度值存在微小偏差或漂移,比如当小车静止时,陀螺仪的输出不为零。经过积分运算后,微小的变化也会变得很大。因此要测量小车倾角也不能全部依赖陀螺仪。

        比较理想的做法是把加速度传感器和陀螺仪组合起来使用。思路如下:每5ms读一次加速度传感器和陀螺仪的值,根据加速度传感器的值计算出一个角度值,angle_acc。再把陀螺仪的值乘以5ms,算得在5ms间隔中,小车倾角的变化值,再加上前一次计算出的小车倾角,得到angle_gyro。这样就得到了加速度传感器测量到的小车倾角和陀螺仪测量到的小车倾角。把这两个角度结合起来使用,就可以保证小车的倾角比较可靠了。结合的方法一般有两种:

        一种是互补滤波,其实就是加权计算:

float K1 =0.02;
angle = K * angle_acc + (1-K) * (angle + angle_gyro * 0.005);

        K是权值,代表更相信加速度传感器还是陀螺仪。

        还有一种是卡尔曼滤波,卡尔曼滤波是什么,自己去搜吧,资料太多了。简易型的代码如下:

float angle, angle_dot; 	
float Q_angle=0.001;// 过程噪声的协方差
float Q_gyro=0.003;//0.003 过程噪声的协方差 过程噪声的协方差为一个一行两列矩阵
float R_angle=0.5;// 测量噪声的协方差 既测量偏差
float dt=0.005;//                 
char  C_0 = 1;
float Q_bias, Angle_err;
float PCt_0, PCt_1, E;
float K_0, K_1, t_0, t_1;
float Pdot[4] ={0,0,0,0};
float PP[2][2] = { { 1, 0 },{ 0, 1 } };
/**************************************************************************
函数功能:简易卡尔曼滤波
入口参数:
Accel:加速度传感器测量角度值
Gyro: 陀螺仪测量角度值
**************************************************************************/
void Kalman_Filter(float Accel,float Gyro)		
{
	angle+=(Gyro - Q_bias) * dt; //先验估计
	Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分

	Pdot[1]=-PP[1][1];
	Pdot[2]=-PP[1][1];
	Pdot[3]=Q_gyro;
	PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
	PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差
	PP[1][0] += Pdot[2] * dt;
	PP[1][1] += Pdot[3] * dt;
		
	Angle_err = Accel - angle;	//zk-先验估计
	
	PCt_0 = C_0 * PP[0][0];
	PCt_1 = C_0 * PP[1][0];
	
	E = R_angle + C_0 * PCt_0;
	
	K_0 = PCt_0 / E;
	K_1 = PCt_1 / E;
	
	t_0 = PCt_0;
	t_1 = C_0 * PP[0][1];

	PP[0][0] -= K_0 * t_0;		 //后验估计误差协方差
	PP[0][1] -= K_0 * t_1;
	PP[1][0] -= K_1 * t_0;
	PP[1][1] -= K_1 * t_1;
		
	angle	+= K_0 * Angle_err;	 //后验估计
	Q_bias	+= K_1 * Angle_err;	 //后验估计
	angle_dot   = Gyro - Q_bias;	 //输出值(后验估计)的微分=角速度
}

        通过上面这两种方法,就可以得到比较可靠的小车倾角了,变量名为angle。

2、控制对象:小车两边电机的转速和方向。

        一般使用直流电机来制作平衡小车,直流电机驱动芯片推荐使用死区小一点的驱动芯片,比如TB6612FNG。

给PWMA、PWMB引脚通入10KHz的PWM,通过控制占空比可以控制电机的转速。

控制AIN1、AIN2、BIN1、BIN2的电平可以控制电机的转动方向。

#define myabs(m) (m>0?m:-m)     //绝对值
/**************************************************************************
函数功能:直流电机方向和转速控制
入口参数:两个电机的pwm值,有正负
**************************************************************************/
void MotorControl(int moto1,int moto2)
{
    int siqu=400;               //电机PWM死区,当PWM太小,电机转不起来。本值根据电机和驱动芯片做调节

    if(moto1<0) AIN2=1,AIN1=0;  //反转
    else        AIN2=0,AIN1=1;  //正转
    PWMA=myabs(moto1)+siqu;     //转速

    if(moto2<0)	BIN1=0,BIN2=1;
    else        BIN1=1,BIN2=0;
    PWMB=myabs(moto2)+siqu;
}

3、控制任务:

1)、控制小车平衡:通过控制两个电机正反向运动保持小车直立平衡状态,这就要使用PID算法了。

#define Angle_AIM 0    //倾角的目标值,如果传感器装得有点偏,可能本值不为0
/**************************************************************************
函数功能:小车平衡PD控制
入口参数:
Angle:小车的倾角值
Gyro:陀螺仪的测量值,即5ms间隔内倾角的变化值
返回  值:对电机转速和方向的控制值,输出给MotorControl(int moto1,int moto2)函数
**************************************************************************/
int PID_Balance(float Angle,float Gyro)
{
    float Bias;
    int pwm;
	
    Bias=Angle-Angle_AIM;    //计算角度偏差值
    pwm=Kp*Bias + Gyro*Kd;   //PD控制,kp是P系数,kd是D系数
    return pwm;              //返回电机的pwm控制值,有正负  
}

2)、控制小车运动速度:要在小车平衡PID控制的基础上加上速度PID控制,即所谓的串级PID,把速度PID的结果作为平衡PID的输入。要让小车前进,那么就不让小车的目标倾角为0,而人为给定一个大于0的倾角值,当目标倾角值大于0了,小车为了平衡,就会前进。目标倾角值越大,前进速度越快。我们可以得到下面关系式:

        式子(1)是直立PD控制,式子(2)是速度PI控制。e(k)是速度控制偏差,a1是速度控制的结果,作为目标倾角输入式子(1)。把式子(2)代入式子(1):

        从上式可以知道,加入速度环后,最终的电机PWM等于直立PD输出值减速度PI输出值乘以Kp。

/**************************************************************************
函数功能:速度PI控制
入口参数:
SpeedL:左电机测量速度值
SpeedL:右电机测量速度值
Speed_Aim:小车目标速度
返回  值:速度控制PWM
**************************************************************************/
int PID_Velocity(int SpeedL,int SpeedR,int Speed_Aim)
{
    static float pwm,bias,Integral;
	
    bias =(SpeedL+SpeedR)/2-Speed_Aim;     //计算速度偏差
	
    Integral +=bias;                       //误差累积	
    if(Integral>15000)  Integral=15000;    //积分限幅
    if(Integral<-15000)	Integral=-15000;   //积分限幅
	
    pwm=Integral*Kp+Integral*Ki;           //速度控制
    return pwm;
}

3)、控制小车运动方向:通过控制两个电机之间的转动差速实现小车转向控制。转向环仍然使用PD控制,根据上面式子的推导,我们知道只要把转向控制的结果加到电机的pwm上就可以了。其中一个电机加上转向控制结果,另一个电机减去转向控制结果,这样就造成了两个电机转速不同,进而转向。

/**************************************************************************
函数功能:转向控制
入口参数:
TurnSpeed:转向速度
gyro:陀螺仪测量到的小车转向速度
返回  值:转向控制PWM
**************************************************************************/
int PID_Turn(int TurnSpeed,float gyro)//转向控制
{
    float Turn;
    
    Turn=TurnSpeed*Kp+gyro*Kd;     //为了消除小车方向控制中的过冲,需要增加微分控制
    return Turn;
}

        其实小车的转向只需要简单的比例控制即可,可是小车上有电池等比较重的物体,具有很大的转动惯量,如果在转动过程中不加抑制,会使小车转向过冲。因此在小车转向控制中,加入了使用小车方向的变化率对电机差动控制量进行修正的控制方式。

二、代码

1、小车倾角的测量(使用MPU6050)

控制板上,小车的前进方向是MPU6050的X轴正方向。

于是倾角测量代码为:(5ms测量一次,因为要对陀螺仪进行积分,故尽量保证5ms调用间隔准确)

float K1 =0.02; 
float angle,Gyro_Balance,Gyro_Turn;  //平衡倾角 平衡陀螺仪 转向陀螺仪
void Get_Angel()
{
	float angle_acc,Accel_X,Accel_Z,Gyro_Y,Gyro_Z;
	
	Gyro_Y=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_L);    //读取Y轴陀螺仪
	Gyro_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L);    //读取Z轴陀螺仪
	Accel_X=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_L); //读取X轴加速度计
	Accel_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_L); //读取Z轴加速度计
	if(Gyro_Y>32768)  Gyro_Y-=65536;               //数据类型转换  也可通过short强制类型转换
	if(Gyro_Z>32768)  Gyro_Z-=65536;               //数据类型转换
	if(Accel_X>32768) Accel_X-=65536;              //数据类型转换
	if(Accel_Z>32768) Accel_Z-=65536;              //数据类型转换
	
	Gyro_Balance=-Gyro_Y;                          //更新平衡角速度
	angle_acc=atan2(Accel_X,Accel_Z)*180/PI;       //计算加速度传感器测量得到倾角值
	Gyro_Y=Gyro_Y/16.4;                            //陀螺仪量程转换
	
	angle = K1 * angle_acc+ (1-K1) * (angle + Gyro_Balance * 0.005);   //互补滤波,加权计算                 
	
	Gyro_Turn=Gyro_Z;                              //更新转向角速度
}

获取小车倾角(变量名为angle)之后,进行直立PD控制:

 

Balance_Pwm =PID_Balance(angle,Gyro_Balance);          //平衡PID控制

速度PI控制:

Velocity_Pwm=PID_Velocity(SpeedL,SpeedR,Speed_Aim);   //速度环PID

转向PD控制:

Turn_Pwm=PID_Turn(TurnSpeed,Gyro_Turn);   //转向PID控制

最后控制电机:

MotorControl(Balance_Pwm+Velocity_Pwm-Turn_Pwm,Balance_Pwm+Velocity_Pwm+Turn_Pwm);

 

  • 22
    点赞
  • 163
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
一、平衡小车原理: 自平衡小车是利用车模自身动力使小车保持相对的平衡,是一个动态平衡的过程。维持车模平衡的动力来自车轮的运动,由两个直流电机驱动。对车模的控制可以分解为三个控制任务: 1、控制小车平衡:通过控制小车车轮正反转使小车保持直立平衡。 2、控制小车速度:通过控制小车的倾角实现小车前后运动和速度的控制,其实最终的仍是通过控制电机的转速实现。 3、控制小车方向:通过控制小车两个电机之间的转速差来实现转向控制。 分解为三个控制任务显得相对简单一点,但是在最终的控制过程中都归结为对一个控制量的控制,这样三个任务之间就会存在耦合,会相互干扰。三个任务中控制平衡是关键,所以对小车的速度和方向控制应该尽量的平滑。 二、硬件方案设计 小车的硬件分为三个部分,分别是主控部分、小车姿态获取部分以及电机驱动部分。主控板采用目前常用的arduino UNO,同时也可以使用其他arduino通用控制板做主控。 小车姿态获取可以有很多方案,使用最多的就是通过加速度计和陀螺仪获取小车姿态。理论上只需要两轴加速度计(垂直方向Z轴和沿小车运动方向X轴)和一个单轴陀螺仪(沿小车车轮轴方向,获取绕小车轮轴的角速度)。陀螺仪通过角度积分可以获得小车角度,但是经过积分会产生累计误差,并且会越来越大,X轴与Z轴加速度计的值也可以算出小车的倾角,但是加速度计的瞬时误差较大,所以结合陀螺仪和加速度计两者获得的角度做数据融合可得真实角度。我们使用一个集成了三轴加速度计和三轴陀螺仪的集成芯片MPU6050,这样极大的简化了我们的传感器电路。 小车通过两个直流电机驱动车轮运动来获得动力,直流电机的驱动电路设计关系到整个系统的稳定性,因为电机反转时会产生反向电动势会干扰到电源系统内其他设备的运行。我们选用L298P做电机驱动器,它内部包含4通道逻辑驱动电路,可同时驱动两个直流电机,输出电流可达2.5A。 三、软件设计之小车姿态获取---卡尔曼滤波 在开始之前应该对MPU6050进行设置,主要设置角速度以及加速度的量程,加速度量程有±2g、±4g±8g与±16g,角速度量程分别为±250、±500、±1000与±2000°/sec (dps),可准确的追踪快速动作与慢速动作。在使用之前先设置好量程以便后面的换算。我们小车轮轴与传感器Y轴平行,即绕Y轴旋转则有: 那竖直方向弧度计算公式为: angle = atan2(x, z) //结果以弧度表示并介于 -pi 到 pi 之间(不包括 -pi) 如果要换算成具体角度: angle = atan2(x, z) *(180/3.14) 陀螺仪获取角速度积分得到角度公式为:anglen = anglen-1 + gyronn*dt ,式中anglen 为第N次采样的角度值,anglen-1 为第N-1次的角度值,gyronn为两次采样值之间的角速度值,dt为两次采样之间的时间。然后将换算后的两个角度数据进行卡尔曼滤波融合,可获得小车真实角度,也可以采用更简单的互补滤波算法。 注意加速度计所得角度与陀螺仪积分角度的方向。 四、软件设计之小车姿态调整---PID参数整定 小车的姿态获取最终结果是一个角度,就是小车偏离平衡位置的倾角。通过以小车的这个倾角为变量进行PID控制,输出用于控制车轮转速的PWM值,那么相当于小车只有一个角度反馈环路,虽然能使小车平衡,但是增加了控制难度,所以通常会使用带测速的电机,再加入一个小车速度反馈环路,这样使得小车更容易控制。关于PID的有下面一个简单易懂的描述: 假设我们想把一个小球稳定在一个光滑的坡顶,这显然是一个不平衡的系统,稍有扰动小球就会滚下来。假设恰好平衡的位置坐标是L,我们可以测量到小球的位置是x,那么怎么给小球施加f(x)的力反馈,让它能够平衡呢? 最直观的想法就是f(x) =Kp*(L-x),简单的说就是你在左边我就向右推,你在右边我就向左推,这就是比例因子P; 现在考虑两种情况,同样是在x位置,小球静止和小球具有速度V这两种情况。很明显,如果V>0,我们只需要施加更小的力,因为小球自身的惯性会让它运动向平衡位置。所以可以修正f(x) = Kp*(L-x) – Kd*V。因为速度一般不容易测量,我们常常用位置的变化Δx除以测量的时间差Δt来计算速度,所以这就是微分因子D; 情况继续发生变化,上面考虑的是斜坡静止的情况,如果这个变态的斜坡是移动的怎么办呢?(例如两轮平衡机器人实际上是可以运动的,对于静止的磁悬浮来说,不需要考虑这个参数)这时候我们需要不断的累加并平均x值,来计算平衡位置的L,这个就是积分因子I; 当PID用在我们自平衡小车中时,我们使用角度PD环与速度PI环进行控制。 pwm=angle*k1+angle_dot*k2+range*k3+wheel_speed*k4; PID参数整定步奏如下: 1、将k1,k2,k3,k4均设为0; 2、逐步增大k1,使得小车刚好能够来回摆动。 3、再逐步增大k2,使得小车相对平稳,太大会使小车发生抖动; 4、增大k3,使得小车能够来回走动(不是摆动也不是抖动); 5、增大k4,使得小车能稳定自平衡。 具体参数调整过程比较繁琐,需要自己体会每个参数的作用。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【ql君】qlexcel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值