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

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

部品と材料

部品 数量 備考
Arduino UNO 1 メイン制御ボード
SparkFun デュアルHブリッジ L298 1 DCモーター駆動用
DIYロボット戦車キット 1 DCモーター×2、ギア、キャタピラ、ネジ等含む
Sony PS2ワイヤレスコントローラー 1 受信機付き
18650 3.7Vバッテリー 3 直列接続で11.1V(12Vモーター駆動用)
3S 18650バッテリーホルダー 1 戦車後部に取付
18650バッテリー充電器 1
ジャンパーワイヤー 1セット オス-メス×6、オス-オス×2 等
Type-B USBケーブル 1 書き込み用

必要な工具

アプリとオンラインサービス

プロジェクト概要

このチュートリアルでは、ワイヤレスPlayStation 2(PS2)ジョイスティックでロボット戦車を操作する方法を解説します。Arduino Unoを核として、ワイヤレスコントローラーからのコマンドを受信し、モーターの回転数を制御します。NodeMCUやFirebeetleなど他の開発ボードでも応用可能で、ここで紹介する原理は他のロボットやガジェットにも転用できます。

筆者はこれまでに、Blynk経由でWi-Fi制御する戦車(こちら)、Googleアシスタントで音声制御するロボット(こちら)、自作シャーシのFPVロボット(こちら)も制作しています。

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

ステップ1: 工具と材料の準備

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

主要パーツの詳細:

※アルミシャーシは導電性があるため、基板との間にEVAフォームを挟んでショート防止しています。

ステップ2: ロボットの組み立て

キットの組み立てマニュアルは中国語のスプレッドシートのみで不親切ですが、パーツ品質は良好でスペア部品も同梱されています。組み立て過程は動画で記録しています。

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

ステップ3: 配線

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

バッテリーパック(3直列)を後部に搭載。L298N Hブリッジでモーターを制御します。Arduinoの5V信号を受け取り、モーターに高電圧を供給し、入力信号の組み合わせで正逆転を切り替えます。

ピン接続一覧

Arduinoピン 接続先
Digital 3Hブリッジ ENA
Digital 5Hブリッジ IN1
Digital 4Hブリッジ IN2
Digital 8Hブリッジ IN3
Digital 7Hブリッジ IN4
Digital 6Hブリッジ ENB
5VHブリッジ 5V
GNDHブリッジ GND
Digital 10PS2受信機 pin 6 (Attention)
Digital 11PS2受信機 pin 2 (Command)
Digital 12PS2受信機 pin 1 (Data)
Digital 13PS2受信機 pin 7 (Clock)
3.3VPS2受信機 pin 5 (Power)
GNDPS2受信機 pin 4 (Ground)

Hブリッジ側の接続:

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

ステップ4: Arduino IDEのセットアップ

  1. Arduino IDE最新版を 公式サイト からダウンロード・インストール
  2. PS2Xライブラリを導入
    GitHub からダウンロードし、解凍後、Arduinoのlibrariesフォルダに配置

ステップ5: PS2ワイヤレスコントローラーライブラリの解説

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

Bill Porter氏のPS2Xライブラリを使用します。主な機能:

ボタン定数

アナログスティック軸

ステップ6: スケッチ #1 - 方向キー制御(レトロゲーム風)

十字キーで基本動作(前進・後退・左旋回・右旋回)を制御。ボタンはオン/オフのみなので、モーターは全速で動作します。

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

コードのポイント

ステップ7: スケッチ #2 - 左アナログスティック + L2/R2ボタン(レーシングゲーム風)

左スティックX軸でステアリング、R2で前進、L2で後退。マリオカート型の操作感覚です。

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

実装のポイント

ステップ8: スケッチ #3 - 左右両アナログスティック(差動駆動・実戦車風)

左スティックで左キャタピラ、右スティックで右キャタピラを独立制御。実戦車の操作感に近く、筆者お気に入りの方式です。

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

実装のポイント

ステップ9: スケッチ #4 - 左アナログスティックのみ(ミキシング制御)

1本のスティックで前進/後進と旋回を同時制御。ボタンを節約できるが操作は難しい。差動ステアリングの数学モデルに基づく実装で、こちらの解説を参考にしています。

PS2ワイヤレスジョイスティックで操作するArduinoロボット戦車

ステップ10: まとめ

4種類の制御方式を実装しました。用途や好みに合わせて選択・改良してください。ご質問はコメント欄へどうぞ。他のロボットプロジェクトも公開していますので、興味があればご覧ください。

ソースコード(4種類のスケッチ)

スケッチ #1: 方向キー制御

