编程实现控制FPV舵机云台
311.6、编程实现控制 FPV 舵机云台
#include <Servo.h> // 引入 Arduino Servo 库,获得舵机对象和控制接口
Servo myservo; // 创建第一个舵机对象,对应云台的左右旋转轴
Servo myservo2; // 创建第二个舵机对象,对应云台的上下俯仰轴
int pos = 0; // 保存本轮要写给舵机的角度值,初始值为 0
void setup() { // 上电或复位后只执行一次的初始化函数
myservo.attach(9); // 把第一个舵机对象关联到数字引脚 D9
myservo2.attach(10); // 把第二个舵机对象关联到数字引脚 D10
} // setup() 初始化结束
void loop() { // 主循环会在开发板运行期间不断重复
for (pos = 0; pos <= 180; pos += 1) { // 让 pos 从 0 逐次增加到 180,包含两个端点
myservo.write(pos); // 把当前角度目标写给第一个舵机
myservo2.write(pos); // 把同一个角度目标写给第二个舵机
delay(15); // 每增加 1° 等待 15 ms,给舵机留出运动时间
} // 结束 0° 到 180° 的递增循环
for (pos = 180; pos >= 0; pos -= 1) { // 让 pos 从 180 逐次减小到 0,包含两个端点
myservo.write(pos); // 反向阶段只向第一个舵机写入角度;这是视频最终代码的原样行为
delay(15); // 每减小 1° 等待 15 ms
} // 结束 180° 到 0° 的递减循环
} // 一轮结束后返回 loop() 开头继续运行
一、编程控制 SG90 舵机
本节先打开 Arduino Servo 库自带的 Sweep 示例,用 D9 测试云台的左右轴;随后在示例上增加第二个 Servo 对象,把上下轴信号接到 D10,并把修改后的草图烧录到 UNO。页首代码是视频最终实际编译、上传的版本,仅替换了原英文注释并逐行补充中文说明,没有擅自补写视频中缺少的控制语句。
1.1 舵机控制原理
普通位置式 RC 舵机有电源、地和信号三根线。控制器在信号线上周期性发送窄高电平脉冲,舵机内部控制电路根据**高电平持续时间(脉宽)**确定目标位置。课程把它称为 PWM 控制,这种说法在舵机应用中很常见;但它不是通过 analogWrite() 改变普通方波占空比来直接驱动电机,真正表达位置的是每帧脉冲的宽度。
视频课件给出的简化关系如下:
| 高电平脉宽 | 课件标注角度 | 精校说明 |
|---|---|---|
| 0.5 ms | 0° | 课件示意值,不应直接当成所有 SG90 兼容品的安全端点 |
| 1.0 ms | 45° | 按课件关系递增 |
| 1.5 ms | 90° | 通常用作中位的示意值 |
| 2.0 ms | 145° | 课件原图如此标注,但与其余等间隔关系不一致;线性示意应为 135°,145°应视为课件笔误 |
| 2.5 ms | 180° | 课件示意值,真实舵机未必能无碰撞地到达该端点 |
课件还把重复周期画成 20 ms,即约 50 Hz。当前 Arduino Servo 库的 AVR 实现也把刷新间隔定义为 20000 µs,但 attach(9) 的默认角度映射并不是课件中的 500~2500 µs,而是把 0~180 映射到默认的 544~2400 µs。attach(pin, min, max) 才能另外指定端点脉宽。脉宽、真实角度和机械极限会因舵机个体、兼容品和安装齿位而变化,所以程序中的“90°”是命令目标,不是经过传感器测得的绝对平台角度。
视频右侧的方向图把下轴的 0°/180°画成右/左,把上轴的 0°/180°画成上/下。这只是课程装配方向下的参考;舵机安装朝向、舵盘齿位或固定端改变后,肉眼看到的方向可能相反。
1.2 编程实现舵机控制
1.2.1 打开编程软件
1.2.1.1 示例
视频使用 Arduino IDE 2.0.1,先选择 Arduino Uno,再依次打开“文件 → 示例 → Servo → Sweep”。原始笔记中的“server”“sweet”和“历程”均为识别错误,正确名称分别是库名 Servo、示例名 Sweep 和“例程”。
Sweep 是 Servo 库附带的示例草图:它先把一个舵机关联到 D9,再令角度变量从 0 增到 180、从 180 减回 0。视频后半段直接在这份示例上增加第二只舵机,没有新建独立工程。
1.2.2 代码分析
| 代码 | 初学者应理解的含义 |
|---|---|
#include <Servo.h> | 引入 Servo 库的声明;它不是把舵机接上电源,也不会自动识别舵机型号 |
Servo myservo; | 以 Servo 类型创建一个软件对象;对象名是 myservo,不是 myServer |
int pos = 0; | 只把循环变量初始化为 0;这一行本身不会让机械轴立即转到物理零位 |
attach(pin) | 把一个舵机对象关联到指定数字信号脚,并开始由库生成控制脉冲 |
write(pos) | 写入目标角度;Servo 库负责把 0~180 的角度值换算为脉宽 |
delay(15) | 让程序在本次 1°步进后等待 15 ms;它不是把舵机信号周期改成 15 ms |
两个 for 循环都包含首尾端点,因此每个方向各执行 181 次。忽略少量指令开销,一个方向约为 181 × 15 ms = 2.715 s,完整往返约为 5.43 s。这个数值表示程序更新目标角度的节奏,不表示舵机一定已经在每个 15 ms 间隔内准确到位;真实速度还取决于供电、负载和舵机性能。
代码中的两次 write() 是先后执行的,不是同一个 CPU 时钟瞬间发生。不过两条语句的时间差相对舵机的机械响应很小,肉眼会看到两轴近似同时开始变化。Servo 库还会在一个刷新周期内依次安排各通道脉冲,因此“同步”在这里应理解为使用相同的角度序列,而不是两路脉冲完全同相。
1.2.3 板子原理图
Arduino UNO R3 上带 ~ 标记的 D3、D5、D6、D9、D10、D11,确实是六个可由 analogWrite() 输出硬件 PWM 的数字引脚。但视频由此得出“控制舵机必须使用这六个引脚”的结论并不正确。
在本节所用的 AVR UNO 和当前官方 Servo 库中,舵机脉冲由 16 位 Timer1 的中断配合普通数字输出生成;attach(pin) 会把传入的数字脚设为输出,并不要求该脚带 ~。所以选 D9、D10 是示例和本项目的具体分配,不是 Servo 库的硬性限制。选择其他有效数字脚时仍要避开项目已经占用的功能,例如 D0/D1 通常用于串口。
还要注意一个容易混淆的反向影响:在经典 AVR UNO 上启用 Servo 库后,Timer1 被舵机控制占用,D9、D10 原有的 analogWrite() PWM 功能会受影响;当所有 Servo 对象都 detach() 后,这两脚才可恢复给普通 PWM 使用。这不妨碍 D9、D10 作为本节的舵机信号脚。
1.2.4 编程控制舵机
视频先只测试下方左右轴:myservo.attach(9) 将该舵机的信号线关联到 D9。attach() 中的 9 是开发板数字引脚编号,不是舵机编号,也不是“第 9 个 PWM 通道”。
首次通电时,舵盘可能立即向当前控制目标转动。第 310 节的机械组装没有先完成电气居中,因此应扶稳机构、让手指和线缆离开转轴,并准备在碰撞、堵转、持续嗡鸣或异常发热时立即断电。直接测试完整 0~180°只能证明视频这样操作过,不能证明这个范围对每一套云台都安全。
1.2.5 舵机接线
视频中两只舵机采用黄色、红色、棕色三芯线,实际接线为:
| 云台轴 | 信号线 | 电源线 | 地线 |
|---|---|---|---|
| 下方左右轴 | 黄色 → D9 | 红色 → 课程板扩展口 5V | 棕色 → 课程板扩展口 GND |
| 上方俯仰轴 | 黄色 → D10 | 红色 → 课程板扩展口 5V | 棕色 → 课程板扩展口 GND |
接线前必须以舵机插头标识、实物资料和扩展口丝印为准,不能把颜色当作所有品牌通用的绝对标准。尤其不能只凭视频口述的“某一排”判断课程板扩展口:画面中的扩展焊点是这块教学板的定制接法,先用丝印或万用表确认 5V/GND,再断电插线。
舵机的红线和棕线是负载供电回路,不能接到普通数字 I/O 脚取电。视频通过 USB 给 UNO 供电,并把两只舵机接到板载 5V/GND 扩展口,这能复现课堂演示,但增加焊点不会增加 5V 电源的供电能力。两只舵机启动、换向或受阻时可能引起压降、UNO 复位和舵机抖动。TowerPro 对正品 SG90 Analog 标出的工作电压为 4.8 V,并建议通过外部适配器供电;课程中的兼容舵机仍应以自身规格为准。使用独立稳压电源时,电源容量应满足负载需求,而且外部电源 GND 必须与 UNO GND 共地,否则 D9/D10 的信号没有共同参考。
1.2.6 烧录代码
视频中的操作顺序是:
- 断电完成接线并检查 D9、5V、GND 没有插反。
- 用 USB 连接 UNO,在 IDE 中选择
Arduino Uno和当时出现的COM3。 - 点击上传,等待编译和写入完成。
- 第一次单舵机测试时,视频确认下方舵机从 0 递增到 180,再从 180 递减到 0。
COM3 只是录制电脑当时分配的端口号,不是项目固定配置;换电脑、USB 插口或驱动后可能显示为其他 COM 号。上传成功也只证明程序能够编译并写入,不能替代接线、供电和机械限位检查。
1.2.7 应用案例
1.2.7.1 舵机控制示例
视频为第二只舵机做了三处可见修改:声明 Servo myservo2、在 setup() 中执行 myservo2.attach(10)、在角度递增循环中执行 myservo2.write(pos)。随后把上方舵机的黄色信号线接 D10,电源和地接入同一组 5V/GND 扩展口,再重新上传程序。
最终引脚分工是:
D9 → 下方舵机信号 → 左右旋转(pan)
D10 → 上方舵机信号 → 上下俯仰(tilt)
5V → 两只舵机电源(课程演示接法)
GND → 两只舵机地,同时也是控制信号参考地
必须指出,视频口述称第二只舵机也会“从 180°减到 0°”,并把演示描述为两轴同步;但逐帧核对最终编译、上传的草图后,可以看到反向循环里只有 myservo.write(pos),没有向 myservo2 写入递减的 pos。因此页首源码的真实逻辑是:
- 递增阶段:两只舵机都依次收到 0~180 的目标值。
- 递减阶段:只有 D9 对应的第一只舵机依次收到 180~0;第二只舵机保持最后写入的 180 目标。
- 下一轮重新进入递增阶段时,第二只舵机的目标会突然从 180 改为 0,然后又从较小值继续递增;它不会按该源码平滑完成 180~0 的反向扫描。
所以这段最终代码不能证明“双轴完整往返同步”。精校稿依据 README 保留视频源码,不在代码块中擅自补齐缺失语句;若项目要求两轴在两个方向都跟随同一角度序列,两个方向的循环都必须分别向两个舵机对象更新目标。
即使两个对象都收到相同的 pos,两个转轴的机械安装方向也不同,相同数值不代表平台在空间中朝同一方向。真正的二维追光还需要光敏传感器输入、误差判断、两个轴各自的角度边界和校准逻辑;本节只演示开环扫描,没有读取任何光照值,因此视频结尾说的“追光效果”是后续用途,不是本节已经实现的自动追光。
1.3 上电验收与故障排查
| 现象 | 优先检查 |
|---|---|
| 两只舵机都不动 | 5V/GND 是否接反或断路、UNO 是否已运行、是否选择了正确端口和开发板 |
| 只有一只完全不动 | 对应 D9/D10 信号线、该对象的 attach()、插头接触和舵机本体 |
| 第二只只正向扫或周期边界抽动 | 页首最终代码只在递增循环更新 myservo2,这是源码逻辑而非必然的接线故障 |
| 舵机抖动、UNO 复位 | 供电压降、外部电源未共地、插头松动、机械卡涩或负载过大 |
| 转向与课件相反 | 舵机安装方向或舵盘齿位不同;先校准,不要仅凭左右/上下文字硬改接线 |
| 到端点持续嗡鸣或支架碰撞 | 命令范围超过真实机械安全范围,应立即断电并缩小角度范围、重新校准舵盘 |
完成测试后,应先确认两轴没有碰撞、线缆没有被拉紧,再安装太阳能板。负载增加后,原来空载可用的供电和角度范围仍可能失效,不能把本节空载演示直接当成整机验收结果。
核对依据
- 本地
videos/311.6、编程实现控制FPV舵机云台.mp4:逐段核对 20 ms/脉宽课件、Arduino IDE 2.0.1、Servo → Sweep示例、D9 单舵机测试、D10 第二舵机接线、最终上传及实物演示;重点逐帧确认最终源码只在递增循环调用myservo2.write(pos)。 - 本地
transcripts/311.6、编程实现控制FPV舵机云台.txt:核对讲解顺序、线色、D9/D10 分工、COM3 和口述的双轴往返意图;对照视频纠正转录中的 “server”“sweet”“P-down”等识别错误,也没有用口述覆盖画面中实际缺失的反向控制语句。 - Arduino Servo 库官方
Sweep示例:核对示例名称、对象、D9、0~180/180~0 两个循环和 15 ms 步进。 - Arduino Servo 库官方 API:核对
attach()、write()、默认 544/2400 µs 端点、角度含义及 D9/D10 普通 PWM 与 Servo 库的资源关系。 - Arduino Servo 库 AVR 实现与定时器定义:核对
attach()将所选数字脚设为输出、Timer1 中断依次产生各通道脉冲、20 ms 刷新和角度到脉宽的映射,从而纠正“必须使用带~的 PWM 脚”这一说法。 - Arduino UNO Rev3 官方资料:核对 UNO 的 14 个数字 I/O,以及供
analogWrite()使用的六个 PWM 引脚 D3、D5、D6、D9、D10、D11。 - TowerPro SG90 Analog 官方规格:核对正品 SG90 Analog 的 4.8 V 工作电压和外部适配器供电建议;课程实物可能是兼容品,不能据此直接断言其所有电气参数。