news 2026/9/5 15:45:18

Arduino控制SG90 360度连续旋转舵机:脉宽控制与开环校准实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Arduino控制SG90 360度连续旋转舵机:脉宽控制与开环校准实战

这次我们来看一个容易被“先入为主”带偏的硬件控制问题:手头的 SG90 舵机,到底能不能当普通 180 度舵机用?

如果你买的型号是SG90 360 度连续旋转舵机,那么答案是不建议直接按角度写。它的真实控制方式是writeMicroseconds() 输出脉宽控制速度,不是 write() 控制角度。这篇内容会围绕 Arduino UNO 展开,讲清楚这类舵机的本质、接线、启动测试、停机值校准、串口实时控制,以及为什么它属于开环控制。

先说结论,方便你判断是否需要继续往下看:

  • 360 度连续旋转舵机没有角度限位,不能精准定位到指定角度。
  • 控制信号仍然是 50Hz 左右的 PWM,核心调用是Servo.writeMicroseconds()
  • 脉宽 1500us 附近通常是停止点,但不是所有舵机都刚好是 1500,必须实测校准。
  • 这类舵机适合转台、云台旋转、简单小车轮子驱动,不适合机械臂关节或需要反馈控制的场景。
  • 后面会给出 3 份可以直接烧录到 Arduino UNO 的测试代码,以及串口输入脉宽的调试方法。

下面直接进入正题。

1. SG90 360 度舵机核心能力速览

能力项说明
项目类型SG90 变体舵机控制,属于 360 度连续旋转舵机
控制方式50Hz PWM 脉宽控制,核心函数writeMicroseconds()
开环/闭环开环控制,不带位置反馈,无法获知当前角度
可调参数脉宽值、旋转方向、电机速度、运行时间
能实现的功能连续正转、连续反转、停止、不同转速的近似控制
不能实现的功能精确角度定位、位置闭环、力矩保持时的角度校正
推荐控制板Arduino UNO、Nano、Mega 等 AVR 平台均可
信号引脚舵机信号线接 UNO 数字引脚,示例中使用 D9
供电建议建议外部 5V 供电并共地,避免直接占用 UNO 板载稳压电流
适合读者刚入门 Arduino 舵机控制的开发者、做简单转台/小车方向的开发者

这个表很重要的一点是:360 度连续旋转舵机是“去掉限位并改写控制逻辑”的产物。不同厂家、不同批次的 SG90-360,控制脉宽范围和停止点都会存在差异。网络上“1000us 正转、1500us 停止、2000us 反转”只能作为默认参考,真正上电以后需要逐个测试。

2. SG90 360 度连续旋转舵机和普通 180 度舵机差在哪

2.1 机械结构差异

普通 SG90 舵机内部有机械限位,输出轴只能在 0 到 180 度左右摆动。你在驱动它的时候,如果脉宽超过最大或最小角度,舵机会顶在限位处,电流升高、发出“嗡嗡”声,长时间堵转还会发热。

360 度连续旋转舵机内部去掉了这个限位挡块,或通过改电路让电机可以连续旋转。它输出的不是角度变化,而是连续转动。

2.2 控制语义差异

普通 180 度舵机,角度和脉宽大致对应:

  • 0 度对应脉宽约 500us 或 1000us
  • 90 度对应脉宽约 1500us
  • 180 度对应脉宽约 2500us 或 2000us

所以直接用write(90)让舵机转到中间位置是合理的。

但 360 度连续旋转舵机上,角度概念不存在了。脉宽变成“停止 / 正转速度 / 反转速度”的指令:

  • 中间脉宽附近(通常约 1500us)对应电机停止。
  • 脉宽偏大或偏小对应不同方向的旋转。
  • 偏离中心越远,电机转速越快。

正因为没有反馈,舵机不知道自己转到哪里,这就是明显的“开环控制”。

2.3 购买时如何分辨

SG90 型号非常多,看包装和商品标题时要注意。如果标题写“SG90 360 度连续旋转”“SG90 无角度限制”,那就是这种版本;如果写“SG90 9g 舵机 180 度”,那才是普通角度舵机。

