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

DIY 智能 Arduino 机械臂:主从控制与动作记忆教程

组件与物料

组件 说明 数量
Arduino UNO 主控板 1
微型舵机 5 个,构成 5 自由度 5
电位器 5 个,对应主控臂关节 5
面包板 原型搭建 1

项目简介

本教程制作一款简单机械臂,通过“主控臂”(电位器模拟关节)控制“从动臂”(舵机驱动),支持动作记录与回放。灵感源自 Stoerpeak 的“迷你机械臂”,多年前想做却因编程基础薄弱搁置,如今重拾并简化分享。

步骤 1:材料清单

步骤 2:机械臂制作

DIY 智能 Arduino 机械臂:主从控制与动作记忆教程
DIY 智能 Arduino 机械臂:主从控制与动作记忆教程

示例用冰棒棒搭建,材料不限。双面胶粘贴舵机再用螺丝加固。主控臂将电位器粘在冰棒棒上模拟关节。所有部件安装在 A4 画板底座上。参考图片可更直观理解。

步骤 3:电路连接

DIY 智能 Arduino 机械臂:主从控制与动作记忆教程
DIY 智能 Arduino 机械臂:主从控制与动作记忆教程
DIY 智能 Arduino 机械臂:主从控制与动作记忆教程

引脚映射:

关键提示: 舵机不由 Arduino 供电时,必须将舵机 GND 与 Arduino GND 共地,否则无法工作。

步骤 4:编程逻辑

DIY 智能 Arduino 机械臂:主从控制与动作记忆教程

核心逻辑:读取电位器值存入数组,回放时遍历数组驱动舵机复现动作。参考教程“Arduino Potentiometer Servo Control & Memory”。

全局变量声明

#include <Servo.h>
// 舵机对象
Servo Servo_0, Servo_1, Servo_2, Servo_3, Servo_4;
// 电位器读值
int Pot_0, Pot_1, Pot_2, Pot_3, Pot_4;
// 舵机当前位置
int Servo_0_Pos, Servo_1_Pos, Servo_2_Pos, Servo_3_Pos, Servo_4_Pos;
// 上一次位置
int Prev_0_Pos, Prev_1_Pos, Prev_2_Pos, Prev_3_Pos, Prev_4_Pos;
// 当前位置(用于比较)
int Current_0_Pos, Current_1_Pos, Current_2_Pos, Current_3_Pos, Current_4_Pos;
int Servo_Position; // 存储角度
int Servo_Number;   // 存储舵机编号
int Storage[600];   // 动作记录数组(增大消耗更多内存)
int Index = 0;      // 数组索引
char data = 0;      // 串口指令

setup() 初始化

void setup() {
  Serial.begin(9600);
  Servo_0.attach(3); Servo_1.attach(5); Servo_2.attach(6);
  Servo_3.attach(9); Servo_4.attach(10);
  // 初始化位置 100°(避免 0/180 极限抖动)
  Servo_0.write(100); Servo_1.write(100); Servo_2.write(100);
  Servo_3.write(100); Servo_4.write(100);
  Serial.println("Press 'R' to Record and 'P' to play");
}

电位器映射函数 Map_Pot()

void Map_Pot() {
  // 舵机限位 1-179°,避免极限抖动
  Pot_0 = analogRead(A0);
  Servo_0_Pos = map(Pot_0, 0, 1023, 1, 179);
  Servo_0.write(Servo_0_Pos);
  
  Pot_1 = analogRead(A1);
  Servo_1_Pos = map(Pot_1, 0, 1023, 1, 179);
  Servo_1.write(Servo_1_Pos);
  
  Pot_2 = analogRead(A2);
  Servo_2_Pos = map(Pot_2, 0, 1023, 1, 179);
  Servo_2.write(Servo_2_Pos);
  
  Pot_3 = analogRead(A3);
  Servo_3_Pos = map(Pot_3, 0, 1023, 1, 179);
  Servo_3.write(Servo_3_Pos);
  
  Pot_4 = analogRead(A4);
  Servo_4_Pos = map(Pot_4, 0, 1023, 1, 179);
  Servo_4.write(Servo_4_Pos);
}

主循环 loop()

