1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PS4コントローラとESP32を使用したラジコンの試作

Last updated at Posted at 2025-12-10

はじめに

ラジコンカーの試作を行いました。車体にはタミヤ バギー工作基本セット、マイコンにはESP32 D1R32、送信機にはPS4コントローラ、舵取り用サーボモータにはSG90、駆動用DCモータには130モータ、モータドライバにはTC78H653FTGを使いました。なお、マイコンにESP32-WROOM-32E開発ボードを使用しても、以下の回路・プログラムで動作すると思います。

使用したもの

  • PS4コントローラ
    ハードオフ店などで安価で入手可能と思います。私は息子が使い古したものをもらいました。

  • タミヤ バギー工作基本セット
    駆動用のモータ(FA-130RA-2270相当品と思われます)も付属しています。

  • マイコン Wemos ESP32 D1R32

  • モータドライバ TC78H653FTG
    130モータ(FA-130RA-2270の相当品?)の駆動のため、安価なTC78H653FTGを使用しましたが、ラジコンに実装したところ、過電流による保護回路が働き、時々停止しました。これを避けるには余裕のあるDRV8835等を使用するのがよいかもしれません。

  • サーボモータ SG90
    180°回転するサーボモータです。

  • 2.1mmDCプラグ付バッテリースナップ(9V電池用)

  • SUS304ワイヤ ∮0.9mm

  • プラ棒5mm

  • その他
    9V電池1個、単3電池2本、ジャンパ線、ジャンパワイヤ、ブレッドボード(小)、はんだ、はんだペースト、小ねじ(ナット付、M2✕10、2本)、プラスチックカッタ(タミヤ)、ピンバイスと∮2ドリル(タミヤ)等

手順

  • マイコンのMacアドレスの取得
    以下の記事などを参考にして取得します。

  • PS4コントローラへのMacアドレスの書き込み
    SixaxisPairTool(windows版のみしかありません!)を使用しました。

  • PS4コントローラとマイコン間の通信確認
    以下のプログラムなどで確認します。実行には、PS4Controllerのライブラリのインストールが必要です。

#include <PS4Controller.h>

// ここにPS4 コントローラに書き込んだ ESP32 の MAC Adressを入れる
const char* esp32Mac = "**:**:**:**:**:**";  // 例:12:34:56:78:9A:BC

// PS4 接続時コールバック
void onConnect() {
  Serial.println("[PS4] コントローラ接続");
}

// PS4 切断時コールバック
void onDisconnect() {
  Serial.println("[PS4] コントローラ切断");
}

