前面我们学了 PWM 输出,用 analogWrite() 控制 LED 亮度和蜂鸣器音调。但你可能好奇:PWM 除了调亮度、调音调,还能干什么?

        答案是:精确控制角度。

        今天这篇,我们要用 PWM 信号驱动舵机(Servo),让它精确转到任意角度。舵机是机器人、机械臂、云台的核心执行器,掌握了它,你就打开了"让东西动起来"的大门。

        学完这篇,你会完成两个项目:

  • 旋钮控制舵机:转动电位器,舵机角度实时跟随
  • 自动扫描舵机:舵机从 0° 到 180° 来回扫描,像雷达一样

一、舵机是什么?

        舵机(Servo Motor)是一种可以精确控制转动角度的电机。和普通电机不同,舵机不是"一直转圈",而是转到指定角度就停住

        常见舵机(如 SG90、MG90S)的角度范围是 0° ~ 180°

        舵机的三根线
线色接到
棕色/黑色GND
红色5V(注意:大扭矩舵机可能需要外部供电)
橙色/黄色信号线 → Arduino 的数字引脚

⚠️ SG90 这种小舵机可以直接用 Arduino 的 5V 供电。但如果用 MG996R 等大舵机,电流需求较大,必须用外部电源,否则会烧坏 Arduino。


二、舵机的工作原理——PWM 控制角度

        舵机内部有一个直流电机 + 电位器 + 控制电路。它通过接收 PWM 信号来确定目标角度:

  • 信号周期:20ms(即频率 50Hz)
  • 高电平脉宽:0.5ms ~ 2.5ms,对应 0° ~ 180°
高电平脉宽对应角度
0.5ms
1.0ms45°
1.5ms90°(中间位置)
2.0ms135°
2.5ms180°

        Arduino 的 Servo 库会自动帮你生成这些精确的 PWM 信号,你只需要告诉它"转到多少度"就行。


三、硬件清单

元件数量作用
Arduino Uno1块主控板
面包板1块搭建电路
SG90 舵机1个角度控制执行器
电位器(10kΩ)1个模拟输入,控制角度
杜邦线若干连接元件

四、电路接线

舵机接线

舵机有三根线(棕/红/橙):

  • 棕色线 → 接 GND
  • 红色线 → 接 5V
  • 橙色线(信号) → 接 Arduino 的 D9
电位器接线
  • 左引脚 → 接 GND
  • 中间引脚 → 接 Arduino 的 A0
  • 右引脚 → 接 5V

五、实验一:旋钮控制舵机

        转动电位器,舵机角度实时跟随变化。

#include <Servo.h>

Servo myServo;              // 创建舵机对象
const int potPin = A0;      // 电位器接 A0
const int servoPin = 9;     // 舵机信号线接 D9

void setup() {
  Serial.begin(9600);
  myServo.attach(servoPin); // 绑定舵机引脚
  Serial.println("=== 旋钮控制舵机 ===");
}

void loop() {
  // 读取电位器值(0~1023)
  int potValue = analogRead(potPin);

  // 映射到舵机角度(0~180)
  int angle = map(potValue, 0, 1023, 0, 180);

  // 控制舵机转到指定角度
  myServo.write(angle);

  // 串口打印调试信息
  Serial.print("电位器: ");
  Serial.print(potValue);
  Serial.print(" → 角度: ");
  Serial.print(angle);
  Serial.println("°");

  delay(20);
}
核心函数
  • Servo.attach(pin):将舵机绑定到指定引脚
  • Servo.write(angle):让舵机转到指定角度(0~180)
  • map():把电位器的 0~1023 映射到舵机的 0~180

转动电位器,你会看到舵机的摇臂平滑地跟着转动,非常直观。


六、实验二:雷达扫描模式

        舵机自动从 0° 扫到 180°,再扫回来,像雷达天线一样来回扫描。

#include <Servo.h>

Servo myServo;
const int servoPin = 9;

void setup() {
  Serial.begin(9600);
  myServo.attach(servoPin);
  Serial.println("=== 雷达扫描模式 ===");
}

