はじめに:ゲームコントローラーで動かすロボットの魅力

ロボットやラジコンを操縦する際、専用の送受信機も良いですが、手に馴染んだゲームコントローラーで操縦できたら便利だと思いませんか? PS4コントローラー(DualShock4)は、優れた操作性と豊富なボタン・アナログスティックを備え、Bluetooth通信にも対応しています。

今回製作するのは、ESP32とPS4コントローラーを無線接続し、テオヤンセン機構で駆動する6脚ロボットを制御するモータードライバシステムです。

テオヤンセン機構とは

テオヤンセン機構(Theo Jansen Mechanism) は、オランダのアーティスト、テオ・ヤンセン氏が考案した、リンク機構のみで滑らかな歩行運動を実現する機構です。

特徴:

  • 回転運動を脚の上下運動に変換
  • まるで生き物のような有機的な動き
  • モーター1つで複数の脚を同期駆動可能

このロボットをPS4コントローラーで無線操縦するために、ESP32を使った高性能モータードライバを自作しました。

本プロジェクトの技術的特徴

  • ESP32のBluetooth Classic通信

    • PS4コントローラーとSPP(Serial Port Profile)で接続
    • 低遅延な無線制御を実現
  • Full-Nch構成Hブリッジ回路

    • 高性能なN-ch MOSFETのみを使用
    • IR2104ハーフブリッジドライバーICでハイサイド駆動
    • 最大4A連続駆動に対応
  • 2ch独立PWM制御

    • 各モーター(左右)を独立制御
    • ESP32のLEDCペリフェラルで8bit分解能PWM生成
  • JLCPCB製2oz銅箔基板

    • 通常の2倍の銅箔厚で大電流対応
    • 2mm幅電源パターンで放熱性確保

必要な部品と推奨購入先

部品名 仕様 数量 備考
ESP32開発ボード ESP32-WROOM-32 1 Bluetooth Classic対応
PS4コントローラー DualShock4(CUH-ZCT2J) 1 第2世代推奨
N-ch MOSFET 2SK2232(Vds=500V、Id=10A) 8 2ch×4個=8個
ハーフブリッジドライバー IR2104(600V、HVIC技術) 4 ハイサイド駆動用
ブートストラップダイオード 1N4148(高速スイッチング) 4 ブートストラップ回路用
ブートストラップコンデンサ 10μF 50V(電解) 4 ゲート駆動電荷供給
ゲート抵抗 10Ω 1/4W 8 スイッチング速度調整
プルダウン抵抗 10kΩ 1/4W 8 MOSFET誤動作防止
レギュレータ AMS1117-3.3V 1 ESP32用3.3V生成
電解コンデンサ 100μF 25V 2 電源平滑化
積層セラミックコンデンサ 0.1μF(パスコン) 10 ノイズ対策
端子台 2P ピッチ5mm 4 モーター・電源接続用

【重要】部品選定のポイント

2SK2232 N-ch MOSFET:

  • オン抵抗(Rds(on)):0.5Ω(Vgs=10V時)→ 発熱が少ない
  • ドレイン電流(Id):10A(連続)→ 余裕のある設計
  • 入手性:秋月電子通商で安価に購入可能(1個約100円)

IR2104 ハーフブリッジドライバー:

  • 耐圧:600V(HVIC技術によるハイサイド駆動)
  • 出力電流:±0.5A(ゲート駆動に十分)
  • ブートストラップ回路内蔵:外付け部品が少ない

Hブリッジ回路の動作原理とFull-Nch構成の優位性

Hブリッジ回路の基本原理

DCモーターの正転・逆転制御には、Hブリッジ回路が広く使われます。4つのスイッチング素子(通常はMOSFET)をH字型に配置し、電流の流れる方向を切り替えることでモーターを制御します。

Hブリッジ回路の電流経路と制御パターン

Hブリッジ回路の電流経路と制御パターン

動作モード:

