前面我们学了光敏电阻,让 Arduino 能感知光线强弱。现在给它装上"肌肉"------舵机,让它能转动、摆动、做动作!
学完这篇,你会完成:
- 认识舵机:了解舵机的工作原理和类型
- 控制舵机角度 :掌握
Servo库的使用 - 综合项目:自动感应垃圾桶:手靠近自动开盖
一、舵机是什么?
舵机(Servo Motor)是一种可以精确控制转动角度 的电机。普通舵机的转动范围是 0° ~ 180°,连续旋转舵机可以 360° 不停转。
核心原理
舵机内部有一个电位器 (可变电阻)和一个控制电路:
- 控制电路接收 PWM 信号
- 电位器反馈当前角度
- 控制电路比较目标角度和实际角度,驱动电机转动到目标位置
舵机有三根线:红(VCC) 、棕/黑(GND) 、橙/黄(信号)
常见类型
| 类型 | 特点 | 适用场景 |
|---|---|---|
| SG90(9g 舵机) | 小巧、便宜、扭矩小 | 小型机器人、云台 |
| MG90S(金属齿轮) | 扭矩大、耐用 | 机械臂、小车转向 |
| MG996R(大扭矩) | 扭矩 15kg·cm | 大型机械臂、四足机器人 |
| 连续旋转舵机 | 可 360° 旋转 | 小车驱动、卷线器 |
SG90 参数
| 参数 | 数值 |
|---|---|
| 工作电压 | 4.8V ~ 6V |
| 扭矩 | 1.8 kg·cm(4.8V) |
| 转动范围 | 0° ~ 180° |
| 响应速度 | 0.12 秒/60° |
| 重量 | 9g |
二、PWM 信号
舵机通过 PWM(脉冲宽度调制) 信号控制角度。
PWM 原理
- 周期:20ms(50Hz)
- 高电平持续时间决定角度:
| 高电平时间 | 对应角度 |
|---|---|
| 0.5ms | 0° |
| 1.0ms | 45° |
| 1.5ms | 90° |
| 2.0ms | 135° |
| 2.5ms | 180° |
Arduino 的
Servo库会自动处理 PWM 信号,你只需要调用write(angle)即可。
三、接线方式
| 舵机线色 | 接法 |
|---|---|
| 红(VCC) | 5V(大扭矩舵机建议外接电源) |
| 棕/黑(GND) | GND(必须与 Arduino 共地) |
| 橙/黄(信号) | 任意数字引脚(推荐 D9) |
️ 重要提示 :SG90 可以直接用 Arduino 5V 供电,但 MG996R 等大扭矩舵机启动电流可达 1A 以上,Arduino 的 5V 引脚最大只能提供 500mA,必须外接电源,否则会导致 Arduino 重启或损坏。
四、实验一:基础控制
让舵机从 0° 转到 180°,再转回来。
#include <Servo.h>
Servo myservo; // 创建舵机对象
#define SERVO_PIN 9
void setup() {
myservo.attach(SERVO_PIN); // 绑定引脚
}
void loop() {
// 从 0° 转到 180°
for (int angle = 0; angle <= 180; angle++) {
myservo.write(angle);
delay(15); // 等待舵机转动到位
}
// 从 180° 转回 0°
for (int angle = 180; angle >= 0; angle--) {
myservo.write(angle);
delay(15);
}
}
代码解读
#include <Servo.h>:引入舵机库Servo myservo:创建舵机对象myservo.attach(pin):绑定信号引脚myservo.write(angle):设置目标角度(0~180)delay(15):SG90 转 60° 需要 0.12 秒,转 1° 约 2ms,15ms 足够到位
五、实验二:串口控制
通过串口输入角度,控制舵机转动到指定位置。
#include <Servo.h>
Servo myservo;
#define SERVO_PIN 9
void setup() {
Serial.begin(9600);
myservo.attach(SERVO_PIN);
Serial.println("Servo Ready! Enter angle (0-180):");
}
void loop() {
if (Serial.available()) {
int angle = Serial.parseInt(); // 读取串口输入的角度
if (angle >= 0 && angle <= 180) {
myservo.write(angle);
Serial.print("Angle set to: ");
Serial.println(angle);
} else {
Serial.println("Invalid angle! Enter 0-180.");
}
}
}
测试方法
- 上传代码后打开串口监视器
- 输入角度值(如 90),按回车
- 舵机转动到指定角度
六、实验三:电位器控制
用旋钮(电位器)控制舵机角度,实现"指哪打哪"。
所需元件
- Arduino Uno
- SG90 舵机
- 10kΩ 电位器
- 面包板 + 杜邦线
接线
| 元件 | 接法 |
|---|---|
| 舵机信号 | D9 |
| 舵机 VCC | 5V |
| 舵机 GND | GND |
| 电位器两端 | 5V + GND |
| 电位器中间 | A0 |
代码
#include <Servo.h>
Servo myservo;
#define SERVO_PIN 9
#define POT_PIN A0
void setup() {
myservo.attach(SERVO_PIN);
Serial.begin(9600);
}
void loop() {
// 读取电位器值(0~1023)
int potValue = analogRead(POT_PIN);
// 映射到舵机角度(0~180)
int angle = map(potValue, 0, 1023, 0, 180);
// 设置舵机角度
myservo.write(angle);
Serial.print("Pot: ");
Serial.print(potValue);
Serial.print(" -> Angle: ");
Serial.println(angle);
delay(15);
}
效果
旋转电位器,舵机跟随转动,角度完全同步。
七、综合项目:自动感应垃圾桶
手靠近时自动开盖,离开后自动关盖。
所需元件
- Arduino Uno
- SG90 舵机
- HC-SR04 超声波传感器
- 面包板 + 杜邦线
接线
| 元件 | 接法 |
|---|---|
| 舵机信号 | D9 |
| 舵机 VCC | 5V |
| 舵机 GND | GND |
| 超声波 Trig | D2 |
| 超声波 Echo | D3 |
| 超声波 VCC | 5V |
| 超声波 GND | GND |
代码
#include <Servo.h>
Servo myservo;
#define SERVO_PIN 9
#define TRIG_PIN 2
#define ECHO_PIN 3
#define OPEN_ANGLE 120 // 开盖角度
#define CLOSE_ANGLE 0 // 关盖角度
#define DISTANCE_THRESHOLD 10 // 触发距离(cm)
void setup() {
myservo.attach(SERVO_PIN);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.begin(9600);
myservo.write(CLOSE_ANGLE); // 初始状态:关盖
delay(500);
}
// 测量距离(cm)
float getDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
return duration * 0.034 / 2;
}
void loop() {
float distance = getDistance();
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
if (distance < DISTANCE_THRESHOLD && distance > 0) {
// 手靠近,开盖
myservo.write(OPEN_ANGLE);
Serial.println("Open!");
} else {
// 手离开,关盖
myservo.write(CLOSE_ANGLE);
Serial.println("Close!");
}
delay(100);
}
效果
- 手靠近超声波传感器(10cm 以内)→ 舵机转动到 120°,开盖
- 手离开 → 舵机转回 0°,关盖
八、进阶:平滑转动
直接 write() 会让舵机"瞬间"转到目标角度,看起来比较生硬。可以用插值实现平滑转动。
#include <Servo.h>
Servo myservo;
#define SERVO_PIN 9
int currentAngle = 0;
int targetAngle = 0;
void setup() {
myservo.attach(SERVO_PIN);
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
targetAngle = Serial.parseInt();
if (targetAngle < 0) targetAngle = 0;
if (targetAngle > 180) targetAngle = 180;
}
// 平滑插值:每次向目标角度靠近 5°
if (currentAngle != targetAngle) {
if (currentAngle < targetAngle) {
currentAngle += 5;
if (currentAngle > targetAngle) currentAngle = targetAngle;
} else {
currentAngle -= 5;
if (currentAngle < targetAngle) currentAngle = targetAngle;
}
myservo.write(currentAngle);
delay(20);
}
}
效果
舵机不再"瞬移",而是匀速平滑地转动到目标角度,看起来更自然。
九、常见问题
| 问题 | 解决方法 |
|---|---|
| 舵机抖动/不动 | 检查供电是否足够,大扭矩舵机必须外接电源 |
| 舵机转动时有异响 | 检查是否被机械结构卡住,或角度超出范围 |
| Arduino 重启 | 舵机启动电流过大,Arduino 供电不足,必须外接电源 |
| 舵机角度不准 | 不同舵机的 PWM 脉宽有差异,可用 attach(pin, min, max) 校准 |
| 舵机一直转不停 | 可能是连续旋转舵机,或信号线接触不良 |
舵机角度校准
// 校准 PWM 脉宽范围(单位:微秒)
myservo.attach(SERVO_PIN, 500, 2500);
// 500 = 0° 对应的高电平时间
// 2500 = 180° 对应的高电平时间
不同品牌舵机的脉宽范围不同,SG90 通常是 500~2500μs,MG996R 可能是 500~2400μs。
十、舵机供电方案
方案一:Arduino 5V 直接供电(仅 SG90)
- 适合 1~2 个 SG90 舵机
- 简单方便,但电流有限
方案二:外接 5V 电源(推荐)
-
适合多个舵机或大扭矩舵机
-
必须共地:外接电源的 GND 与 Arduino 的 GND 连接
外接 5V 电源
+5V ──→ 舵机 VCC
GND ──→ 舵机 GND ──→ Arduino GND(共地!)
方案三:电池供电
- 4 节 AA 电池(6V)或锂电池(7.4V)+ 降压模块
- 适合移动机器人项目
十一、本篇小结
回顾一下今天学到的核心知识:
- 舵机原理:通过 PWM 信号控制转动角度,内部电位器反馈位置
- PWM 信号:周期 20ms,高电平 0.5~2.5ms 对应 0°~180°
Servo库 :attach()绑定引脚,write()设置角度- 供电注意:SG90 可用 Arduino 供电,大扭矩舵机必须外接电源
- 共地原则:外接电源的 GND 必须与 Arduino 的 GND 连接
- 综合项目:串口控制 + 电位器控制 + 自动感应垃圾桶
- 平滑转动:用插值实现匀速转动,避免"瞬移"
舵机是机器人项目的核心执行元件,广泛应用于机械臂、云台、小车转向等场景。下一篇,我们学习直流电机 + L298N 驱动模块------让 Arduino 驱动小车跑起来!