两轮平衡电动车原理简单叙述

一、计算倾斜角度与角速率

void Get_Tiltangle( void )				//¼Ƌ㽇˙м°ǣб½Ƕȍ
{
	float buf;
	static uint32_t time;
    buf = total_ADXL_GYRO / total_looptime;
    total_ADXL_GYRO -= buf;
	total_ADXL_GYRO *=0.918;

	if( TIMER_MS>time+100 )
	{
		time = TIMER_MS;
		if( CarStus.limit_run )
		{
			if( CarStus.limit_angle <100 )
				CarStus.limit_angle++;
				
		}
		else
			CarStus.limit_angle=0;
	}
    // ADXL part
    total_ADXL_GYRO += (float)(ACCEL_X()-(config.s.ACCEL_X_M-CarStus.limit_angle));
    
    // Gyro part
    buf = Average_Gyro/total_looptime;
    Average_Gyro -= buf;
   	Average_Gyro += (float)GYRO_X();

    buf = Average_Gyro/(total_looptime);
	buf =  buf - (float)GYRO_X();
    buf *= 3;
    Angle_Rate = buf;

    total_ADXL_GYRO += Angle_Rate;
    Tilt_ANGLE = total_ADXL_GYRO/(total_looptime/10);
}

total_ADXL_GYRO *=0.918;为一个高通滤波,叠加角度数值与角速率值,除采样次数得到当前倾斜角度
Angle_Rate,利用滑动平均值滤波,叠加采样AD值得到乘以系数

二、计算平衡值

Balance_moment =  Angle_Rate*(long)(config.s.Dangle) + (long)(config.s.Pangle)*(Tilt_ANGLE) + Protect;

倾斜角度计算使用P参数,角速率计算使用D参数,全车调试主要针对P参数与D参数调整

Drivespeed = Drive_sum /240  + Balance_moment / 225 + slope_add;

加入slope_add校正,计算电机需要保持平衡的PWM值

三、计算两轮电机的轮速差值

if( EncoderData )
		{
			EncoderData = 0;
			
			if (SpeedDiff>50)         // ±«ƷϠ²0Ҕɏ£¬½øА±£»¤
				SpeedDiff=50;
			else if (SpeedDiff<-50)
				SpeedDiff=-50;

			if( SpeedDiff>5 )         // ±«ƷϠ²ԉϲŽøА¾Àƫ
			{
				if( DiffAdjust<10 )      // Ӄ׮´󲵵ĵ绺ֵÀ´¾Àƫ
					DiffAdjust+=(float)SpeedDiff*0.08;   // ¾Àƫµ绺ֵÿ5ms׮С0.8£¬׮´󸍊				else
					DiffAdjust = 10;
			}
			else if( SpeedDiff<-5 )
			{
				if( DiffAdjust>-10 )
					DiffAdjust+=(float)SpeedDiff*0.08;
				else
					DiffAdjust = -10;
			}
		}

0.08为调整系数

四、计算转向摇杆数值

if( turn<config.s.RCOKER_M-ROCKER_DEADBAND )	//ҡ¸˗󗪍
		{
			if( LeftFlag == 0 )
			{
				#if MODEL_BW
				Steeringsignal = -12;     //BW -12, ST -8
				#elif MODEL_ST
				Steeringsignal = -8;     //BW -12, ST -8
				#else
				Steeringsignal = -8;     //BW -12, ST -8
				#endif
				if( fabs(Drivespeed)<3 && fabs(CarStus.Speed)>360)
					Steeringsignal = 0;
			}
			if( RightFlag )
			{
				RightFlag = 0;
				Steeringsignal = 0;
			}
			#if FIRMWARE15
			if (TurnSpeed > (700/(fabs(CarStus.Speed)/500+5))*(-1) )
			#elif FIRMWARE10
			if (TurnSpeed > (420/(fabs(CarStus.Speed)/300+5))*(-1) )
			#else
			if (TurnSpeed > (700/(fabs(CarStus.Speed)/500+5))*(-1) )
			#endif
			{
				#if MODEL_BW
				Steeringsignal -= 0.25;    //BW 0.15, ST 0.1
				#elif MODEL_ST
				Steeringsignal -= 0.2;    //BW 0.15, ST 0.1
				#else
				Steeringsignal -= 0.2;    //BW 0.15, ST 0.1
				#endif
				if( fabs(Drivespeed)<1.1 )
					Steeringsignal -= 0.04;
			}
			/*#if FIRMWARE15
			else if (TurnSpeed < (800/(fabs(CarStus.Speed)/500+5))*(-1) )
			#elif FIRMWARE10
			else if (TurnSpeed < (500/(fabs(CarStus.Speed)/300+5))*(-1) )
			#else
			else if (TurnSpeed < (800/(fabs(CarStus.Speed)/500+5))*(-1) )
			#endif
			{
				#if MODEL_BW
				Steeringsignal += 0.25;  
				#elif MODEL_ST
				Steeringsignal += 0.2; 
				#else
				Steeringsignal += 0.2; 
				#endif
				if( fabs(Drivespeed)<1.1 )
					Steeringsignal += 0.04;
			}*/
			LeftFlag = 1;
		}
        else if( turn>config.s.RCOKER_M+ROCKER_DEADBAND )	//Ӓת
		{
			if( RightFlag == 0 )
			{
				#if MODEL_BW
				Steeringsignal = 12;       //BW 12, ST 8
				#elif MODEL_ST
				Steeringsignal = 8;       //BW 12, ST 8
				#else
				Steeringsignal = 8;       //BW 12, ST 8
				#endif
				if( fabs(Drivespeed)<5 && fabs(CarStus.Speed)>360)
					Steeringsignal = 0;
			}
			if( LeftFlag )
			{
				LeftFlag = 0;
				Steeringsignal = 0;
			}
			#if FIRMWARE15
			if (TurnSpeed < (700/(fabs(CarStus.Speed)/500+5)) )
			#elif FIRMWARE10
			if (TurnSpeed < (420/(fabs(CarStus.Speed)/300+5)) )
			#else 
			if (TurnSpeed < (700/(fabs(CarStus.Speed)/500+5)) )
			#endif
			{
				#if MODEL_BW
				Steeringsignal += 0.25; 
				#elif MODEL_ST
				Steeringsignal += 0.2; 
				#else
				Steeringsignal += 0.2;
				#endif
				if( fabs(Drivespeed)<1.1 )
					Steeringsignal += 0.04;
			}
/*			#if FIRMWARE15
			else if (TurnSpeed > (800/(fabs(CarStus.Speed)/500+5)) )
			#elif FIRMWARE10
			else if (TurnSpeed > (500/(fabs(CarStus.Speed)/300+5)) )
			#else 
			else if (TurnSpeed > (800/(fabs(CarStus.Speed)/500+5)) )
			#endif
			{
				#if MODEL_BW
				Steeringsignal -= 0.25;
				#elif MODEL_ST
				Steeringsignal -= 0.2;
				#else
				Steeringsignal -= 0.2;
				#endif
				if( fabs(Drivespeed)<1.1 )
					Steeringsignal -= 0.04;
			}*/
			RightFlag = 1;
		}
        else								//»ָ´µ½֐µ㍊		{
            if (Steeringsignal > 0)
			{
				Steeringsignal -= 1;
				if( Steeringsignal<0.5 )
				{
					Steeringsignal = 0;
					RightFlag = 0;
				}
			}
			else if (Steeringsignal < 0)
			{
				Steeringsignal += 1;
				if( Steeringsignal>-0.5 )
				{
					Steeringsignal = 0;
					LeftFlag = 0;
				}
			}
		}
		//Ϟֆתϲµķù¶ȍ
		if( Steeringsignal>70 )
			Steeringsignal = 70;
		else if( Steeringsignal<-70 )
			Steeringsignal = -70;

