3. 位置数据处理:编码器计数与角度换算、零点校准与寻零逻辑、多圈位置累加与防溢出

各位同学,咱们今天聊点实在的。位置环要跑得准,第一步就是得把编码器的原始数据伺候好。说白了,你算法写得再漂亮,位置数据一塌糊涂,电机照样抖成筛子。我这些年踩过的坑,十有八九都出在数据处理的细节上。

3.1 编码器计数与角度换算

编码器输出的原始值,通常是一个脉冲计数值。比如增量式编码器,每转一圈输出 N 个脉冲。那问题来了:怎么把这个计数值变成我们控制算法里用的角度?

公式其实很简单:

角度(度) = (编码器计数值 / 单圈总脉冲数) * 360

但这里有个坑——分辨率。我见过有人直接用整型除法,结果角度永远是 0。你想想看,计数值 100,单圈 1024 脉冲,100/1024 在整型里就是 0。所以一定要用浮点运算,或者先乘后除。

核心要点:

  • 单圈脉冲数 = 编码器物理线数 × 4(如果是正交解码)
  • 角度范围:0 ~ 360 度,或者 -180 ~ 180 度,看你的习惯
  • 数据类型:建议用 float,精度够用,STM32 的 FPU 跑起来也不慢

我个人习惯把角度归一化到 0~360 度。为什么?因为后面做位置环 PID 时,误差计算更直观。你想想,目标 350 度,当前 10 度,误差是 -20 度还是 340 度?归一化之后,我们就能用简单的取模运算搞定。

3.2 零点校准与寻零逻辑

编码器上电时,位置是随机的。你得告诉系统:哪里是机械零点

零点校准有两种常见做法:

方法 原理 适用场景
硬件限位开关 电机撞到限位后,记录当前位置为零点 有物理限位的系统,如 3D 打印机
软件寻零(Z 信号) 编码器每圈输出一个 Z 脉冲,检测到后清零 增量式编码器,需要绝对参考点
上电自动校准 电机主动转动到预设位置,记录零点 无传感器或低成本方案

我在项目中遇到过一个问题:用 Z 信号寻零时,电机刚上电就高速旋转,结果 Z 脉冲太快没抓到。后来我加了个逻辑——先低速寻零,再切回正常速度。嗯,这里要注意,寻零速度不能太快,否则容易丢脉冲。

我的经验:

寻零逻辑最好做成状态机。比如:

  • 状态1:等待寻零指令
  • 状态2:低速正向旋转,等待 Z 信号
  • 状态3:检测到 Z 信号,记录位置,停止
  • 状态4:回退一小段,消除机械间隙
  • 状态5:确认零点,进入正常运行

这样做的好处是——每个步骤都可控,出了问题也好排查。

3.3 多圈位置累加与防溢出

单圈角度只能表示 0~360 度。但很多应用需要多圈位置,比如机械臂、转台。这时候就要做多圈累加

累加逻辑其实不复杂:

// 伪代码示例
int32_t multi_turn_position = 0;
float last_angle = 0.0f;

void update_position(float current_angle) {
    float delta = current_angle - last_angle;
    
    // 处理过零点
    if (delta > 180.0f) {
        delta -= 360.0f;
    } else if (delta < -180.0f) {
        delta += 360.0f;
    }
    
    multi_turn_position += (int32_t)(delta * 1000); // 放大1000倍,保留精度
    last_angle = current_angle;
}

这段代码里,最关键的是过零点处理。你想想,从 359 度变到 1 度,实际只转了 2 度,但如果不处理,delta 就是 -358 度,位置直接跳变。所以我们要判断:如果 delta 绝对值大于 180 度,说明它跨过了零点,需要修正。

防溢出警告:

多圈位置累加用的是 int32_t,最大约 21 亿。如果你放大 1000 倍,那就是 21 亿 / 1000 = 210 万圈。听起来很多,但如果你电机转速 3000 RPM,跑 700 分钟就溢出了。

我曾经在一个自动化产线上吃过这个亏——设备连续运行三天后,位置突然跳变,差点把机械臂撞坏。从那以后,我养成了两个习惯:

  • 定期做位置快照,保存到非易失存储器
  • 溢出时做饱和处理,而不是直接归零

防溢出的另一种思路是使用浮点数累加。float 的精度虽然有限,但范围大得多。不过要注意,浮点数累加久了会有累积误差。我一般会在每次寻零后重置累加值,这样误差就不会累积。

3.4 本章知识体系

下面这张图,是我自己总结的位置数据处理流程。你看一眼,基本就明白整个链路了。

位置数据处理流程 编码器原始脉冲 增量式/绝对值 角度换算 计数值 → 角度(0~360°) 零点校准 Z信号/限位开关 多圈 累加 防溢出处理 饱和/快照/浮点 寻零状态机 低速→检测→回退→确认 最终位置数据 给位置环PID使用

这张图把整个流程串起来了。从编码器原始数据开始,经过角度换算、零点校准、多圈累加,最后输出给位置环。中间还有防溢出和寻零逻辑两个分支。你写代码的时候,就按这个顺序来,基本不会乱。

一个小技巧:

调试阶段,我习惯把每一步的中间结果都打印出来。比如编码器原始值、换算后的角度、多圈累加值。这样一旦位置出问题,一眼就能看出是哪一步算错了。别嫌麻烦,这能省你半天时间。

好了,位置数据处理这块就聊到这儿。记住一句话:数据不准,算法白费。把编码器伺候好了,后面的位置环才能跑得稳。


公众号:蓝海资料掘金营,微信deep3321