本教程完整记录 Arduino 机械臂 的制作全过程:3D 建模打印、电子硬件连接、Arduino 编程、自制 Android App 蓝牙控制。机械臂 5 自由度,支持手动滑块控制、轨迹记录回放、暂停/重置。
可观看视频或阅读图文教程。
功能概览
- App 滑块实时控制 6 个舵机(腰、肩、肘、腕翻、腕俯、夹爪)
- “保存”键记录当前姿态为步骤,“运行”循环执行,“暂停”暂停,“重置”清空轨迹
- 速度滑块调节动作快慢
3D 模型设计
SolidWorks 设计,5 自由度。前三轴 (腰/肩/肘) 用 MG996R 大扭矩金属齿轮舵机,后两轴与夹爪用 SG90 微型舵机。
3D 模型在线查看/下载:Thangs(感谢 Thangs 赞助)
STL 文件下载
Arduino Robot Arm STL Files
1 file(s) 0.00 KB Download
3D 打印
使用 Creality CR-10 打印全套零件,几小时完成。CR-10 性价比高、90% 预组装、打印质量优秀。
组装前检查滚轮偏心螺母张紧,调平热床即可打印。参考:3D 打印机必备 15 种配件工具
机械臂组装
- 底座安装第 1 号舵机 (MG996R),输出轴锁圆盘舵盘
- 上体覆盖并锁螺丝
- 肩关节同理,建议加装弹簧/橡皮筋分担重力
- 依次组装肘、腕翻、腕俯
- 夹爪用 M4 螺栓螺母组装,最后装上第 6 号舵机
电路原理图
核心:Arduino + HC-05 蓝牙模块 + 6 路舵机信号线接数字引脚 D5–D10。舵机供电**必须外接 5V ≥2A 电源**,Arduino 与外接电源共地。
所需元件
- MG996R 舵机 ×3
- SG90 微型舵机 ×3
- HC-05 蓝牙模块
- Arduino 开发板
- 5V 2A 直流电源
Arduino 代码详解
代码较长,分段讲解,文末给出完整源码。
变量与初始化
#include
#include
Servo servo01, servo02, servo03, servo04, servo05, servo06;
SoftwareSerial Bluetooth(3, 4); // Arduino RX=3, TX=4 接 HC-05 TX/RX
int servo1Pos, servo2Pos, servo3Pos, servo4Pos, servo5Pos, servo6Pos; // 当前目标
int servo1PPos, servo2PPos, servo3PPos, servo4PPos, servo5PPos, servo6PPos; // 上一位置
int servo01SP[50], servo02SP[50], servo03SP[50], servo04SP[50], servo05SP[50], servo06SP[50]; // 轨迹数组
int speedDelay = 20; int index = 0; String dataIn = "";
setup():初始化舵机与蓝牙,设定初始姿态
void setup() {
servo01.attach(5); servo02.attach(6); servo03.attach(7);
servo04.attach(8); servo05.attach(9); servo06.attach(10);
Bluetooth.begin(38400); // HC-05 默认波特率
Bluetooth.setTimeout(1); delay(20);
// 初始姿态
servo1PPos = 90; servo01.write(servo1PPos);
servo2PPos = 150; servo02.write(servo2PPos);
servo3PPos = 35; servo03.write(servo3PPos);
servo4PPos = 140; servo04.write(servo4PPos);
servo5PPos = 85; servo05.write(servo5PPos);
servo6PPos = 80; servo06.write(servo6PPos);
}
loop():蓝牙指令解析与舵机平滑移动
void loop() {
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString(); // 读取完整字符串指令
// 舵机 1 (腰) 前缀 "s1"
if (dataIn.startsWith("s1")) {
String val = dataIn.substring(2); servo1Pos = val.toInt();
// 平滑移动:for 循环逐步逼近,delay 控制速度
if (servo1PPos > servo1Pos) for (int j = servo1PPos; j >= servo1Pos; j--) { servo01.write(j); delay(20); }
if (servo1PPos < servo1Pos) for (int j = servo1PPos; j <= servo1Pos; j++) { servo01.write(j); delay(20); }
servo1PPos = servo1Pos;
}
// 舵机 2-6 同理,前缀 "s2"..."s6",延时各异 (50/30/30/30/30ms)
// ...
// 保存当前姿态到轨迹数组
if (dataIn.startsWith("SAVE")) {
servo01SP[index] = servo1PPos; servo02SP[index] = servo2PPos;
servo03SP[index] = servo3PPos; servo04SP[index] = servo4PPos;
servo05SP[index] = servo5PPos; servo06SP[index] = servo6PPos;
index++;
}
// 运行自动模式
if (dataIn.startsWith("RUN")) runservo();
// 重置轨迹
if (dataIn == "RESET") {
memset(servo01SP, 0, sizeof(servo01SP)); // 清零所有数组
memset(servo02SP, 0, sizeof(servo02SP));
memset(servo03SP, 0, sizeof(servo03SP));
memset(servo04SP, 0, sizeof(servo04SP));
memset(servo05SP, 0, sizeof(servo05SP));
memset(servo06SP, 0, sizeof(servo06SP));
index = 0;
}
}
}
自动运行函数 runservo()
void runservo() {
while (dataIn != "RESET") {
for (int i = 0; i <= index - 2; i++) {
// 实时检查蓝牙指令:暂停/继续/调速
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString();
if (dataIn == "PAUSE") {
while (dataIn != "RUN") {
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString();
if (dataIn == "RESET") break;
}
}
}
if (dataIn.startsWith("ss")) { // 速度滑块前缀 "ss"
speedDelay = dataIn.substring(2).toInt();
}
}
// 逐轴插值移动到下一步
// 舵机 1
if (servo01SP[i] > servo01SP[i+1]) for (int j = servo01SP[i]; j >= servo01SP[i+1]; j--) { servo01.write(j); delay(speedDelay); }
if (servo01SP[i] < servo01SP[i+1]) for (int j = servo01SP[i]; j <= servo01SP[i+1]; j++) { servo01.write(j); delay(speedDelay); }
// 舵机 2-6 同理...
}
}
}
完整源码
/* DIY Arduino Robot Arm Smartphone Control by Dejan, www.HowToMechatronics.com */
#include
#include
Servo servo01, servo02, servo03, servo04, servo05, servo06;
SoftwareSerial Bluetooth(3, 4);
int servo1Pos, servo2Pos, servo3Pos, servo4Pos, servo5Pos, servo6Pos;
int servo1PPos, servo2PPos, servo3PPos, servo4PPos, servo5PPos, servo6PPos;
int servo01SP[50], servo02SP[50], servo03SP[50], servo04SP[50], servo05SP[50], servo06SP[50];
int speedDelay = 20; int index = 0; String dataIn = "";
void setup() {
servo01.attach(5); servo02.attach(6); servo03.attach(7);
servo04.attach(8); servo05.attach(9); servo06.attach(10);
Bluetooth.begin(38400); Bluetooth.setTimeout(1); delay(20);
servo1PPos = 90; servo01.write(servo1PPos);
servo2PPos = 150; servo02.write(servo2PPos);
servo3PPos = 35; servo03.write(servo3PPos);
servo4PPos = 140; servo04.write(servo4PPos);
servo5PPos = 85; servo05.write(servo5PPos);
servo6PPos = 80; servo06.write(servo6PPos);
}
void loop() {
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString();
// 舵机 1
if (dataIn.startsWith("s1")) { String v = dataIn.substring(2); servo1Pos = v.toInt();
if (servo1PPos > servo1Pos) for (int j = servo1PPos; j >= servo1Pos; j--) { servo01.write(j); delay(20); }
if (servo1PPos < servo1Pos) for (int j = servo1PPos; j <= servo1Pos; j++) { servo01.write(j); delay(20); }
servo1PPos = servo1Pos; }
// 舵机 2
if (dataIn.startsWith("s2")) { String v = dataIn.substring(2); servo2Pos = v.toInt();
if (servo2PPos > servo2Pos) for (int j = servo2PPos; j >= servo2Pos; j--) { servo02.write(j); delay(50); }
if (servo2PPos < servo2Pos) for (int j = servo2PPos; j <= servo2Pos; j++) { servo02.write(j); delay(50); }
servo2PPos = servo2Pos; }
// 舵机 3
if (dataIn.startsWith("s3")) { String v = dataIn.substring(2); servo3Pos = v.toInt();
if (servo3PPos > servo3Pos) for (int j = servo3PPos; j >= servo3Pos; j--) { servo03.write(j); delay(30); }
if (servo3PPos < servo3Pos) for (int j = servo3PPos; j <= servo3Pos; j++) { servo03.write(j); delay(30); }
servo3PPos = servo3Pos; }
// 舵机 4
if (dataIn.startsWith("s4")) { String v = dataIn.substring(2); servo4Pos = v.toInt();
if (servo4PPos > servo4Pos) for (int j = servo4PPos; j >= servo4Pos; j--) { servo04.write(j); delay(30); }
if (servo4PPos < servo4Pos) for (int j = servo4PPos; j <= servo4Pos; j++) { servo04.write(j); delay(30); }
servo4PPos = servo4Pos; }
// 舵机 5
if (dataIn.startsWith("s5")) { String v = dataIn.substring(2); servo5Pos = v.toInt();
if (servo5PPos > servo5Pos) for (int j = servo5PPos; j >= servo5Pos; j--) { servo05.write(j); delay(30); }
if (servo5PPos < servo5Pos) for (int j = servo5PPos; j <= servo5Pos; j++) { servo05.write(j); delay(30); }
servo5PPos = servo5Pos; }
// 舵机 6
if (dataIn.startsWith("s6")) { String v = dataIn.substring(2); servo6Pos = v.toInt();
if (servo6PPos > servo6Pos) for (int j = servo6PPos; j >= servo6Pos; j--) { servo06.write(j); delay(30); }
if (servo6PPos < servo6Pos) for (int j = servo6PPos; j <= servo6Pos; j++) { servo06.write(j); delay(30); }
servo6PPos = servo6Pos; }
// 保存
if (dataIn.startsWith("SAVE")) {
servo01SP[index] = servo1PPos; servo02SP[index] = servo2PPos;
servo03SP[index] = servo3PPos; servo04SP[index] = servo4PPos;
servo05SP[index] = servo5PPos; servo06SP[index] = servo6PPos;
index++; }
// 运行
if (dataIn.startsWith("RUN")) runservo();
// 重置
if (dataIn == "RESET") {
memset(servo01SP, 0, sizeof(servo01SP)); memset(servo02SP, 0, sizeof(servo02SP));
memset(servo03SP, 0, sizeof(servo03SP)); memset(servo04SP, 0, sizeof(servo04SP));
memset(servo05SP, 0, sizeof(servo05SP)); memset(servo06SP, 0, sizeof(servo06SP));
index = 0; }
}
}
void runservo() {
while (dataIn != "RESET") {
for (int i = 0; i <= index - 2; i++) {
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString();
if (dataIn == "PAUSE") {
while (dataIn != "RUN") {
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString();
if (dataIn == "RESET") break;
}
}
}
if (dataIn.startsWith("ss")) { speedDelay = dataIn.substring(2).toInt(); }
}
// 6轴同步插值移动
if (servo01SP[i] > servo01SP[i+1]) for (int j = servo01SP[i]; j >= servo01SP[i+1]; j--) { servo01.write(j); delay(speedDelay); }
if (servo01SP[i] < servo01SP[i+1]) for (int j = servo01SP[i]; j <= servo01SP[i+1]; j++) { servo01.write(j); delay(speedDelay); }
if (servo02SP[i] > servo02SP[i+1]) for (int j = servo02SP[i]; j >= servo02SP[i+1]; j--) { servo02.write(j); delay(speedDelay); }
if (servo02SP[i] < servo02SP[i+1]) for (int j = servo02SP[i]; j <= servo02SP[i+1]; j++) { servo02.write(j); delay(speedDelay); }
if (servo03SP[i] > servo03SP[i+1]) for (int j = servo03SP[i]; j >= servo03SP[i+1]; j--) { servo03.write(j); delay(speedDelay); }
if (servo03SP[i] < servo03SP[i+1]) for (int j = servo03SP[i]; j <= servo03SP[i+1]; j++) { servo03.write(j); delay(speedDelay); }
if (servo04SP[i] > servo04SP[i+1]) for (int j = servo04SP[i]; j >= servo04SP[i+1]; j--) { servo04.write(j); delay(speedDelay); }
if (servo04SP[i] < servo04SP[i+1]) for (int j = servo04SP[i]; j <= servo04SP[i+1]; j++) { servo04.write(j); delay(speedDelay); }
if (servo05SP[i] > servo05SP[i+1]) for (int j = servo05SP[i]; j >= servo05SP[i+1]; j--) { servo05.write(j); delay(speedDelay); }
if (servo05SP[i] < servo05SP[i+1]) for (int j = servo05SP[i]; j <= servo05SP[i+1]; j++) { servo05.write(j); delay(speedDelay); }
if (servo06SP[i] > servo06SP[i+1]) for (int j = servo06SP[i]; j >= servo06SP[i+1]; j--) { servo06.write(j); delay(speedDelay); }
if (servo06SP[i] < servo06SP[i+1]) for (int j = servo06SP[i]; j <= servo06SP[i+1]; j++) { servo06.write(j); delay(speedDelay); }
}
}
}
Android App (MIT App Inventor)
App 界面:顶部蓝牙连接按钮,左侧机械臂示意图,右侧 6 个舵机滑块 + 速度滑块,底部 SAVE/RUN/RESET 三按钮及步数显示。
滑块拖动 → 蓝牙发送 s1角度~s6角度;按钮发送 SAVE/RUN/RESET/PAUSE;速度滑块发送 ss延时值。
下载:
Arduino Robot Arm Control MIT App Inventor Project File
1 file(s) 24.85 KB Download
Arduino Robot Arm Control Android App
1 file(s) 2.57 MB Download
现在可以尽情玩转你的机械臂了!
希望您喜欢本教程。欢迎评论区提问,别忘了查看我的 Arduino 项目合集!