基于大疆RM3508电机的串级PID(角度环+速度环)

1.前言

最近参加ROBOCON,我负责编写传球机器人,由于传球机构需要一个电机转固定角度来带动球,所以便用大疆3508电机通过串级PID来实现,不得不说3508电机还是真的强,先看一下效果吧。

视频

2.配置程序

关于3508的配置程序以及一些其他部分在我的另外一篇博客里有详细的介绍,本篇主要是详细讲解3508串级pid(转固定角度)。
大疆3508/2006/6020电机使用教程

3.角度位置控制

3508电机的串级PID控制比起其他直流电机要简单一些,不需要过多的处理编码盘的反馈,只需要读取电调反馈的角度。
关于串级PID的知识,csdn上有很多,我就不赘述了。
直流电机角度位置控制详解(附源码)
直流电机角度控制

3.1 先看一下电调反馈的数据


if((rx_message.StdId == (MOTOR_ID_READ+5)) ) //电机5
		{
						
			MOTOR_FEEDBACK[5].angle_value  = rx_message.Data[0] << 8 | rx_message.Data[1];
			MOTOR_FEEDBACK[5].speed_rpm    = rx_message.Data[2] << 8 | rx_message.Data[3];
			MOTOR_FEEDBACK[5].real_current = rx_message.Data[4] << 8 | rx_message.Data[5];
			MOTOR_FEEDBACK[5].temperature = rx_message.Data[6];
			
			MOTOR_FEEDBACK[5].real_angle = MOTOR_FEEDBACK[5].angle_value/8192.0f*360.0f;
			
		}


这里电调ID要对应上,否则回接受不到数据,另外我们主要用的反馈是real.angle这个数据。

3.2角度处理程序

先说一下这个入口参数motor_num是电调ID,T是一个周期的角度值(自设360),通过这个函数可以得到电机的绝对角度POS_ABS。

u8 cnt = 1;
void Motor_Angle_Cal(unsigned short int motor_num,float T)
{
	float  res1, res2;
//	int  res3, res4;
	static float pos[MOTOR_MAX], pos_old[MOTOR_MAX];
	
	if(flag.cnt_calib&&cnt)
	{
		pos_old[motor_num]=MOTOR_FEEDBACK[motor_num].real_angle;
		cnt=0;
	}	
	pos[motor_num] =MOTOR_FEEDBACK[motor_num].real_angle;
	motor.ANGLE[motor_num].eer=pos[motor_num] - pos_old[motor_num];
	
	if(motor.ANGLE[motor_num].eer>0) 	
	{
		res1=motor.ANGLE[motor_num].eer-T;//反转,自减
		res2=motor.ANGLE[motor_num].eer;
	}
	else
	{
		res1=motor.ANGLE[motor_num].eer+T;//正转,自加一个周期的角度值(360)
		res2=motor.ANGLE[motor_num].eer;
	}
	
	if(ABS(res1)<ABS(res2)) //不管正反转,肯定是转的角度小的那个是真的
	{
		motor.ANGLE[motor_num].eer_eer = res1;
	}
	else
	{
		motor.ANGLE[motor_num].eer_eer = res2;
	}
	
	motor.ANGLE[motor_num].POS_ABS += motor.ANGLE[motor_num].eer_eer;
	pos_old[motor_num]  = pos[motor_num];
}


//一些角度控制的结构体变量
typedef struct
{
	float POS_GAOL;//目标位置
	float POS_ABS;//绝对位置0
	float POS_OFFSET;
	float eer;
	float eer_eer;
}ANGLE_TypeDef;


typedef struct
{
	ANGLE_TypeDef ANGLE[8];
	_PID   PID_SPEED[8];
	_PID   PID_ANGLE[8];
	
}MOTOR_TypeDef;

3.3 主要程序

//PID
float PID_Cal_Limt(_PID *PID, float limit, float get, float set)//PID死区修改
{
	PID->err = set - get;
	PID->err_err = PID->err - PID->err_old;
	
	PID->P_OUT  = PID->P * PID->err;
	PID->I_OUT += PID->I * PID->err;
	PID->D_OUT  = PID->D * PID->err_err;
	
	PID->I_OUT = (PID->I_OUT > PID->I_LIMIT)?(PID->I_LIMIT):((PID->I_OUT < -PID->I_LIMIT)?(-PID->I_LIMIT):(PID->I_OUT));
	
	PID->OUT = PID->P_OUT + PID->I_OUT + PID->D_OUT;
	
	PID->OUT = (PID->OUT > PID->OUT_LIMIT)?(PID->OUT_LIMIT):((PID->OUT < -PID->OUT_LIMIT)?(-PID->OUT_LIMIT):(PID->OUT));
	
	if(ABS(PID->err) <= ABS(limit))
	{
	  PID->I_OUT=0;
	  PID->OUT=0;
	}
	
	PID->err_old = PID->err;
	
	return PID->OUT;
}