// ボタン・スティック入力イベントコールバック
void onEvent() {
  // 左スティック例
  int lx = PS4.LStickX();
  int ly = PS4.LStickY();

  // R2 / L2 トリガー
  uint8_t l2 = PS4.L2Value();
  uint8_t r2 = PS4.R2Value();

  // ×ボタン
  if (PS4.event.button_down.cross) {
    Serial.println("[PS4] × 押した");
  }
  if (PS4.event.button_up.cross) {
    Serial.println("[PS4] × 離した");
  }

  // デバッグ用に時々スティックとトリガーを出力(適当に間引き)
  static uint32_t lastPrint = 0;
  uint32_t now = millis();
  if (now - lastPrint > 200) {
    lastPrint = now;
    Serial.printf("[PS4] L(%4d,%4d)  L2=%3d  R2=%3d\n", lx, ly, l2, r2);
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("PS4 コントローラ接続待ちを開始します...");

  // PS4 ライブラリ初期化(引数は「コントローラに登録した ESP32 のMAC」)
  if (!PS4.begin(esp32Mac)) {
    Serial.println("PS4.begin に失敗しました。MAC 文字列が正しいか確認してください。");
    while (true) {
      delay(1000);
    }
  }
  
  // 各種コールバック登録
  PS4.attach(onEvent);
  PS4.attachOnConnect(onConnect);
  PS4.attachOnDisconnect(onDisconnect);

  Serial.println("初期化完了。PS4 コントローラの電源を入れてください。");
}

void loop() {
  // コールバック駆動なので、ループ中は特に何もしなくてOK
  delay(10);
}
  • バギーカーの作成
    マニュアルに沿って作成します。下の画像にはありませんが、電池ケースも作成します。
    IMG_20251026_103857 (1).jpg

  • 回路の作成
    下図のように配線します。右端は、回路に使われているモータドライバTC78H653FTGを拡大表示してピンの名前を記載したものです。
    ESP32DR32_Motor_Survo_TC78H653FTG_ブレッドボード.jpg
    この回路図において、サーボモータの電源はマイコンから取っていますが、マイコンに負担がかかるため、別に電源を取っても良いかもしれません。
    なお、130モータにはノイズ対策として、参考資料3のようにコンデンサを入れました。

  • モータドライバについて
    モータドライバに使用したTC78H653FTGは、低電圧で動作し、ある程度の電流も出力できるため、小型DCモータの動作に向いています。
    今回使用したDCモータは外観からFA-130RA-2270の相当品と思われます。ここではモーラドライバに流す電流を増やすため、TC78H653FTGをラージモードで動作させています。なお、TC78H653FTGはスモールモードでは2個のDCモータを同時に駆動可能で、ラージモードでは1個のDCモータを駆動可能です。

  • バギーカーの舵取り機構へのサーボモータの取付け
    サーボモータの取り付け位置・取り付け方法、ステンレスワイヤの取り付け位置を適当に決めます。そして、バギーカーの舵取り部のシャフトに、U字型に加工したSUS304ワイヤをはんだ付けします。私は電子工作用のはんだとフラックスを使用しましたが、はんだ付けがうまくいかず苦労しました。できれば、ステンレス専用のはんだやフラックスを使用するとよいと思います。さらに、サーボモータをプラ棒を使ってバギーカーに固定します。サーボモータはM2ネジとナットでプラ棒に固定して、プラ棒同士と、プラ棒と車体は、アロンアルファで接着しました。
    IMG_20251206_194724.jpg
    IMG_20251206_194704.jpg

  • ラジコンのプログラムの作成
    Arduinoで作成しました。加減速が緩やかになる制御としています。モータドライバが過負荷で落ちやすいため、コントローラの「✕」キーでドライバをリセットする機能を入れています。なお、プログラムはchatgptにほとんど作成してもらいました。

#include <ESP32Servo.h>
#include <PS4Controller.h>

#define SERVO_PIN   14
#define MOTOR_PIN1  2
#define MOTOR_PIN2  4

// ★ TC78H653FTG の STBY ピンにつなぐ GPIO
#define STBY_PIN    16

// モータ用のLEDC設定
const int MOTOR_CH1 = 6;
const int MOTOR_CH2 = 7;
const int MOTOR_FREQ = 1000;
const int MOTOR_RES  = 8;

// スピード制御用
int angle = 90;
int8_t  stickY       = 0;     // -128〜127
int16_t targetSpeed  = 0;     // 目標速度 -255〜255
int16_t currentSpeed = 0;     // 実際に出力している速度 -255〜255

const int DEADZONE   = 15;    // 中立の幅
//const int ACCEL_STEP = 5;     // 1ループで変化させる最大量
const int ACCEL_STEP = 2; // 5 → 2 などにしてみる

Servo myServo;

// ★ モータドライバ(TC78H653)をリセットする関数
void resetDriver()
{
  Serial.println("Motor driver reset (STBY L->H)");
  digitalWrite(STBY_PIN, LOW);   // スタンバイに入れる
  delay(5);                      // 数ms待つ(十分短くてOK)
  digitalWrite(STBY_PIN, HIGH);  // 復帰
}

void setup() {
  Serial.begin(115200);

  // ★ STBYピン制御設定
  pinMode(STBY_PIN, OUTPUT);
  digitalWrite(STBY_PIN, HIGH);  // 通常動作状態にしておく

  // モータPWM
  ledcSetup(MOTOR_CH1, MOTOR_FREQ, MOTOR_RES);
  ledcSetup(MOTOR_CH2, MOTOR_FREQ, MOTOR_RES);
  ledcAttachPin(MOTOR_PIN1, MOTOR_CH1);
  ledcAttachPin(MOTOR_PIN2, MOTOR_CH2);
  ledcWrite(MOTOR_CH1, 0);
  ledcWrite(MOTOR_CH2, 0);

  // サーボ
  myServo.attach(SERVO_PIN);
  myServo.write(90);

  // PS4
  PS4.begin("**:**:**:**:**:**"); //マイコンのMacアドレスを入力します
  Serial.println("Ready.");
}

void loop() {
  if (PS4.isConnected()) {

    // ★ ×ボタンが押されたときにドライバリセット
    //   (押している間ずっと何度呼ばれても問題ない程度の処理)
    if (PS4.Cross()) {
      resetDriver();
    }

    // ステアリング(右スティックX)
    // angle = map(PS4.RStickX(), -128, 127, 0, 180);
    angle = map(PS4.RStickX(), -128, 127, 120, 50);
    // 120と50はステアリングのキレ具合により調整が必要
    myServo.write(angle);

    // スピード(左スティックY)
    stickY = PS4.LStickY();  // -128〜127

    // デッドゾーン処理
    if (stickY > DEADZONE) {
      // 下側(+)を後進とする例
      targetSpeed = map(stickY, DEADZONE + 1, 127, 0, 255);  // 0〜255
      targetSpeed = +targetSpeed;                            // 後進を + と定義
    } else if (stickY < -DEADZONE) {
      // 上側(−)を前進とする例
      targetSpeed = map(stickY, -DEADZONE - 1, -128, 0, 255); // 0〜255
      targetSpeed = -targetSpeed;                             // 前進を - と定義
    } else {
      targetSpeed = 0; // 中立
    }

    // ★ 加減速をなまらせる処理 ★
    if (currentSpeed < targetSpeed) {
      currentSpeed += ACCEL_STEP;
      if (currentSpeed > targetSpeed) currentSpeed = targetSpeed;
    } else if (currentSpeed > targetSpeed) {
      currentSpeed -= ACCEL_STEP;
      if (currentSpeed < targetSpeed) currentSpeed = targetSpeed;
    }
    // これで currentSpeed は毎ループ ACCEL_STEP ずつしか変わらない

    // ★ currentSpeed に応じてモータに出力 ★
    if (currentSpeed > 0) {
      // 後進(例):MOTOR_PIN2にPWM
      ledcWrite(MOTOR_CH1, 0);
      ledcWrite(MOTOR_CH2, currentSpeed);
    } else if (currentSpeed < 0) {
      // 前進(例):MOTOR_PIN1にPWM
      int pwm = -currentSpeed;  // 絶対値
      ledcWrite(MOTOR_CH1, pwm);
      ledcWrite(MOTOR_CH2, 0);
    } else {
      // 停止
      ledcWrite(MOTOR_CH1, 0);
      ledcWrite(MOTOR_CH2, 0);
    }

    // デバッグ表示
    Serial.print("stickY: ");
    Serial.print(stickY);
    Serial.print(" | targetSpeed: ");
    Serial.print(targetSpeed);
    Serial.print(" | currentSpeed: ");
    Serial.println(currentSpeed);
  }
  • 試作したラジコンカー
    見てくれは悪いですが、動作することを確認しました。マイコンの電源は006P(9V電池)を使用し、モータ駆動用に単3電池2本(3V)を使用しました。

IMG_20251206_194638.jpg

IMG_20251206_195311.jpg

改良点など

  • 本文で書いたように、より大きな電流に対応可能なモータドライバの使用や、サーボモータの電源への直接接続が挙げられます。

  • ステアリング部の部品がずれたり外れたりします。耐久性のある構造ではありませんので、おもちゃとして遊ぶにはステアリング部の補強が必要と思います。

  • PS4コントローラへのMacアドレスの書き込みにSixaxisPairToolを使用した際、次のような現象を確認しました(私はESP32ボードを複数所有しています)。
    ① 1台めのESP32のMacアドレスをPS4コントローラに書き込む・・・1台めのESP32とPS4コントローラの通信成功
    ② 2台めのESP32のMacアドレスをPS4コントローラに書き込む・・・2台めのESP32とPS4コントローラの通信成功
    ③ 再び1台めのESP32のMacアドレスをPS4コントローラに書き込む・・・1台めのESP32とPS4コントローラの通信失敗
    ④ 2台めのESP32のMacアドレスをPS4コントローラに書き込む・・・2台めのESP32とPS4コントローラの通信失敗

参考資料

1. M5StackGray モータ駆動デモプログラム TC78H653FTG

2. ESP32とPSコントローラーでラジコンを作る方法

3. モータドライバTC78H653FTGの過電流検出ISDを回避できた

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?