低成本舵机的批次差异很大。有些号称 360 度连续旋转,实际死区很宽,很难找到完全停止的脉宽;有些在同一脉宽下正反转速度也不对称。因此拿到手后先跑一遍测试程序,比直接翻参数更靠谱。

3. 适用场景与安全边界

3.1 适合的场景

  • 需要一个持续旋转的云台底盘,比如小型摄像头云台的左右旋转轴。
  • 做一个简单的转盘演示,展示圆周运动。
  • 小车上使用这类舵机作为减速轮驱动,虽然精度和扭矩都有限,但入门够用。
  • 模拟雷达扫描效果,可以做 360 度旋转,但没角度反馈就需要配合外部传感器做限位。
  • 测试 Arduino PWM 输出、脉宽控制电机基本逻辑。

3.2 不适合的场景

  • 需要精确到达某个角度的机械臂关节。
  • 需要位置闭环的高精度云台指向。
  • 需要承受持续大扭矩的负载或长时间堵转。
  • 对重复精度有要求的生产级设备。

360 度连续旋转舵机本质上是给小功率设备做“速度调节”的,而不是做“位置控制”的。如果坚持让它在没有反馈的情况下完成精确角度动作,结果会非常脆弱:供电电压波动、齿轮间隙、负载变化都会累计误差。

3.3 使用边界与安全提醒

  1. 舵机没有限位,如果外部结构加了机械挡板,不要高速长时间让舵机顶住挡板,否则齿轮和电机容易损坏。
  2. 空载测试最安全,尽量不要一开始就带大负载。
  3. 涉及自制转台、小车、云台时,注意不要夹到手指,不要让 USB 线缠绕到旋转轴。
  4. 本项目只适合学习、原型验证和合法自用设备改造,不要用于未经授权的自动化设备或任何违规场合。

4. 硬件准备与 Arduino UNO 接线

4.1 硬件清单

器件数量
Arduino UNO 或兼容板1 块
SG90 360 度连续旋转舵机1 个
杜邦线(公对公或母对公)3 根
外部 5V 电源可选但推荐
USB 数据线1 根
串口监视器由 Arduino IDE 提供

如果手上只有普通 SG90,也不影响练习,只是你的舵机会被限位挡住,达不到连续旋转效果。

4.2 SG90 引脚定义

SG90 的 3 根线颜色常见如下:

线色功能接法
棕色GND接 Arduino GND 和外部电源 GND
红色VCC接 5V 电源正极
橙色或黄色Signal接 Arduino 数字引脚,示例接 D9

不同厂家线序可能不同,接线前仔细看舵机标签。插反信号线有可能损坏舵机驱动板或引脚。

4.3 供电方式选择

原则只有一条:舵机的电源不要只依赖 UNO 的板载 5V 输出,能用外部电源就尽量用外部电源。

常见的错误接法是直接把舵机红线接到 UNO 的 5V 引脚,然后 USB 供电给 UNO。这种做法对于 1 个空载 SG90 也许能跑,但一旦舵机启动电流变大,USB 口电压被拉低,Arduino 可能自动复位。更坏的情况是舵机堵转,电流长时间过大。

推荐接线方式:

Arduino UNO SG90 360 D9 -------> 橙色信号线 5V (来自外部电源) --- 红色正极,注意先不接 UNO 5V,而是接外部电源+ GND <------- 棕色 GND 外部电源 GND ----> Arduino GND

更稳妥的接法:

  • 舵机正极接外部 5V 电源。
  • 舵机 GND 同时连接 Arduino GND 和外部电源 GND,这叫共地。
  • Arduino 用 USB 独立供电。
  • 舵机信号线直接接 Arduino D9。

4.4 UNO 引脚占用说明

Arduino 的 Servo 库在 UNO 上会占用 Timer1。Timer1 与引脚 D9、D10 的 PWM 输出有关。当使用 Servo 库时,D9 和 D10 的analogWrite()会受到影响,不能同时可靠工作。如果后面需要 D10 输出 PWM 控制其他设备,需要重新规划引脚。

