news 2026/7/14 10:03:47

位置式PID调节PWM占空比控制电动机转速的程序方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
位置式PID调节PWM占空比控制电动机转速的程序方案

位置式PID控制原理

位置式PID算法的离散形式为:

u(k)=Kp×e(k)+Ki×∑e(j)+Kd×[e(k)−e(k−1)]u(k) = Kp × e(k) + Ki × ∑e(j) + Kd × [e(k) - e(k-1)]u(k)=Kp×e(k)+Ki×e(j)+Kd×[e(k)e(k1)]

其中:

  • u(k)u(k)u(k):当前时刻控制输出(PWM占空比)
  • e(k)e(k)e(k):当前误差 = 目标转速 - 实际转速
  • ∑e(j)∑e(j)e(j):误差累积和(积分项)
  • Kp,Ki,KdKp, Ki, KdKp,Ki,Kd:PID参数

硬件配置

所需外设

  • 编码器接口:测量电机转速
  • PWM输出:控制电机驱动
  • 定时器:用于定时采样和PID计算

引脚配置示例

// PWM输出引脚 (控制电机)#defineMOTOR_PWM_PINGPIO_Pin_8#defineMOTOR_PWM_PORTGPIOA#defineMOTOR_PWM_TIMTIM1// 编码器输入引脚#defineENCODER_A_PINGPIO_Pin_6#defineENCODER_B_PINGPIO_Pin_7#defineENCODER_PORTGPIOA#defineENCODER_TIMTIM3

完整程序代码

1. PID结构体定义