Q1 Q2 Q3 Q4 動作 電流経路
ON OFF OFF ON 正転 V+ → Q1 → Motor → Q4 → GND
OFF ON ON OFF 逆転 V+ → Q3 → Motor → Q2 → GND
OFF ON OFF ON フリーラン Motor → Q2 → GND → Q4 → Motor
OFF OFF OFF OFF 停止 フリーラン状態
ON OFF ON OFF ショート(禁止) V+ → Q1 → Q3 → GND

【重要】同時ON防止(デッドタイム挿入)

Q1とQ2、またはQ3とQ4を同時にONにすると、電源ショートが発生します。IR2104などのドライバーICには、デッドタイム生成機能が内蔵されており、自動的に短時間(数百ns)のOFF期間を挿入して貫通電流を防ぎます。

Full-Nch構成 vs PN混合構成

モータードライバには、大きく分けて2つの構成があります。

PN混合構成(P-ch + N-ch)

回路構成:

  • ハイサイド(Q1、Q3):P-ch MOSFET
  • ローサイド(Q2、Q4):N-ch MOSFET

メリット:

  • 回路がシンプル:P-chは負電圧でONするため、ハイサイドドライバー不要
  • 部品点数が少ない

デメリット:

  • P-ch MOSFETは高価:同等性能のN-chと比べて2-3倍の価格
  • オン抵抗が大きい:P-chはN-chより性能が劣る(同価格帯で比較)
  • 発熱が大きい:Rds(on)が大きいため、大電流時に発熱

Full-Nch構成(本プロジェクト採用)

回路構成:

  • ハイサイド(Q1、Q3):N-ch MOSFET + ハイサイドドライバー
  • ローサイド(Q2、Q4):N-ch MOSFET

メリット:

  • 高性能:N-ch MOSFETのみ使用でオン抵抗が小さい
  • 低発熱:同じ電流でも発熱が少ない
  • コスト効率:同じ予算でより高性能な回路を構築可能
  • 部品選定の自由度:N-chは種類が豊富

デメリット:

  • 回路が複雑:ハイサイドドライバーICとブートストラップ回路が必要
  • 部品点数が増える:ブートストラップダイオード、コンデンサが必要

ハイサイドドライバーとブートストラップ回路

【用語解説】ハイサイド・ローサイド・ブートストラップとは?

まず、Hブリッジ回路で使われる重要な用語を理解しましょう。

ハイサイド(High Side):

  • Hブリッジ回路の電源側(V+側)に接続されたスイッチング素子のこと
  • 上記の回路図ではQ1とQ3がハイサイド
  • 「高い電位側」という意味で「ハイサイド」と呼ばれる

ローサイド(Low Side):

  • Hブリッジ回路のグランド側(GND側)に接続されたスイッチング素子のこと
  • 上記の回路図ではQ2とQ4がローサイド
  • 「低い電位側」という意味で「ローサイド」と呼ばれる

ブートストラップ(Bootstrap):

  • 「自分の靴紐を引っ張って自分を持ち上げる」という英語の慣用句に由来
  • 電源電圧を自己昇圧して、より高い電圧を生成する回路のこと
  • Hブリッジでは、ローサイドの動作を利用してハイサイド駆動用の高電圧を作り出す仕組み

このように、ブートストラップ回路は「自分自身の動作で自分を助ける」という特性から名付けられています。


なぜハイサイドN-chは難しいのか?

N-ch MOSFETは、ゲート電圧がソース電圧より約10V高い状態でONします。ローサイドはソースがGNDに接続されているため、ゲートに+10Vを加えれば簡単にONできます。

しかし、ハイサイドのソースはモーター電圧と同じ電位(例:+12V)まで上昇するため、ゲートには+22V程度が必要になります。この高電圧を生成するのがブートストラップ回路です。

ブートストラップ回路の動作原理:

ブートストラップ回路は、ローサイドMOSFETのON/OFF動作を利用して、ハイサイド駆動用の電圧を「自己生成」 します。

