
电机驱动开发学习9. PID位置式算法实现与串口修改目标值一、位置式与增量式 PID介绍1.1 位置式 PID1.2 增量式 PID1.3 两种形式对比1.4 位置式离散公式本章实现1.5 为何本章先学位置式1.6 工程上必须处理的点1. 输出限幅out_min / out_max2. 积分限幅3. 积分抗饱和Anti-windup4. 固定采样周期 dt定时器中断二、实验简介2.1 本章目标2.2 与前后章节的关系2.3 硬件与工程说明三、程序设计3.1 目录与模块划分3.2 PID 结构体设计3.3 位置式 PID 核心流程3.4 被控对象一阶惯性软件仿真3.5 采样周期 dt四、串口命令与 FireWater 输出4.1 串口命令上电默认值仅首次初始化之后可被串口命令覆盖指令一览常用示例4.2 FireWater 波形输出本章核心修改目标时的注意点与前后实验的关系协议选择通道定义FireWater逗号分隔行尾 \n下位机发送示例VOFA 上位机设置建议观察的曲线五、主程序流程5.1 初始化5.2 定时器中断PID 任务5.3 主循环六、实验步骤6.1 上电过程6.2 仅 P 控制目标值改为70 t 706.2 加入 I6.3 加入 D6.4 与 lesson8 对照一、位置式与增量式 PID介绍PID 在嵌入式里常见两种离散写法位置式和增量式。二者用的是同一套 P/I/D 思想差别在于控制器输出表示什么。1.1 位置式 PID位置式每次直接算出控制量的绝对值u(k) Kp·e(k) Ki·Σe(i)·dt Kd·[e(k)-e(k-1)]/dt项目说明输出含义第 k 次采样时执行机构应处于的完整控制量如 PWM800、DAC3.3V使用方式pwm pid_update(目标, 反馈)把返回值直接赋给执行器直观性输出就是「当前该输出多少」与 lesson8 仿真一致典型场景速度环给定 PWM、位置环、温度/液位等例子目标转速 500 RPM当前 400 RPM位置式 PID 算出u650→ 直接set_pwm(650)。1.2 增量式 PID增量式不算绝对输出只算相对上一次的调整量 ΔuΔu(k) Kp·[e(k)-e(k-1)] Ki·e(k)·dt Kd·[e(k)-2e(k-1)e(k-2)]/dt u(k) u(k-1) Δu(k)项目说明输出含义在现有控制量上再加或减多少使用方式u pid_update(...)需保存上次输出u(k-1)直观性输出是「这一步微调多少」典型场景步进电机脉冲频率微调、阀门开度微调、部分执行器只能增量调节例子当前 PWM 已是 600增量式算出Δu50→ 新 PWM 650。1.3 两种形式对比对比项位置式增量式输出控制量绝对值u(k)控制量增量Δu(k)积分项显式累加Σe·dt含在Ki·e·dt中微分项e(k)-e(k-1)e(k)-2e(k-1)e(k-2)需保存的状态积分、上次误差上次/上上次误差、上次输出输出限幅对u(k)限幅常对Δu或u限幅手动/异常干预改执行器后宜pid_reset()清积分改执行器后u(k-1)易与真实不同步切换手动/自动需重新对齐输出有时切换更平滑从当前 u 继续累加如何选择无刷 PWM 调速、位置环本系列统一采用位置式lesson9 起增量式常见于步进加减速等场景本 BLDC 主线不单独成章二者调好的Kp/Ki/Kd数值通常不能直接互换因为公式形式不同需分别整定。1.4 位置式离散公式本章实现e(k) setpoint - measurement P项 Kp · e(k) I项 Ki · e(k) · dt D项 Kd · [e(k) - e(k-1)] / dt output P I D1.5 为何本章先学位置式输出为控制量绝对值直观便于限幅与 lesson8 仿真、set_bldcm_speed()等接口一致速度环 / 位置环常用位置式或在其基础上封装1.6 工程上必须处理的点1. 输出限幅out_min/out_maxPID 算出的output P I D会被限制在[out_min, out_max]内。作用对应实际执行器的物理范围例如 PWM 0100%、电机最大允许占空比。超出范围的控制量既无效还可能损坏硬件。2. 积分限幅积分累加值integral被限制在[-integral_max, integral_max]内见代码第 53–54 行。作用防止 I 项因长期误差过大而无限增长。即使还没触发输出饱和也能限制积分“蓄力”的上限减轻超调和恢复慢的问题。3. 积分抗饱和Anti-windup输出已经顶到out_max/out_min但误差仍会让积分继续往“更饱和”的方向累加时会把刚才加进去的那一步积分撤销回去代码第 62–71 行。作用解决“积分饱和windup”——输出已满却还在积分导致误差反向时 I 项很大、响应迟钝、超调明显。Anti-windup 让饱和时积分不再无效累积。4. 固定采样周期dt定时器中断离散 PID 里 I、D 都依赖时间I Ki·e·dtD Kd·(e(k)-e(k-1))/dt。dt应固定且由定时器中断周期性调用pid_update()。作用保证公式与整定参数一致。若dt忽大忽小同一组 Kp/Ki/Kd 表现会变D 项也会因除法放大噪声控制不稳定。二、实验简介2.1 本章目标在 STM32 上实现可复用的位置式 PID 模块bsp_pid.c/h用软件一阶惯性被控对象验证算法与 lesson8 Python 仿真同一模型用VOFA FireWater协议输出 PID 波形7 通道50ms 一帧对照 lesson8 曲线调参串口命令在线修改目标值与Kp/Ki/Kd无需重新编译为后续lesson10 无刷速度环打好 PID 代码基础2.2 与前后章节的关系章节内容lesson8PID 原理、离散公式、Python 交互仿真本章位置式 PID 上板 FireWater 波形输出 串口改目标lesson10速度环霍尔反馈 位置式 PID 控 PWM2.3 硬件与工程说明实验平台野火骄阳 F407 无刷驱动板本章暂不驱动电机闭环先在 MCU 内用仿真对象验证 PID保留 lesson7 的监测代码电压/电流/霍尔等便于工程统一PID 实验不依赖电机转动三、程序设计3.1 目录与模块划分User/ ├── pid/ │ ├── bsp_pid.h # 结构体、接口声明 │ └── bsp_pid.c # 位置式 PID 实现 ├── plant/ │ ├── bsp_plant.h # 一阶惯性被控对象可选独立模块 │ └── bsp_plant.c ├── usart/ # 串口命令 FireWater 波形发送 ├── vofa/ │ ├── bsp_vofa.h # FireWater 帧发送 │ └── bsp_vofa.c └── main.c # 初始化、定时 PID、50ms 发 FireWater3.2 PID 结构体设计参数Kp、Ki、Kd限幅out_min、out_max、integral_max状态integral、prev_error可选调试量p_term、i_term、d_term、output接口pid_init()、pid_reset()、pid_update(setpoint, measurement, dt)3.3 位置式 PID 核心流程计算误差e setpoint - measurement求 P / I / D 三项合成输出并限幅抗饱和输出顶满且误差同向时撤销本次积分保存prev_error供下次 D 项使用3.4 被控对象一阶惯性软件仿真T · dy/dt y K · u离散化欧拉法y (K*u - y) / T * dt建议初值K1.0T2.0与 lesson8 仿真一致PID 输出u作为对象输入对象输出y作为反馈3.5 采样周期 dt使用定时器周期中断如10ms→dt0.01fdt必须与中断周期一致不可在 main 循环里“随缘”调用对比 lesson8dt0.05s为仿真步长上板常用 5~20ms四、串口命令与 FireWater 输出本章不再使用lesson6/7 的0xAA 0x55二进制帧改为 VOFAFireWater输出 PID 曲线目标值仍通过串口文本命令修改。VOFA方便看曲线不是必须使用。后续章节会改用FreeMASTER。4.1 串口命令本章所有实验命令均通过USART1、115200发送。可在 VOFA「命令/调试」窗口或任意串口助手输入以回车结束字母大小写均可如t 60与T 60等效。与 FireWater 波形共用同一串口命令回显带[MOT]前缀如Target: 60波形数据为纯 CSV、无前缀二者不要混淆。上电默认值仅首次初始化之后可被串口命令覆盖项目默认值串口能否修改目标 SP50能tKp1.5能kpKi0.35能kiKd0.25能kd对象输出 ACT0不能随 PID 运算变化采样周期 dt0.01 s10 ms不能输出限幅0100不能指令一览命令作用取值范围执行后副作用t [值]修改目标值SP0100自动pid_reset()触发阶跃响应kp [值]修改比例系数Kp010自动pid_reset()ki [值]修改积分系数Ki05自动pid_reset()kd [值]修改微分系数Kd05自动pid_reset()pid打印当前 SP、Kp、Ki、Kd—无r清 PID 内部状态积分、上次误差等—仅pid_reset()不改SP 与 Kp/Ki/Kd?打印帮助与当前参数—无非法命令会提示Invalid command并再次打印帮助。常用示例? # 查看帮助与当前参数 pid # 仅查看 SP / Kp / Ki / Kd t 70 # 目标改为 70阶跃非改 PID kp 1.5 # 仅 P 实验时可先设 Kp ki 0 # 关闭积分 → 纯 P 控制 kd 0 # 关闭微分 t 60 # 改目标观察阶跃响应 r # 波形异常时可手动清积分一般不必单独发说明t 70改的是目标值 SP不是 Kp/Ki/Kd。改t/kp/ki/kd时程序会自动清积分避免旧积分拖累新参数或新目标。做6.2 仅 P 控制时典型顺序ki 0→kd 0→kp 1.5或其它 Kp→t 70。做6.3 加 I时在 P 基础上ki 0.1逐步加大做6.4 加 D时再kd 0.1等。下位机帮助信息与上表一致Serial: t [0-100] kp [val] ki [val] kd [val] pid r ? Example: t 60 | kp 1.5 ki 0.35 kd 0.254.2 FireWater 波形输出本章核心修改目标时的注意点目标突变等价于阶跃响应便于在 VOFA 上观察 SP/ACT 曲线大幅改目标时可调用pid_reset()清积分按需串口收命令与 FireWater 发波形共用 USART1命令在 main 解析波形按固定周期发送与前后实验的关系章节串口输出方式用途lesson6 / 7自定义二进制帧帧头0xAA 0x55电压、电流、霍尔 RPM 等需配套解析lesson8Python matplotlib仿真曲线无上位机本章VOFA FireWaterPID 多通道曲线对应 lesson8 的「看波形调参」lesson10预告可改JustFloat速度环通道增多、PID 周期更快时再换本章是用 VOFA软件对象 7 路 float、50ms 一帧FireWater 最合适。协议选择VOFA 内置三种协议详见 vofa.plus协议格式优点缺点本章FireWaterCSV 浮点 \nprintf即可调试直观带宽比二进制大推荐JustFloat小端 float 数组 帧尾省带宽适合多通道高速需组包不如字符串直观lesson10 可选RawData原始字节当普通串口助手不能自动画曲线不用通道定义FireWater逗号分隔行尾\n序号通道名含义ch0SP目标值 setpointch1ACT被控对象输出反馈ch2ERR误差 SP − ACTch3OUTPID 输出ch4P比例项ch5I积分项ch6D微分项下位机发送示例每50ms发送一行与 lesson7 波形刷新节奏一致voidvofa_send_firewater(constpid_handle_t*pid,floatsp,floatact){floaterrsp-act;motor_log(%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n,sp,act,err,pid-output,pid-p_term,pid-i_term,pid-d_term);}注意必须是FireWater纯浮点 CSV以\n结尾不要加SP等前缀否则 VOFA 无法按列解析发送频率20Hz 左右即可不必与 PID 中断同频10ms PID、50ms 发波形VOFA 上位机设置安装并打开 VOFA串口115200与DEBUG_USART_BAUDRATE一致协议FireWater通道数7按上表命名SP / ACT / ERR / OUT / P / I / D打开串口后下位机运行应看到多条曲线在「命令/调试」窗口发送t 60改目标观察 ACT 阶跃响应与 lesson8 阶跃实验对照建议观察的曲线曲线作用SP ACT是否跟踪目标、有无超调/稳态误差对应 lesson8 响应曲线ERR误差是否收敛到 0OUT是否长时间顶在限幅P / I / D调 Kp/Ki/Kd 时分项变化五、主程序流程5.1 初始化时钟、LED、串口pid_init()设置 Kp/Ki/Kd 与限幅启动定时器中断PID 周期5.2 定时器中断PID 任务setpoint ← 全局目标串口命令已更新 measurement ← plant_get_output() output ← pid_update(setpoint, measurement, dt) plant_update(output, dt)5.3 主循环解析串口命令更新setpoint或Kp/Ki/Kd见 4.1 节每 50ms 调用vofa_send_firewater()发送 FireWater 帧六、实验步骤实验前请确认VOFA 已按 4.2 节 配置115200、FireWater、7 通道串口指令见 4.1 节——改目标用t改 PID 用kp/ki/kd全程无需重新编译烧录。6.1 上电过程上电时参数SP: 50ACT: 0ERR: 50PID: 0从图可以看到ACT在0升到近目标50ERR值近1.47。在这个过程中P的值一直下降而积分值一路累加到后面积分值成为OUT主力而D的值接近0轻微阻尼6.2 仅 P 控制kp1.5,ki0,kd0目标值改为70t 70最后有稳态误差42。6.2 加入 I固定Kp1.5Ki从 0.1 调到 0.5误差缩至0.6.3 加入 D本章被控对象是 一阶惯性响应 平滑、基本无超调而D 的主要作用是抑制超调、加快边沿、阻尼振荡。由于对象本身就不振荡Kd 能发挥的空间很小。本节不作过多D项调整测试。6.4 与 lesson8 对照项目lesson8 Python本章 STM32对象一阶 滞后一阶可先不加滞后dt0.05s0.01s示例改目标滑块 / 阶跃串口t [值]观察matplotlib 曲线VOFA FireWater 曲线源码地址https://gitee.com/xundh/learn-motor-stm32