Arduino下SG90 360度连续旋转舵机实测:PWM控制与开环控制详解

发布时间:2026/9/5 15:45:40
Arduino下SG90 360度连续旋转舵机实测:PWM控制与开环控制详解 刚入手 SG90 舵机时我想做一个小型摇头云台按网上的教程写servo.write(90)确实能转但换成另一颗“SG90”后角度却对不上甚至出现“明明让舵机转 180°结果它自己转了一圈又一圈”的现象。后来才发现我拿到的是 SG90 的 360 度连续旋转版本和普通位置舵机根本不是一回事。本文就以 Arduino UNO 和 SG90 360 度连续旋转舵机为例从硬件接线、PWM 控制原理、writeMicroseconds用法到开环控制的概念做一个完整实测。新手可以把这篇当作入门教程有基础的开发者也可以直接跳到第 4 节查看可复制代码和排错清单。1. SG90 与 360 度连续旋转舵机1.1 舵机是什么舵机Servo是一种能根据控制信号执行动作的小型电机驱动模块。常见的模型舵机内部由直流电机、减速齿轮、控制电路组成。与传统直流电机不一样的是舵机通常只需要一根信号线就能让电机轴按要求动作不需要自己做 H 桥驱动使用门槛很低。普通 SG90 是 180 度位置舵机内部带有一个电位器用来测量当前输出轴的位置。控制电路通过电位器反馈不断修正电机让输出轴稳定停在指定角度。而 360 度连续旋转舵机则是另一种形态。它的内部电位器往往被去掉或者被固定替换成一个电阻分压网络因此控制电路不再知道输出轴转到哪里。这时给它一个 PWM 脉宽它不会像普通舵机那样回到某个角度而是会按某个方向和速度连续旋转。1.2 SG90 标准版与 360 度连续旋转版的区别很多初学者看到“SG90”就直接认为是 180 度舵机实际上市场上常见两类对比项标准 SG90位置舵机SG90 360 度连续旋转舵机输出轴限位有机械限位约 0~180 度无机械限位可连续旋转内部电位器有用于位置反馈无或被固定替代控制量PWM 脉宽对应目标角度PWM 脉宽对应方向和转速典型行为给一定脉宽停在指定角度给一定脉宽持续朝某方向旋转适合场景机械臂、云台角度控制小车驱动、摇头风扇、卷帘机构从外部看两种舵机都长一个样重量也差不多都是 9g 左右的微型舵机。购买时一定要向卖家确认是“180 度标准舵机”还是“360 度连续旋转舵机”最好看产品标题和外包装有些商家会把 360 度版本标成“带减速箱的连续旋转舵机”。1.3 什么是开环控制连续旋转舵机是一个典型的开环控制对象。所谓开环是指控制器只管“输出指令”不检测“实际结果”。比如我让舵机以某一个速度正转 2 秒舵机到底转了多少圈是否因为负载太大而转速下降控制器并不知道。因此如果你试图用 360 度舵机精确控制云台转到某个固定角度会发现很难。就算同样给writeMicroseconds(1700)空载时可能转得比较快带负载后转速会明显下降。要做到精确定位必须再加位置反馈例如编码器或霍尔传感器组成闭环控制。本文的实测重点是在理解这种开环特性的前提下掌握如何让 360 度舵机稳定正转、反转、变速和停止。2. 项目准备硬件与接线2.1 所需元件清单我这次使用的环境如下Arduino UNO 开发板SG90 360 度连续旋转舵机 1 个面包板 若干公对公杜邦线外部 5V 电源可选推荐100~470uF 电解电容可选用于电源稳定电脑 Arduino IDE如果你手头只有 USB 供电的 Arduino UNO只接一个 SG90 空载测试也能转起来但我不建议在带负载时继续依赖 Arduino 的 5V 引脚供电原因后面单独讲。2.2 SG90 引脚定义与接线方式SG90 通常引出三根线常见颜色和含义如下线色作用接到 Arduino UNO棕色或黑色GNDGND红色VCC / 电源正极5V或外部 5V 正极橙色或黄色信号线数字引脚 D9给出接线表SG90 360 度舵机 Arduino UNO 棕色线 --------------- GND 红色线 --------------- 5V 橙色线 --------------- D9这里有一个需要特别注意的地方不同品牌、不同批次舵机的线序并不完全一致。有的舵机红色线在中间有的是棕色线在中间建议先查看舵机外壳上的丝印或商家提供的规格书不要凭颜色盲接。接反电源线轻则舵机不转重则烧毁舵机控制板。由于本文需要演示舵机转动效果建议把舵机轴朝上放在桌面上方便观察输出轴旋转方向。2.3 供电建议为什么不能只靠 Arduino 5VSG90 正常工作电压一般在 4.8V~6V 左右。单独一个舵机堵转时电流可能达到几百毫安甚至更高启动瞬间也会有较大电流波动。Arduino UNO 的 5V 引脚由 USB 或 Vin 降压后提供能输出的电流有限。如果舵机负载较大电流会把板载 5V 电压拉低轻则舵机无力、抖动重则 Arduino 直接重启串口监视器会看到连接断开或输出乱码。更稳妥的接法如下舵机红色线接外部 5V 电源正极。舵机棕色线接外部 5V 电源负极同时接到 Arduino 的 GND。Arduino UNO 单独通过 USB 供电。这种“共地”做法很重要。Arduino 输出的是信号电平而舵机的功率电流主要从外部电源获取。信号参考地必须和电源地一致否则信号无法形成完整回路。如果手头没有外部电源临时测试时可以用 Arduino 5V但最好在 Arduino 5V 和 GND 之间并联一个 100uF 以上的电解电容。注意电容正极接 5V负极接 GND反接会损坏电容。3. 控制核心PWM 脉宽与 writeMicroseconds3.1 舵机识别什么样的 PWM 信号舵机的信号本质是一路周期约 20ms 的 PWM 方波也就是 50Hz。输出脉冲的宽度通常被称为脉宽单位是微秒。标准位置舵机的脉宽和角度大致对应关系如下0.5ms - 0 度左右 1.5ms - 90 度左右 2.5ms - 180 度左右不过实际电路中SG90 的脉宽范围通常取 1ms~2ms 更常见比如 1ms 对应 0 度1.5ms 对应 90 度2ms 对应 180 度。这也是为什么很多人习惯调用writeMicroseconds(1000)、writeMicroseconds(1500)和writeMicroseconds(2000)来让舵机分别转到两端和中间。对 360 度连续旋转舵机来说脉宽不再对应位置而对应方向和转速因此不能用“脉宽等于角度”的思路去理解。常见对应关系如下约 1500us停止 大于 1500us一个方向连续旋转脉宽越大转速越快 小于 1500us另一个方向连续旋转脉宽越小转速越快更精确地说舵机内部有一个“中心点”脉宽通常默认在 1500us 附近。只要信号脉宽接近中心点舵机就不会转偏离中心点越远目标转速越快。3.2 writeMicroseconds 与 write 的区别Arduino 的 Servo 库提供了两个常用方法servo.write(angle); servo.writeMicroseconds(pulseWidth);write()是为普通位置舵机设计的参数单位是角度。比如servo.write(90)会转换成约 1.5ms 的脉宽输出。如果你使用的是连续旋转舵机还按角度去思考就会出现混乱。writeMicroseconds()则直接输出指定的脉宽单位是微秒绕开了“角度换算”的中间层。连续旋转舵机本身没有角度概念用这个函数更直观servo.writeMicroseconds(1500); // 停止 servo.writeMicroseconds(1700); // 正向旋转速度较快 servo.writeMicroseconds(1300); // 反向旋转速度较快使用 Servo 库时还会用到attach(pin)它默认支持标准舵机脉宽范围。如果希望自定义角度映射范围可以写成servo.attach(9, 1000, 2000);这里第二个和第三个参数是角度换算的最小脉宽和最大脉宽。对于 360 度舵机我们不依赖write()的角度换算所以通常直接attach(9)就够了。有一点需要提醒Servo 库对脉冲宽度有一定限制太极端或太宽的脉宽可能被裁剪掉。我们实际常用范围在 1000~2000us 之间完全在支持范围内不需要担心。3.3 找到自己舵机的停止脉宽不同厂家生产的 360 度舵机中心点不一定是精确的 1500us。有的舵机写 1500us 可能还在缓慢转动需要手动微调到 1480us 或 1520us 才会停。因此拿到舵机后先做一个中心点测试非常有必要。最简单的测试代码如下#include Servo.h Servo sg90; void setup() { sg90.attach(9); sg90.writeMicroseconds(1500); } void loop() { // 让舵机一直保持 1500us 脉宽观察是否停止 }把程序上传到 Arduino 后观察舵机。如果它还在缓慢转动就把脉宽改成 1480、1490、1510、1520 逐个测试找到让它完全静止的那个值。后面所有速度控制都围绕这个实测出的中心值展开。4. 实战Arduino UNO 控制 360 度舵机正转、反转、变速、停止4.1 演示逻辑设计接下来完成一个完整可运行的实测程序。为了直观地展示 360 度舵机的行为我们分阶段让舵机执行以下动作高速正转 2 秒 中速正转 2 秒 停止 2 秒 中速反转 2 秒 高速反转 2 秒 停止 3 秒正转方向取决于舵机安装方式如果发现方向反了代码中正反转的脉宽对调即可。4.2 编写完整代码固定动作演示新建一个 Arduino 工程在 IDE 中创建文件写入如下代码#include Servo.h Servo sg90; const int servoPin 9; const int stopPulse 1500; // 实测中心停止脉宽 void setup() { sg90.attach(servoPin); sg90.writeMicroseconds(stopPulse); delay(500); } void loop() { // 1. 高速正转 sg90.writeMicroseconds(1800); delay(2000); // 2. 中速正转 sg90.writeMicroseconds(1650); delay(2000); // 3. 停止 sg90.writeMicroseconds(stopPulse); delay(2000); // 4. 中速反转 sg90.writeMicroseconds(1350); delay(2000); // 5. 高速反转 sg90.writeMicroseconds(1200); delay(2000); // 6. 停止 sg90.writeMicroseconds(stopPulse); delay(3000); }代码逻辑很简单#include Servo.h引入 Servo 库。sg90.attach(servoPin)把舵机信号线绑定到 D9 引脚。每次切换速度前先调用一次writeMicroseconds()然后延时一段时间让舵机转够指定时长。这里有一个细节连续旋转舵机写入脉宽后舵机会持续保持当前转速不会自动停。所以程序里每个阶段都要明确写新的脉宽。最后写1500us就是为了让舵机停下来。4.3 编写完整代码串口在线调速固定动作演示只能验证舵机基本能力不方便测试不同脉宽对应的实际转速。我们再用串口做一个更实用的“在线调速”工具电脑向 Arduino 发送一个脉宽值舵机立刻按该脉宽运行。完整代码如下#include Servo.h Servo sg90; const int servoPin 9; void setup() { Serial.begin(9600); sg90.attach(servoPin); sg90.writeMicroseconds(1500); Serial.println(SG90 360 servo serial test); Serial.println(Please input pulse width, e.g. 1500); } void loop() { if (Serial.available() 0) { int pulse Serial.parseInt(); // 简单范围保护避免输入明显异常的值 if (pulse 800 pulse 2200) { sg90.writeMicroseconds(pulse); Serial.print(Set pulse: ); Serial.println(pulse); } else { Serial.println(Out of range, please input 800-2200); } // 清空串口缓冲区避免连续触发多次 while (Serial.available() 0) { Serial.read(); } } }上传后打开 Arduino IDE 的串口监视器把波特率设为 9600在输入框中依次输入1500 1600 1700 1800 1400 1300 1200观察舵机变化。输入 1500 时舵机应停止输入 1700、1800 时朝一个方向旋转脉宽越大转速越快输入 1300、1200 时朝另一个方向旋转脉宽越小转速越快。4.4 运行与预期结果说明正常现象如下写入 1500us舵机轴基本静止用手轻捏输出轴能感觉到电机处于锁止或不输出扭矩的状态。写入 1700us舵机以较慢速度持续朝一个方向旋转。写入 1800us舵机更快地朝同方向旋转。写入 1300us舵机朝另一个方向旋转。写入 1200us反转速度更快。如果通电后舵机不仅不转还发出“嗡嗡”的抖动声通常说明信号不正常或供电不足可以按照第 5 节排查。4.5 结合电位器做一个简易转速调节如果希望不依赖电脑串口也可以用一个 10k 电位器来调节 PWM 脉宽。将电位器两端接 Arduino 5V 和 GND中间抽头接 A0 引脚然后用analogRead()读到的 0~1023 映射到 1000~2000us。示例代码如下#include Servo.h Servo sg90; const int potPin A0; const int servoPin 9; void setup() { sg90.attach(servoPin); sg90.writeMicroseconds(1500); } void loop() { int potValue analogRead(potPin); // 将 0~1023 映射到 1000~2000us int pulse map(potValue, 0, 1023, 1000, 2000); sg90.writeMicroseconds(pulse); delay(15); }这个例子说明了一个关键点360 度舵机的输入信号在 1000~2000us 之间是连续可调的因此改变电位器位置就能平滑改变舵机转速和方向。电位器旋到中间位置时输出约 1500us舵机停止往两边旋转时舵机开始加速转动。5. 常见问题与排查思路5.1 问题汇总表问题现象常见原因解决思路舵机不转一点反应都没有接线错误或供电不足核对三条线改用外部 5V 电源舵机抖动、进退反复信号线接触不良或脉宽处于临界死区重新插紧杜邦线微调脉宽避开临界值舵机一直转、无法停止停止脉宽不是 1500us用 3.3 节方法找到真实中心点转动方向与预期相反正反转脉宽定义反了把大于中心点和小于中心点的值对调一接舵机 Arduino 就重启舵机启动电流拉低板载电压使用外部电源增加滤波电容带负载后转速明显下降电源功率不足或舵机超载换更大电流电源或降低机械负载想转固定角度但始终不准360 度舵机无位置反馈改用反馈舵机或添加编码器闭环5.2 Arduino 一接舵机就重启这是最常见的问题。由于舵机启动和堵转时电流突增Arduino 的稳压器件会被严重拉低甚至 USB 供电自动复位。解决步骤断开舵机红线与 Arduino 5V 的连接。使用外部 5V 电源的正极接舵机红线。外部电源负极同时接舵机棕线和 Arduino GND。如果仍然不稳定可以在舵机电源两端并联一个 100~470uF 电解电容电容尽量靠近舵机电源引脚。5.3 停止位置需要校准一部分 360 度舵机标称中心点就是 1500us但实际会有偏差。比如我手头有一颗舵机写入 1500us 时还在缓慢正转改成 1470us 才停。校准步骤可以按下面来先把脉宽设成 1500us观察舵机是否停。如果还转每次增减 10us例如 1480、1470、1460。找到“临界停止点”如果 1470us 不转但 1460us 会反转说明停止点就在两者之间。把这个停止点保存为常量stopPulse后续代码都用它代替固定 1500。校准之后转速控制才能准确。否则你会觉得舵机转速忽快忽慢其实只是中心点偏移导致的“假象”。5.4 脉宽接近中心值时舵机抖动在中心点附近舵机控制电路会进入临界状态可能出现输出轴轻微抖动或发出电流声。这是正常现象。工程上可以设置一个“死区”让脉宽落在一定范围内时强制输出停止脉宽if (pulse 1490 pulse 1510) { sg90.writeMicroseconds(stopPulse); } else { sg90.writeMicroseconds(pulse); }这样执行器就不会因为微小脉宽变化而频繁抖动。6. 最佳实践与工程建议6.1 供电设计放在第一位微型 360 度舵机虽然看起来小但工程应用时必须把供电当成大头问题。建议不要用 Arduino 5V 引脚驱动多个舵机。选用能持续输出 1A 以上的 5V 电源具体按舵机数量和负载评估。舵机电源与单片机控制板共地但尽量分别供电。长线供电时在舵机端并联一个电容。如果使用锂电池或大容量电源还应该在电源输入端并联一个大电容避免热插拔时拉弧损坏接口。6.2 把“停止脉宽”定义成常量与其在代码里到处写 1500不如在校准后给它一个名字const int SERVO_STOP_US 1470;这样后期如果更换舵机只需要修改这一处常量不需要搜索整个程序替换数字。这也是良好的代码习惯。6.3 明确开环控制的边界360 度连续旋转舵机的核心特征是开环速度控制它适合以下场景摇头风扇叶片旋转。摄像头持续扫描。小车简单前进后退。机械结构往复运动。它不适合以下场景云台需要精确停在某个角度。机械臂关节需要位置保持。需要判断当前是否发生堵转。需要知道舵机转了多少圈。如果你的项目是上面这些“位置敏感”需求建议换回标准位置舵机或选用带反馈的 360 度舵机、双轴编码器电机再配合 PID 控制器实现闭环。6.4 程序结构建议即使是一个小小的舵机控制程序我也建议把关键参数集中管理。示例#include Servo.h Servo sg90; const int SERVO_PIN 9; const int STOP_PULSE_US 1500; const int MAX_SPEED_US 1800; const int MIN_SPEED_US 1200; void setup() { sg90.attach(SERVO_PIN); sg90.writeMicroseconds(STOP_PULSE_US); } void drive(int pulseUs, int durationMs) { sg90.writeMicroseconds(pulseUs); delay(durationMs); } void loop() { drive(MAX_SPEED_US, 2000); drive(STOP_PULSE_US, 1000); drive(MIN_SPEED_US, 2000); drive(STOP_PULSE_US, 1000); }封装之后后续如果要增加更多动作只需要维护drive()的调用序列即可。对稍微复杂一点的项目还能用状态机代替delay()这里不展开。6.5 安全与异常保护连续旋转舵机的输出轴一直转动如果机械结构卡住电机会持续堵转并发热严重时会烧坏舵机内部驱动芯片。在项目中建议在程序中增加运行时间保护避免舵机长时间同一方向运行。机械结构预留限位或过载打滑空间。必要时在电源回路中串联自恢复保险丝。举个例子如果你在做一个自动卷帘机构舵机正转 3 秒应该到达上限但万一限位开关失效程序就会一直输出正转信号。此时可以加一个简单判断连续正转超过 5 秒就强制停止并报错。7. 总结与上手清单写到这里关于 SG90 360 度连续旋转舵机的基础知识和测试方法已经讲得比较完整了。我建议你拿到舵机后按下面这个顺序做一遍初测第 1 步确认舵机确实是 360 度连续旋转版本。 第 2 步正确接线尽量使用外部电源并共地。 第 3 步写入 1500us观察舵机是否停止。 第 4 步如果还在转用串口工具微调出真实停止脉宽。 第 5 步分别测试 1700us 和 1300us确认正反转方向。 第 6 步把测试结果整理成常量再开始做实际项目。这样做的好处是你不会跳过供电和停止脉宽校准这两个最容易踩坑的步骤。后面无论是做云台摇头、小车驱动还是其他自动化工装都能少走不少弯路。如果遇到舵机抖动、方向相反或 Arduino 重启的问题可以直接参考本文第 5 节的排查表。