工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

MeArmロボット用精密ジョイスティックコントローラー - 座標の記録・再生機能付き

必要な部品と材料

部品 数量
Arduino UNO 1
アナログジョイスティック(汎用) 2
抵抗 10kΩ 2
抵抗 680Ω 1
5mm赤色LED 1
マイクロサーボ SG90 4

使用するアプリとオンラインサービス

プロジェクト概要

Arduino UnoベースのMeArm®ロボットアーム用ジョイスティックコントローラーで、座標の記録・再生機能を搭載しています。追加基板なしでArduino Uno単体で動作します。USB接続(2A)または6V/2A電源が必要です。SG90サーボ4個で動作確認済みです。

操作方法

メモ: 追加の抵抗とLEDを不要としたシンプル版「MeArm Robot - Recording of Coordinates (Minimalized Version)」も公開しています。MeArmジョイスティックボードをお持ちの場合は、「MeArm 1.6.1 Robot Joystick Board Recording Movements (IR)」版をご利用ください。

コード

Arduinoジョイスティックコントローラー for MeArm® ロボット(バージョン 1.3.1)

Arduino IDEでArduino UNOベースボードをUSBポート経由でプログラミングしてください。

/* meArm analog joysticks version 1.3.1 - UtilStudio.com Dec 2018
 * 2つのアナログジョイスティックと4つのサーボを使用
 * v1.3で座標記録機能を改善、いくつかのバグを修正
 * 
 * ジョイスティック1: グリッパーの前後左右移動、ボタンで記録開始/停止
 * ジョイスティック2: グリッパーの上下移動と開閉、ボタンで再生開始/停止
 * ボタン2秒長押しで自動再生
 * 
 * ピン配置:
 * Arduino    Stick1    Stick2    Base    Shoulder  Elbow   Gripper  Record/
 * GND        GND       GND       Brn     Brn       Brn     Brn      Auto play
 * 5V         VCC       VCC       Red     Red       Red     Red
 * A0         HOR       -         -       -         -       -
 * A1         VER       -         -       -         -       -
 * PD2        BUTT      -         -       -         -       -
 * A2         -         HOR       -       -         -       -
 * A3         -         VER       -       -         -       -
 * PD3        -         BUTT      -       -         -       -
 * 11         -         -         Yellow  -         -       -
 * 10         -         -         -       Yellow    -       -
 * 9          -         -         -       -         Yellow  -
 * 6          -         -         -       -         -       Yellow
 * PD4        -         -         -       -         -       -       X (LED)
 */
#include <Servo.h>

bool repeatePlaying = false;  // 記録サイクルを繰り返し再生
int delayBetweenCycles = 2000; // サイクル間ディレイ

int basePin = 11;       // ベースサーボ
int shoulderPin = 10;   // ショルダーサーボ
int elbowPin = 9;       // エルボーサーボ
int gripperPin = 6;     // グリッパーサーボ

int xdirPin = 0;        // ベース - ジョイスティック1
int ydirPin = 1;        // ショルダー - ジョイスティック1
int zdirPin = 3;        // エルボー - ジョイスティック2
int gdirPin = 2;        // グリッパー - ジョイスティック2

int pinRecord = PD2;    // 記録ボタン - 推奨(A4は非推奨、追加ジョイスティック用に予約)
int pinPlay = PD3;      // 再生ボタン - 推奨(A5は非推奨、追加ジョイスティック用に予約)
int pinLedRecord = PD4; // LED - 記録中点灯、自動再生モードで点滅

bool useInternalPullUpResistors = false;
const int buffSize = 512; // 録音バッファサイズ

// サーボ初期位置
int startBase = 90, startShoulder = 90, startElbow = 90, startGripper = 0;
int posBase = 90, posShoulder = 90, posElbow = 90, posGripper = 0;
int lastBase = 90, lastShoulder = 90, lastElbow = 90, lastGripper = 90;

// サーボ可動範囲
int minBase = 0, maxBase = 150;
int minShoulder = 0, maxShoulder = 150;
int minElbow = 0, maxElbow = 150;
int minGripper = 0, maxGripper = 150;

