亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

本教程完整记录 Arduino 机械臂 的制作全过程:3D 建模打印、电子硬件连接、Arduino 编程、自制 Android App 蓝牙控制。机械臂 5 自由度,支持手动滑块控制、轨迹记录回放、暂停/重置。

可观看视频或阅读图文教程。

功能概览

  • App 滑块实时控制 6 个舵机(腰、肩、肘、腕翻、腕俯、夹爪)
  • “保存”键记录当前姿态为步骤,“运行”循环执行,“暂停”暂停,“重置”清空轨迹
  • 速度滑块调节动作快慢

3D 模型设计

SolidWorks 设计,5 自由度。前三轴 (腰/肩/肘) 用 MG996R 大扭矩金属齿轮舵机,后两轴与夹爪用 SG90 微型舵机。

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

3D 模型在线查看/下载:Thangs(感谢 Thangs 赞助)

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

STL 文件下载

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

Arduino Robot Arm STL Files

1 file(s) 0.00 KB Download

3D 打印

使用 Creality CR-10 打印全套零件,几小时完成。CR-10 性价比高、90% 预组装、打印质量优秀。

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

组装前检查滚轮偏心螺母张紧,调平热床即可打印。参考:3D 打印机必备 15 种配件工具

机械臂组装

  1. 底座安装第 1 号舵机 (MG996R),输出轴锁圆盘舵盘
  2. 上体覆盖并锁螺丝
  3. 肩关节同理,建议加装弹簧/橡皮筋分担重力
  4. 依次组装肘、腕翻、腕俯
  5. 夹爪用 M4 螺栓螺母组装,最后装上第 6 号舵机
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

电路原理图

核心:Arduino + HC-05 蓝牙模块 + 6 路舵机信号线接数字引脚 D5–D10。舵机供电**必须外接 5V ≥2A 电源**,Arduino 与外接电源共地。

DIY 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 三按钮及步数显示。

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

滑块拖动 → 蓝牙发送 s1角度~s6角度;按钮发送 SAVE/RUN/RESET/PAUSE;速度滑块发送 ss延时值。

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程
DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

下载:

DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

Arduino Robot Arm Control MIT App Inventor Project File

1 file(s) 24.85 KB Download DIY Arduino 机械臂:智能手机蓝牙无线控制与编程

Arduino Robot Arm Control Android App

1 file(s) 2.57 MB Download

现在可以尽情玩转你的机械臂了!

希望您喜欢本教程。欢迎评论区提问,别忘了查看我的 Arduino 项目合集!

制造工艺

  1. 智能存钱罐:Arduino Nano 控制硬币识别器实现余额显示
  2. Arduino 与智能手机打造智能电压表——简单易做的 DIY 项目
  3. 基于 Arduino MKR1000 与 ThingSpeak 的远程 IoT 机械臂控制系统
  4. 舵机驱动避障机器人:基于 Arduino 与 HC-SR04 构建
  5. Arduino + HC-05 蓝牙控制 LED:MIT App Inventor 手机 App 开发全攻略
  6. Arduino Mega 驱动 Wii Nunchuk 控制 6 自由度机械臂
  7. Arduino Nano + 摇杆控制双步进电机:Visuino 图形化教程
  8. MobBob:3D 打印智能机器人,Android 手机无缝控制,语音视觉一体
  9. LittleArm 2C:3D 打印 Arduino 机械臂 - STEM 教学专用,坚固易装
  10. ThimbleKrox:基于 Arduino Micro 与 MPU-6050 的指戴式鼠标控制器
  11. DIY 手势控制机械臂:基于 Arduino + 柔性传感器 + IMU + 蓝牙的六自由度仿生臂
  12. Yama Seiki GA-2000CR:配备机械臂与托盘系统的紧凑型车削中心