Steeringsignal 通过编码器不同速度条件下计算的转向PWM值

五、计算实际输出电机PWM数值

Drive_A = Drivespeed + Steeringsignal - DiffAdjust;
Drive_B = Drivespeed - Steeringsignal + DiffAdjust;

Drivespeed 为陀螺仪与加计计算出来电机驱动值
Steeringsignal 为摇杆计算出来电机驱动值
DiffAdjust 为两电机编码器差值补偿值
Drive_A 与 Drive_B 输出到电机实际PWM值

### PID控制在平衡中的应用 PID控制的核心目标是通过调节系统的输出来最小化实际与期望之间的误差。对于两轮平衡而言,其核心挑战在于保持身的动态稳定性和方向控制。具体来说,PID控制器通过对角度传感器(如陀螺仪和加速度计)获取的数据进行处理,实时调整电机速度以维持辆的平衡。 #### 原理概述 平衡通常依赖于倾角测量作为输入信号,该信号由惯性测量单元(IMU)提供。IMU能够检测小当前的姿态变化,并将其转换为数形式传递给控制系统。PID控制器接收这些数据并与设定的目标姿态比较得出偏差。随后,利用比例项(P)、积分项(I)以及微分项(D),计算出合适的校正量作用于驱动电机上,从而抵消外界干扰力矩的影响,使整个系统趋于平稳状态[^1]。 #### 参数调优的重要性 由于不同硬件配置下的响应特性存在差异,在实际开发过程中往往需要反复试验才能找到最适配的一组Kp(比例增益),Ki(积分时间常数),Kd(微分校正系数)[^2]。这一步骤至关重要,因为它直接影响最终产品的性能表现——过高可能导致震荡失稳;过低则可能反应迟缓无法有效纠正倾斜趋势。 #### 转向环路设计 除了基本的姿态矫正外,还需要考虑如何让子按照预定轨迹前进或者转弯等问题。这就涉及到另一个层面即“转向环”的构建工作了。在此环节里同样会引入类似的闭环机制来进行精细化管理,只不过这里的参考变量变成了横向偏离距离而非纵向俯仰角而已[^3]。 ### 示例代码展示 下面是基于STM32平台编写的一个简单版本PID算法实现片段: ```c #include "stm32f10x.h" // 定义全局变量 float Kp = 1.2, Ki = 0.05, Kd = 0.8; float error = 0.0, last_error = 0.0, integral = 0.0; // 初始化定时器或其他必要组件... void SystemInit(void){ // 配置GPIOs,TIMers etc. } // 主循环内的逻辑流程 int main(){ SystemInit(); while (1){ float current_angle = ReadSensorData(); // 获取当前角度 // 计算误差及其导数/累积 error = TARGET_ANGLE - current_angle; integral += error * SAMPLE_TIME; float derivative = (error - last_error)/SAMPLE_TIME; // 更新上次记录以便下次迭代使用 last_error = error; // 执行PID运算得到新的PWM占空比设置 int pwm_duty_cycle = Kp*error + Ki*integral + Kd*derivative; SetMotorSpeed(pwm_duty_cycle); // 将结果应用于马达控制端口 } } ``` 上述程序展示了最基本的框架结构,其中包含了几个关键要素:初始化过程定义了各个固定参数初始条件;主函数体内持续监测环境状况并通过一系列数学操作求解最优解决方案最后反馈至执行机构完成一次完整的调控周期[^4]^。 另外得注意的是,尽管这里给出的例子相对简化了一些细节上的考量因素比如限幅保护措施等等,但在真实场景下这些都是不可或缺的部分必须加以完善才能够保障设备长期可靠运行[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

纵向深耕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值