typedefstruct{floatTarget;// 目标转速floatCurrent;// 当前转速floatError;// 当前误差floatLastError;// 上一次误差floatPreError;// 上上次误差floatKp;// 比例系数floatKi;// 积分系数floatKd;// 微分系数floatIntegral;// 积分累计floatIntegralMax;// 积分限幅floatOutput;// PID输出floatOutputMax;// 输出限幅floatOutputMin;// 输出下限}PID_TypeDef;// 初始化PID参数voidPID_Init(PID_TypeDef*pid,floatkp,floatki,floatkd,floatmax_output){pid->Kp=kp;pid->Ki=ki;pid->Kd=kd;pid->Integral=0;pid->Target=0;pid->Current=0;pid->Output=0;pid->OutputMax=max_output;pid->OutputMin=0;pid->IntegralMax=max_output*0.8f;// 积分限幅为输出的80%}

2. 位置式PID计算函数

// 位置式PID计算floatPID_Calculate(PID_TypeDef*pid,floattarget,floatcurrent){floatincrement=0;// 更新目标值和当前值pid->Target=target;pid->Current=current;// 计算误差pid->PreError=pid->LastError;pid->LastError=pid->Error;pid->Error=pid->Target-pid->Current;// 积分项处理(带积分限幅和抗积分饱和)pid->Integral+=pid->Error;// 积分限幅if(pid->Integral>pid->IntegralMax){pid->Integral=pid->IntegralMax;}elseif(pid->Integral<-pid->IntegralMax){pid->Integral=-pid->IntegralMax;}// 位置式PID计算pid->Output=pid->Kp*pid->Error+pid->Ki*pid->Integral+pid->Kd*(pid->Error-pid->LastError);// 输出限幅if(pid->Output>pid->OutputMax){pid->Output=pid->OutputMax;}elseif(pid->Output<pid->OutputMin){pid->Output=pid->OutputMin;}returnpid->Output;}

3. 编码器速度测量

// 编码器相关变量volatileint32_tEncoderCount=0;volatileint32_tLastEncoderCount=0;volatilefloatMotorSpeed=0;// 转速 RPM// 编码器计数读取(在编码器中断中调用)voidEncoder_Update(void){EncoderCount=(int32_t)TIM_GetCounter(ENCODER_TIM);TIM_SetCounter(ENCODER_TIM,0);// 清零计数器}// 速度计算函数(在定时中断中调用,如10ms)voidSpeed_Calculate(void){staticuint32_tlast_time=0;uint32_tcurrent_time=HAL_GetTick();uint32_ttime_diff=current_time-last_time;if(time_diff>=10){// 10ms计算一次速度int32_tpulse_diff=EncoderCount;EncoderCount=0;// 计算转速 (RPM)// 假设编码器分辨率: 1000脉冲/转// 公式: RPM = (脉冲数 / 编码器分辨率) × (60000 / 采样时间ms)MotorSpeed=(pulse_diff/1000.0f)*(60000.0f/time_diff);last_time=current_time;}}

4. PWM输出控制

// PWM初始化voidPWM_Init(void){TIM_OC_InitTypeDef sConfigOC={0};// PWM频率设置 (例如: 10kHz)htim1.Instance=TIM1;htim1.Init.Prescaler=84-1;// 84MHz/84 = 1MHzhtim1.Init.CounterMode=TIM_COUNTERMODE_UP;htim1.Init.Period=100-1;// 1MHz/100 = 10kHzhtim1.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;HAL_TIM_PWM_Init(&htim1);sConfigOC.OCMode=TIM_OCMODE_PWM1;sConfigOC.Pulse=0;// 初始占空比0%sConfigOC.OCPolarity=TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode=TIM_OCFAST_DISABLE;HAL_TIM_PWM_ConfigChannel(&htim1,&sConfigOC,TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);}// 设置PWM占空比voidSet_PWM_Duty(floatduty_cycle){uint32_tpulse;// 限制占空比范围 0~100%if(duty_cycle<0)duty_cycle=0;if(duty_cycle>100)duty_cycle=100;// 计算PWM脉冲值pulse=(uint32_t)(duty_cycle*(TIM1->ARR+1)/100.0f);// 更新PWM占空比__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,pulse);}

5. 主控制程序

PID_TypeDef MotorPID;floatTargetSpeed=1000.0f;// 目标转速 1000 RPMintmain(void){// 系统初始化HAL_Init();SystemClock_Config();// 外设初始化PWM_Init();Encoder_Init();// 编码器初始化(需要自己实现)TIM_Init();// 定时器初始化(用于定时采样)// PID参数初始化(需要根据实际电机调试)PID_Init(&MotorPID,0.5f,0.01f,0.05f,100.0f);while(1){// 在定时中断中调用Speed_Calculate()更新速度// 主循环中可以处理目标速度设定等// 每50ms执行一次PID控制staticuint32_tlast_pid_time=0;if(HAL_GetTick()-last_pid_time>=50){floatpwm_output;// PID计算pwm_output=PID_Calculate(&MotorPID,TargetSpeed,MotorSpeed);// 更新PWM输出Set_PWM_Duty(pwm_output);last_pid_time=HAL_GetTick();// 可以通过串口输出调试信息printf("Target: %.1f, Current: %.1f, PWM: %.1f%%\r\n",TargetSpeed,MotorSpeed,pwm_output);}// 其他任务...HAL_Delay(1);}}

6. 定时器中断处理

// 定时器中断回调函数(例如1kHz)voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim){if(htim->Instance==TIM2){// 假设TIM2用于定时采样// 更新编码器计数Encoder_Update();// 计算速度(每10次调用计算一次速度)staticuint8_tspeed_counter=0;if(++speed_counter>=10){Speed_Calculate();speed_counter=0;}}}

PID参数整定方法

手动整定步骤:

  1. 先调Kp:将Ki、Kd设为0,逐渐增大Kp直到系统开始振荡
  2. 再调Ki:加入Ki消除静差,但不要太大以免超调
  3. 最后调Kd:加入Kd抑制超调,改善动态性能

典型参数范围(需要根据实际电机调整):

// 直流有刷电机典型参数#defineKP_START0.1f// 开始调试值#defineKI_START0.001f#defineKD_START0.01f// 无刷电机典型参数#defineKP_BLDC0.3f#defineKI_BLDC0.005f#defineKD_BLDC0.02f

参考代码 位置式PID调节PWM占空比控制电动机转速www.3dddown.com/csa/70961.html

注意事项

  1. 采样时间选择:速度采样和PID计算周期要匹配,通常10-50ms
  2. 积分抗饱和:必须对积分项进行限幅
  3. 输出限幅:PWM占空比限制在安全范围内
  4. 编码器分辨率:根据实际编码器参数调整速度计算公式
  5. 电机死区:有些电机在低占空比时不转动,需要设置最小启动占空比

调试技巧

  1. 串口监控:实时输出目标速度、实际速度、PWM占空比
  2. 阶跃响应:观察系统对目标速度突变的响应
  3. 抗扰动测试:在电机运行时施加负载,观察恢复性能
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/9 19:03:16

如何用AI快速搭建Yande引擎入口页面

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个Yande搜索引擎的入口页面&#xff0c;包含搜索框、热门标签展示区和图片瀑布流布局。前端使用HTML/CSS/JavaScript实现响应式设计&#xff0c;后端使用Node.js处理搜索请求…

作者头像 李华
网站建设 2026/7/13 7:40:24

前端新手必学:10分钟上手viewer.js基础用法

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个面向初学者的viewer.js教学示例&#xff0c;包含&#xff1a;1. 最基本的viewer.js引入和使用方法 2. 5个最常用配置项的说明和示例 3. 常见问题解答(如图片加载失败处理) …

作者头像 李华
网站建设 2026/7/10 7:07:06

【Android酒店预订系统App】(免费领源码+演示录像)|可做计算机毕设Java、Python、PHP、小程序APP、C#、爬虫大数据、单片机、文案

摘 要 基于Android平台的酒店预订系统App是一款专为移动用户设计的应用程序&#xff0c;它允许用户通过智能手机或平板电脑方便快捷地进行酒店搜索、预订及管理。这款App拥有一个直观的用户界面&#xff0c;为用户提供了广泛的功能&#xff0c;包括浏览酒店信息、查看房间价格…

作者头像 李华
网站建设 2026/7/14 1:22:42

CD-II-DBU动态制动装置

CD-II-DBU 动态制动装置应用领域详解起重与搬运设备电梯、升降机、起重机、葫芦、自动堆垛机输送机、滚筒输送线快速停止或防止负载下滑&#xff0c;保障安全机床及金属加工行业数控机床、车床、铣床、磨床、冲床激光切割机、折弯机、剪板机实现高精度停机&#xff0c;防止工件…

作者头像 李华
网站建设 2026/7/12 23:03:41

UVa 10654 The Uxuhul Voting System

题目分析 本题描述了一个古代文明的投票系统&#xff0c;我们需要根据每位祭司的偏好顺序&#xff0c;推算出最终三个议题的投票结果。这个问题的核心在于每位祭司都会基于后续祭司的最优选择来做出自己的最优决策&#xff0c;因此我们需要逆向推理 整个投票过程。 问题重述 …

作者头像 李华
网站建设 2026/7/11 7:16:29

UVa 10663 Non-Powerful Subsets

题目描述 我们定义一个自然数子集为“非幂集”&#xff0c;如果该子集中不存在任何子集&#xff08;可以是它本身&#xff09;使得其元素之和等于某个幂数。这里的幂数定义为&#xff1a;对于所有 NNN 和 M≥2M \geq 2M≥2 &#xff0c;形如 NMN^MNM 的数。注意&#xff0c; 11…

作者头像 李华