直立代码分析__两轮平衡小车原理

本文依据网上资源整理而来,适用于初学直立车者。

一、原理

平衡小车是通过两个电机运动下实现小车不倒下直立行走的多功能智能小

车,在外力的推拉下,小车依然保持不倒下。这么一说可能还没有很直观的了解

究竟什么是平衡小车,不过这个平衡小车实现的原理其实是在人们生活中的经验

得来的。如果通过简单的练习,一般人可以通过自己的手指把木棒直立而不倒的

放在指尖上,所以练习的时候,需要学会的两个条件:一是放在指尖上可以移动

二是通过眼睛观察木棒的倾斜角度和倾斜趋勢(角速度)。通过手指的移动去抵

消木棒倾斜的角度和趋势,使得木棒能直立不倒。这样的条件是不可以缺一的,

实际上加入这两个条件,控制过程中就是负反馈机制。

而世界上没有任何一个人可以蒙眼不看,就可以直立木棒的,因为没有眼睛

的负反馈,就不知道笔的倾斜角度和趋势。这整个过程可以用一个执行式表达:

 

 

 

 

 

 

 

 

 

二、平衡代码

balance.c

#include "Balance.h"

S_FLOAT_XYZ 
	GYRO_Real,		// 陀螺仪转化后的数据
	ACC_Real,		// 加速度计转化后的数据
	Attitude_Angle,	// 当前角度
	Last_Angle,		// 上次角度
	Target_Angle;	// 目标角度
	

S_INT16_XYZ
	GYRO,			// 陀螺仪原始数据
	GYRO_Offset,	// 陀螺仪温飘
	GYRO_Last,		// 陀螺仪上次数据
	ACC, 			// 加速度计数据
	ACC_Offset,		// 加速度计温飘
	ACC_Last;		// 加速度计上次数据
S_INT32_XYZ
	Tar_Ang_Vel,	// 目标角速度
	Tar_Ang_Vel_Last;	// 上次目标角速度

int32 
	Speed_Now = 0,	// 当前实际速度
	Speed_Min = 0,	// 左右最小速度
	Speed_Set = 0, 	// 目标设定速度
	Theory_Duty = 0,// 理论直立占空比
	Vel_Set = 0,	// 目标转向角速度
	Direct_Parameter = 0,// 转向系数
	Direct_Last = 0,
	Radius = 0;		// 目标转向半径倒数

uchar Point = 80;
int32 Difference = 0;
  
	  			/* 各种标志位,放定时器中进行时序控制 */
char Speed_Flag, Angle_Flag, Ang_Velocity_Flag, DMP_Flag;
/********************************************************/