// PS2 Tank by Igor Fonseca @2019
// D-pad buttonsで戦車を制御
#include <PS2X_lib.h>
#define ENA 3
#define MOTORA_1 4
#define MOTORA_2 5
#define MOTORB_1 8
#define MOTORB_2 7
#define ENB 6
PS2X ps2x;
int error = 0;
byte type = 0;
byte vibrate = 0;

void setup() {
  pinMode(ENA, OUTPUT); pinMode(MOTORA_1, OUTPUT); pinMode(MOTORA_2, OUTPUT);
  pinMode(ENB, OUTPUT); pinMode(MOTORB_1, OUTPUT); pinMode(MOTORB_2, OUTPUT);
  digitalWrite(ENA, 0); digitalWrite(ENB, 0);
  Serial.begin(57600);
  error = ps2x.config_gamepad(13, 11, 10, 12, true, true);
  if (error == 0) Serial.println("Found Controller, configured successful");
  else if (error == 1) Serial.println("No controller found, check wiring or reset the Arduino");
  else if (error == 2) Serial.println("Controller found but not accepting commands");
  else if (error == 3) Serial.println("Controller refusing to enter Pressures mode, may not support it.");
  type = ps2x.readType();
  if (type == 1) Serial.println("DualShock Controller Found");
  else if (type == 2) Serial.println("GuitarHero Controller Found");
  else Serial.println("Unknown Controller type");
}

void loop() {
  if (error == 1) return;
  ps2x.read_gamepad(false, vibrate);
  if (ps2x.Button(PSB_PAD_UP)) {
    digitalWrite(MOTORA_1, LOW); digitalWrite(MOTORA_2, HIGH);
    digitalWrite(MOTORB_1, HIGH); digitalWrite(MOTORB_2, LOW);
    analogWrite(ENB, 1023); analogWrite(ENA, 1023);
  } else if (ps2x.Button(PSB_PAD_RIGHT)) {
    digitalWrite(MOTORA_1, HIGH); digitalWrite(MOTORA_2, LOW);
    digitalWrite(MOTORB_1, HIGH); digitalWrite(MOTORB_2, LOW);
    analogWrite(ENB, 1023); analogWrite(ENA, 1023);
  } else if (ps2x.Button(PSB_PAD_LEFT)) {
    digitalWrite(MOTORA_1, LOW); digitalWrite(MOTORA_2, HIGH);
    digitalWrite(MOTORB_1, LOW); digitalWrite(MOTORB_2, HIGH);
    analogWrite(ENB, 1023); analogWrite(ENA, 1023);
  } else if (ps2x.Button(PSB_PAD_DOWN)) {
    digitalWrite(MOTORA_1, HIGH); digitalWrite(MOTORA_2, LOW);
    digitalWrite(MOTORB_1, LOW); digitalWrite(MOTORB_2, HIGH);
    analogWrite(ENB, 1023); analogWrite(ENA, 1023);
  } else {
    analogWrite(ENB, 0); analogWrite(ENA, 0);
  }
  delay(50);
}

スケッチ #2: 左スティック + L2/R2

// ...(共通部分省略)...
int motor_right_speed = 0, motor_left_speed = 0;

void loop() {
  if (error == 1) return;
  ps2x.read_gamepad(false, vibrate);
  int nJoyL = ps2x.Analog(PSS_LX);
  nJoyL = map(nJoyL, 0, 255, 1023, -1023);
  motor_right_speed = 1023; motor_left_speed = 1023;
  if (nJoyL < 0) motor_right_speed += nJoyL;
  if (nJoyL > 0) motor_left_speed -= nJoyL;
  if (ps2x.Button(PSB_R2)) {
    digitalWrite(MOTORA_1, LOW); digitalWrite(MOTORA_2, HIGH);
    digitalWrite(MOTORB_1, HIGH); digitalWrite(MOTORB_2, LOW);
    analogWrite(ENA, motor_right_speed); analogWrite(ENB, motor_left_speed);
  } else if (ps2x.Button(PSB_L2)) {
    digitalWrite(MOTORA_1, HIGH); digitalWrite(MOTORA_2, LOW);
    digitalWrite(MOTORB_1, LOW); digitalWrite(MOTORB_2, HIGH);
    analogWrite(ENA, motor_right_speed); analogWrite(ENB, motor_left_speed);
  } else {
    analogWrite(ENA, 0); analogWrite(ENB, 0);
  }
  delay(50);
}

スケッチ #3: 左右両スティック(差動駆動)