仕組み(電源12Vの場合):

  1. ローサイドON時(充電フェーズ)

    • ハイサイドのソースがGNDに近い電位(約0V)に落ちる
    • ブートストラップダイオードを通じて、ブートストラップコンデンサが約12Vまで充電される
    • この時、コンデンサには「予備電荷」が蓄えられる
  2. ハイサイドON時(昇圧フェーズ)

    • ハイサイドのソースが電源電圧(約12V)まで上昇
    • 充電されたコンデンサ(12V)がソース(12V)に「乗っかる」形になる
    • 結果:ゲート電圧 = ソース(12V)+ コンデンサ(12V)= 約24V
    • これでゲート-ソース間に約12Vの電位差が生まれ、MOSFETがONする

この「コンデンサの電圧が回路の電位上昇に合わせて持ち上がる」動作が、まさに 「靴紐を引っ張って自分を持ち上げる(bootstrap)」 に似ているため、この名前が付けられました。

【重要】ブートストラップ回路の制約:

  • ローサイドを定期的にONしないと、コンデンサが放電してハイサイドを駆動できなくなる
  • 100% Duty(常にハイサイドON)では動作不可
  • PWM制御では、ローサイドON期間でコンデンサが再充電されるため問題なし
Full-Nch構成Hブリッジ回路図(2ch)

Full-Nch構成Hブリッジ回路図(2ch)

IR2104の主要機能:

  • 入力信号レベル変換(3.3V → 10-15V)
  • デッドタイム自動生成(約520ns)
  • ブートストラップ回路サポート
  • 過電流・過熱保護(オプション)

回路設計と部品配置

主要部品の電気的特性

2SK2232 N-ch MOSFET:

Vds(ドレイン-ソース電圧): 500V
Id(ドレイン電流): 10A(連続)、40A(パルス)
Rds(on)(オン抵抗): 0.5Ω(Vgs=10V時)
Vgs(th)(ゲートしきい値電圧): 2-4V
Qg(ゲート総電荷): 22nC

発熱計算例(4A駆動時):

P = I² × Rds(on)
  = 4² × 0.5
  = 8W(1個あたり)

4個のMOSFETが同時にONする場合、合計32Wの発熱が発生します。放熱器の取り付けを推奨します。

IR2104 ハーフブリッジドライバー:

電源電圧範囲: 10-20V
ロジック入力: 3.3V/5V CMOS互換
出力電流: ±0.5A(ピーク)、±0.25A(連続)
デッドタイム: 520ns(typ)
応答時間: 120ns(ton)、80ns(toff)

PCB設計のポイント

銅箔厚の選定:2oz(約70μm)

通常のPCBは1oz(約35μm)ですが、モーター駆動では大電流が流れるため、2ozに設定しました。

許容電流の計算:

1ozの場合(1mm幅): 約1A
2ozの場合(1mm幅): 約2A
2ozの場合(2mm幅): 約4A ← 今回の設計
PCBレイアウト:2mm幅電源パターンと2oz銅箔

PCBレイアウト:2mm幅電源パターンと2oz銅箔

レイアウト設計の工夫:

  • 電源パターンの太線化:V+、GNDラインは2mm幅確保
  • ベタGNDプレーン:裏面全面をGNDプレーンにしてノイズ対策
  • パスコン配置:各ICの直近に0.1μFのパスコンを配置
  • MOSFETの放熱対策:大型パッド + 裏面ベタGNDでヒートシンク接続可能

KiCadによる基板設計とJLCPCB発注

KiCad を初めて使う方は「ESP32 PCB設計:KiCad で回路図を描いて基板を発注するまで」も参考にしてください。

JLCPCB発注仕様

発注オプション:

  • 基板サイズ:70mm × 50mm
  • 層数:2層(表裏)
  • 基板色:緑色(標準)
  • 表面処理:HASL(鉛フリーはんだ)
  • 基板厚:1.6mm(標準)
  • 銅箔厚2oz(約70μm) ← 通常の2倍!
  • 数量:5枚(最小ロット)
  • 納期:発注から7日で到着(DHLエキスプレス)

費用内訳(参考):

  • 基板代(5枚):約$5
  • 銅箔2ozオプション:約$15
  • 送料(DHL):約$20
  • 合計:約$40(約5,000円)

