元器件 · 执行器
N20 编码器减速电机
N20 是一款带金属齿轮箱、内置磁性编码器的小电机,也是既需要扭矩、又需要知道轮子位置的平衡机器人最常用的驱动电机。
它是什么
N20 是那种在极小空间里需要真实扭矩时就会出现的金属减速箱小电机。裸电机大约 5 号电池那么大;前端的减速箱用它极高的转速换来的扭矩,而在编码器版本上,后端轴上的一片磁铁盘会报告它转了多远。
后半句正是它能在平衡机器人里占一席之地的原因。没有轮子反馈的平衡车能站得笔直,却完全不知道自己在哪儿——它会一边把垂直保持得漂亮无比,一边在房间里到处乱走。编码器补上的正是这个缺口。
金属减速箱为什么这里要紧
TT 减速电机塑料箱循迹够好,循迹大都往前开。平衡车是另一种负载:持续换向,每秒几百次,小增量。
每个减速箱都有**背隙**——齿轮脱开的小死区,齿到另一边贴上之前输出不动。塑料箱死区大,平衡车上正落在修正最要紧处:换向瞬间,轮子要现在响应。结果就是小车绕着垂直方向来回振荡,永远稳定不下来,增益调得再细也没用。
金属齿消不掉背隙但小到环能干活。剩多少十分钟能量出来——方法在这里。
读编码器
编码器出两路 90° 相差方波——标准正交。相位关系给方向,数边沿给距离。
| 线(典型) | 接到 | 说明 |
|---|---|---|
M1、M2 |
电机驱动输出 | 电机本体;极性定方向 |
VCC |
3.3 V 或 5 V | 编码器电源,不是电机电源 |
GND |
地 | 和控制器共地 |
C1 |
能中断的脚 | 编码器 A 通道 |
C2 |
任一数字脚 | 编码器 B 通道 |
不同供应商的线色不一样,所以要去看商品说明,别靠猜。最容易坑人的一个错误,是让编码器从电机电源轨取电:编码器需要干净的逻辑电源,喂给它电机电压,要么直接烧掉,要么每次电机切换时都让计数里塞满噪声。
A 通道放能中断的脚。平衡车上 loop() 轮询编码器丢计数,丢计数外环慢慢不知车在哪。
选减速比
减速比决定了扭矩与速度之间的取舍,而平衡机器人两者都需要:
- 减速比太大(1:250 及以上)扭矩充足,但轮子转速不够快,追不上正在倒下的机身。
- 减速比太小(1:30 及以下)转得很快,却没法有力地推动机器人的质量。
12 V 1:100——约 200 RPM——小车可靠起点。小扰动接得住大扰动接不住,多半要速度不要增益。
驱动它
N20 要配 TB6612FNG,别配 L298N。原因在于压降:L298N 的输出级大约要吃掉 2 V,所以电池里很大一部分根本到不了电机,那些细小的修正指令会落到电机压根转不起来的电压之下。而在平衡机器人上,这个死区正好就住在精细修正必须起作用的地方。
用一块电池包供电,它得能在两台电机同时堵转时给出电流而不发生电压下垂——电源轨一下垂,单片机就会在修正过程中途复位,而机器人摔倒的原因跟你的控制循环毫无关系。
算每轮转计数
距离计算全靠这个数,也是最常错的数——经常四倍。
counts per wheel revolution = PPR x 4 x gear ratio
磁编码器每电机转每通道 7 脉冲。正交两通道 90° 相差,每脉冲周期四条可数边沿。减速箱电机转好多圈轮子一圈。
| 减速比 | 每轮转计数(×4) | 43 mm 轮分辨率 |
|---|---|---|
| 1:30 | 840 | 0.16 mm |
| 1:50 | 1400 | 0.10 mm |
| 1:100 | 2800 | 0.048 mm |
| 1:150 | 4200 | 0.032 mm |
| 1:298 | 8344 | 0.016 mm |
距离直接推出:
mm per count = (pi x wheel_diameter_mm) / counts_per_revolution
第一个公式两陷阱。×4 只在真数四边沿时对——双通道双边沿。例程很多只数 A 通道上升沿,那是 ×1,×1 计数配 ×4 常数距离整四倍。电机印的减速比经常约数:“1:100”N20 常 1:99.5 或 1:100.37。跑长距离的里程计,请实测标定:把机器人推正好 2 m,然后做除法。
边沿一个不丢地数
1:100 箱 200 RPM,电机轴 20000 RPM,每电机每秒 20000/60 × 7 × 4 ≈ 9300 边沿。两电机近每秒 19000 中断,还是空载全速。
中断处理函数必须真的足够小:
volatile long countL = 0;
// Full x4 decoding, table-driven. Both channels, both edges.
const int8_t QUAD_TABLE[16] = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0};
volatile uint8_t prevL = 0;
void isrLeft() {
uint8_t now = (digitalRead(ENC_L_A) << 1) | digitalRead(ENC_L_B);
countL += QUAD_TABLE[(prevL << 2) | now];
prevL = now;
}
void setup() {
pinMode(ENC_L_A, INPUT_PULLUP);
pinMode(ENC_L_B, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENC_L_A), isrLeft, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENC_L_B), isrLeft, CHANGE);
}
long readCount() { // long is not atomic on an 8-bit AVR
noInterrupts();
long v = countL;
interrupts();
return v;
}
三细节要紧:
**volatile 加原子读。**AVR 上 long 四字节分四次读。中断落读一半得到半新半旧值——里程计偶发巨大跳变,随机,几千读一次。
查表解码跳变,而不是只凭一个通道去猜方向。它还天然会拒绝非法跳变(两个位同时变化,说明你漏掉了一次跳变),因为那一次的贡献值为零。
**引脚压力。**两台电机做完整 ×4 解码需要四个支持中断的引脚,而 Arduino Uno 正好只有两个。可选方案有:用 ×2 解码(每台电机一个通道,CHANGE),分辨率减半但仍能给出方向;换到中断引脚更多的板子,比如 Mega 或 ESP32;或者用引脚变化中断,AVR 的每个引脚都支持,但必须整组端口一起处理。
计数变速度
位置是计数,速度要差分除时间,怎么取决定控制环能不能用。
long lastCount = 0;
unsigned long lastMicros = 0;
float speedMmPerSec() {
long c = readCount();
unsigned long t = micros();
float dt = (t - lastMicros) * 1e-6f;
if (dt < 0.005f) return lastSpeed; // too short: quantisation dominates
float mm = (c - lastCount) * MM_PER_COUNT;
lastCount = c; lastMicros = t;
lastSpeed = mm / dt;
return lastSpeed;
}
dt 这道保护是关键的一行。采样太快,就等于拿一两个计数去除以极短的时间间隔,量化误差便占主导,“速度”读数里大部分其实是噪声——而 PID 里的微分项会兴高采烈地把这些噪声放大。
用编码器测速有两种诚实的办法,各擅胜场。在固定窗口内数边沿(上面那段代码)在高速下表现好,在低速下表现差,因为每个窗口里到的边沿太少。测量边沿之间的时间间隔恰好相反:低速极好,高速嘈杂。既需要两端表现的项目,通常会在某个阈值上切换。
故障排查
| 现象 | 可能原因 | 解决 |
|---|---|---|
| 计数小 4 倍 | 数单边沿配 ×4 常数 | 四边沿全解,或修正数 |
| 正反转都加 | 只读单通道 | 正交要双通道——查表解码 |
| 位置偶发巨大跳 | long 非原子读 |
noInterrupts() 包读 |
| 电机停了计数漂 | 编码器线电气噪声 | 编码器干净供电,不走电机轨;双绞 |
| 高速丢计数 | 中断处理函数太慢,或者在轮询 | 保持 ISR 极小;绝不轮询 |
| 距离稳定地差 2–3% | 标称减速比和轮径 | 在 2 m 上标定,推导每个计数对应多少毫米 |
| 一轮计数一轮不计 | 编码器通道不在中断脚 | 查脚能力;Uno 只有 D2、D3 |
| 接线烧编码器 | 电机电压进编码器 VCC | 编码器要 3.3–5 V 逻辑,绝不电机轨 |
| 长跑位置漂 | 里程计天生就没有上界 | 正常——用绝对参考来修正 |
N20 还是 TT 减速电机?
| TT 减速电机 | N20 金属减速电机 | |
|---|---|---|
| 减速箱 | 塑料 | 金属 |
| 背隙 | 大——输出好几度 | 小 |
| 个头 | 笨 | 约 5 号电池 |
| 电压 | 3–6 V | 6–12 V 版本 |
| 减速比 | 基本一款(约 1:48) | 1:30 到 1:298 |
| 编码器 | 第三方配件,装起来别扭 | 内置磁式,标准做法 |
| 价格 | 约$2 | 约$8 |
| 适合 | 循迹、第一台车 | 平衡、精确里程计、紧凑 |
决定因素很少是扭矩,几乎总是背隙和反馈。循迹车大都只朝前开,靠一个看地面的传感器来转向——减速箱里的间隙它根本察觉不到,而 TT 电机正是又便宜又合适的答案。平衡机器人每秒要反向几百次,每次都是极小的增量,于是每次换向处的死区正好就是它的修正必须起作用的地方,而塑料齿轮会让这个闭环无论怎么调都不稳定。
同样的逻辑也适用于迷宫机器人:它靠数距离来导航,所以每次转弯丢掉的行程会直接累积成位置误差。
用在
- 自平衡车——驱动电机,编码器喂外环位置环
探索关联图谱
用到它的搭建
包含 N20 编码器减速电机 的项目、学习路线和模拟器。
对比
替代方案
问题
N20 编码器减速电机 常见问题
N20 编码器电机是什么?
N20 是一种约 12 × 10 × 26 mm 的微型减速电机,带金属减速箱;编码器版本还在电机轴后端加了一片小磁盘和一个传感器。减速箱让它输出的扭矩远超其体积给人的印象,而编码器报告的是输出轴实际转了多少,而不是你让它转多少。
平衡机器人为什么用 N20 电机而不用 TT 电机?
有两个原因。金属减速箱的背隙比 TT 电机的塑料减速箱小得多,而背隙对平衡机器人来说是毒药——电机每次换向,松垮的减速箱都会把修正动作的前几度白白浪费掉。此外,编码器还为外层控制环提供了真实的轮子位置,这正是让机器人能停在原地、而不是四处漂移的关键。
N20 每转一圈轮子能给出多少编码器计数?
用电机轴的脉冲数乘以减速比。典型的编码器每个通道在电机每转一圈时给出 7 个脉冲;在 1:100 的减速箱上,就是输出轴每转 700 个脉冲,如果把正交信号的四个边沿全部解码,则是 2800 个计数。一定要确认你手上那台电机的具体数值,因为脉冲数和确切的减速比在不同供应商之间都有差异。
能直接用 Arduino 引脚驱动 N20 吗?
不能。N20 运转时要几百毫安电流,堵转时约 700 mA,远超引脚能提供的电流,而且电感反冲还会损坏引脚。请使用 TB6612FNG 这样的电机驱动,它的压降也足够低,细小的修正指令仍然能真正让电机转起来。
平衡机器人应该选多大的减速比?
通常在 1:50 到 1:150 之间折中。减速比太大,扭矩充足,但轮子加速不够快,接不住正在倒下的机身;太小,电机又没有足够的扭矩去推动机器人的质量。12 V 下 1:100 左右、约 200 RPM 的配置,适合典型的小型平衡机器人。
延伸阅读