5. 第一个测试程序:用 writeMicroseconds 把舵机转起来

5.1 代码思路

连续旋转舵机的输入是脉宽。Servo库中:

servo.writeMicroseconds(1500);

表示输出 1500 微秒的脉宽,这是最常见的停止值。

但要注意,writeMicroseconds()并不是“写微秒时间长度”这么简单,它最终会换算成对应周期的 PWM 占空比。Arduino Servo 库默认周期约 20ms,也就是 50Hz,符合常规遥控舵机信号标准。

5.2 示例代码

下面程序会让舵机按顺序执行:停止 -> 正转 -> 停止 -> 反转 -> 停止。每个状态持续 2 秒,方便观察方向是否正确。

#include <Servo.h> Servo myServo; const int servoPin = 9; void setup() { Serial.begin(9600); // 显式设置脉宽范围,避免不同商家舵机范围不一致 myServo.attach(servoPin, 500, 2500); myServo.writeMicroseconds(1500); Serial.println("SG90 360 test start"); delay(1000); } void loop() { // 停止 Serial.println("1500us -> stop"); myServo.writeMicroseconds(1500); delay(2000); // 正转 Serial.println("1000us -> forward"); myServo.writeMicroseconds(1000); delay(2000); // 停止 Serial.println("1500us -> stop"); myServo.writeMicroseconds(1500); delay(2000); // 反转 Serial.println("2000us -> reverse"); myServo.writeMicroseconds(2000); delay(2000); }

5.3 预期观察现象

烧录程序后,舵机应该先停 2 秒,然后转动约 2 秒,再停 2 秒,再反向转动 2 秒,循环运行。

如果 1000us 时舵机不转,只听到“吱吱”声,说明 1000us 落在停止死区内,或者舵机批次的最小运行脉宽不够低。可以改成 900 或 800 再试。如果 2000us 时舵机停转或轻微抖动,也可以继续加大到 2100 甚至 2400。

这个测试的意义不是运行一个“好看”的动作,而是确认:

  1. 舵机信号线是否接对。
  2. 供电是否足够。
  3. 当前脉宽与旋转方向、停止位置的实际对应关系。

6. 串口实时控制与停机值校准

6.1 为什么需要校准

“1500us 停止”是一个理论值。实际 SG90-360 舵机的停止点可能落在 1450 到 1550 之间,甚至有些批次漂移更严重。如果 1500us 输出后舵机还在慢慢转,后面的控制逻辑会整个乱掉。

所以拿到舵机后的第一步,不是直接写小车控制代码,而是先在串口监视器里手动输入脉宽,找到它的真实停止点。

6.2 串口输入脉宽控制代码

这份代码读取串口十进制整数,并把它作为脉宽输出。你可以在 Arduino IDE 串口监视器输入150010002000等值,观察舵机状态。

#include <Servo.h> Servo myServo; const int servoPin = 9; void setup() { Serial.begin(9600); myServo.attach(servoPin, 500, 2500); myServo.writeMicroseconds(1500); Serial.println("Input pulse width, e.g. 1500"); } void loop() { if (Serial.available() > 0) { int value = Serial.parseInt(); if (value >= 500 && value <= 2500) { myServo.writeMicroseconds(value); Serial.print("Set pulse: "); Serial.println(value); } else { Serial.println("Invalid range, use 500-2500"); } } delay(10); }

6.3 校准步骤

  1. 打开串口监视器,波特率选 9600。
  2. 输入1500,观察舵机是否完全停止。
  3. 如果仍在微转,尝试输入14901480147015101520等,直到舵机完全停住。
  4. 把找到的“完全停止值”记为STOP_PULSE
  5. 输入1000,舵机应朝一个方向转动;输入2000,舵机应朝另一个方向转动。如果方向和你预期相反,调整程序中正转/反转对应的脉宽即可。
  6. 继续用900110020002100测试,记录基本转速差异。

校准完成后,把1500替换成自己实测的STOP_PULSE。比如你的舵机在1480才停,那么代码中所有停止位置都写1480