【重要】2oz銅箔オプション

通常の1ozから2ozに変更すると、追加料金が発生しますが、許容電流が約2倍になります。モータードライバのような大電流回路では必須のオプションです。

基板の到着とはんだ付け

JLCPCB到着基板(表面)

JLCPCB到着基板(表面)

JLCPCB到着基板(裏面)

JLCPCB到着基板(裏面)

品質チェック結果:

  • ✅ パターン欠損なし
  • ✅ ビアホール導通OK
  • ✅ シルク印刷鮮明
  • ✅ ソルダーレジスト均一
  • ✅ 2oz銅箔の厚みを目視確認可能

1週間で5枚の基板が到着しました。1枚あたり約1,000円で高品質な基板が手に入るのは驚異的です。

部品実装

部品実装完了後の基板

部品実装完了後の基板

実装順序:

  1. 低背部品から:抵抗 → ダイオード → 小型コンデンサ
  2. IC類:IR2104(DIP8)をICソケットに(後で交換可能)
  3. MOSFET:TO-220パッケージ、放熱器取り付け検討
  4. 電解コンデンサ:極性に注意
  5. 端子台:最後に実装(高さがあるため)

実装所要時間:約1.5時間


PS4コントローラーとESP32のBluetooth接続

Bluetooth Classic SPP通信の概要

ESP32は、Bluetooth Classic(BR/EDR)とBluetooth Low Energy(BLE)の両方に対応しています。PS4コントローラーとの接続には、Bluetooth Classic + SPP(Serial Port Profile) プロトコルを使用します。

SPP(Serial Port Profile):

  • 仮想シリアル通信を提供するBluetoothプロファイル
  • 透過的なデータ転送が可能
  • 低遅延(通常10-30ms程度)

PS4-esp32ライブラリの役割:

  • DualShock4のHIDレポート解析
  • ボタン・アナログスティック状態の取得
  • 振動・ライトバー制御(オプション)

PS4-esp32ライブラリのインストールと設定

【ステップ1】ライブラリのダウンロード

GitHubから最新版をダウンロードします。

PS4-esp32 ライブラリ(GitHub)

【ステップ2】Arduino IDEへのインストール

ESP32 の Arduino IDE 環境が未構築の方は「ESP32 Arduino IDE セットアップガイド」を先に確認してください。

  1. ZIPファイルをダウンロード
  2. Arduino IDE → スケッチ → ライブラリをインクルード → .ZIP形式のライブラリをインストール
  3. ダウンロードしたZIPファイルを選択

【ステップ3】コンパイルエラーの対処

一部のESP32 Arduinoコアバージョンでは、esp_bt_gap_set_scan_mode()関数でコンパイルエラーが発生します。

エラー内容:

error: 'esp_bt_gap_set_scan_mode' was not declared in this scope

対処法:該当行をコメントアウト

ライブラリフォルダ内のps4_spp.cファイルを編集します。

ファイルパス(Windows):

C:\Users\<ユーザー名>\Documents\Arduino\libraries\PS4-esp32\src\ps4_spp.c

編集箇所(86-90行目付近):

//#if CONFIG_IDF_TARGET_ESP32
//    esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
//#endif
//
//esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);

この修正により、コンパイルが通るようになります。

【注意】 この修正は、ライブラリがESP32の新しいBluetoothスタックに完全対応していないための暫定措置です。機能的には問題なく動作します。


ESP32とPS4コントローラーのペアリング手順

PS4コントローラー(DualShock4)は、通常PS4本体とペアリングされています。ESP32と接続するには、コントローラーに記録されたBluetooth MACアドレスをESP32のものに書き換える必要があります。

ステップ1:ESP32のBluetooth MACアドレス取得

以下のスケッチをESP32に書き込みます。

#include <esp_bt.h>