void loop() {
  // 正向扫描:0° → 180°
  Serial.println("--- 正向扫描 ---");
  for (int angle = 0; angle <= 180; angle += 1) {
    myServo.write(angle);
    Serial.print("角度: ");
    Serial.print(angle);
    Serial.println("°");
    delay(15);  // 每步延迟 15ms,控制扫描速度
  }

  delay(500);  // 到达 180° 后暂停 0.5 秒

  // 反向扫描:180° → 0°
  Serial.println("--- 反向扫描 ---");
  for (int angle = 180; angle >= 0; angle -= 1) {
    myServo.write(angle);
    Serial.print("角度: ");
    Serial.print(angle);
    Serial.println("°");
    delay(15);
  }

  delay(500);  // 到达 0° 后暂停 0.5 秒
}
效果

        舵机摇臂从最左扫到最右,停顿半秒,再扫回来,循环往复。配合超声波传感器,就是一台简易的"雷达扫描仪"。


七、进阶:用串口直接输入角度

        除了电位器,你还可以通过串口监视器直接输入角度,让舵机转到指定位置。

#include <Servo.h>

Servo myServo;
const int servoPin = 9;

void setup() {
  Serial.begin(9600);
  myServo.attach(servoPin);
  myServo.write(90);  // 初始位置:中间
  Serial.println("=== 串口控制舵机 ===");
  Serial.println("输入角度 (0~180),按回车发送:");
}

void loop() {
  if (Serial.available() > 0) {
    int angle = Serial.parseInt();  // 读取串口输入的整数

    // 限制角度范围
    if (angle >= 0 && angle <= 180) {
      myServo.write(angle);
      Serial.print("舵机转到: ");
      Serial.print(angle);
      Serial.println("°");
    } else {
      Serial.println("⚠️ 角度超出范围!请输入 0~180 之间的值。");
    }
  }
}
使用方法
  1. 上传代码,打开串口监视器(波特率 9600)
  2. 在输入框中输入一个数字(如 45),按回车
  3. 舵机会立即转到 45° 位置

八、深入理解:舵机的"抖动"问题

        新手常遇到的一个问题:舵机到位后轻微抖动。原因有几个:

  • 电源不稳定:舵机启动瞬间电流较大,拉低了 5V 电压。解决方案:给舵机单独供电,并共地。
  • 信号线干扰:杜邦线太长或接触不良。解决方案:缩短信号线,确保连接牢固。
  • 更新频率过高Servo.write() 被过于频繁地调用。解决方案:只在角度变化时才调用 write()
优化技巧:只在角度变化时更新
int lastAngle = -1;  // 记录上次的角度

void loop() {
  int angle = map(analogRead(potPin), 0, 1023, 0, 180);

  if (angle != lastAngle) {  // 角度变化了才更新
    myServo.write(angle);
    lastAngle = angle;
  }
}

九、舵机的应用场景

        掌握了舵机控制,你可以做很多有趣的项目:

  • 机械臂:用 3~6 个舵机搭建多自由度机械臂
  • 云台:两个舵机组合,实现水平 + 垂直方向的角度控制
  • 智能小车转向:用舵机控制前轮转向角度
  • 雷达扫描:舵机 + 超声波传感器,扫描前方障碍物
  • 开关控制:用舵机推拉物理开关(如灯开关、门把手)

十、本篇小结

        回顾一下今天学到的核心知识:

  • 舵机原理:通过 PWM 脉宽(0.5ms~2.5ms)控制 0°~180° 角度
  • Servo 库attach() 绑定引脚,write() 设置角度
  • 旋钮控制舵机analogRead() + map() + Servo.write() 的组合
  • 雷达扫描:用 for 循环实现角度递增/递减
  • 串口控制Serial.parseInt() 读取用户输入的角度
  • 抖动排查:电源、信号线、更新频率三个方向

        舵机是"让 Arduino 产生物理运动"的第一步。下一篇,我们学习超声波传感器——让 Arduino 能够"看见"前方的障碍物,测量距离,为做避障小车打基础。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