零基础学 Arduino(四):简易机械臂
第三篇学会了控制单个舵机,这篇我们用三个幻尔 LD-25MG 舵机搭一个简易机械臂——底座左右转、大臂上下抬、爪子开合抓东西。把前面三篇学的 API 全部用上。
1. 你手上的硬件
| 硬件 | 品牌 | 作用 |
|---|---|---|
| Arduino UNO R3 | — | 主控 |
| 幻尔 Arduino 扩展板(C款) | 幻尔科技 | 引脚即插即用,供电集中管理 |
| LD-25MG 数字舵机 ×3 | 幻尔科技 | 三关节驱动:底座 + 大臂 + 爪子 |
2. 机械臂结构
三个舵机各管一个关节,组装起来就是一个三自由度机械臂:
┌──────────────┐
│ 舵机3:爪子 │ ← 开合,抓取物体
└──────┬───────┘
│
┌──────┴───────┐
│ 舵机2:大臂 │ ← 上下抬放,控制高度
└──────┬───────┘
│
┌──────┴───────┐
│ 舵机1:底座 │ ← 左右旋转,控制方向
└──────┬───────┘
│
┌─────┴─────┐
│ 扩展板 │
│ (插UNO上) │
└───────────┘
| 舵机编号 | 关节 | 功能 | 角度范围 | 信号脚 |
|---|---|---|---|---|
| 舵机1 | 底座 | 整臂左右旋转 | 0°~180° | D3 |
| 舵机2 | 大臂 | 大臂上下抬放 | 0°~180° | D5 |
| 舵机3 | 爪子 | 夹爪开合 | 30°~150° | D6 |
3. 新知识点
3.1 多个 Servo 对象
一个舵机一个对象,互不干扰:
#include <Servo.h>
Servo servo1; // 底座
Servo servo2; // 大臂
Servo servo3; // 爪子
void setup() {
servo1.attach(3);
servo2.attach(5);
servo3.attach(6);
}
3.2 用数组管理多个舵机
舵机多了之后,用数组统一管理更简洁:
Servo servos[3]; // 3 个舵机
int pins[3] = {3, 5, 6}; // 对应引脚
void setup() {
for (int i = 0; i < 3; i++) {
servos[i].attach(pins[i]);
}
}
3.3 步进式移动——平滑过渡
一次 write() 是瞬间到位的。想平滑运动,需要从一个角度"一步步"走到目标角度:
void moveSmoothly(Servo &servo, int from, int to, int speedDelay) {
if (from < to) {
for (int angle = from; angle <= to; angle++) {
servo.write(angle);
delay(speedDelay); // 数字越小越快
}
} else {
for (int angle = from; angle >= to; angle--) {
servo.write(angle);
delay(speedDelay);
}
}
}
4. 实战示例
示例 1:三舵机回零——初始化到默认位置
上电后先把三个舵机归位到安全角度:
#include <Servo.h>
Servo servo1, servo2, servo3;
void setup() {
servo1.attach(3); // 底座
servo2.attach(5); // 大臂
servo3.attach(6); // 爪子
// 归零:底座居中,大臂放下,爪子打开
servo1.write(90);
servo2.write(0);
servo3.write(150);
}
void loop() {
// 保持初始位置不动
}
示例 2:顺序动作——底座转 → 大臂抬 → 爪子抓
模拟"找东西 → 伸过去 → 抓起来"的动作序列:
#include <Servo.h>
Servo servo1, servo2, servo3;
void setup() {
servo1.attach(3);
servo2.attach(5);
servo3.attach(6);
// 回到初始姿态
servo1.write(90);
servo2.write(0);
servo3.write(150); // 爪子张开
delay(2000);
}
void loop() {
// 第1步:底座右转 45°,对准目标
servo1.write(135);
delay(1000);
// 第2步:大臂抬到 120°,伸过去
servo2.write(120);
delay(1000);
// 第3步:爪子合拢,抓住
servo3.write(50);
delay(1000);
// 第4步:大臂抬起,举起来
servo2.write(50);
delay(1000);
// 第5步:底座转回来
servo1.write(90);
delay(1000);
// 第6步:放下,爪子张开
servo2.write(0);
servo3.write(150);
delay(1000);
}
这就是一个完整的"抓取-搬运-放下"流程。改每个步骤的角度和延时,就能编排出不同的动作。
示例 3:多舵机同步运动
三个舵机同时平滑动起来,不是一个个排队等:
#include <Servo.h>
Servo servos[3];
int pins[3] = {3, 5, 6}; // 底座、大臂、爪子
int current[3] = {90, 0, 150}; // 当前角度
int target[3] = {90, 0, 150}; // 目标角度
void setup() {
for (int i = 0; i < 3; i++) {
servos[i].attach(pins[i]);
servos[i].write(current[i]);
}
Serial.begin(9600);
}
void loop() {
// 目标姿态:底座左转、大臂抬起、爪子半合
target[0] = 45;
target[1] = 100;
target[2] = 80;
// 三个舵机同时一步步走向目标
for (int step = 0; step < 50; step++) {
for (int i = 0; i < 3; i++) {
if (current[i] < target[i]) current[i]++;
if (current[i] > target[i]) current[i]--;
servos[i].write(current[i]);
}
delay(15);
}
delay(1000);
// 回到初始姿态
target[0] = 90;
target[1] = 0;
target[2] = 150;
for (int step = 0; step < 50; step++) {
for (int i = 0; i < 3; i++) {
if (current[i] < target[i]) current[i]++;
if (current[i] > target[i]) current[i]--;
servos[i].write(current[i]);
}
delay(15);
}
delay(1000);
}
核心思想:每一帧每个舵机只动 1°,50 帧后全部到位。step 越多越平滑。
示例 4:用旋钮选关节,逐个调试
调试机械臂时需要一个关节一个关节地找角度。接一个旋钮,每次控制一个关节:
#include <Servo.h>
Servo servos[3];
int pins[3] = {3, 5, 6};
int joint = 0; // 当前控制的关节(0=底座, 1=大臂, 2=爪子)
void setup() {
for (int i = 0; i < 3; i++) {
servos[i].attach(pins[i]);
servos[i].write(90);
}
Serial.begin(9600);
Serial.println("输入 0/1/2 选择关节(底座/大臂/爪子)");
}
void loop() {
// 串口输入切换关节
if (Serial.available()) {
int newJoint = Serial.parseInt();
if (newJoint >= 0 && newJoint <= 2) {
joint = newJoint;
Serial.print("当前控制:");
Serial.println(joint == 0 ? "底座" : joint == 1 ? "大臂" : "爪子");
}
}
// 旋钮控制当前关节角度
int val = analogRead(A0);
int angle = map(val, 0, 1023, 0, 180);
servos[joint].write(angle);
Serial.print("关节");
Serial.print(joint);
Serial.print(" → ");
Serial.println(angle);
delay(30);
}
先在串口监视器输入 0 选底座,拧旋钮调到最佳角度记下来;再输入 1 调大臂,输入 2 调爪子。全部定好后把角度值填进示例 2 的动作序列里。
5. API 速查
| API | 作用 | 示例 |
|---|---|---|
myservo.attach(pin) |
舵机绑定引脚 | servo1.attach(3); |
myservo.write(deg) |
转到指定角度 | servo2.write(120); |
myservo.detach() |
释放舵机 | servo3.detach(); |
map(val, a,b, c,d) |
数值范围映射 | map(val, 0,1023, 0,180) |
constrain(x, min, max) |
限制数值区间 | constrain(angle, 30, 150) |
Serial.parseInt() |
串口读取整数 | int n = Serial.parseInt(); |