void setup() {
  Serial.begin(115200);
  
  // BluetoothスタックをInitialize
  esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  esp_bt_controller_init(&bt_cfg);
  esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT);
  
  // Bluetooth MACアドレスを取得
  uint8_t bt_mac[6];
  esp_read_mac(bt_mac, ESP_MAC_BT);
  
  Serial.println("============================================");
  Serial.println("  ESP32 Bluetooth MAC Address");
  Serial.println("============================================");
  Serial.printf("  %02X:%02X:%02X:%02X:%02X:%02X\n", 
                bt_mac[0], bt_mac[1], bt_mac[2], 
                bt_mac[3], bt_mac[4], bt_mac[5]);
  Serial.println("============================================");
  Serial.println("このアドレスをメモしてください");
}

void loop() {
  // 何もしない
}

シリアルモニター出力例:

============================================
  ESP32 Bluetooth MAC Address
============================================
  AC:67:B2:5B:AB:96
============================================
このアドレスをメモしてください

このアドレス(例:AC:67:B2:5B:AB:96)を必ずメモしてください。

ステップ2:SixaxisPairToolでMACアドレス書き換え

SixaxisPairToolは、PS3/PS4コントローラーのペアリング先MACアドレスを変更できるWindowsソフトです。

【ダウンロード】

SixaxisPairTool ダウンロードページ

【使用手順】

  1. コントローラーをPCに接続

    • USB Type-Bケーブルで接続
    • Windowsがドライバーを自動インストール
  2. SixaxisPairToolを起動

    • 管理者権限で実行を推奨
  3. 認識確認

SixaxisPairTool画面:コントローラー認識状態

SixaxisPairTool画面:コントローラー認識状態

画面表示項目:

  • Current Master:現在のペアリング先(PS4本体のMACアドレス)
  • Change Master:新しいペアリング先を入力

【重要】認識に失敗する場合

  • 「No device found」と表示される場合:
    • USBケーブルを変更(充電専用ケーブルはNG)
    • 別のUSBポートを試す
    • Windowsを再起動
    • ドライバーを手動インストール
  1. ESP32のMACアドレスを入力

    • Change Masterフィールドに先ほど取得したアドレスを入力
    • 例:AC:67:B2:5B:AB:96
    • 区切り文字は:(コロン)
  2. Updateボタンをクリック

    • 書き込み完了後、「Updated」と表示される
  3. 確認

    • Current MasterがESP32のアドレスに変更されていることを確認

【PS4本体に再接続する方法】

ESP32との接続後、再びPS4で使用したい場合:

  1. PS4本体とUSBケーブルで接続
  2. PSボタンを押す
  3. 自動的にPS4のMACアドレスに再ペアリング

ESP32と再接続する際は、再度SixaxisPairToolでMACアドレスを書き換える必要があります。


Arduino IDE スケッチの実装

完全なサンプルコード

以下は、2chモータードライバをPS4コントローラーで制御する完全なコードです。

#include <ps4.h>
#include <PS4Controller.h>
#include <ps4_int.h>

// ============================================
// ピン定義
// ============================================
// モーターA(左側)
#define MOTOR_A_PWM  27  // GPIO27 - PWM出力
#define MOTOR_A_IN1  18  // GPIO18 - 方向制御1
#define MOTOR_A_IN2  19  // GPIO19 - 方向制御2

// モーターB(右側)
#define MOTOR_B_PWM  14  // GPIO14 - PWM出力
#define MOTOR_B_IN1  25  // GPIO25 - 方向制御1
#define MOTOR_B_IN2  26  // GPIO26 - 方向制御2

// ============================================
// PWM設定
// ============================================
#define PWM_FREQ     12800   // PWM周波数 12.8kHz
#define PWM_RESOLUTION 8     // PWM分解能 8bit (0-255)
#define PWM_CHANNEL_A  0     // LEDCチャンネル0
#define PWM_CHANNEL_B  1     // LEDCチャンネル1

// ============================================
// 速度プリセット
// ============================================
int speedMode = 0;           // 速度モード(0:高速, 1:低速)
int speedHigh = 255;         // 高速モード速度(100%)
int speedMid = 200;          // 中速モード速度(78%)
int speedLow = 170;          // 低速モード速度(67%)
bool touchpadPressed = false; // タッチパッド状態管理