6.4 死区问题

连续旋转舵机的死区指的是:脉宽在某个范围内时,舵机既不转也不产生明显扭矩。死区过宽会让控制“迟钝”,指令变化一点但舵机没反应;死区过窄则可能导致舵机在停止点附近抖动。

如果发现舵机在停止点附近出现来回抖动,最直接的办法是:把停止脉宽设置在死区中心,避免使用临界值。

7. 开环控制入门:动作时间与角度估测

7.1 什么是开环控制

开环控制的意思是:控制器发出指令后,不检查执行结果是否达到预期。360 度连续旋转舵机就是典型的开环执行器——它没有角度传感器,没有编码器,也没有电流反馈。你发出“以某速度转 1 秒”,它理论上转过的角度是多少,控制器并不知道。

这意味着,如果你希望它“转 90 度后停下”,只能通过“某个脉宽跑多少毫秒”来估算。这种估算会受到供电电压、负载、温度、齿轮阻力影响,误差会逐步累积。

7.2 开环动作序列示例

下面的程序演示一个不含反馈的简单流程:启动 -> 正向转 1.5 秒 -> 停止 -> 反向转 1.2 秒 -> 停止。

这里用STOP_PULSE变量统一管理停止值,校准后只需要改一个地方。

#include <Servo.h> Servo myServo; const int servoPin = 9; const int STOP_PULSE = 1500; // 改为你实测的停止值 const int FORWARD_PULSE = 1000; // 正向脉宽 const int REVERSE_PULSE = 2000; // 反向脉宽 void setup() { Serial.begin(9600); myServo.attach(servoPin, 500, 2500); myServo.writeMicroseconds(STOP_PULSE); delay(1000); } void moveForMs(int pulse, int durationMs) { myServo.writeMicroseconds(pulse); delay(durationMs); myServo.writeMicroseconds(STOP_PULSE); delay(500); } void loop() { Serial.println("forward 1.5s"); moveForMs(FORWARD_PULSE, 1500); Serial.println("reverse 1.2s"); moveForMs(REVERSE_PULSE, 1200); delay(2000); }

实际运行时会发现,两次运行之间,最终停留在哪个角度往往不一致。这正好说明开环控制的局限。

7.3 辅助限位与外部传感器

如果你确实需要在一个开环系统里“大致回到起点”,可以加一个外部传感器做辅助:

  • 在转台上安装一个挡片,配合红外对管或霍尔传感器,每次触碰到传感器就清零位置。
  • 使用电位器检测转轴位置,把模拟电压读到 Arduino,形成简单的角度反馈。
  • 使用 MPU6050 陀螺仪估算旋转角速度,不过积分漂移会随时间增大。

这些方法都不需要改造舵机本身,但只有加上反馈之后,控制系统才从“开环”变成“闭环”,才能谈得上有定位能力。

8. 资源占用、供电影响与性能观察

8.1 Arduino UNO 上的软硬件资源

Arduino UNO 的 ATmega328P 资源有限。Servo 库在 UNO 上会占用 Timer1,同时库内部最多可以驱动 12 路舵机,但每路舵机的刷新仍然依赖同一个定时器中断。

实际项目中如果还要用millis()做非阻塞计时,需要注意:Servo 库的中断频率较高,虽然millis()不受影响,但如果你自己注册了Timer1中断或依赖 D9、D10 的 PWM 输出,就很可能冲突。

更稳妥的设计是:把“舵机控制”和“业务逻辑”在程序结构上分离,舵机只使用一个引脚,其他 PWM 输出尽量放到 D3、D5、D6、D11 这些由 Timer2/Timer0 控制的引脚。

8.2 电流与电压观察方法

实测过程中建议这样观察:

  • USB 供电时,舵机高速转动瞬间,USB 电压可能被拉低。如果 Arduino 莫名其妙复位,优先怀疑供电。
  • 用万用表串联测量舵机电流,可以非常直观地看到空载、转动、堵转三个状态下的电流差值。
  • 堵转时电流最大,因此不要让舵机长时间顶着机械结构。

