Lazy loaded image
ODrive 源码分析(一):闭环控制、限幅与参数整定
Words 3441Read Time≈ 9 min
2026-9-19
2026-9-21
🎯
本文目标
不是继续背 FOC 公式,而是回答三个工程问题:目标怎样逐级变成 PWM?每一层怎样限幅和防止积分饱和?出现振荡、跟随慢或飞转时,怎样沿源码定位?

一、源码阅读边界

重点文件:
  • controller.cpp:输入模式、位置环、速度环、转矩限幅、抗齿槽转矩与 Spinout 检测。
  • motor.cpp:转矩到 、电流矢量限幅、电阻/电感与反电动势前馈。
  • foc.cpp:Clarke/Park、电流 PI、调制限幅、逆 Park 与 SVM。

二、控制数据链

2.1 输入不是直接进入控制器

Controller::update() 先根据 input_mode 处理命令。
ℹ️
这些名称不是依次执行的一组同步命令,而是 input_mode 枚举中的互斥处理模式。每个控制周期进入 Controller::update() 时,switch 只执行当前选中的一个分支。
从执行方式看,各分支都在当前控制周期内同步、非阻塞地完成一次计算;但斜坡、滤波、轨迹和调试信号需要跨多个控制周期逐步更新状态,并不是一次调用就完成整个动作。
输入模式
主要处理目标
每周期具体处理
时间特征
PASSTHROUGH
位置、速度、转矩三个目标
将 input_pos、input_vel、input_torque 直接复制到对应设定值,不做平滑
单周期立即生效,输入阶跃会直接传入后级
VEL_RAMP
速度目标
按 vel_ramp_rate 限制每周期速度变化量,并根据惯量和加速度生成转矩前馈
多周期逐步逼近目标速度
TORQUE_RAMP
转矩目标
按 torque_ramp_rate 限制每周期转矩变化量
多周期逐步逼近目标转矩
POS_FILTER
位置目标,同时兼顾速度与转矩前馈
用二阶跟踪滤波器处理位置、速度误差,更新位置设定、速度设定,并由估算加速度生成转矩前馈
连续跨周期跟踪,降低位置阶跃冲击
TRAP_TRAJ
点到点位置运动
收到新位置目标时规划梯形轨迹;之后每周期根据轨迹时间输出位置、速度和加速度前馈
规划触发一次,轨迹在后续多个周期中推进
TUNING
控制器辨识与整定
生成指定频率和幅值的正弦位置、速度或转矩测试信号
持续周期注入,只用于测试,不是正常运动模式
INACTIVE
保持现有内部设定
不更新设定值
当前周期无输入处理
MIRROR
跟随另一轴
读取另一轴的位置、速度和转矩,并按比例映射到当前轴
每周期同步读取并更新;依赖另一轴估计有效
工程含义:这些模式解决的是“外部命令怎样变成控制器内部设定值”,而不是选择位置环、速度环或电流环。闭环层级由 control_mode 决定,命令整形方式由 input_mode 决定。两者是两个不同维度:例如位置控制既可以搭配 PASSTHROUGH,也可以搭配 POS_FILTER 或 TRAP_TRAJ。
控制器参数没有变,但输入整形不同,机械冲击、峰值电流和跟随误差会完全不同。
notion image
notion image

2.2 位置环输出的是速度修正量

位置模式下:
随后 vel_des 被速度限制器约束。位置环本身没有直接输出电压或PWM。

2.3 速度环输出的是转矩

速度模式下:
源码先加入比例项和积分项,再根据 max_available_torque() 限幅。发生限幅时,速度积分按比例衰减;未限幅时才继续累加,并再次受 vel_integrator_limit 限制。
这不是“给积分项随便加个上限”,而是针对执行器当前是否还能继续输出和积分器历史状态是否过大设置的两层保护:
  1. 执行器饱和保护:当转矩命令已经超过电机当前可用转矩,继续积分也无法增加实际输出,只会把误差累积成更大的积分状态。因此源码在饱和时停止正常积分,并衰减已有积分,避免解除饱和后出现长时间过冲或反向恢复迟缓。
  1. 积分状态限幅:即使执行器尚未触发转矩限幅,积分状态本身仍被约束在 ±vel_integrator_limit 内,防止小误差长期累积、参数异常或反馈偏置把积分项推到不可控范围。