// ============================================
// モーター制御関数
// ============================================

/**
 * 前進
 * @param pwmA モーターA速度(0-255)
 * @param pwmB モーターB速度(0-255)
 */
void motorForward(int pwmA, int pwmB) {
  ledcWrite(PWM_CHANNEL_A, pwmA);
  ledcWrite(PWM_CHANNEL_B, pwmB);
  digitalWrite(MOTOR_A_IN1, HIGH);
  digitalWrite(MOTOR_A_IN2, LOW);
  digitalWrite(MOTOR_B_IN1, HIGH);
  digitalWrite(MOTOR_B_IN2, LOW);
}

/**
 * 後退
 * @param pwmA モーターA速度(0-255)
 * @param pwmB モーターB速度(0-255)
 */
void motorBackward(int pwmA, int pwmB) {
  ledcWrite(PWM_CHANNEL_A, pwmA);
  ledcWrite(PWM_CHANNEL_B, pwmB);
  digitalWrite(MOTOR_A_IN1, LOW);
  digitalWrite(MOTOR_A_IN2, HIGH);
  digitalWrite(MOTOR_B_IN1, LOW);
  digitalWrite(MOTOR_B_IN2, HIGH);
}

/**
 * 左旋回(信地旋回)
 * モーターA逆転、モーターB正転
 * @param pwmA モーターA速度(0-255)
 * @param pwmB モーターB速度(0-255)
 */
void motorTurnLeft(int pwmA, int pwmB) {
  ledcWrite(PWM_CHANNEL_A, pwmA);
  ledcWrite(PWM_CHANNEL_B, pwmB);
  digitalWrite(MOTOR_A_IN1, LOW);
  digitalWrite(MOTOR_A_IN2, HIGH);
  digitalWrite(MOTOR_B_IN1, HIGH);
  digitalWrite(MOTOR_B_IN2, LOW);
}

/**
 * 右旋回(信地旋回)
 * モーターA正転、モーターB逆転
 * @param pwmA モーターA速度(0-255)
 * @param pwmB モーターB速度(0-255)
 */
void motorTurnRight(int pwmA, int pwmB) {
  ledcWrite(PWM_CHANNEL_A, pwmA);
  ledcWrite(PWM_CHANNEL_B, pwmB);
  digitalWrite(MOTOR_A_IN1, HIGH);
  digitalWrite(MOTOR_A_IN2, LOW);
  digitalWrite(MOTOR_B_IN1, LOW);
  digitalWrite(MOTOR_B_IN2, HIGH);
}

/**
 * 停止(フリーラン)
 */
void motorStop() {
  ledcWrite(PWM_CHANNEL_A, 0);
  ledcWrite(PWM_CHANNEL_B, 0);
  digitalWrite(MOTOR_A_IN1, LOW);
  digitalWrite(MOTOR_A_IN2, LOW);
  digitalWrite(MOTOR_B_IN1, LOW);
  digitalWrite(MOTOR_B_IN2, LOW);
}

/**
 * ブレーキ(両方向ショート)
 */
void motorBrake() {
  ledcWrite(PWM_CHANNEL_A, 0);
  ledcWrite(PWM_CHANNEL_B, 0);
  digitalWrite(MOTOR_A_IN1, HIGH);
  digitalWrite(MOTOR_A_IN2, HIGH);
  digitalWrite(MOTOR_B_IN1, HIGH);
  digitalWrite(MOTOR_B_IN2, HIGH);
}