不同批次 SG90-360 的工作电压、堵转电流差异很大。以你手头实物为准,不要直接把某个教程的电流值硬套到自己项目里。

8.3 转速非线性的影响

脉宽从停止点向两侧偏移得越多,舵机转速通常越快,但“脉宽差值”和“转速”不是严格的线性关系。比如从 1500 改为 1300,转速可能变化很小;从 1200 改为 1000,转速增速却很明显。

所以在做开环动作序列时,不要把转速直接按脉宽差值线性估算。在实际负载下,建议用秒表或计时器量出“1 秒大概转几圈”,再用转速做时间换算。

9. 常见问题与排查方法

问题现象可能原因排查方式解决方案
上电后完全不动信号线没接对、脉宽落在停止点或死区检查接线颜色,使用串口程序输入偏离中心脉宽重新接信号线;输入 1000 或 2000 测试
舵机持续“嗡嗡”响但不转供电不足或脉宽仍在死区附近听声音判断是否堵转;用可调脉宽逐个扫描改外部电源;逐渐把脉宽调到更偏中心的值
1500us 时舵机还在缓慢转动停止点不在默认中心值串口输入 1450-1550 之间的值逐个测试找到真实停止值并更新STOP_PULSE
1000us 和 2000us 转向不符合预期方向定义与自己设计不一致测试中记录实际方向在代码里把“正转”和“反转”的常量值对调
正反转速差异大舵机批次差异、供电电压不稳空载对比 1000us 和 2000us 的转速如果应用允许,给不同方向设置不同脉宽值
Arduino 在转动瞬间重启电流过大,USB 口供电能力不足打开串口监视器观察复位信息舵机使用外部 5V 电源,GND 共地
转动到一半卡住并抖动机械负载过大或外部挡板限制让舵机空载测试去掉负载;不要在有机械限位的情况下持续旋转
D9 或 D10 的analogWrite()失效Servo 库占用 Timer1查看项目里是否同时使用这两个引脚舵机换到其他引脚,或在架构上分开控制
串口输入脉宽没反应波特率不一致或程序被阻塞检查串口监视器波特率是否为 9600确认Serial.begin(9600)与实际选择一致
停止时舵机“吱吱”微调停止脉宽落在死区边缘用更小步进找中心使用更稳定的停止值,不要在临界值附近运行

10. 最佳实践与后续升级方向

10.1 调试阶段建议

先把舵机固定在测试台或桌面上,不要让它在桌上乱跑。调试时尽量使用“停止 -> 低速 -> 停止”的节奏,不要一上来就给最大脉宽,避免突然的高转速和冲击。

把找到的停止脉宽、正转速度范围、反转速度范围记录在代码开头,形成一组可复用的常量。这样后续写小车、云台或机械结构时,不必每次都从零校准。

10.2 批量测试思路

如果需要测试多台 SG90-360 舵机的一致性,比如验收一批模块,建议用串口发送指令的方式写一个简单测试脚本。思路是:

  • 上位机通过串口发送脉宽值。
  • Arduino 接收后输出到舵机。
  • 人工或摄像头观察舵机是否动作、是否停在预期位置。

如果只是寿命测试,可以让 Arduino 程序自己循环运行“正转 1 秒、停 0.5 秒、反转 1 秒、停 0.5 秒”,然后记录运行时长。这种批量测试需要避免长时间堵转,并给舵机留出散热时间。

10.3 从开环走向闭环

当你发现开环控制不够用时,升级路径有两条:

  1. 更换带反馈的舵机或电机,比如带编码器的直流减速电机、总线舵机等。
  2. 保留 SG90-360,但外部增加编码器、电位器或测速模块,把位置或速度反馈给 Arduino。

如果只是做简单的小车转向或转台旋转,360 度舵机很好用;但一旦需要精确角度、重复定位或闭环调速,就应该尽早换方案。

10.4 把舵机接入更大系统

