[基于STM32底盘控制与ROS上层导航小车制作] 第二节 stm32电机pid控制

系列文章目录

第一节 stm32电机驱动与编码器读取反馈

第二节 stm32电机pid控制

第三节 stm32线速度标定

第四节 stm32添加mpu6050得到angle角度 

第五节 实现STM32与ubuntu系统下的ROS串口DMA通信,传输底盘速度等信息

第六节 ROS计算和发布里程计与tf变换

系列教材包含

底盘搭建与stm32代码编写,ros激光雷达建图与导航编写,实现动态避障与导航

底盘包含

两轮差速轮(自制)

四轮全向轮(所属团队大家一起搭建)

底盘不同就是在底盘的运动分解与控制,ros部分里程计计算和本地规划器不同,两轮用的base_local_Planner,四轮用的teb_local_planner,来规划发布速度控制底盘

gjhhust / Repositories · GitHubicon-default.png?t=L892https://github.com/gjhhust?tab=repositories


目录

系列文章目录

前言

一、pid介绍

二、pid简单调整方法

总结



前言

今天来为大家介绍pid控制


一、pid介绍

相信pid大家不陌生,就算陌生也没关系,从头写一下pid控制,pid就是要明确控制目标(setpoint)控制对象当前量(current_value),以及pid输出

在我刚开始就已知不懂控制三个量的关系,这里避雷一下,就是pid最终计算的量与控制目标不是一个量纲的概念

  打个比方,你需要控制电机转速至50cm/s,则setpoint就是50,此时当前量肯定就是编码器测得的速度而输出量是什么?是0-900的一个数字!因为你能改变电机转速,也就是改变current_value的直接手段就是改变占空比,也就是TIM_SetCompare1(TIM1,500);中500的那个值,至于500与速度什么关系我们不需要清除,只要pid知道当前占空比低,也就是转速低,还未达到setpoint,那么pid输出就大,当current_value越接近setpointpid输出也就减小,最后基本达到setpoint,输出就基本不变了,也就是你只需要有三个量在,然后调一下pid三个参数,也就是三个参数组成的算法来推这个pid输出量。

先贴出pid算法代码

pid.c


typedef struct
{
  float Kp;                       //比例系数Proportional
  float Ki;                       //积分系数Integral
  float Kd;                       //微分系数Derivative
 
  float Ek;                       //当前误差
  float Ek1;                      //前一次误差 e(k-1)
  float Ek2;                      //再前一次误差 e(k-2)
  float LocSum;                   //累计积分位置
}PID_LocTypeDef;
 
/************************************************
函数名称 : PID_Loc
功    能 : PID位置(Location)计算
参    数 : SetValue ------ 设置值(期望值)
            ActualValue --- 实际值(反馈值)
            PID ----------- PID数据结构
返 回 值 : PIDLoc -------- PID位置
作    者 : strongerHuang
*************************************************/
float PID_Loc(float SetValue, float ActualValue, PID_LocTypeDef *PID)
{
  float PIDLoc;                                  //位置
 
  PID->Ek = SetValue - ActualValue;
  PID->LocSum += PID->Ek;                         //累计误差
 
  PIDLoc = PID->Kp * PID->Ek + (PID->Ki * PID->LocSum) + PID->Kd * (PID->Ek1 - PID->Ek);
 
  PID->Ek1 = PID->Ek;  return PIDLoc;

}

代码解释

有了pid算法如上,我们只需要定义一个pid的结构体,比如是left_PID;来控制左电机转速

则pid控制流程就是,先硬件初始化好,然后能够得到左电机当前速度赋值给left_speed_now,接着定义PID结构体这里是left_PID

  然后调用如下语句即可pid控制,我一般放在一个固定的计时器中断里,比如上一节的TIM6内,5ms测速一次,我可以定义一个计数器flag,进一次中断+1,判断10ms时可以pid控制一次。

//左电机速度由TIM1 CH1pwm控制,目标控制到50cm/s
TIM_SetCompare1(TIM1,PID_Loc(50, left_speed_now, &left_PID));

下载程序完后你会发现电机不动,这是因为你没有给PID三个kp,ki,kd参数,都是0

二、pid简单调整方法

在keil的debug中,此时将添加到left_PID watch1内,监控发现参数都是0,此时尝试给kp值20,观察电机情况,如果不稳定转动,那么你就减小kp值直到转速稳定,此时再观察测速得到的left_speed_now,大概率会在40cm/s左右或者其它某个值附近波动(这里假设是40cm/s附近),你看反正达不到50cm/s,这就是静态误差,需要增加ki。

  与此同时我们要先给left_PID.LocSum赋值大小200(具体怎么给可以专门去学,这里简单就是,你静态误差此时速度差了10cm/s左右,而对应的占空比差了应该就是100左右,也就是你TIM_SetCompare1内给了500测速比如说是40cm/s,对应的占空比600测速是50cm/s,所有此时速度固定差了10cm/s,占空比固定差了100,而这个LocSum则要根据输出量也就是占空比来给,这就是最大静态误差就是200,上面情况是差了100,所以我们的ki给个0.5就差不多,0.5*200 = 100,这是个经验公式,就是大概教会你这几个值的含义)

此时如果静态误差还有,则继续增大ki到基本没有误差,过大会导致转速不稳定,上下浮动大。

以上只是简单的电机pid调控,满足普通需求,适合入门,更深入可以搜索资料。


总结

完成了pid的速度控制,底盘就动起来了。你给一个速度就可以转起来了。

你可能感兴趣的:(stm32)