在机器人领域舵机编码器是赋予舵机“感知能力”的关键元件它让舵机从一个只能被动执行指令的“盲从者”变为一个能够实时反馈自身状态的“智能”关节。https://www.bilibili.com/video/BV134sFzwEXT 什么是舵机编码器舵机编码器是一种将舵机输出轴的机械旋转角度、位置转换为电信号的传感器。它作为闭环控制系统中的反馈环节实时向主控板报告舵机的精确位置使控制系统能够进行精准的修正和调整。编码器 vs. 电位器许多标准舵机如SG90内部使用电位器进行位置反馈。它结构简单、成本低但存在明显缺点精度较低通常为几度的误差。机械磨损滑动触点会随使用次数增加而磨损影响寿命和稳定性。易受干扰输出的是模拟信号容易受到电磁干扰。相比之下编码器尤其是数字编码器具有显著优势高精度分辨率可达0.1°甚至更高。长寿命多为非接触式如光学、磁性无机械磨损。抗干扰强输出数字信号稳定可靠。因此在需要高精度控制的机器人关节、云台或机械臂中使用带编码器的舵机或为舵机加装外部编码器是常见的做法。⚙️ 编码器的工作原理编码器主要分为两大类增量式和绝对式。增量式编码器这种编码器通过输出连续的脉冲信号来工作。核心原理编码器内部有一个码盘旋转时会产生两路相位差为90°的方波脉冲A相和B相。判断方向通过检测A相和B相信号的相位先后关系可以判断旋转方向顺时针或逆时针。计算位置控制器通过计算脉冲的数量来确定相对位移。例如编码器每转一圈输出1000个脉冲1000 PPR那么每个脉冲就代表0.36°的转动。优点结构简单、成本低、响应快。缺点断电后会丢失当前位置信息重新上电时需要“回零”校准。绝对式编码器这种编码器为旋转范围内的每一个角度都提供一个独一无二的数字编码。核心原理码盘上有多圈复杂的编码轨道传感器读取这些轨道的组合直接输出一个代表绝对位置的数字值如二进制码或格雷码。优点上电即知当前位置无需校准抗干扰能力更强。缺点结构复杂成本较高。 应用示例为何需要编码器一个典型的应用场景是控制一个连续旋转舵机也称360°舵机精确转动指定圈数。问题所在普通的连续旋转舵机内部没有位置反馈移除了电位器它只能响应“正转”、“反转”、“停止”这类速度指令。你无法直接命令它“转5圈然后停下”因为它不知道自己转了多少。编码器解决方案加装“眼睛”在舵机的输出轴上安装一个编码器如磁性编码器AS5048A让它实时监测舵机轴的转动。构建闭环主控板如Arduino向舵机发送“正转”指令同时持续读取编码器的数据。精确停止程序设定一个目标值例如转动10圈。主控板计算编码器反馈的脉冲数当累计脉冲数达到10圈对应的数值时立刻向舵机发送“停止”指令。通过这种方式一个原本“盲目”旋转的舵脉冲计数值机就变成了一个可以精确控制圈数和角度的智能执行器可以应用于自动云台、卷帘门控制等需要精确定位的场景。️ 代码示例读取编码器并控制舵机下面是一个使用 Arduino 读取旋转编码器如EC11模块来控制普通舵机如SG90角度的入门示例。这模拟了“所见即所得”的控制方式你转动编码器旋钮舵机就跟着转动。所需材料Arduino UNOSG90 舵机EC11 旋转编码器模块杜邦线硬件连接表格组件引脚连接到 Arduino舵机VCC (红)5VGND (棕)GNDSignal (黄)D9编码器VCC5VGNDGNDCLK (A相)D2 (中断引脚)DT (B相)D3SW (按键)(可选)示例代码此代码利用中断来精确、快速地读取编码器的转动并控制舵机角度。#include Servo.h Servo myservo; // 创建舵机对象 // 定义编码器引脚 const int encoderPinA 2; // 连接到CLK使用中断0 const int encoderPinB 3; // 连接到DT volatile long encoderPos 0; // 编码器位置计数使用volatile因为在中断中修改 int currentAngle 90; // 舵机当前角度初始为90度 void setup() { pinMode(encoderPinA, INPUT_PULLUP); pinMode(encoderPinB, INPUT_PULLUP); // 附加中断服务函数到A相引脚的CHANGE事件 attachInterrupt(digitalPinToInterrupt(encoderPinA), readEncoder, CHANGE); myservo.attach(9); // 舵机连接到D9 myservo.write(currentAngle); // 初始化舵机到90度 Serial.begin(9600); // 开启串口监视 } void loop() { // 将编码器的计数值映射到舵机的0-180度范围 // 这里假设编码器转动一圈40个计数对应舵机转动180度 // 实际项目中需要根据编码器分辨率和舵机范围进行调整 int targetAngle map(encoderPos, 0, 40, 0, 180); targetAngle constrain(targetAngle, 0, 180); // 限制角度在0-180之间 // 只有当目标角度变化时才更新舵机减少不必要的操作 if (targetAngle ! currentAngle) { myservo.write(targetAngle); currentAngle targetAngle; Serial.print(Encoder Pos: ); Serial.print(encoderPos); Serial.print( - Servo Angle: ); Serial.println(currentAngle); } delay(50); // 简单的延时稳定读取 } // 中断服务函数读取编码器A/B相判断方向和计数 void readEncoder() { static uint8_t oldAB 0; // 读取A、B两相的当前状态 oldAB (oldAB 2) | (digitalRead(encoderPinA) 1) | digitalRead(encoderPinB); // 根据A、B相的相位关系判断旋转方向 if ((oldAB 0x0F) 0x07) { // 顺时针旋转 encoderPos; } if ((oldAB 0x0F) 0x0B) { // 逆时针旋转 encoderPos--; } }