Arduino UNO 只是其中一种控制器。你可以把同样的脉宽控制逻辑移植到 ESP32、ESP8266、树莓派 Pico 等平台。如果通过上位机或 ROS 控制,也是按“20ms 周期脉宽”发送控制信号。

在接入实际设备前,务必确认:供电能力是否满足、机械结构是否安全、舵机堵转保护策略是否存在。舵机只是执行器,不负责判断边界,边界逻辑要由代码和机械设计来保证。

11. 总结

这篇内容围绕 SG90 360 度连续旋转舵机在 Arduino UNO 上的控制展开,重点是掌握writeMicroseconds()的脉宽控制思路,理解连续旋转舵机为什么是开环控制,以及如何通过串口校准找到真实的停止点。

建议收藏备用。如果你还没开始动手,第一件事不是写复杂控制逻辑,而是先把“串口输入脉宽”程序烧进去,输入 1500、1000、2000,确认舵机的停止、正转、反转都能正常响应。校准完成后,再把脉宽和时间组合成动作序列,后续写小车、转台或云台项目会顺利很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 15:44:52

从原理到实践:SG90舵机与Arduino UNO接线、供电与故障排查

很多玩 Arduino 的新手&#xff0c;第一次接触 SG90 时都会有一个直观感受&#xff1a;三根线、一个舵机臂&#xff0c;代码里写一句servo.write(90)&#xff0c;舵机就能转到中间位置。看起来非常简单&#xff0c;但真正上手后&#xff0c;问题往往一口气冒出来&#xff1a;为…

作者头像 李华
网站建设 2026/9/5 15:43:48

STM32与PAJ7620手势识别实战:从I2C驱动到智能台灯应用

简介&#xff1a;本资源是一套基于STM32F10x系列微控制器与PAJ7620红外手势识别传感器的完整嵌入式开发实践方案&#xff0c;面向嵌入式初学者、课程设计学生及智能交互项目开发者&#xff0c;解决非接触式人机交互系统从硬件驱动到手势逻辑解析的全流程实现问题。压缩包共98个…

作者头像 李华
网站建设 2026/9/5 15:43:37

微信小程序+Spring Boot打造个人学习打卡系统:全栈开发实战指南

简介&#xff1a;本资源是一个面向计算机专业学生与Java初学者的毕业设计/课程设计级实战项目&#xff0c;聚焦于微信小程序与Java后端协同开发的学习打卡系统&#xff0c;旨在帮助用户培养自律学习习惯并掌握前后端一体化开发流程。压缩包共71个文件&#xff0c;含12个JS逻辑文…

作者头像 李华
网站建设 2026/9/5 15:42:32

OmniVoice 维吾尔语 TTS 完整部署指南

OmniVoice 维吾尔语 TTS 完整部署指南一、前言有一个本人非常不舒服的地方官方的图像界面有丑有慢&#xff0c;还不如直接命令行跑&#xff01;本文档旨在帮助用户在 Windows 10/11 系统上从零开始部署 OmniVoice 维吾尔语 TTS&#xff0c;实现批量语音合成。OmniVoice 是小米 …

作者头像 李华
网站建设 2026/9/5 15:41:11

Unity 图集底层揭秘:一张“拼图“如何拯救你的帧率

引子:一个让 GPU "累到崩溃"的午后 假设你在做一款 2D 卡牌游戏。界面上有 100 张卡牌,每张卡牌有独立的图片:card_001.png、card_002.png……你满心欢喜地把它们拖进场景,运行—— 帧率从 60 掉到了 20。手机开始发烫,风扇狂转(如果它有风扇的话)。 你百思…

作者头像 李华
网站建设 2026/9/5 15:40:42

Simulink储能模型合集:从锂电到燃料电池的多物理场仿真实践

简介&#xff1a;本资源是一套面向新能源汽车与储能系统研究者的动力电池及电化学储能器件Simulink建模仿真资料合集&#xff0c;覆盖锂离子电池、铅酸电池、燃料电池、超级电容器四大类核心能源部件的系统级建模方法。资源共70个文件&#xff0c;包含12个可直接运行的.slx模型…

作者头像 李华