一、前情回顾

在上篇文章中,我们成功实现了STM32F103C8T6对RM3508电机的开环控制。接下来,我们将为系统加入速度环PID控制,使电机能够稳定维持设定转速。关于PID控制算法的原理分析已有大量优质资料可供参考,考虑到本文重点,我们将不再赘述理论部分。同时,由于速度环实现相对简单,同时因为本人实力有限,所以这里就不再去过多讲述。

关于PID的相关原理和STM32F103C8T6是如何与RM3508之间进行CAN通讯的,依旧给大家推荐两篇写的不错的文章进行学习。https://blog.csdn.net/skythinker616/article/details/123019829https://blog.csdn.net/skythinker616/article/details/123019829

https://blog.csdn.net/2401_89392458/article/details/151257906?spm=1001.2014.3001.5501https://blog.csdn.net/2401_89392458/article/details/151257906?spm=1001.2014.3001.5501

二、引入速度环PID

1.定义PID结构体

// 定义PID结构体
typedef struct {
    float Target;       // 目标值(此处为目标速度)
    float Current;      // 当前值(此处为反馈的实际速度)
    float Error;        // 当前误差
    float LastError;    // 上一次误差
    float Integral;     // 积分项
    float Derivative;   // 微分项
    float Kp;           // 比例系数
    float Ki;           // 积分系数
    float Kd;           // 微分系数
    float Output;       // PID输出值
    float IntegralLimit; // 积分限幅
    float OutputLimit;  // 输出限幅
} PID_TypeDef;

// 为电机1定义一个速度环PID控制器
PID_TypeDef speed_pid_m1;

2.初始化速度环PID参数

	// 初始化速度环PID参数
speed_pid_m1.Target = 0.0f;     // 初始目标速度设为0
	
speed_pid_m1.Kp = 5.0f;         // 需要调试:比例系数,从小到大试
	
speed_pid_m1.Ki = 0.1f;         // 需要调试:积分系数,补足静差
	
speed_pid_m1.Kd = 0.0f;         // 需要调试:微分系数,先设为0
	
speed_pid_m1.IntegralLimit = 1000.0f; // 积分限幅,防止积分饱和
	
speed_pid_m1.OutputLimit = 30000.0f;   // 输出限幅,最大电流值
	
speed_pid_m1.Integral = 0.0f;
	
speed_pid_m1.LastError = 0.0f;
	
speed_pid_m1.Output = 0.0f;

3.PID计算函数

/**
  * @brief  PID计算函数
  * @param  pid: PID结构体指针
  * @retval PID输出值
  */
float PID_Calculate(PID_TypeDef *pid) {
    // 1. 计算误差
    pid->Error = pid->Target - pid->Current;

    // 2. 比例项
    float p_out = pid->Kp * pid->Error;

    // 3. 积分项 (并限幅)
    pid->Integral += pid->Error;
    // 积分限幅
    if (pid->Integral > pid->IntegralLimit) pid->Integral = pid->IntegralLimit;
    if (pid->Integral < -pid->IntegralLimit) pid->Integral = -pid->IntegralLimit;
    float i_out = pid->Ki * pid->Integral;

    // 4. 微分项
    pid->Derivative = pid->Error - pid->LastError;
    float d_out = pid->Kd * pid->Derivative;
    pid->LastError = pid->Error; // 更新上一次误差

    // 5. 计算总输出
    pid->Output = p_out + i_out + d_out;

    // 6. 输出限幅
    if (pid->Output > pid->OutputLimit) pid->Output = pid->OutputLimit;
    if (pid->Output < -pid->OutputLimit) pid->Output = -pid->OutputLimit;

    return pid->Output;
}
/* USER CODE END 4 */

4.PID调参建议

【参数调试】耐心调试PID:我这里的参数没有细调,因为我的考核要求没那么高,这里的参数刚好够用

第一步:将 Kp, Ki, Kd 全部设为0。电机应不转。

第二步:只调P。慢慢增大 Kp(比如从1.0 -> 2.0 -> 5.0 -> 10.0...),观察电机是否开始转动并加速。目标是让电机能稳定在一个接近目标速度(1000RPM)的值,即使有静差(比如只能稳定在800RPM)也没关系。

第三步:加入I。慢慢增大 Ki(比如从0.01 -> 0.05 -> 0.1...),观察电机速度是否逐渐接近并最终稳定在目标速度1000RPM上,消除静差。

第四步:(可选)如果电机在目标速度附近震荡,加入一点点 Kd(比如0.1)来抑制震荡。

5.主循环调用

  /* USER CODE BEGIN WHILE */
  while (1)
  {    
//    	CAN_Send_Motor_Command(400, 0, 0, 0); // 发送指令:电机1电流1000,其他电机0  纯开环控制

		// 1. 设置目标速度 (例如:让电机1以 1000 RPM 的速度转动)
    speed_pid_m1.Target = 600.0f;

    // 2. 更新当前速度 (从反馈数据中获取)
    // motor_feedback[0] 对应ID为1的电机 (因为 motor_id = StdId - 0x201)
    speed_pid_m1.Current = motor_feedback[0].rpm;

    // 3. 进行PID计算,得到需要发送的电流值
    int16_t output_current = (int16_t)PID_Calculate(&speed_pid_m1);

    // 4. 发送电流指令
    CAN_Send_Motor_Command(output_current, 0, 0, 0);

    // 5. 控制周期延时,保持控制频率稳定 (例如1kHz)
    HAL_Delay(1);

    /* USER CODE END WHILE */

三、结尾

在第一篇文章的基础上,按照本章的内容引入速度环对电机转速实现精准控制还是比较简单的。我这里代码编写时间有限(金工实习期),没有对代码进行封装处理,大家可以根据自己的需求对代码进行优化和更新。

PS:其实我是有视频的,但是我认为个人实力有限没有发B站所以没法上传CSDN上面,大家如果有想看视频的也可以联系我发视频。

最后,速度环是角度环的基础,必须调好速度环的参数才可以去调角度环。精准的速度环会让角度环的控制效果更上一层楼。下一篇文章我会详细讲解角度环的引入,这是串级PID控制的难点,也是本次考核任务中最有意思的部分。我的代码部分给出的比较详细,基本直接添加就可以实现电机速度环精准控制。想要源码的私信或者在评论区留下邮箱,有空看见了就会发。

下面请期待STM32F103C8T6控制RM3508电机的最后一章:角度环控制!

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