速度 PI 的两层抗积分饱和保护:输出饱和保护解决“现在已经加不动,别再继续积”;积分状态限幅解决“过去积下的量不能无限大”。
速度 PI 的两层抗积分饱和保护:输出饱和保护解决“现在已经加不动,别再继续积”;积分状态限幅解决“过去积下的量不能无限大”。
💡
一句话理解
第一层看的是输出能力:执行器已经顶到上限,就不要继续制造积分欠账;第二层看的是内部状态:无论是否饱和,历史欠账都必须有封顶值。两层缺一不可。

2.4 转矩如何变成电流

对 PMSM/BLDC:
Motor::update() 不是分别裁剪 、 后就结束,而是在总电流圆内限制:
因此 占用越多,可供转矩使用的 越少。只看单轴限幅会错误估计实际转矩能力。

2.5 电流环与调制限幅

FieldOrientedController::get_alpha_beta_output() 完成:
  1. 相电流 Clarke 变换;
  1. 用采样时刻预测的电角度做 Park 变换;
  1. 计算 误差;
  1. PI 与前馈共同产生 ;
  1. 按母线电压转换为调制度;
  1. 对调制矢量限幅;
  1. 饱和时衰减电流环积分,否则继续积分;
  1. 逆 Park 后进入 SVM。
电流环参数由电机模型计算:
其中 对应配置的电流环带宽。电阻、电感测错,PI参数也会跟着错。

三、三个典型故障的判断路径

3.1 空载也出现高频电流振荡

按顺序检查:
  1. 电流采样偏置和极性;
  1. 电角度方向与相序;
  1. 相电阻、相电感是否可信;
  1. 电流环带宽是否过高;
  1. 控制数据时间戳是否错位。
不要先调速度环。速度环默认把电流环看成一个可信、快速的转矩执行器:它给出多少转矩命令,内环就应当稳定地产生对应电流和实际转矩。
如果电流采样、极性、电角度、相序、电机参数或采样时序有误,内环反馈就会失真,实际转矩也会随之振荡。速度环看到的只是转速偏差,并不知道偏差来自错误的内环,于是会继续增大或反复修正转矩命令。此时调整 vel_gain 或积分增益,本质上只是给错误信号增加增益:参数调低可能暂时掩盖振荡,调高则通常让振荡更严重,但都没有修复根因。
内环反馈失真会沿“电流异常 → 转矩不稳 → 速度振荡 → 外环继续修正”的链路向外传播。正确顺序是先证明电流环和转矩输出可信,再整定速度环。
内环反馈失真会沿“电流异常 → 转矩不稳 → 速度振荡 → 外环继续修正”的链路向外传播。正确顺序是先证明电流环和转矩输出可信,再整定速度环。
⚠️
判断原则
先断开或弱化外环,验证电流采样、电角度、相序、电机参数和时间同步;确认电流阶跃稳定、实际转矩方向正确后,再调速度环。否则不是在调控制器,而是在用外环放大内环的错误。

3.2 速度跟随慢,但电流没有到限值

检查:
  • vel_gain 是否过小;
  • 速度估计滤波是否过重;
  • 轨迹或斜坡模式是否主动限制变化率;
  • 转矩常数配置是否让“转矩→电流”换算偏小。

3.3 目标减速,电机反而继续加速

ODrive 使用机械功率和电功率方向不一致检测 SPINOUT。常见根因是编码器方向、相位偏移或相序错误,而不是简单的“速度PI太大”。

四、面试问题与参考答案

问题1:为什么电流环必须比速度环快?