void loop() {
  Map_Pot(); // 实时跟随主控臂
  
  // 串口指令处理
  while (Serial.available() > 0) {
    data = Serial.read();
    if (data == 'R') Serial.println("Recording Moves...");
    if (data == 'P') Serial.println("Playing Recorded Moves...");
  }
  
  // 录制模式
  if (data == 'R') {
    // 保存当前位置为上一帧
    Prev_0_Pos = Servo_0_Pos; Prev_1_Pos = Servo_1_Pos;
    Prev_2_Pos = Servo_2_Pos; Prev_3_Pos = Servo_3_Pos;
    Prev_4_Pos = Servo_4_Pos;
    
    Map_Pot(); // 重新读取对比
    
    // 对比各舵机位置变化,记录差异帧
    if (abs(Prev_0_Pos - Servo_0_Pos) > 0) { // 修正:原代码逻辑有误,应比较差值
      if (Current_0_Pos != Servo_0_Pos) {
        Storage[Index] = Servo_0_Pos + 0; // 舵机 0 标识偏移 0
        Index++;
      }
      Current_0_Pos = Servo_0_Pos;
    }
    // 舵机 1-4 同理,偏移量分别 +100, +200, +300, +400
    if (abs(Prev_1_Pos - Servo_1_Pos) > 0) {
      if (Current_1_Pos != Servo_1_Pos) {
        Storage[Index] = Servo_1_Pos + 100; Index++;
      }
      Current_1_Pos = Servo_1_Pos;
    }
    if (abs(Prev_2_Pos - Servo_2_Pos) > 0) {
      if (Current_2_Pos != Servo_2_Pos) {
        Storage[Index] = Servo_2_Pos + 200; Index++;
      }
      Current_2_Pos = Servo_2_Pos;
    }
    if (abs(Prev_3_Pos - Servo_3_Pos) > 0) {
      if (Current_3_Pos != Servo_3_Pos) {
        Storage[Index] = Servo_3_Pos + 300; Index++;
      }
      Current_3_Pos = Servo_3_Pos;
    }
    if (abs(Prev_4_Pos - Servo_4_Pos) > 0) {
      if (Current_4_Pos != Servo_4_Pos) {
        Storage[Index] = Servo_4_Pos + 400; Index++;
      }
      Current_4_Pos = Servo_4_Pos;
    }
    
    // 串口打印调试信息
    Serial.print(Servo_0_Pos); Serial.print(" \t ");
    Serial.print(Servo_1_Pos); Serial.print(" \t ");
    Serial.print(Servo_2_Pos); Serial.print(" \t ");
    Serial.print(Servo_3_Pos); Serial.print(" \t ");
    Serial.println(Servo_4_Pos);
    Serial.print("Index = "); Serial.println(Index);
    delay(50);
  }
  
  // 回放模式
  if (data == 'P') {
    for (int i = 0; i < Index; i++) {
      Servo_Number = Storage[i] / 100;      // 解码舵机编号
      Servo_Position = Storage[i] % 100;    // 解码角度
      switch (Servo_Number) {
        case 0: Servo_0.write(Servo_Position); break;
        case 1: Servo_1.write(Servo_Position); break;
        case 2: Servo_2.write(Servo_Position); break;
        case 3: Servo_3.write(Servo_Position); break;
        case 4: Servo_4.write(Servo_Position); break;
      }
      delay(50);
    }
  }
}

代码文件下载: Record-Play.ino

步骤 5:测试验证

上传代码后打开“串口监视器”(工具菜单),Arduino 复位。此时主控臂可实时驱动从动臂,但未录制。

动作流畅度尚不及 Stoerpeak 原版,欢迎大神优化代码或提出建议。

代码文件

原理图

DIY 智能 Arduino 机械臂:主从控制与动作记忆教程

制造工艺

  1. 基于 Arduino 与 Python 的可靠 RFID 考勤系统
  2. 基于 Arduino、1Sheeld 与红外控制的万能安卓遥控器
  3. Arduino 与智能手机打造智能电压表——简单易做的 DIY 项目
  4. 基于 Arduino MKR1000 与 ThingSpeak 的远程 IoT 机械臂控制系统
  5. 智能物联网罐:ESP8266 + Arduino + 超声波传感器实时监测罐内物位
  6. 基于Arduino UNO的精准频率与占空比测量
  7. 打造功能完整的 Arduino 驱动 3D 打印机械臂:分步指南
  8. 智能自系鞋带鞋:内置压电发电与计步功能
  9. Arduino Mega 驱动 Wii Nunchuk 控制 6 自由度机械臂
  10. Arduino 声纳实时测距与 Processing 可视化
  11. Bolt IoT + Arduino UNO 实现 6 路 LED 无级调光
  12. 基于 Arduino 与 ESP8266 的 WiFi 智能门锁:手机扫码解锁