// ============================================
// 初期化
// ============================================
void setup() {
  Serial.begin(115200);
  Serial.println("ESP32 Motor Driver - PS4 Controller");
  
  // ピンモード設定
  pinMode(MOTOR_A_IN1, OUTPUT);
  pinMode(MOTOR_A_IN2, OUTPUT);
  pinMode(MOTOR_B_IN1, OUTPUT);
  pinMode(MOTOR_B_IN2, OUTPUT);
  
  // LEDC PWM設定
  ledcSetup(PWM_CHANNEL_A, PWM_FREQ, PWM_RESOLUTION);
  ledcSetup(PWM_CHANNEL_B, PWM_FREQ, PWM_RESOLUTION);
  ledcAttachPin(MOTOR_A_PWM, PWM_CHANNEL_A);
  ledcAttachPin(MOTOR_B_PWM, PWM_CHANNEL_B);
  
  // 初期状態:全HIGH(動作確認LED点灯)
  digitalWrite(MOTOR_A_IN1, HIGH);
  digitalWrite(MOTOR_A_IN2, HIGH);
  digitalWrite(MOTOR_B_IN1, HIGH);
  digitalWrite(MOTOR_B_IN2, HIGH);
  
  // PS4コントローラー接続開始
  // ★★★ここに自分のESP32のBluetooth MACアドレスを入力★★★
  PS4.begin("AC:67:B2:5B:AB:96");
  
  Serial.println("Waiting for PS4 controller...");
  
  // 接続待機
  while (!PS4.isConnected()) {
    delay(100);
  }
  
  Serial.println("PS4 Controller Connected!");
  
  // 接続確認後、全LOW(待機状態)
  delay(1000);
  motorStop();
  
  Serial.println("Ready to control!");
}

// ============================================
// メインループ
// ============================================
void loop() {
  // PS4コントローラーが切断された場合
  if (!PS4.isConnected()) {
    motorStop();
    Serial.println("Controller disconnected");
    delay(1000);
    return;
  }
  
  // タッチパッドで速度モード切替(トグル動作)
  if (PS4.Touchpad()) {
    if (!touchpadPressed) {
      touchpadPressed = true;
      speedMode = !speedMode;  // モード反転
      
      Serial.printf("Speed Mode: %s\n", 
                    speedMode ? "LOW" : "HIGH");
      
      // 振動フィードバック(オプション)
      // PS4.setRumble(100, 100);
      // delay(200);
      // PS4.setRumble(0, 0);
    }
  } else {
    touchpadPressed = false;
  }
  
  // 現在の速度設定
  int currentSpeedFull = speedMode ? speedLow : speedHigh;
  int currentSpeedMid = speedMode ? speedLow : speedMid;
  
  // ボタン入力に応じたモーター制御
  // 優先順位:上下左右 > 斜め方向
  
  if (PS4.Right()) {
    // 右旋回(信地旋回)
    motorTurnRight(currentSpeedFull, currentSpeedFull);
    Serial.println("Turn Right");
  }
  else if (PS4.Left()) {
    // 左旋回(信地旋回)
    motorTurnLeft(currentSpeedFull, currentSpeedFull);
    Serial.println("Turn Left");
  }
  else if (PS4.Up()) {
    // 前進
    motorForward(currentSpeedFull, currentSpeedFull);
    Serial.println("Forward");
  }
  else if (PS4.Down()) {
    // 後退
    motorBackward(currentSpeedFull, currentSpeedFull);
    Serial.println("Backward");
  }
  else if (PS4.UpRight()) {
    // 右前進(右モーター減速)
    motorForward(currentSpeedFull, currentSpeedMid);
    Serial.println("Forward Right");
  }
  else if (PS4.UpLeft()) {
    // 左前進(左モーター減速)
    motorForward(currentSpeedMid, currentSpeedFull);
    Serial.println("Forward Left");
  }
  else if (PS4.DownRight()) {
    // 右後退(右モーター減速)
    motorBackward(currentSpeedFull, currentSpeedMid);
    Serial.println("Backward Right");
  }
  else if (PS4.DownLeft()) {
    // 左後退(左モーター減速)
    motorBackward(currentSpeedMid, currentSpeedFull);
    Serial.println("Backward Left");
  }
  else {
    // 入力なし:停止
    motorStop();
  }
  
  delay(10);  // 制御周期 100Hz
}

コードの詳細解説

【LEDC PWM制御】

ESP32のLEDC(LED Control)ペリフェラルを使用してPWM信号を生成します。

ledcSetup(PWM_CHANNEL_A, PWM_FREQ, PWM_RESOLUTION);

