很多人第一次买 SG90 舵机时,会看到两个版本在货架上并排出现:标准 180° 舵机和 360° 连续旋转舵机。如果你买的是后者,又习惯性地用write(90)想让它转到一个固定角度,很快就会发现问题:舵机要么上电就朝一个方向猛转,要么转起来根本停不到指定位置,甚至有人怀疑自己买到了坏件。其实问题不在硬件,而在控制逻辑。
这次我们来看 SG90 360 度连续旋转舵机在 Arduino UNO 上的控制方法,重点聚焦writeMicroseconds()这个函数、开环控制的基本概念,以及一套从接线到验证的实测流程。文章会覆盖接线方式、Arduino IDE 配置、控制代码示例、方向与转速测试、故障排查,还有供电和资源占用层面的注意事项。如果你想搞清楚“为什么 360° 舵机不能直接转到指定角度”以及“用脉宽控制旋转到底该怎么写”,这篇文章可以直接收藏。
要特别说明的是:SG90 360° 连续旋转舵机并不是把标准舵机的角度范围扩大到 360°,而是改变了反馈结构。它内部不再通过电位器检测角度,所以脉冲宽度不控制角度,而是控制“方向和速度”。这意味着它是一个典型的开环系统:你只能发出“正转全速”“反转半速”“停止”之类的指令,却无法读取当前转到哪个位置。所有关于“转了多远”的判断,只能靠外部传感器或程序里的计时来补充。
1. SG90 360° 舵机核心认知速览
| 项目 | 说明 |
|---|---|
| 模块类型 | 微型连续旋转舵机,常见 9g 级别 |
| 控制方式 | PWM 脉宽控制,通常周期 20ms(50Hz) |
| 标准角度舵机 | 脉宽映射角度,例如 500us~2500us 对应 0°~180° |
| 360° 连续旋转舵机 | 脉宽映射方向和转速,通常在 1500us 附近停止 |
| 常见脉宽范围 | 以舵机规格为准,常见约为 1000us 全速正转、1500us 停止、2000us 全速反转 |
| 控制函数 | Arduino Servo 库的writeMicroseconds() |
| 是否能精确转角度 | 不能。无位置反馈,属于开环控制 |
| 停止方式 | 连续输出约 1500us 的停止脉宽 |
| 推荐开发板 | Arduino UNO、Nano 等 AVR 开发板 |
| 引脚兼容 | Servo 库通过普通数字引脚输出信号 |
| 电源需求 | 单个舵机建议独立 5V 供电,避免直接吃开发板稳压 |
| 适合场景 | 云台持续旋转、小型小车驱动、简单传动、实验中需要连续转动的机构 |
这张表里最需要记住的是:不要用角度思维写代码,要用方向和速度思维写代码。
市面上标“SG90 360°”的模块,不同批次的中位脉宽和全速脉宽可能不一样,有些舵机的停止点在 1480us 或 1520us,甚至左右死区不对称。所以拿到新舵机后,第一步不是跑你的项目代码,而是先校准中位。
2. 适用场景与使用边界
先泼一盆冷水:SG90 360° 连续旋转舵机不适合做精确位置控制。因为普通版内部没有输出轴角度传感器,你无法得知轴当前处于什么状态;如果负载发生变化,同一段脉宽下的实际转速也会变化,严格意义上连“精确调速”都做不到。它能保证的是“方向和占空比之间的定性关系”:脉宽偏向一边就正转,偏向另一边就反转,越偏离中位,通常转速越快。
它适合这几类场景:
- 小型机器人小车,直接驱动轮子实现前进、后退和调速。
- 云台转盘,需要持续或受控旋转,而不要求停在精确刻度。
- 简单门闸、卷帘、传送演示机构,配合外部限位开关闭环。
- 学习 PWM 脉宽控制原理,观察不同脉宽对电机转速的影响。
- 配合编码器、霍尔传感器或光电开关,把开环运动改造成带反馈的运动系统。
不适合的场景包括:
- 多关节机械臂的角度控制:如果没有编码器或外部传感器,定位误差会积累。
- 需要实时感知负载碰撞的应用:舵机内部没有电流反馈,堵转后只能靠外部检测判断。
- 长时间堵转运行:9g 舵机内部电机和齿轮都很小,长时间堵转发热严重,容易损坏。
- 对噪音和寿命要求高的商业项目:这种微型舵机的齿轮强度和电机寿命都有限。
合规提醒同样值得放前面。这类旋转机构如果装配到任何可能接触人体的设备上,必须增加机械限位、防护罩和安全切断逻辑。不要用普通舵机改造的装置直接用于载人、医疗或高可靠工业场景。教学和原型验证用途下,也要注意供电安全、防止短路,以及不要让线材卡进齿轮。
关于编码器或反馈:有经验的玩家会拆开舵机加装磁编码器,但普通使用者不建议这么折腾。更好的方式是选用自带反馈的“连续旋转舵机升级版”或带编码器的直流减速电机。开环适合验证运动逻辑,闭环才适合做有精度要求的落地产物。
3. 硬件准备与接线说明
3.1 硬件清单
针对一套最基础的验证环境,建议准备这些器材:
| 硬件 | 数量 | 用途 |
|---|---|---|
| Arduino UNO 板 | 1 块 | 主控,产生 PWM 信号 |
| SG90 360° 连续旋转舵机 | 1 个 | 被控对象 |
| USB 数据线 | 1 根 | 下载程序和供电 |
| 外部 5V 电源 | 可选 | 给舵机供电,避免 USB 供电不足 |
| 面包板及跳线 | 若干 | 完成信号连接和电源连接 |
| 万用表 | 可选 | 检查供电电压和接线是否短路 |
如果只用 USB 给 Arduino UNO 供电并带一个空载的 9g 舵机,多数情况下能转,但一旦堵转或接了两个以上舵机,很容易出现电压跌落、复位、异常抖动。更稳妥的做法是给舵机单独接 5V 电源,并和 Arduino 共地。
3.2 接线表
SG90 系列常见是三根线,颜色一般为橙(信号)、红(电源)、棕(地),但不同厂家会有差异。接线前先看舵机标签或卖家图纸:
| 舵机线颜色 | 常见引脚名 | 接到哪里 |
|---|---|---|
| 橙 / 黄 | Signal / PWM | Arduino 数字引脚 D9 |
| 红 / 中间 | VCC / +5V | 外部 5V 正极,或 UNO 的 5V 引脚 |
| 棕 / 黑 | GND / - | 外部 5V 负极或 UNO GND,并共地 |
如果按照 Arduino 和外部电源共地的接法,典型连线如下:
- 舵机信号线 → Arduino D9。
- 舵机电源线 → 外部 5V 电源正极。
- 舵机地线 → 外部电源负极,同时外部电源负极用跳线接到 Arduino GND。
共地这一步很容易漏。Arduino 发出的是参考自身 GND 的 PWM 信号,舵机如果只接外部电源、不共地,信号电平没有公共参考点,可能出现不转或乱转。
3.3 供电设计建议
SG90 连续旋转舵机正常工作电压一般是 4.8V~6V。采用外部 5V 电源时,还要注意:
- 电源电流能力至少要几百毫安,如果驱动多个舵机,电流能力要按舵机数量放大。
- 电源纹波要控制好。劣质 USB 供电或手机充电头空载电压偏高,可能导致舵机转速异常。
- 舵机启动瞬间电流较大,可以在舵机电源两端并联一个 100uF~470uF 的电解电容,减少电压跌落。电容极性不能接反。
如果你用的就是 Arduino UNO 的 5V 引脚供电,可以把它看作“实验可行但不够稳健”的方案,尤其当程序里让舵机频繁启停时,建议直接改成外置电源。
4. Arduino IDE 环境准备与驱动确认
写代码之前,先把 Arduino IDE 装好,并把板卡识别出来。
4.1 安装 IDE 并选择开发板
在 Arduino 官网下载对应操作系统的 IDE,安装后打开,按以下步骤操作:
- 用 USB 线连接 Arduino UNO 和电脑。
- 在“工具 -> 开发板 -> 开发板管理器”里确认安装了
Arduino AVR Boards包。 - 选择开发板为
Arduino Uno。 - 在“工具 -> 端口”里选择正确串口。
Windows 下如果设备管理器里看不到串口,通常是 CH340 或 CP210x 驱动问题。UNO 原厂板多使用 ATmega16U2 芯片,不需要额外驱动;国产兼容板可能使用 CH340,需要安装 CH340 驱动。在 Linux 下,如果出现权限不足,需要把当前用户加入dialout组。
4.2 编译烧录前的最小检查
可以先烧一个最简单的 Blink 例程,确认下载链路没问题。如果 Blink 能亮,说明开发板、端口、驱动都正常,后面可以聚焦舵机控制问题。
常见情况是:开发板选错、端口选错、IDE 版本缓存异常。切换端口后如果下载失败,可以先重新插拔 USB,并确认没有多个串口工具占用同一 COM 口。
5. writeMicroseconds 核心控制代码
5.1 包含头文件与创建舵机对象
Arduino 的 Servo 库自带writeMicroseconds()函数,它直接指定输出到舵机信号线上的脉宽,单位是微秒。
#include <Servo.h> Servo myServo; void setup() { myServo.attach(9); // 信号线接 D9 myServo.writeMicroseconds(1500); // 先给停止脉宽 } void loop() { }注意attach()之后,最好立刻调用一次writeMicroseconds(1500)。如果不调用,有些舵机可能停留在上一次的脉宽状态。对 360° 连续旋转舵机来说,上电瞬间如果输出脉宽偏了,就会转动,所以先给停止脉宽是一个比较安全的初始化习惯。
5.2 为什么用 writeMicroseconds 而不是 write
对标准 180° 舵机,write(90)表示转到 90°,write(180)表示转到 180°,Servo 库内部会把它换算成合适的脉宽。这个函数对 360° 连续旋转舵机没有意义,因为舵机内部没有“角度”概念。
writeMicroseconds()是直接写脉宽,例如:
myServo.writeMicroseconds(1500); // 常见停止脉宽这里 1500us 只是一个常见的停止中点参考值。不同舵机可能略有差异,需要通过实测校准。而标准舵机的 0° 和 180° 对应的脉宽范围,在 360° 连续旋转舵机上也不一定适用,所以“照抄 180° 舵机代码”是很多新手翻车的原因。
5.3 正转、反转、停止的完整示例
下面这个示例演示了一个循环动作:停止 2 秒,正转 2 秒,停止 1 秒,反转 2 秒。
#include <Servo.h> Servo myServo; int servoPin = 9; void setup() { Serial.begin(9600); myServo.attach(servoPin); myServo.writeMicroseconds(1500); // 停止 } void loop() { // 正转 Serial.println("Forward"); myServo.writeMicroseconds(1700); delay(2000); // 停止 Serial.println("Stop"); myServo.writeMicroseconds(1500); delay(1000); // 反转 Serial.println("Reverse"); myServo.writeMicroseconds(1300); delay(2000); // 停止 Serial.println("Stop"); myServo.writeMicroseconds(1500); delay(2000); }这里 1700us 和 1300us 是示例值,并不代表你的舵机正好是“半速”。实际舵机可能 1600us 就转动明显,也可能 1700us 才动,需要通过测试确定。
5.4 用 millis() 实现非阻塞旋转控制
delay()的写法简单,但在多传感器项目里会阻塞主循环,不适合做需要同时检测按键、串口或传感器的逻辑。更合理的方式是用millis()记录时间。
下面做一个简单的非阻塞状态机:舵机前 2 秒正转,后 2 秒停止,再进入反转。
#include <Servo.h> Servo myServo; unsigned long previousMillis = 0; int state = 0; void setup() { myServo.attach(9); myServo.writeMicroseconds(1500); } void loop() { unsigned long currentMillis = millis(); switch (state) { case 0: // 正转 myServo.writeMicroseconds(1700); if (currentMillis - previousMillis >= 2000) { previousMillis = currentMillis; state = 1; } break; case 1: // 停止 myServo.writeMicroseconds(1500); if (currentMillis - previousMillis >= 2000) { previousMillis = currentMillis; state = 2; } break; case 2: // 反转 myServo.writeMicroseconds(1300); if (currentMillis - previousMillis >= 2000) { previousMillis = currentMillis; state = 0; } break; } }millis()方案不会阻塞主循环,之后要接入超声波传感器、串口调试或按键中断都更方便。写这种状态机时要注意currentMillis - previousMillis的写法,用无符号长整型减法可以避免millis()溢出带来的大部分问题,这是 Arduino 常见的节拍写法。
6. 功能测试与效果验证
新舵机到手后,建议按下面的顺序逐步测试。不要直接把自己的项目代码烧进去,因为如果硬件或舵机中位有问题,你很难判断是接线问题还是逻辑问题。
6.1 测试一:不上电检查是否短路
先不要给 Arduino 上电,用万用表电阻档检查电源线和地线之间是否有短路。信号线接错一般不会烧,电源线正负接反或短路风险更大。确认接线正确后,再插入 USB。
6.2 测试二:确认停止脉宽
先写入下面的测试代码:
#include <Servo.h> Servo myServo; void setup() { myServo.attach(9); myServo.writeMicroseconds(1500); } void loop() { }烧录后观察舵机轴:
- 如果不转,或者转动很微弱,说明 1500us 接近中位。
- 如果明显持续旋转,可以微调脉宽值,例如从 1450us 到 1550us 找一个停止点。
推荐在串口里边观察边调试:
#include <Servo.h> Servo myServo; int pulseWidth = 1500; void setup() { Serial.begin(9600); myServo.attach(9); myServo.writeMicroseconds(pulseWidth); Serial.println("Input pulse width in microseconds."); } void loop() { if (Serial.available() > 0) { pulseWidth = Serial.parseInt(); if (pulseWidth >= 800 && pulseWidth <= 2200) { myServo.writeMicroseconds(pulseWidth); Serial.print("Set pulse: "); Serial.println(pulseWidth); } else { Serial.println("Out of range."); } } }打开串口监视器,输入1500,观察舵机停不停止。再把1500改成1480、1520对比。这样能很快找到实际停止点。
6.3 测试三:方向与转速
在中位确认没问题后,测试两个方向的响应:
- 输入
1600,观察舵机是否向一个方向旋转。 - 输入
1400,观察舵机是否向另一个方向旋转。 - 逐渐增大差值,例如 1550、1600、1700、1800,观察转速是否大致增大。
如果发现某一边不转,或者脉宽只在中位附近抖动却不持续旋转,可以考虑两个原因:一是舵机不同轴的启动电流需求大但供电不足;二是你的舵机定义的中位和全速点不对称。
把结果整理成测试记录表:
| 测试条件 | 预期结果 | 实际结果 |
|---|---|---|
| 脉宽 1500 | 轴静止 | 按实测记录 |
| 脉宽 1600 | 一侧旋转 | 按实测记录 |
| 脉宽 1400 | 另一侧旋转 | 按实测记录 |
| 脉宽 1800 | 转速提高 | 按实测记录 |
| 脉宽 1200 | 反向转速提高 | 按实测记录 |
不同舵机的脉宽范围不宜盲目加大,超出规格容易导致舵机内部电路异常发热。常见的 180° 舵机 500us~2500us 范围对 360° 连续旋转版本不一定适用,所以测试时应当先保守地从 1300us~1700us 区间开始,再逐步扩大。这个习惯可以避免舵机堵转。
6.4 测试四:用时间近似判断旋转量
如果需要粗略估计“让舵机转半圈”,只能通过控制旋转时间来实现。例如,你先测出某一脉宽下舵机每分钟转速,然后据此计算需要转多少毫秒。这个方案没有反馈,意味着负载变化、电池电压降低都会影响结果。
测试方法是在舵机输出轴上贴一个明显标记,例如用黑色胶带贴一条线,然后让舵机旋转固定时间:
#include <Servo.h> Servo myServo; void rotateTime(int pulseWidth, unsigned long durationMs) { myServo.writeMicroseconds(pulseWidth); delay(durationMs); myServo.writeMicroseconds(1500); } void setup() { myServo.attach(9); myServo.writeMicroseconds(1500); delay(500); rotateTime(1700, 1000); // 假设正转1秒 } void loop() { }烧录后观察输出轴转过的角度,如果和你预期的半圈或一圈不一致,就去调整时间参数。实际项目中这个时长还会受电源电压、温度、负载和齿轮磨损影响,不要把它当作精确参数长期沿用。
6.5 判断是否成功
一套完整的入门验证,至少应该满足下面几条:
- 舵机在某个中位脉宽下能稳定静止。
- 偏离中位后能朝指定方向旋转。
- 脉宽偏离越远,转速有明显提升或至少能区分低高速。
- 程序下载后上电不会无规律猛转。
- 停止脉宽连续输出时,舵机没有明显抖动。
如果以上都能满足,说明你的 SG90 360° 连续旋转舵机已经能按开环方式工作了。
7. 开环控制原理与常见误区
7.1 为什么脉宽控制转速,而不是角度
标准角度舵机内部有控制电路和电位器。控制电路读取外部脉宽,读取电位器反馈的当前位置,然后驱动电机让两者一致,构成一个闭环。而 360° 连续旋转舵机通常不再使用位置反馈,或者把反馈限位移除,控制电路只能根据脉宽决定电机的通电方向和 PWM 占空比。没有电位器告诉你“位置在哪”,CPU 也没有角度信息,所以它是一个开环速度系统。
如果从控制理论的角度理解,你可以这样看:
- 输入量:脉宽值。
- 控制量:内部电机的电压方向和等效占空比。
- 被控量:输出轴的旋转速度。
- 反馈量:无。
没有反馈的直接结果就是:不能进行“增量式角度控制”。就算你用机械限位让舵机每次转固定角度,长期运行后也会因为启动和停止延迟累积误差。
7.2 标准舵机和连续旋转舵机的代码差异
很多教程里的舵机云台程序,使用的是myservo.write(angle);。这种代码对角度舵机有效,对连续旋转舵机无效。Servo 库在write()内部会把角度换算为脉宽,但连续旋转舵机并不关心角度映射,它只看最终脉宽。你可以写myservo.write(90);让标准舵机去中位;对连续旋转舵机,write(90)通常对应一个接近停止的脉宽,但绝不是所有舵机都刚好如此。
所以,最实用的建议是直接放弃write(),改用writeMicroseconds()。这样代码意图明确,也方便后期调整脉宽。
7.3 常见误区
误区一:1500us 一定代表停止。实际上,不同舵机的停止点可能有偏差,需要实测。
误区二:加大脉宽一定等比提高转速。舵机内部有控制离散化,脉宽从小偏离中位到较大偏离,转速不会严格线性变化,而且接近上下限时会饱和。
误区三:360° 舵机转过的“角度”可以由程序稳定复现。没有外部反馈时,这种经验参数只能用于对精度没有要求的演示。
误区四:烧录程序前舵机不会转。很多舵机在没有收到有效信号时,会有自己的默认状态;而 Arduino 复位瞬间引脚为高阻或未初始化状态,也可能让舵机抖动。程序里要尽快attach()并给出中位脉宽。
8. 多舵机、资源占用与供电观察
8.1 Servo 库的资源占用
Arduino UNO 使用 ATmega328P,Servo 库默认使用定时器 Timer1 来维护最多 12 个舵机的脉冲生成。这就会带来两个直接结果:
- 如果你用的是标准 Servo 库,
Servo库和依赖 Timer1 的其他库不能同时使用。 - 12 路只是“库上限”,不是“硬件供电上限”。真正限制因素是电源能够提供多少电流。
一个 9g 舵机在空载时电流小,但启动和堵转时的电流可以明显高于稳定运行电流。多个舵机同时启动时,峰值电流叠加,USB 口很难扛住。更合理的做法是给舵机单独供电,并且不要把所有舵机的地线或电源线共用太细的杜邦线。
8.2 多舵机接线参考
下面是一个简化的双舵机接线表:
| 舵机 | 信号引脚 | 电源 | 地线 |
|---|---|---|---|
| 舵机 1 | D9 | 外部 5V+ | 外部 GND |
| 舵机 2 | D10 | 外部 5V+ | 外部 GND |
代码里创建两个 Servo 对象并分别attach():
#include <Servo.h> Servo servo1; Servo servo2; void setup() { servo1.attach(9); servo2.attach(10); servo1.writeMicroseconds(1500); servo2.writeMicroseconds(1500); } void loop() { servo1.writeMicroseconds(1600); servo2.writeMicroseconds(1400); delay(2000); servo1.writeMicroseconds(1500); servo2.writeMicroseconds(1500); delay(2000); }外部电源的地线必须和 Arduino 的 GND 相连,这个共地不能被省略。否则两个舵机虽然能分别收到高电平脉冲,但信号参考地不一致,很容易出现随机抖动。
8.3 如何观察系统是否“供电不足”
供电不足的典型表现包括:
- 舵机原地抖动,但输出轴没有力气。
- 程序运行到一半 Arduino 自动复位。
- 舵机只能朝一个方向转,反向后没有反应。
- USB 连接不稳定,串口监视器频繁断开。
如果出现这些现象,不要在代码里浪费太多时间,先给舵机接上独立电源,再加入滤波电容,问题往往能解决。也可以用万用表在舵机启动瞬间测量电源电压,如果电压跌落明显,说明电源内阻或者线材压降过大。
9. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 上电后舵机一直转,代码里写了 1500 也没用 | 1500us 不是该舵机中位,或 attach 后未立即给脉宽 | 串口在线输入 1450~1550 脉宽测试 | 校准实际停止脉宽 |
| 舵机完全不动 | 信号线接错、供电不足或舵机损坏 | 检查接线、换 D9 引脚、测电源输出 | 重新接线,使用独立 5V 电源 |
| 舵机抖动 | 供电电压跌落、信号线接触不良或脉宽处于临界点 | 检查电源电流、检查杜邦线、调节脉宽 | 加电容、换粗短线、错开临界脉宽 |
| 程序烧录成功但舵机响应串口输入异常 | 串口被占用或波特率不一致 | 确认串口监视器波特率 | 统一波特率为 9600 或按代码设置 |
| 只能向一个方向转 | 左右脉宽范围不对称,或中位校准偏了 | 测试 1400/1600 两个方向 | 找到真正中位,重新校准 |
| 舵机发热明显 | 持续堵转、VCC 电压过高或负载太大 | 测电源电压,观察输出轴是否卡住 | 降低电压、卸载负载、减少堵转时间 |
| 舵机转动速度不稳定 | 电源电压波动、开环控制固有现象 | 用独立电源供电,测电压纹波 | 加强滤波,避免过大负载变化 |
| 使用 Servo 后其他库冲突 | Timer1 被占用 | 查看库文档确认定时器冲突 | 换支持其他定时器的库,或换主控 |
| Arduino 频繁复位 | 舵机启动电流把板载电压拉低 | 观察 USB 是否重连 | 外接电源,USB 只做通信 |
这个排查表不用按顺序从头看到尾,而是出现现象时对号入座。大部分问题和代码没关系,先查供电和接线,再看程序逻辑,效率最高。
10. 最佳实践与使用建议
10.1 用限幅函数保护舵机
舵机支持的脉宽范围不是越大越好。写一个简单的限幅函数能避免调试时意外输入过宽的脉宽:
#include <Servo.h> Servo myServo; void safeWrite(Servo &servo, int pulse) { if (pulse >= 700 && pulse <= 2300) { servo.writeMicroseconds(pulse); } } void setup() { myServo.attach(9); safeWrite(myServo, 1500); } void loop() { safeWrite(myServo, 1700); delay(2000); safeWrite(myServo, 1500); delay(2000); }实际使用中,你需要根据舵机规格书把700和2300替换成更保守的上下限。不要猜一个“听起来差不多”的值,要尊重硬件手册。
10.2 第一次上电先用手扶住舵机
每次修改程序烧录前,最好把舵机输出轴握住,或者让旋转部位远离手和线束。因为复位瞬间,Arduino 引脚和 Servo 库的初始化顺序可能导致很短时间内的脉冲输出不为中位,舵机突然快速转一下。虽然不是每次都发生,但安全习惯值得养成。
10.3 给舵机做一组中位标定
每个舵机都不一样,甚至同一盒里的两个也会有差异。建议专门写一个小工具固件,通过串口输入脉宽来控制舵机,用来标定每个舵机的中位和最大最小脉宽。标定结果记录下来,项目代码里用常量统一管理。
const int SERVO_A_STOP = 1500; const int SERVO_A_MAX_FWD = 1700; const int SERVO_A_MAX_REV = 1300;用常量的好处是:换舵机或调参数时,只改顶部定义即可,不用搜代码里的魔法数字。
10.4 把串口打印当作调试工具
如果你的程序是自动运行的,可以在每次切换状态时打印当前时间和脉宽,方便判断舵机到底有没有收到新的指令。
myServo.writeMicroseconds(1600); Serial.print("Time: "); Serial.print(millis()); Serial.println(" ms, Pulse: 1600");串口输出只占很少执行时间,对舵机控制影响很小。但在最终产品里,如果不需要调试信息,可以关掉它,减少串口处理带来的那一点时序波动。
10.5 把开环升级成半闭环
如果项目确实需要知道舵机转了多少圈,可以考虑加一个外部光电开关或霍尔传感器。比如在转盘的某个位置贴上反光标记,每次转到那里就触发一次计数。这样可以用中断记录圈数,和舵机旋转方向组成一个“半闭环”系统。用传感器做位置矫正,远比靠脉宽和时间估算可靠。这也把 360° 连续旋转舵机从开环玩法带入了更可控的范围。
这种改造不需要换主控,Arduino UNO 就能实现:
- 信号输出引脚用一个 GPIO。
- 传感器计数引脚接在支持中断的 D2 或 D3 上。
- 每次计数后修正旋转圈数,并决定是否停止。
需要强调的是,外部传感器只能提供“经过某个位置”的信息,无法提供“当前绝对角度”。如果要求绝对角度,应选用带编码器反馈的舵机或电机组件,而不是在普通 9g 舵机上强行改造。
10.6 不同负载下的参数不是通用的
你在空载时标定的时间和转速关系,加了负载后会变化。搬运式小车、带齿轮箱的云台,都会拉低实际速度。所以凡是涉及时间和距离换算的项目,都要做带载测试。换电池、换电源适配器以后,也需要重新验证一遍参数。
10.7 关于批量“同型号”舵机
有些项目会买十几个同型号的 360° 舵机。这里要提醒:同一型号不同个体的中位脉宽差异明显。批量使用时不要指望所有舵机都停在 1500us,务必给每个舵机单独标定并把参数烧录到各自的 EEPROM,或者使用统一的控制板做在线校准。
10.8 关于 RoboMaster、竞赛和复杂应用
如果你是在机器人竞赛里使用连续旋转舵机,通常需要自己设计运动控制。开环舵机更适合作为学习载体,不太适合作为精确运动系统的核心执行机构。真正比赛用的底盘驱动一般会选择带编码器或霍尔传感器的直流减速电机,或使用带反馈的舵机。竞赛场景里建议在项目初期就确认所需传感器和控制精度,避免机械搭完以后再换执行器。
11. 实测流程回顾与下一步玩法
到这里,一套完整的 SG90 360° 连续旋转舵机入门验证流程已经跑完:
- 拿到舵机后先确认是角度版还是连续旋转版。
- 接好信号线和独立电源,记得共地。
- 用
writeMicroseconds(1500)找停止点。 - 用不同脉宽测方向。
- 测试时间与旋转量的关系。
- 根据项目需求决定继续用开环,还是加外部传感器闭环。
最容易踩的坑有三处:第一个是把 360° 舵机当 180° 舵机写角度代码;第二个是忽略外部电源和共地;第三个是盲目相信 1500us 就是停止点。只要把这三个问题想清楚,后面的玩法就顺畅很多。
下一步可以尝试的方向很多。如果你做小车,可以把两个这种舵机装在底盘上,用刚才的脉宽控制实现前进后退和差速转向。如果你想做云台,可以搭配 Hall 传感器做归零和圈数累计。如果你感兴趣的是控制理论,可以在此基础上加编码器、PID 调速,比较一下有反馈和没有反馈的巨大差异。也可以尝试自己写 PWM 信号,不用 Servo 库,而是用analogWrite()配置频率和占空比,或者用定时器中断模拟舵机信号,进一步理解 50Hz 和脉宽本身的含义。
最后再强调一条建议:把这篇验证流程里的标定方法固化下来,每次拿到新舵机都先跑一遍。开环系统不可怕,可怕的是没有标定就盲目上项目。你花在标定中位上的十分钟,会在后面省掉大量排查问题的时间。