const int countServo = 4;
int buff[buffSize];
int buffAdd[countServo];
int recPos = 0, playPos = 0;
int buttonRecord = HIGH, buttonPlay = HIGH;
int buttonRecordLast = LOW, buttonPlayLast = LOW;
bool record = false, play = false, debug = false;
String command = "Manual";
int printPos = 0;
int buttonPlayDelay = 20, buttonPlayCount = 0;
bool ledLight = false;

Servo servoBase, servoShoulder, servoElbow, servoGripper;

void setup() {
  Serial.begin(9600);
  if (useInternalPullUpResistors) {
    pinMode(pinRecord, INPUT_PULLUP);
    pinMode(pinPlay, INPUT_PULLUP);
  } else {
    pinMode(pinRecord, INPUT);
    pinMode(pinPlay, INPUT);
  }
  pinMode(xdirPin, INPUT);
  pinMode(ydirPin, INPUT);
  pinMode(zdirPin, INPUT);
  pinMode(gdirPin, INPUT);
  pinMode(pinLedRecord, OUTPUT);

  servoBase.attach(basePin);
  servoShoulder.attach(shoulderPin);
  servoElbow.attach(elbowPin);
  servoGripper.attach(gripperPin);

  StartPosition();
  digitalWrite(pinLedRecord, HIGH);
  delay(1000);
  digitalWrite(pinLedRecord, LOW);
}

void loop() {
  buttonRecord = digitalRead(pinRecord);
  buttonPlay = digitalRead(pinPlay);

  // 再生ボタン長押し検出(自動ループ再生)
  if (buttonPlay == LOW) {
    buttonPlayCount++;
    if (buttonPlayCount >= buttonPlayDelay) repeatePlaying = true;
  } else buttonPlayCount = 0;

  // 再生ボタン状態変化
  if (buttonPlay != buttonPlayLast) {
    if (record) record = false;
    if (buttonPlay == LOW) {
      play = !play;
      repeatePlaying = false;
      if (play) StartPosition();
    }
  }

  // 記録ボタン状態変化
  if (buttonRecord != buttonRecordLast) {
    if (buttonRecord == LOW) {
      record = !record;
      if (record) {
        play = false; repeatePlaying = false; recPos = 0;
      } else if (debug) PrintBuffer();
    }
  }
  buttonPlayLast = buttonPlay;
  buttonRecordLast = buttonRecord;

  // ジョイスティック入力読み取り(-5.0〜5.0にマッピング、デッドゾーン±1.5)
  float dx = map(analogRead(xdirPin), 0, 1023, -5.0, 5.0);
  float dy = map(analogRead(ydirPin), 0, 1023, 5.0, -5.0);
  float dz = map(analogRead(zdirPin), 0, 1023, 5.0, -5.0);
  float dg = map(analogRead(gdirPin), 0, 1023, 5.0, -5.0);

  if (abs(dx) < 1.5) dx = 0;
  if (abs(dy) < 1.5) dy = 0;
  if (abs(dz) < 1.5) dz = 0;
  if (abs(dg) < 1.5) dg = 0;

  posBase += dx;
  posShoulder += dy;
  posElbow += dz;
  posGripper += dg;

  // 再生モード処理
  if (play) {
    if (playPos >= recPos) {
      playPos = 0;
      if (repeatePlaying) {
        delay(delayBetweenCycles);
        StartPosition();
      } else play = false;
    }
    bool endOfData = false;
    while (!endOfData) {
      if (playPos >= buffSize - 1) break;
      if (playPos >= recPos) break;
      int data = buff[playPos];
      int angle = data & 0xFFF;
      int servoNumber = data & 0x3000;
      endOfData = data & 0x4000;
      switch (servoNumber) {
        case 0x0000: posBase = angle; break;
        case 0x1000: posShoulder = angle; break;
        case 0x2000: posElbow = angle; break;
        case 0x3000: posGripper = angle; dg = posGripper - lastGripper; break;
      }
      playPos++;
    }
  }

  // 可動範囲制限
  posBase = constrain(posBase, minBase, maxBase);
  posShoulder = constrain(posShoulder, minShoulder, maxShoulder);
  posElbow = constrain(posElbow, minElbow, maxElbow);
  posGripper = constrain(posGripper, minGripper, maxGripper);

  servoBase.write(posBase);
  servoShoulder.write(posShoulder);
  servoElbow.write(posElbow);

  bool waitGripper = false;
  if (dg < 0) { posGripper = minGripper; waitGripper = true; }
  else if (dg > 0) { posGripper = maxGripper; waitGripper = true; }
  servoGripper.write(posGripper);

  if (play && waitGripper) delay(1000);

  // 位置変化時の記録処理とシリアル出力
  if (lastBase != posBase || lastShoulder != posShoulder || 
      lastElbow != posElbow || lastGripper != posGripper) {
    if (record && recPos < buffSize - countServo) {
      int buffPos = 0;
      if (lastBase != posBase) { buffAdd[buffPos] = posBase; buffPos++; }
      if (lastShoulder != posShoulder) { buffAdd[buffPos] = posShoulder | 0x1000; buffPos++; }
      if (lastElbow != posElbow) { buffAdd[buffPos] = posElbow | 0x2000; buffPos++; }
      if (lastGripper != posGripper) { buffAdd[buffPos] = posGripper | 0x3000; buffPos++; }
      buffAdd[buffPos - 1] |= 0x4000; // 終端フラグ
      for (int i = 0; i < buffPos; i++) buff[recPos + i] = buffAdd[i];
      recPos += buffPos;
    }
    command = "Manual"; printPos = 0;
    if (play) { command = "Play"; printPos = playPos; }
    else if (record) { command = "Record"; printPos = recPos; }
    Serial.print(command); Serial.print("\t");
    Serial.print(printPos); Serial.print("\t");
    Serial.print(posBase); Serial.print("\t");
    Serial.print(posShoulder); Serial.print("\t");
    Serial.print(posElbow); Serial.print("\t");
    Serial.print(posGripper); Serial.print("\t");
    Serial.print(record); Serial.print("\t");
    Serial.println(play);
  }

  lastBase = posBase; lastShoulder = posShoulder;
  lastElbow = posElbow; lastGripper = posGripper;

  // LED制御:自動再生中は点滅、記録中は点灯
  if (repeatePlaying) ledLight = !ledLight;
  else { if (ledLight) ledLight = false; if (record) ledLight = true; }
  digitalWrite(pinLedRecord, ledLight);

  delay(50);
}