float motor_err[10]; //死区控制
float mode=0; //mode0-发射;mode1-回收
float angle_a=0,angle_b=0;//a-发射角度;b-回收角度

void Motor_Auto_Run(void)
{
	motor_err[5]=50;
	
	float abs_err[10];
	static float abs_err_old[10]; 
	Motor_Angle_Cal(5,360);//得到绝对角度
	//发射
	if(mode == 0)
	{
		
	motor.ANGLE[5].POS_GAOL = angle_a;
	PID_Cal_Limt(&motor.PID_ANGLE[5], motor_err[5], motor.ANGLE[5].POS_ABS,motor.ANGLE[5].POS_GAOL);

	
	abs_err[5] = motor.ANGLE[5].POS_ABS - abs_err_old[5];
	
	
	PID_Cal_Limt( &motor.PID_SPEED[5], 10, abs_err[5], motor.PID_ANGLE[5].OUT);
	
	
	abs_err_old[5] = motor.ANGLE[5].POS_ABS;
	Motor_Set_Current2((int16_t)(motor.PID_SPEED[5].OUT) ,0,0,0);
	}
	//回
	else if (mode == 1)
	{
		
	motor.ANGLE[5].POS_GAOL = angle_b  ;
	PID_Cal_Limt(&motor.PID_ANGLE[6], motor_err[5], motor.ANGLE[5].POS_ABS,motor.ANGLE[5].POS_GAOL);
	
	abs_err[5] = motor.ANGLE[5].POS_ABS - abs_err_old[5];
		
	PID_Cal_Limt( &motor.PID_SPEED[6], 10, abs_err[5], motor.PID_ANGLE[6].OUT);
		
	abs_err_old[5] = motor.ANGLE[5].POS_ABS;
	Motor_Set_Current2((int16_t)(motor.PID_SPEED[6].OUT) ,0,0,0);
		
	}
	else
	

}


这个部分有几个小细节主要注意:
1.角度控制一套PID参数即可,为了不损害机械机构所以我写了两套PID参数来控制电机的发射和回收。
2.motor_err()是电机角度死区控制,目的是防止电机在目标角度附件来回跳动。
3. 角度控制的主要流程是先将目标角度在角度环里计算,将角度环的输出发送给速度环,再将速度环的输出发射给电调即可。
4. 一般串级PID的调参主要是调角度环,如果需要电机的爆发力很大,角度环的输出限制不能设置的很大。
5.若是电机在目标值附近来回震动很大,则需要在角度环里加大d的值。
6.角度环的程序需要放在 投射电机 的can接收中断里。

if((rx_message.StdId == (MOTOR_ID_READ+5)) ) //电机5
		{
			Motor_Auto_Run();	//串级PID  3508 正方向-向上
			
			MOTOR_FEEDBACK[5].angle_value  = rx_message.Data[0] << 8 | rx_message.Data[1];
			MOTOR_FEEDBACK[5].speed_rpm    = rx_message.Data[2] << 8 | rx_message.Data[3];
			MOTOR_FEEDBACK[5].real_current = rx_message.Data[4] << 8 | rx_message.Data[5];
			MOTOR_FEEDBACK[5].temperature = rx_message.Data[6];
			
			MOTOR_FEEDBACK[5].real_angle = MOTOR_FEEDBACK[5].angle_value/8192.0f*360.0f;
			
		}

上文若有错误,请指正。

<think>嗯,用户想了解PID控制中角速度环的设计与实现。首先,我需要回忆一下PID的基本结构。PID通常由外组成,外的输出作为内的设定值。在角速度环的情况下,可能外角度,内是角速度环,对吧?比如无人机或者电机控制中常见这种结构。 接下来,用户的问题具体是角速度环的设计实现。我需要分步骤来解答。首先,明确角速度环的作用,作为内,它应该负责快速响应,抑制干扰,比如电机的负载变化。然后,设计步骤可能包括确定控制目标、传感器选择、数学模型建立、参数整定等。 然后,数学模型部分可能需要用到电机的传递函数,比如电机角速与输入电压的关系。可能需要微分方程或者状态空间模型,这里可能需要引用一些公式,比如角速度环的误差计算,PID的输出公式。记得用户要求数学表达式用$...$格式,比如$P_{out} = K_p \cdot e(t)$。 参数整定方法方面,通常内先整定,再外。角速度环作为内,可能需要先调整其PID参数,使用试凑法、临界比例法或者自整定算法。这部分需要解释清楚步骤,可能还要提到实时性要求,采样频率的选择。 实现部分,用户可能需要代码示例,比如伪代码或者Python代码,但用户之前给的示例中有Python代码,所以可以考虑提供一个简化的控制代码,用$$...$$格式包裹。同时,要说明代码中的关键点,比如传感器数据读取、误差计算、PID输出、执行机构控制等。 然后,注意事项方面,需要提到实时性、抗积分饱、噪声滤波,以及角度的协同工作。比如角速度环的响应速要快于角度,避免冲突。 相关问题部分,需要考虑用户可能进一步的问题,比如参数整定方法、与角度的协同、抗干扰措施、代码中的常见问题,以及应用场景。这些需要生成3-5个相关问题,帮助用户深入理解。 引用部分,用户提供了两个参考,一个是PID的结构优势,另一个是电机角速处理的具体实现。需要在回答中合适的地方加入引用标识,比如在提到结构优势时引用[^1],在传感器数据处理时引用[^2]。 最后,检查是否符合所有系统指令:行内公式用$...$,独立公式用$$...$$,正确的中文回答,生成相关问题,引用标识正确。确保LaTeX语法正确,比如积分、微分符号的正确使用,公式单独成段时需要双美元符号。</think>### PID速度环设计与实现 #### 1. **角速度环的作用** 角速度环作为PID的内,直接控制执行机构(如电机)的转速,快速响应外部扰动(如负载变化)。其输出作用于执行机构,外角度)的输出则作为角速度环的设定值[^1]。例如,在无人机控制中,角速度环确保电机转速快速跟踪姿态调整指令。 #### 2. **设计步骤** **a. 确定控制目标** 角速度环需稳定跟踪设定值,例如电机转速需快速达到目标值$ \omega_{\text{target}} $,同时抑制扰动。 **b. 传感器选择** 使用编码器或IMU(惯性测量单元)测量实际角速$ \omega_{\text{real}} $,如大疆RM3508电机通过`real.angle`反馈数据。 **c. 数学模型** 建立被控对象(如电机)的传递函数。例如,电机角速与输入电压的关系可简化为: $$ \frac{\omega(s)}{V(s)} = \frac{K}{Ts + 1} $$ 其中$ K $为增益,$ T $为时间常数。 **d. PID参数整定** 采用试凑法或Ziegler-Nichols方法,先整定内(角速度环),再整定外角度)。角速度环需高比例增益$ K_p $以提高响应速,适当微分增益$ K_d $抑制超调。 #### 3. **实现流程** ```python # 伪代码示例:角速度环PID控制 class VelocityPID: def __init__(self, Kp, Ki, Kd): self.Kp = Kp self.Ki = Ki self.Kd = Kd self.last_error = 0 self.integral = 0 def update(self, target_omega, real_omega, dt): error = target_omega - real_omega self.integral += error * dt derivative = (error - self.last_error) / dt output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative self.last_error = error return output # 主控制 while True: target_angle = get_target_angle() # 外角度)设定值 real_angle = read_encoder() # 外反馈 angle_pid_output = angle_pid.update(target_angle, real_angle, dt) target_omega = angle_pid_output # 角速度环设定值来自外 real_omega = read_gyro() # 内反馈(角速) motor_voltage = velocity_pid.update(target_omega, real_omega, dt) set_motor_voltage(motor_voltage) # 执行机构控制 ``` #### 4. **关键参数与注意事项** - **实时性**:角速度环需高采样频率(通常>100Hz),避免延迟导致系统不稳定。 - **抗积分饱**:需对积分项限幅,防止长时间误差积累。 - **噪声滤波**:角速测量信号需低通滤波,避免高频噪声影响微分项。 - **协同外**:角速度环带宽需高于角度,典型比例为5~10倍。 #### 5. **调试技巧** - **阶跃响应测试**:观察角速跟踪的上升时间、超调量,调整$ K_p $$ K_d $。 - **抗扰动测试**:手动施加负载,验证角速恢复速
评论 80
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不会武功不懂江湖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值