/********************* 串级平衡控制 *********************/ 
// 频率控制在定时器中设置
void Balance_Control(void)
{
	if (Ang_Velocity_Flag)	// 直立角速度环	2ms
	{
		Ang_Velocity_Flag = 0;
		
		MPU6050_GetData(&GYRO, &ACC);	// 读取陀螺仪数据
		Data_Filter();					// 对原始数据滑动滤波												
												/* 角速度环作为最内环控制直立 */
		Theory_Duty += PID_Increase(&Ang_Vel_PID, Ang_Vel, (int32)(GYRO_Real.Y*10),  (int32)(Tar_Ang_Vel.Y));	// 计算直立PWM  (int32)(Tar_Ang_Vel.Y)
		Theory_Duty = range_protect(Theory_Duty, -950, 950);
			
//		if (System_OK)       
//		{													//Speed_Min
//			Direct_Parameter = PID_Realize(&Direct_PID, Direct, (int32)(GYRO_Real.Z*100), Radius*Speed_Min);// 转向环左正右负
//			Direct_Parameter = range_protect(Direct_Parameter, -1200, 1200);
//		}
//		
//		Direct_Last = Direct_Last*0.3 + Direct_Parameter*0.7;	// 更新上次角速度环结果
		
		MOTOR_Duty_Left  =Theory_Duty ;	// 左右电机根据转向系数调整差速- Direct_Last
		MOTOR_Duty_Right =Theory_Duty ;       //+ Direct_Last	

//		if (Run_Flag)
//		{
			MOTOR_Control(MOTOR_Duty_Left, MOTOR_Duty_Right);	// 控制左右电机
//		}
//		else
//		{
//			if (Stop_Flag)
//			{
//				if (Speed_Now > 20)
//				{
//					MOTOR_Control(-350, -350);
//				}
//				else
//				{
//					MOTOR_Control(0, 0);
//				}
//			}
//
//			else
//			{
//				MOTOR_Control(0, 0);
//			}
//		}
		Get_Attitude();
		mpu_dmp_get_data(&Attitude_Angle.Y, &Attitude_Angle.X, &Attitude_Angle.Z);	// 使用DMP直接读取欧拉角
	        
        }       
	
               
	if (Angle_Flag)		// 直立角度环	10ms
	{
		Angle_Flag = 0;	
                Speed_Measure();// 获取当前速度/* 角度环加到角速度环上串级控制 */
		Tar_Ang_Vel.Y = PID_Realize(&Angle_PID, Angle, (int32)(Attitude_Angle.Y*100), (int32)Target_Angle.Y);	// 结果为放大10倍的目标角速度	(int32)Target_Angle.Y
//		Tar_Ang_Vel.Y = range_protect(Tar_Ang_Vel.Y, -1500, 1500);	// 注意正负号
	}
	if (Speed_Flag)		// 速度环	100ms
	{
		Speed_Flag = 0;
		Target_Angle.Y = PID_Realize(&MOTOR_PID, MOTOR, Speed_Now, Speed_Set);	// 结果为放大100倍的目标角度
		Target_Angle.Y += Zero_Angle*100;	// 目标角度叠加在零点上	
 //               Target_Angle.Y = range_protect((int32)Target_Angle.Y, 1000, 4000);	// -44 22

		Speed_Min = Speed_Min * 0.1 + Speed_Now * 0.9;
		if (Speed_Min < 40)
		{
			Speed_Min = 40;
		}
	}
}

/* 初始化用到的一些变量 */
void Balance_Init(void)
{
	Attitude_Angle.Y = 0;
	Target_Angle.Y = 0;
	Tar_Ang_Vel.Y = 0;
	Tar_Ang_Vel.Z = 0;
}

 balance.h

#ifndef __BALANCE_H__
#define __BALANCE_H__
#include "common.h"
#include "include.h"

#define Zero_Angle -37.8f	// 蓝色电池-3.8  
//#define Zero_Angle 22.0f	// 白色电池

extern S_FLOAT_XYZ 
	GYRO_Real,		// 陀螺仪转化后的数据
	ACC_Real,		// 加速度计转化后的数据
	Attitude_Angle,	// 当前角度 
	Last_Angle,		// 上次角度
	Target_Angle;	// 目标角度
	

extern S_INT16_XYZ
	GYRO,			// 陀螺仪原始数据
	GYRO_Offset,	// 陀螺仪温飘
	GYRO_Last,		// 陀螺仪上次数据
	ACC, 			// 加速度计数据
	ACC_Offset,		// 加速度计温飘
	ACC_Last;		// 加速度计上次数据
extern S_INT32_XYZ
	Tar_Ang_Vel,	// 目标角速度
	Tar_Ang_Vel_Last;	// 上次目标角速度

extern int32 
	Speed_Now,		// 当前实际速度
	Speed_Min,		// 左右最小速度
	Speed_Set, 		// 目标设定速度
	Vel_Set,		// 目标转向角速度
	Direct_Parameter,
	Radius;

extern uchar Point;
extern int32 Difference;

extern char Speed_Flag, Angle_Flag, Ang_Velocity_Flag, DMP_Flag;
//extern float Zero_Angle ;
void Balance_Control(void);
void Balance_Init(void);

#endif

 

一、平衡小车原理: 自平衡小车是利用车模自身动力使小车保持相对的平衡,是一个动态平衡的过程。维持车模平衡的动力来自车轮的运动,由两个直流电机驱动。对车模的控制可以分解为三个控制任务: 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,使得小车能稳定自平衡。 具体参数调整过程比较繁琐,需要自己体会每个参数的作用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

身在江湖的郭大侠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值