参考答案:速度环把电流环视为近似理想的转矩执行器。如果两者带宽接近,速度环发出的转矩命令在电流环尚未建立时又继续修正,两个环相互追加相位滞后,容易振荡。工程上先保证采样和电流环稳定,再降低一个数量级设计速度环,最后设计位置环。具体比例需结合采样频率、机械惯量、传感器噪声和稳定裕度验证,不能背固定数字。
带宽到底是什么?
带宽描述的是闭环系统能够有效跟随多快的目标变化。工程上通常用闭环幅频响应下降到低频增益的 时对应的频率 表示。目标变化远低于该频率时,系统通常能较准确地跟随;接近带宽时,幅值开始衰减且相位滞后增加;高于带宽后,控制器基本追不上,也不应继续强行放大。
对近似一阶闭环,可用下面的关系粗略理解带宽与响应速度:
其中 是约 10% 到 90% 的上升时间。它只是数量级估算,不等同于整定结果;机械共振、采样延迟、滤波和限幅都会改变真实响应。
⚠️
带宽不等于控制循环频率
控制循环频率表示控制器每秒计算多少次;带宽表示闭环能够跟随多快的变化。循环跑到 20 kHz,不代表系统带宽就是 20 kHz。为保留离散控制和相位裕度,控制频率通常至少是目标带宽的 10~20 倍,实际还要结合 PWM、ADC、编码器更新率和计算延迟。
一个三环设计示例
假设某 PMSM 伺服系统满足以下条件:FOC/PWM 控制频率为 20 kHz,编码器与电流采样可靠,机械结构没有落入目标频段的强共振。可以先用下面的数值作为保守起点,而不是直接照抄的最终参数。
控制环
示例执行频率
示例闭环带宽
近似上升时间
该环看到的执行器
电流环
20 kHz
1 kHz
0.35 ms
逆变器、电机
速度环
2 kHz
100 Hz
3.5 ms
已闭合的电流环,即近似转矩源
位置环
500 Hz
10 Hz
35 ms
已闭合的速度环,即近似速度源
该示例采用约 10:1:1 的“执行频率相对本环带宽”下限和约 10:1 的相邻环带宽分离:
它的真正含义不是“三环必须永远差十倍”,而是让外环发出新命令之前,内环已经基本建立响应。这样每一层都可以把内层近似成一个稳定、快速的执行器,环间耦合和额外相位滞后更小。
怎样确定实际三环带宽?
  1. 先确定硬上限:从 PWM/ADC 频率、计算延迟、电机电气时间常数 、编码器更新率和机械共振频率中找出最严格约束。
  1. 先闭合电流环:从较低带宽开始做小幅电流阶跃或扫频,检查上升时间、过冲、噪声、调制饱和与相位裕度;电流环稳定后才进入速度环。
  1. 再闭合速度环:初始带宽取电流环的约 ~,通过速度阶跃观察振荡、转矩峰值和负载扰动恢复,再逐步提高。
  1. 最后闭合位置环:初始带宽取速度环的约 ~,同时避开机械共振,并根据定位时间、超调和轨迹平滑要求调整。
  1. 用波形验证而不是背比例:至少记录目标值、反馈值、误差、控制输出、积分项和饱和标志。若出现持续振铃、噪声明显放大或频繁饱和,应退回上一档,而不是继续加增益。
💡
面试时可以这样总结
三环带宽按“电流环最快、速度环次之、位置环最慢”设计。先由采样频率、延迟和被控对象确定电流环上限,再让相邻外环低约 5~10 倍,并通过阶跃或扫频验证稳定裕度。1 kHz / 100 Hz / 10 Hz 是便于解释的示例,不是脱离硬件和机械结构的固定答案。
 

问题2:ODrive 如何避免速度环积分饱和?

参考答案:速度环输出先受电机可用转矩限制。未饱和时积分按误差累加;饱和时不再继续正常累加,而是衰减已有积分,同时积分状态受独立上限约束。这样解除饱和后,控制量不会被历史积分长期顶在极限。

问题3:为什么调制饱和时也要处理电流环积分?

参考答案:调制度达到母线电压能够提供的上限后,增加 命令已经不能增加实际输出。积分若继续累加,退出饱和时会造成过冲和恢复缓慢。因此 ODrive 对调制矢量缩放,并在饱和期间衰减 d/q 积分。

问题4:转矩限幅与电流限幅有什么关系?

参考答案:转矩上限最终受有效电流上限和转矩常数共同决定。有效电流还会受到硬件量程、电机温度、MOS温度和配置值限制。转矩转换成 后,还必须与 一起满足总电流圆,因此转矩限制不是一个孤立常数。

问题5:如何证明自己真的掌握了这一部分?

参考答案:做三组阶跃实验:电流、速度、位置。记录目标与反馈、积分项、限幅标志、 和调制度。分别制造带宽过高、输出饱和和编码器偏移错误,能够根据波形定位并恢复,而不是只展示“电机能转”。

五、建议实验

绘制一次速度阶跃的 vel_setpoint / vel_estimate / torque / Iq / mod_q。
人为降低电流上限,观察速度积分在饱和与解除饱和时的变化。
修改相电阻或相电感配置,观察电流环响应并解释原因。
对比直通、速度斜坡和梯形轨迹三种输入模式的峰值电流。
制造错误编码器方向,记录 Spinout 前的机械功率与电功率方向。

六、结论

掌握这一部分的标准不是能写出 Clarke/Park 公式,而是能够沿 Controller → Motor → FOC → SVM 解释每个目标、反馈、限幅和积分状态,并用波形证明自己的判断。
上一篇
ODrive 源码分析(三):状态机、故障保护与调试闭环
下一篇
学习笔记 - Effective C++

Comments
Loading...