Featured image of post 基于无刷电机的平衡小车(PID)

基于无刷电机的平衡小车(PID)

记录从LQR到PID的学习过程

一、用PID和LQR控制平衡小车的区别

来看看deepseek描述:

二、实物部署

基于上一节LQR的代码,我们只要将相关计算公式用离散位置式PID的公式代替即可。
其中离散位置式PID的数学公式如下:

在stm32代码中表示如下,以角度环为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* ---------- PID 计算函数 ---------- */
float pid_ang_update(PID_t *pid, float err, float dt)
{	
    float out;
    pid->integral += err * dt;
    float derivative = (err - pid->prev_err) / dt;
    out = pid->kp * err + pid->ki * pid->integral + pid->kd * derivative;
    pid->prev_err  = err;
    return out;
}

位置式PID直接输出控制量的绝对值(非增量),可直接作用在电机的控制上,这里和LQR控制也有本质区别。

PID的控制原理是“误差反馈 + 经验调参”,控制平衡车的本质是控制加速度,但我们只能通过控制速度来控制加速度,所以PID公式输出的控制量是电机的速度大小。

LQR的控制原理是“状态反馈 + 模型优化”,在它的动力学模型里就已将力矩作为他的输入输出。

所以在PID控制的平衡小车里还需要将mit控制改为速度控制。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
void ChassisR_task(void)
{
	while(INS.ins_flag==0)
	{//等待加速度收敛
	  osDelay(1);	
	}

  ChassisR_init(&chassis_move);

	while(1)
	{	
		chassisR_feedback_update(&chassis_move,&INS);//更新数据
		
		out_ang = pid_ang_update(&pid_ang, 0.03f-chassis_move.myPithR, 0.002);
		out_x = pid_x_update(&pid_x, chassis_move.x_set-chassis_move.x, 0.002);
		out_vel = pid_vel_update(&pid_vel, chassis_move.v_set-chassis_move.v, 0.002);
		
		chassis_move.wheel_motor[0].wheel_T = out_ang - out_x + out_vel;
		
		out_gyr = pid_gyr_update(&pid_gyr, chassis_move.turn_set-INS.Gyro[2], 0.002);
		
		chassis_move.wheel_motor[1].wheel_T=-chassis_move.wheel_motor[0].wheel_T-out_gyr;
		
		chassis_move.wheel_motor[0].wheel_T=chassis_move.wheel_motor[0].wheel_T-out_gyr;
		
		scaled_down(&chassis_move.wheel_motor[0].wheel_T, &chassis_move.wheel_motor[1].wheel_T,-50.0f,50.0f);
			
		if(chassis_move.start_flag==1)	
		{
			speed_ctrl(&hfdcan1,0x01,chassis_move.wheel_motor[0].wheel_T);
			osDelay(CHASSR_TIME);
			speed_ctrl(&hfdcan1,0x02,chassis_move.wheel_motor[1].wheel_T);
			osDelay(CHASSR_TIME);
		}
		else if(chassis_move.start_flag==0)	
		{
			speed_ctrl(&hfdcan1,0x01,0);
			osDelay(CHASSR_TIME);
			speed_ctrl(&hfdcan1,0x02,0);
			osDelay(CHASSR_TIME);
		}
	}
}

在代码中将直立环、位置环、速度环、转向环分别计算再按正负号进行累加,这里的wheel_motor[*].wheel_T代表的是速度。

三、错将PID输出作为力矩

如果将PID输出作为力矩量输送给mit,经过调试也能实现直立行走的功能,但人为干扰的时候明显没速度控制的反应 “硬”,且因为单位的不同,PID的数值大小差距也会较大。

所涉及资料都已放在github,有需要可自行下载。
所用代码、BOM及3D文件 https://github.com/wenke-chen/DM-segway

其中
lqr算法的平衡小车代码《DM-car-lqr》
pid算法的平衡小车代码《DM-car-pid》
pid算法输入到力矩的平衡小车代码《DM-car-pid-torque》

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy