前面两篇博文已经实现了电机测速和PID速度环控制,在这篇博文中,我们主要说明位置环的代码怎么写以及PID参数怎么调。
1. 位置环代码实现
写完速度环后位置环就很简单了。
在串级PID中,内环的控制量一般是外环控制量的微分。在我们这里,外环是控制量是电机转动的位置(也可以说是角度),内环是电机转动的速度,刚好满足这个微分关系。
我们的思路是这样的,我们给外环PID设定电机转动的目标位置,位置环PID计算得到电机此时的理想转速,送到内环速度环,速度环计算得到此时PWM理想的占空比,并输出给电机。双环PID就需要两个反馈量,速度环的反馈量仍然是电机的速度,而位置环的反馈量可以使用编码器输出的脉冲总数。由于电机正转时脉冲总数会增加,而反转时脉冲总数会减少,所以脉冲总数其实是和电机转动的位置一一对应的。
位置环实现代码如下
因为死区和刹车这些东西位置环和速度环不一样,为了和速度环区分开,我们需要在PID.c中加上一个位置环的PID函数。
PID pid_speed,pid_position;
/**********************************
* 功能:PID结构体参数初始化
* 输入:无
* 返回:无
* *******************************/
void PID_Init(void)//PID参数初始化
{
pid_speed.err = 0;
pid_speed.integral = 0;
pid_speed.maxIntegral = 1000;
pid_speed.maxOutput = __HAL_TIM_GetAutoreload(&PWM_TIM);
pid_speed.lastErr = 0;
pid_speed.output = 0;
pid_speed.kp = KP_speed;
pid_speed.ki = KI_speed;
pid_speed.kd = KD_speed;
pid_position.err = 0;
pid_position.integral = 0;
pid_position.maxIntegral = 80;
pid_position.maxOutput = __HAL_TIM_GetAutoreload(&PWM_TIM);
pid_position.lastErr = 0;
pid_position.output = 0;
pid_position.kp = KP_position;//这几个宏定义要自己补充
pid_position.ki = KI_position;
pid_position.kd = KD_position;
}
/****************************************
* 作用:位置环PID计算
* 参数:PID参数结构体地址;目标值;反馈值
* 返回值:无
* ****************************************/
float Location_PID_Realize(PID* pid,float target,float feedback)//一次PID计算
{
if(pid->err < 0.5 && pid->err > -0.5) pid->err = 0;//pid死区
pid->err = target - feedback;
pid->integral += pid->err;
if(pid->ki * pid->integral < -pid->maxIntegral) pid->integral = -pid->maxIntegral / pid->ki;//积分限幅
else if(pid->ki * pid->integral > pid->maxIntegral) pid->integral = pid->maxIntegral / pid->ki;
pid->output = (pid->kp * pid->err) + (pid->ki * pid->integral) + (pid->kd * (pid->err - pid->lastErr));//全量式PID
//输出限幅
if(pid->output > pid->maxOutput) pid->output = pid->maxOutput;
if(pid->output < -pid->maxOutput) pid->output = -pid->maxOutput;
pid->lastErr = pid->err;
return pid->output;
}
定时器函数如下
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
Motor_Contorl(htim);//我把测速和PID封装成一个函数了
}
void Motor_Contorl(TIM_HandleTypeDef *htim)
{
Motor_Get_Speed(htim);//得到电机转速
Now_Position = (float)(motor1.totalCount-10000)// 得到当前位置 10000编码器脉冲计数的初始值
Target_Speed = Location_PID_Realize(&pid_position,Target_Position,Now_Position);//位置环 Target_Position是目标位置,自行定义即可
motor_Out = Speed_PID_Realize(&pid_speed,Target_Speed,motor1.speed);//速度环
if(motor_L_Out >= 0)
{
__HAL_TIM_SetCompare(&MOTOR_TIM, MOTOR_CHANNEL_FORWARD, 1000);
__HAL_TIM_SetCompare(&MOTOR_TIM, MOTOR_CHANNEL_BACKWARD, 1000-motor_Out);
}
else
{
__HAL_TIM_SetCompare(&MOTOR_TIM, MOTOR_CHANNEL_BACKWARD, 1000);
__HAL_TIM_SetCompare(&MOTOR_TIM, MOTOR_CHANNEL_FORWARD, 1000+motor_Out);
}
}
现在位置环的代码就完成了,下一步我们需要进行PID调参
2. 位置环PID调参
位置环调参和速度环有很大区别,按我的经验来说,一般用不到I和D,我们只要调整P就好。
我们从0开始逐步增大P,直到电机在前往目标位置的过程中是满速,而到达目标位置后不会超调、震荡就行,位置环调好后曲线应该是这样的:
上图中,红线是目标位置,绿线是当前位置,这里的位置并不是脉冲数,而是换算到了实际场景中,单位是cm,用脉冲数也是一样的。文章来源:https://www.toymoban.com/news/detail-787907.html
如果觉得电机达到目标速度的过程中速度过快,可以对位置环的输出进行限幅。文章来源地址https://www.toymoban.com/news/detail-787907.html
到了这里,关于【程序】【必须】PID位置环控制,代码+调参的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!