パラメータ:

  • PWM_CHANNEL_A(0):LEDCチャンネル番号(0-15)
  • PWM_FREQ(12800Hz):PWM周波数
  • PWM_RESOLUTION(8bit):分解能(0-255の256段階)

PWM周波数の選定:

  • 可聴域を避ける:20kHz以上または12kHz以下
  • 今回は12.8kHz:モーター駆動に最適、ノイズが少ない

【方向制御ロジック】

Hブリッジ回路では、IN1とIN2の組み合わせで動作が決まります。

IN1 IN2 動作
HIGH LOW 正転
LOW HIGH 逆転
LOW LOW フリーラン(惰性)
HIGH HIGH ブレーキ(ショート)

【斜め方向の実装】

左右のモーター速度を変えることで、緩やかなカーブを実現します。

motorForward(currentSpeedFull, currentSpeedMid);  // 右カーブ
// 右モーターを減速 → 右に曲がる

動作確認とテオヤンセン機構ロボットへの実装

基板の搭載

テオヤンセン機構ロボットにモータードライバを搭載

テオヤンセン機構ロボットにモータードライバを搭載

自作基板はロボットのボディにピッタリ収まりました。設計段階でサイズを考慮した成果です。

実装のポイント:

  • 配線の短縮:モーターへの配線を最短経路で接続
  • 電源の安定化:モーターと基板に別々のコンデンサを配置
  • 放熱対策:MOSFETに小型ヒートシンクを取り付け

実際の動作

動作確認項目:

  • ✅ 前進・後退の正常動作
  • ✅ 左右旋回の応答性
  • ✅ 斜め方向への滑らかな移動
  • ✅ 速度モード切替の動作
  • ✅ 約10mの通信距離確保
  • ✅ バッテリー駆動約30分(模擬テスト)

PS4コントローラーとの接続は非常に安定しており、遅延もほとんど感じられませんでした。


まとめと今後の展望

本プロジェクトで習得できる技術

【ハードウェア設計】

  • ✅ Hブリッジ回路の動作原理
  • ✅ Full-Nch構成のメリット・デメリット
  • ✅ ハーフブリッジドライバーIC(IR2104)の使用方法
  • ✅ ブートストラップ回路の設計
  • ✅ 大電流対応PCB設計(2oz銅箔、太線化)

【ソフトウェア開発】

  • ✅ ESP32のBluetooth Classic SPP通信
  • ✅ PS4-esp32ライブラリの導入と設定
  • ✅ LEDC PWM制御の実装
  • ✅ MACアドレス書き換え手法

【基板製作】

  • ✅ KiCadによる回路図・PCB設計
  • ✅ JLCPCBへの発注(2ozオプション)
  • ✅ 部品実装技術

製作費用の目安

項目 費用
ESP32開発ボード 約800円
PS4コントローラー(中古) 約3,000円
2SK2232 MOSFET × 8 約800円
IR2104 × 4 約400円
その他部品一式 約1,000円
JLCPCB基板製作(2oz) 約5,000円
合計 約11,000円

市販の無線モータードライバ(同等性能)は15,000円以上するため、コストパフォーマンスは良好です。

応用アイデア

【機能拡張】

  • アナログスティック対応PS4.LStickY()で無段階速度制御
  • ライトバー表示:バッテリー残量をLEDで表示
  • 振動フィードバック:障害物検知時に振動

【他のロボットへの応用】

  • 2輪駆動ラジコンカー
  • 4輪駆動オフロードロボット
  • ドローンのサーボ制御
  • ロボットアームの関節制御

【上位版の設計】

  • 4ch版:4モーター独立制御(メカナムホイール対応)
  • 電流センサ追加:過電流保護機能
  • エンコーダー対応:速度フィードバック制御

関連記事


最後までお読みいただき、ありがとうございました!

Full-Nch構成モータードライバは、設計は複雑ですが高性能で拡張性も高く、様々なロボット製作に応用できます。ぜひ皆さんもチャレンジしてみてください。

質問やフィードバックは、コンタクトフォームまたはTwitter(@electwork_jp)までお気軽にどうぞ!