3軸リアクションホイール倒立振子を作るアドカレの8日目です。
1. はじめに:脳(AI)から体(ハードウェア)へ
前回(Day 7)までで、シミュレーション空間において2.5Nmの外乱にも耐える「最強のAIモデル」が完成しました。
今日からは、このAIを現実世界に降臨させる 「Sim-to-Real」 のフェーズに入ります。
今回は、AIモデルを実装し、3つのモーターをマイクロ秒単位で制御するための 「ハードウェア選定」 の詳細を解説します。
「Raspberry Piでいいじゃん」と言われそうですが、あえて 「STM32G4マイコン(ベアメタル)」 を選んだのには、制御屋としての譲れない技術的な理由があります。
2. 構成概要とスペック選定
制御基板の中核となるBOM(部品表)です。
| カテゴリ | 選定部品 | スペック・選定理由 |
|---|---|---|
| MCU | STM32G474RET6 | Cortex-M4F (170MHz), Flash 512KB, RAM 128KB. CORDIC/FMAC/OPAMP搭載。 |
| Sensor | ICM-42688-P | 6軸IMU (TDK)。低ノイズ密度 ($2.8 \mu g/\sqrt{Hz}$)。SPI接続。 |
| Actuator | GBM2804 | ジンバルモーター(14極12スロット)。内部抵抗が大きくFOC制御しやすい。 |
| Encoder | AS5600 | 12bit磁気エンコーダ。I2C接続。安価だがアドレス固定(0x36)。 |
| Driver | DRV8313 | 3ハーフブリッジドライバ。最大60V/2.5A。SVPWM駆動に最適。 |
3. なぜ STM32G474 なのか?(技術的深掘り)
STM32G4シリーズは、STマイクロエレクトロニクスが「ミックスドシグナル・モーター制御・数学演算」に特化させて開発したマイコンです。
今回のCubliにおいて、具体的にどの機能が「刺さる」のかを解説します。
理由①:FOCをハードウェア化する「CORDIC」
FOC(ベクトル制御)の演算プロセスは、以下の2段階の座標変換が核心となります。
-
クラーク変換 (Clarke Transform):
3相の電流値 ($I_u, I_v, I_w$) を、2相の静止座標系 ($\alpha, \beta$) に変換します。\begin{bmatrix} I_\alpha \\ I_\beta \end{bmatrix} = \frac{2}{3} \begin{bmatrix} 1 & -\frac{1}{2} & -\frac{1}{2} \\ 0 & \frac{\sqrt{3}}{2} & -\frac{\sqrt{3}}{2} \end{bmatrix} \begin{bmatrix} I_u \\ I_v \\ I_w \end{bmatrix} -
パーク変換 (Park Transform):
静止座標系 ($\alpha, \beta$) を、モーターの回転に合わせて回転する座標系 ($d, q$) に変換します。ここで回転角 $\theta$ を用いた三角関数演算 ($\sin\theta, \cos\theta$) が必須となります。\begin{bmatrix} I_d \\ I_q \end{bmatrix} = \begin{bmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{bmatrix} \begin{bmatrix} I_\alpha \\ I_\beta \end{bmatrix}
このパーク変換の行列を見てください。回転角 $\theta$ に応じた三角関数 ($\sin\theta, \cos\theta$) の計算 が含まれています。
これをPWM周期(例えば20kHz = 50$\mu$s毎)で常に計算し続ける必要があり、ソフトウェア(math.h)で実装すると数百サイクルを消費してしまいます。
しかし、STM32G4は CORDIC (Coordinate Rotation Digital Computer) という専用ハードウェアを積んでいます。
- CPUの演算負荷をオフロード: レジスタに「ベクトル($I_\alpha, I_\beta$)」と「角度($\theta$)」を書き込むだけで、ハードウェアが回転計算を行い、数サイクル後に結果($I_d, I_q$)が生成されます。
- 並列動作: CORDICが計算している間、CPUはAIの推論(行列演算)を進めることができます。
理由②:カルマンフィルタの前処理を担う「FMAC」
倒立振子において、姿勢推定(カルマンフィルタ等)の精度は、入力されるセンサデータの質で決まります。
特に今回はモータの振動ノイズがIMUに乗るため、強力なローパスフィルタが必須です。
通常はCPUでソフトフィルタ(IIR/FIR)を書きますが、G4は FMAC (Filter Math Accelerator) を搭載しています。
-
役割分担:
- FMAC (Hardware): 生データに対してIIRフィルタをかけ、高周波ノイズを物理的にカットする「前処理」を担当。
- CPU (Software): 綺麗になったデータを使い、カルマンフィルタや相補フィルタで角度を「推定」することに専念。
このように、「単純な計算処理はハードウェアに任せて、CPUは高度なアルゴリズムのみを行う」 という分業ができるのがG4の魅力です。
理由③:3軸同時制御のための「3つのAdvanced Timer」
3つのモーターをFOCで回すには、正確な電流計測が必要です。
PWMノイズの影響を避けるため、「PWMがONになっている瞬間の、ノイズが落ち着いた真ん中のタイミング」 でサンプリングする必要があります。
通常、この機能を持つ「Advanced Control Timer」は1つのマイコンに1〜2個しかありませんが、STM32G474は TIM1, TIM8 に加えて TIM20 という3つ目の高級タイマーを搭載しています。

- X軸: TIM1
- Y軸: TIM8
- Z軸: TIM20
これらを連携させることで、以下の動作を3軸完全に独立かつ同期して行えます。
- Center-Aligned PWM: 山型のPWM波形を生成。
- TRGO (Trigger Output): 波形の中心でトリガー信号を発火。
- ADC Injection: トリガーを受け取ったADCが、CPUの指示を待たずに即座に電流値を変換。
「3軸すべてのモータ制御ループを、ハードウェアレベルで完全に同期させる」。
これができるマイコンはG474以外になかなかありません。
理由④:外付け部品を減らす「内蔵オペアンプ (PGA)」
FOCには、モータに流れる電流を測定するための回路が不可欠です。
通常、モータドライバ(DRV8313)の下流に入れたシャント抵抗($0.01\Omega$等)の両端電圧を測りますが、発生する電圧は数mVレベルと極小です。
これをADCで読むには数十倍に増幅する必要がありますが、STM32G4は PGA (Programmable Gain Amplifier) 機能付きのオペアンプ を内蔵しています。
- 外付けIC不要: 基板上にオペアンプICを置く必要がなく、省スペース化できます。
- ゲイン可変: ソフトウェアで増幅率(x2, x4, x8...)を変更できるため、低速トルク制御時と高速回転時でレンジを切り替えるような運用も可能です。
- 内部結線: オペアンプの出力はチップ内部でADCに直結されるため、配線ノイズの影響も最小限に抑えられます。
理由⑤:絶対的なリアルタイム性を保証する「CCM SRAM」
制御周期の乱れ(ジッター)は、倒立振子の安定性を損なう要因になります。
STM32G4には、メインのRAMとは別に、CPUコアに直結された CCM SRAM (Core Coupled Memory) が搭載されています。
ここに「モータ制御の割り込み処理プログラム」を配置することで、他のバスマスター(DMAやUSB通信など)の影響を受けず、常にゼロウェイト(最速)での命令実行 が保証されます。
「AI推論が重くてモータ制御が遅れた!」という事態を物理的に防ぐことができるのです。
理由⑥:爆速ログ収集のための「USB 2.0 FS (CDC)」
AIの学習には、大量のセンサデータ(ログ)が必要です。
従来のUART(シリアル通信)では、せいぜい115.2kbps〜921.6kbps程度が限界で、数kHzでサンプリングしたデータを全量PCに送ることは困難でした。
STM32G4は USB 2.0 Full Speed (12Mbps) コントローラ を内蔵しています。
これを USB CDC (Communication Device Class) として実装することで、仮想COMポート経由で 数Mbps級の実効スループット を叩き出せます。
-
メリット:
- 外付けIC不要: USB-シリアル変換IC(FTDIなど)が不要になり、USBコネクタを直結できます。
- 大容量ログ転送: 1msごとに数百バイトの全センサデータ・内部状態変数をPCに垂れ流しても余裕です。
-
低負荷デバッグ:
printfデバッグも爆速になり、通信待ちによる処理落ちのリスクが激減します。
4. ピン配置のパズル:64ピンで足りるのか?
STM32G474には 48/64/100/144ピンのパッケージがありますが、今回は実装面積と手はんだの容易さから LQFP64 を選びました。
しかし、3軸制御には多くのピンが必要です。
- モーターPWM: 3本 $\times$ 3個 = 9ピン
- エンコーダ(I2C): 2本 $\times$ 3個 = 6ピン (※後述)
- 電流センス(ADC): 1本 $\times$ 3個 = 3ピン
- IMU(SPI): SCK, MISO, MOSI, CS, INT = 5ピン
- 通信/デバッグ: USB(2), UART(2), SWD(2) = 6ピン
合計30ピン強。余裕に見えますが、「タイマーのチャンネル割り当て」や「ADCの入力チャンネル」の制約があるため、パズルは複雑です。
難所:I2Cアドレス競合の解決策
採用したエンコーダ AS5600 は、I2Cアドレスが 0x36 に固定されており変更できません。
3つ同時に使うにはI2Cマルチプレクサが必要…と思いきや、STM32G4は I2Cモジュールを4つ(I2C1〜I2C4) も持っています。
- X軸: I2C1 (PB6, PB7)
- Y軸: I2C2 (PA9, PA10)
- Z軸: I2C3 (PC0, PC1)
このように 「贅沢にバスを分ける」 ことで、追加部品なしで解決しました。これができるのがG4の強みです。
5. AIの実装:STM32Cube.AI (X-CUBE-AI)
「Pythonで作ったAIをどうやってマイコンで動かすの?」
ここには、ST公式の STM32Cube.AI を使用します。
ワークフロー
-
学習 (PC): PyTorch/Stable Baselines3 で学習し、
.onnx形式でモデルをエクスポート。 -
変換 (CubeMX): STM32CubeMXのプラグインとして
.onnxを読み込む。 -
分析: 必要なRAM/Flashサイズと、推論時間(MACC)が算出される。
- 今回のモデル (3層MLP): Flash使用量は約10KB、推論時間は数$\mu$s。G474のスペックなら余裕です。
- 生成: 最適化されたCコードが生成される。
コードイメージ
生成されたコードは、以下のようにC言語の関数として main.c から呼ぶだけです。
// 1. センサデータを入力バッファにセット
ai_input[0] = imu.roll_error;
ai_input[1] = imu.gyro_x;
// ...
// 2. 推論実行 (この関数の中身はCube.AIが生成)
ai_run(ai_handle, &ai_input, &ai_output);
// 3. 出力をトルク指令に変換
float torque_cmd = ai_output[0];
FOC_set_torque(torque_cmd);
まとめ
今回の選定は、単にスペックが高いからではなく、「AIとFOCを共存させるための機能(CORDIC, 多チャンネルI2C, 高機能タイマー, 内蔵オペアンプ)」 が揃っているからこそ、STM32G474 を選びました。
OSに頼らず、シリコンが持つペリフェラル機能を限界まで使い倒して「知的」な動きを実現する。これこそが組み込みAI開発の醍醐味です。
次回予告 [Day 9]
部品と機能が決まりました。次はこのパズルを回路図に落とし込みます。 Day 9は 「回路設計 Part 1:STM32G474とモータドライバ」。 KiCadを使い、ノイズに強く、かつ手はんだ可能な回路図を描いていきます。
アドベントカレンダー参加中
STM32×AIで「3軸倒立振子」を作る25日間(ひとりアドカレ)Advent Calendar 2025