void loop() {
  if (error == 1) return;
  ps2x.read_gamepad(false, vibrate);
  int nJoyL = ps2x.Analog(PSS_LY);
  int nJoyR = ps2x.Analog(PSS_RY);
  nJoyL = map(nJoyL, 0, 255, 1023, -1023);
  nJoyR = map(nJoyR, 0, 255, -1023, 1023);
  // 右モーター (ENA)
  if (nJoyR > 50) { digitalWrite(MOTORA_1, HIGH); digitalWrite(MOTORA_2, LOW); analogWrite(ENA, 1023); }
  else if (nJoyR < -50) { digitalWrite(MOTORA_1, LOW); digitalWrite(MOTORA_2, HIGH); analogWrite(ENA, 1023); }
  else analogWrite(ENA, 0);
  // 左モーター (ENB)
  if (nJoyL > 50) { digitalWrite(MOTORB_1, HIGH); digitalWrite(MOTORB_2, LOW); analogWrite(ENB, 1023); }
  else if (nJoyL < -50) { digitalWrite(MOTORB_1, LOW); digitalWrite(MOTORB_2, HIGH); analogWrite(ENB, 1023); }
  else analogWrite(ENB, 0);
  delay(50);
}

スケッチ #4: 左スティックのみ(ミキシング)

void loop() {
  if (error == 1) return;
  ps2x.read_gamepad(false, vibrate);
  int nJoyX = ps2x.Analog(PSS_LX);
  int nJoyY = ps2x.Analog(PSS_LY);
  nJoyX = map(nJoyX, 0, 255, -1023, 1023);
  nJoyY = map(nJoyY, 0, 255, 1023, -1023);
  // 差動ステアリング計算(ImpulseAdventure方式)
  float fPivYLimit = 1023.0;
  float nMotPremixL, nMotPremixR;
  if (nJoyY >= 0) {
    nMotPremixL = (nJoyX >= 0) ? 1023.0 : (1023.0 + nJoyX);
    nMotPremixR = (nJoyX >= 0) ? (1023.0 - nJoyX) : 1023.0;
  } else {
    nMotPremixL = (nJoyX >= 0) ? (1023.0 - nJoyX) : 1023.0;
    nMotPremixR = (nJoyX >= 0) ? 1023.0 : (1023.0 + nJoyX);
  }
  nMotPremixL *= nJoyY / 1023.0;
  nMotPremixR *= nJoyY / 1023.0;
  int nPivSpeed = nJoyX;
  float fPivScale = (abs(nJoyY) > fPivYLimit) ? 0.0 : (1.0 - abs(nJoyY) / fPivYLimit);
  int nMotMixL = (1.0 - fPivScale) * nMotPremixL + fPivScale * nPivSpeed;
  int nMotMixR = (1.0 - fPivScale) * nMotPremixR + fPivScale * (-nPivSpeed);
  // モーター出力(デッドバンド ±50)
  if (nMotMixR > 50) { digitalWrite(MOTORB_1, HIGH); digitalWrite(MOTORB_2, LOW); }
  else if (nMotMixR < -50) { digitalWrite(MOTORB_1, LOW); digitalWrite(MOTORB_2, HIGH); }
  else { digitalWrite(MOTORB_1, LOW); digitalWrite(MOTORB_2, LOW); }
  if (nMotMixL > 50) { digitalWrite(MOTORA_1, LOW); digitalWrite(MOTORA_2, HIGH); }
  else if (nMotMixL < -50) { digitalWrite(MOTORA_1, HIGH); digitalWrite(MOTORA_2, LOW); }
  else { digitalWrite(MOTORA_1, LOW); digitalWrite(MOTORA_2, LOW); }
  analogWrite(ENA, abs(nMotMixL));
  analogWrite(ENB, abs(nMotMixR));
  delay(50);
}

回路図

プロジェクトページのSchematicsセクションに配線図が掲載されています。

製造プロセス

  1. Arduino & Raspberry Pi でインターネット制御ビデオストリーミングロボットを構築
  2. Unopad: Ableton Live連携シームレスなArduino MIDIコントローラー
  3. ArduinoとHC-SR04で作るサーボ駆動障害物回避ロボット
  4. ArduinoとAndroidでRoomba Create 2をリモコン操作 ─ Bluetooth経由のステップバイステップガイド
  5. Arduinoベースのヌンチャク操作6自由度ロボットアームキット
  6. Arduino Nanoとジョイスティックで2軸ステッピングモーターを制御:Visuinoで簡単プログラミング
  7. ゲーム用カスタムArduinoジョイスティックハンドルの製作
  8. PS2コントローラーで操作するリモコンバトルボットの作り方
  9. Arduinoロボットアーム「LittleArm」をAndroidアプリでBluetooth制御
  10. Arduino Nanoで作る「食べさせロボット」:超音波センサーで食べ物検知し口を開閉
  11. 4輪ArduinoロボットをDabbleアプリでBluetooth制御しよう