void PrintBuffer() {
  for (int i = 0; i < recPos; i++) {
    int data = buff[i];
    int angle = data & 0xFFF;
    int servoNumber = data & 0x3000;
    bool endOfData = data & 0x4000;
    Serial.print("Servo="); Serial.print(servoNumber);
    Serial.print("\tAngle="); Serial.print(angle);
    Serial.print("\tEnd="); Serial.print(endOfData);
    Serial.print("\tData="); Serial.println(data, BIN);
  }
}

void StartPosition() {
  int angleBase = servoBase.read();
  int angleShoulder = servoShoulder.read();
  int angleElbow = servoElbow.read();
  int angleGripper = servoGripper.read();
  Serial.print(angleBase); Serial.print("\t");
  Serial.print(angleShoulder); Serial.print("\t");
  Serial.print(angleElbow); Serial.print("\t");
  Serial.println(angleGripper);

  posBase = startBase; posShoulder = startShoulder;
  posElbow = startElbow; posGripper = startGripper;
  servoBase.write(posBase);
  servoShoulder.write(posShoulder);
  servoElbow.write(posElbow);
  servoGripper.write(posGripper);
}

製造プロセス

  1. DIY Arduino USBゲームコントローラー - 高性能ゲームパッドを自作
  2. MeArmロボットアーム V1.0 – Arduino/Raspberry Piで作るロボットアーム
  3. 古いラジコンカーをXboxコントローラーで操作可能に - ArduinoとUSBホストシールドで実現
  4. Arduino UNOで作る完全自律ライントラッカーロボット ─ 入門に最適な自作キット
  5. Arduino UNOで作るシンプル電卓 - シリアルモニターで四則演算
  6. Arduino Nanoで音声制御ロボットを自作
  7. Arduino UNOとATtiny85で作る携帯型POV(残像)ディスプレイ
  8. ゲーム用カスタムArduinoジョイスティックハンドルの製作
  9. ESP32-CAMで作るAI顔認識ドアロックシステム:ローカル処理でプライバシー保護
  10. ArduinoとBluetoothでスマートフォン温度監視システムを構築
  11. Arduino向けスマート屋内ナビゲーションロボットキット