教程 · 入门 · 阅读约 17 分钟
读取正交编码器,测出轮子的行驶距离与速度
解码正交编码器的信号,把计数换算成轮子的行驶距离和速度,处理方向判断与计数溢出,并在真实的机器人上标定测量结果。
轮子编码器把转动变成数字脉冲。数这些脉冲就能量出机器人走了多远;把它们按时间数起来就能估计速度。正交编码器提供两个脉冲通道,A 和 B,错开四分之一个周期。哪个通道先变,就揭示了方向。
编码器量的是相对运动,不是绝对位置。计数只有在开机之后或一次有意复位之后才有意义;而它也只有在你明确规定了“多少个计数算轮子转一圈”之后才有用。
读那个双通道模式
有效的正交状态是 00、01、11 和 10。往一个方向转就沿着这个序列走,反方向转则逆着走。每次只应该有一个位变化。像 00 直接跳到 11 这样的跳变,说明漏掉了一个边沿,或者噪声把信号搞坏了。
有三种常见的计数模式:
- **1× 解码:**每周期数 A 通道的一个边沿。
- **2× 解码:**数 A 通道的两个边沿。
- **4× 解码:**数两个通道的每一个边沿。
所以一份写“每转 12 个脉冲”的数据手册,软件上可能产生每编码器轴转 12、24 或 48 个计数。如果编码器装在电机上而不是轮子上,还要乘上减速比。把完整的约定写在那个常数旁边;不明所以的两倍和四倍因子是里程计最常见的缺陷之一。
把信号正确接上
先确定输出是推挽、开集还是开漏。集电极开路或漏极开路的输出需要上拉电阻,而那个上拉可能是内部的也可能是外部的,取决于边沿速率和接线方式。确认信号电压对控制器是安全的——5 V 的编码器输出可能烧掉 3.3 V 的输入。
让线缆远离电机线。跑得更长时,用编码器厂家给的线缆和终端指导。一条干净的数字边沿,比事后在软件里修假计数值钱得多。
在跑电机之前先用手慢慢转轮子。两个通道都应该在有效逻辑电平之间交替。如果有一个卡住了,先修接线再调代码。
解出方向而不丢计数
速度适中时,在通道 A 每次变化时触发一次中断,采样 B 来定方向:
volatile long encoderCount = 0;
void onEncoderA() {
bool a = digitalRead(ENCODER_A);
bool b = digitalRead(ENCODER_B);
encoderCount += (a == b) ? 1 : -1;
}
符号取决于通道顺序和物理安装。把 A 和 B 对调或者把结果取反,让轮子前进对应正计数。在硬件边界上一次做完这件事,而不是把符号变化散落在里程计代码里。
边沿速率高时,反复调用 digitalRead() 可能太慢。用硬件正交外设、一个成熟的平台编码器库,或者针对该控制器的直接端口访问。选之前先估算最坏情况:每秒边沿数 = 每轮转计数 × 轮子每秒最大转数。
把中断里的活保持简短。更新计数,然后返回。打印、浮点换算和控制计算都属于主循环。
把计数换算成轮子行程
设 N 是每轮转的解码计数,D 是有效轮径。轮周长是 πD,于是:
distance = count × πD / N
对一只 65 mm 的轮子和每轮转 1,440 个解码计数来说,每个计数约合 0.142 mm。那个数学分辨率不等于真实精度:轮胎压缩、轮子打滑和直径误差通常要大得多。
安全地读多字节计数器。在小型单片机上,中断可能在主循环读到一半时更新它。短暂关中断,或者用平台的原子设施:
noInterrupts();
long snapshot = encoderCount;
interrupts();
float distanceM = snapshot * (PI * wheelDiameterM) / countsPerWheelRev;
用足够宽的有符号计数器,并对快照之间求差。无符号的模减也能处理回绕,但只有在类型和采样间隔都是有意为之的前提下。
估计速度而不放大噪声
在固定采样间隔上,计算计数差:
velocity = (newCount - oldCount) × distancePerCount / elapsedTime
间隔短响应快,但会把低速量化成零和一跳一计数。间隔长更平滑,但加了滞后。先从控制环周期附近起步,只有在控制器真的需要时才做几采样平均。
对非常慢的运动,测量边沿之间的时间可能比在固定窗口里数边沿更好。无论用哪种方法,都要用单调时钟打时间戳,并用实测的流逝时间,而不是假设每一轮循环都完美地按时刻执行。
在整条上传动上标定
在轮子上做个标记,让它精确转十圈并记录计数。除以十可以减小“在各个边沿之间停下来”的影响。然后让机器人沿一段量过的直线走,比较编码器距离和地面距离,调整有效轮径。
左右轮分别标定。如果机器人报告的距离相等却走弯,说明两个有效直径或者传动增益不同。保留各自独立的缩放系数;真实的轮胎和减速箱需要这个标定旋钮。
在第二个速度上重复一次。变化很大就提示打滑、轮毂松动、漏掉的边沿或时序问题,而不是简单的直径误差。
坏读数的诊断
- **静止时计数在变:**电气噪声或输入悬空;检查信号和上拉。
- **计数量级正好差 2 倍或 4 倍:**软件解码模式和数据手册的脉冲定义不一致。
- **方向随机翻转:**有一个通道嘈杂或采样太晚;检查边沿质量和解码方法。
- **高速时计数卡住:**控制器跟不上那个边沿速率;改用硬件解码或降低中断开销。
- **距离可重复但不对:**标定有效轮径和减速比。
- **距离随地面变化:**编码器量的是轮子转动,不是地面真值;轮子打滑是真实存在的不确定度。
可靠的计数是差速里程计的输入,而速度反馈可以闭合PID 控制器模拟器里探索的那个电机环。那份位姿也是每个路径跟踪器都假定的输入,这也是为什么它的误差就变成了它们的误差。
下一步
数数只是一半。测出来的速度之所以值得拥有,是因为你可以保持它——见闭环轮速控制,它把 PWM 从一个电压变成一个速度,也正是它阻止了机器人因为一台电机变弱而走弯。在全向底盘上,这就不再是个锦上添花的做法:四个轮速的比例就是转向,而开环没有任何东西可以保持它们。
探索关联图谱
本教程所属的搭建
包含本教程的项目和学习路线。
延伸阅读