STM32に永久磁石同期モータ(Permanent Magnet Synchronous Motor)のエンコーダ付きベクトル制御を実装し、実際にモータの動作確認を行いましたので紹介させて頂きます
開発環境はVSCodeの拡張機能のPlatformIOとコード生成ツールのSTM32CubeMXを組み合わせた環境にて構築しています
詳細につきましては以下記事を参照下さい

また、デバッグ用のシリアル通信による標準入出力とSTM32CubeMonitorによる変数モニタについては以下記事を参照ください


ハードウェア構成(nucleo-G474RE+X-NUCLEO-IHM16M1)
マイコンボードはnucleo-G474REを使用し、モータドライバ回路はnucleoの拡張ボードX-NUCLEO-IHM16M1を使用しました
X-NUCLEO-IHM16M1は低圧の三相インバータ回路で3シャント電流検出回路を搭載しています
三相インバータ回路の概要については以下記事を参照ください

また、ブラシレスDCモータは手持ちにあった日本電産のFH6S20E-X81という14極のSPMモータを使用しました
FH6S20E-X81にはホールセンサと2相インクリメンタルエンコーダが搭載されています
今回はインクリメンタルエンコーダのみを使用しました
X-NUCLEO-IHM16M1を使用するにあたり、デフォルトの回路構成より一部変更しました
- R12(0Ω)を取り外し、R11に取り付け
→デッドタイム生成機能を無効化(マイコン側で対応) - R86(0Ω)を取り外し
→T_SWO(PB3)とH2信号(エンコーダB相信号)を分離


X-NUCLEO-IHM16M1はSTSPIN830に内蔵のコンパレータにて過電流検出回路を構成していますが、U相にしか繋がっていません
これでは過電流検出回路としては不十分なので過電流検出についてはマイコンに内蔵のコンパレータも使用して構成するようにしました(詳細は後述)

STM32CubeMXの設定(TIM+ADC+DAC+COMP)
モータ駆動用の三相相補PWM出力と3シャント電流検出回路のためにPWMに同期したA/D変換を構成する必要があります
また、今回はエンコーダで位相検出を行うため、エンコーダパルスの取り込みを行う必要があります
具体的な設定内容は以下記事の内容をそのまま使用しました


一点だけ、先にも述べた通り過電流検出については不十分なところがあるためマイコンで過電流を検出するように追加で設定しました
使用するモジュールはCOMPモジュール(コンパレータ)とCOMPの基準電圧を生成するためのDACモジュールです
COMPモジュールで過電流検出を行い、TIM1のPWM出力を遮断する機能を構成します
それぞれ各相電流ごとに設定する必要がありますが、先ほど紹介した記事の設定の通りであれば下記表の通りとなります
A/Dポート | COMPポート | DACチャンネル | |
---|---|---|---|
U相電流 | ADC1_IN2(PA1) | COMP1_INP | DAC1_OUT1 |
V相電流 | ADC2_IN14(PB11) | COMP6_INP | DAC2_OUT1 |
W相電流 | ADC3_IN12(PB0) | COMP4_INP | DAC3_OUT2 |
以下はU相電流用(DAC_OUT1)の設定ですが、V相、W相に対しても同様に設定します

まずは各相電流検出用のA/Dポートにコンパレータのポート機能を追加します
下記のように端子設定画面から追加で選択を行えばOKです

次に各COMPモジュールの設定です
以下はU相電流用(COMP1)の設定ですが、V相、W相に対しても同様に設定します

COMPモジュールで検出した結果をTIM1のBRKの検出要因に追加します

ソースコード
ソースコードはGitHubにて公開しております
STM32CubeMXが出力したコードから手を加えたファイルは以下の通りです
- main.c
・初期設定の処理を追加(各HALドライバのStart関数など)
・回転数指令値を発行する処理を追加
・BRK割り込み処理を追加 - motorControl.c(追加ファイル)
・モータ制御に係る処理を記述 - define.h(追加ファイル)
・パラメータを記述 - serial.c(追加ファイル)
・標準入出力用 - syscalls.c(追加ファイル)
・標準入出力用
なお、定時処理用にTIM6も設定してますが今回は未使用です
制御仕様
基板に搭載のプッシュスイッチにて運転/停止状態を切り替えられるようにしました
なお、電源投入後の初期状態は停止状態です(一度押すと運転状態に遷移し、もう一度押すと再び停止状態に遷移)
基板に搭載のボリューム抵抗で回転数を変えられるようにしました(0~2,000rpm)
なお、X-NUCLEO-IHM16M1に搭載のボリュームは左回しで検出電圧値が上昇する極性となっており、回転数も電圧値にならって上昇するようにしています
直感的には右回しで上昇だと思いますので反転した方が良いかもしれません
今回のモータはインクリメンタルエンコーダなので初回運転時に初期位置合わせの動作を行います
具体的にはオープンループで少しだけ(1/40回転くらい)モータを回転させて位相を特定しています
オープンループで回転させているので以下のような問題点があります
- 若干逆方向に回転する可能性がある
- モータの負荷状況によっては回転しない可能性がある
①については少なくとも体感ではわからないレベルだと思いますが、少しの逆転も許されないようなアプリケーションではNGとなります(そんなのに使用されることはないと思いますが・・・)
②については必要に応じてオープンループ制御のところの調整が必要となります
- オープンループ制御時に流すd軸電流をより大きくする(今回は0.5A流す設定)
- オープンループ制御時の加速度を緩やかにする(今回は約8.5rpmまで1msで加速)
今回の記事はあくまでも紹介なので詳細の説明は割愛いたします・・・
なお、初期位置合わせ失敗時の処理などは実装していません(実用性考えるのであれば実装すべきだと思います)
ベクトル制御(d軸電流=0A)で回転数一定制御としています
また、今回のモータはエンコーダの1パルスカウントあたり電気角で2.1度とかなり粗いのでPLL制御にて位相補完を行っております
今回は回転方向は一定方向としておりますが、回転数指令値をマイナスにすれば(多分)逆方向にも回ると思います
位相制御までは実装していませんが、ボリュームを右一杯回し(0rpm指令)とすればなんちゃってサーボロック状態にはなります
プッシュスイッチで停止した場合はフリーラン停止となります
初期位置合わせ後は停止中も位相を更新しているので、たとえフリーラン停止中に運転開始したとしてもシームレスに起動します
モータ電流(ピーク値)が2.0Aに達したら過電流異常として保護停止するようにしています
過電流検出はCOMPモジュールとDACモジュールにて実現しています
電流検出回路はモータ停止中にオフセット電圧値の補正を行っていますが、それに応じてDACモジュールが生成するCOMPモジュールのリファレンス電圧にも補正をかけるようにしています
動作確認結果
写真では伝わらないと思いますが2,000rpmで動作中の写真です
音や振動もなくかなり静かに回ってます

以下はSTM32CubeMonitorで測定した結果です
いかんせん無負荷動作なので電流などはまともなデータではないので回転数のデータのみ測定しました
ほとんど重なってますがオレンジ色が回転数指令値で青色が回転数検出値です(いずれも電気角速度)
運転開始して数秒後に運転停止したときの波形です

起動時の拡大波形です
なお検出値の方はマイコン内部でローパスをかけた結果を表示しています

停止はフリーランですが停止中に再起動することも可能です
以下はいじわる操作で運転と停止を短時間で繰り返したときの波形です
さすがエンコーダといった感じできちんと追従出来てます

次の波形は初期位置合わせを行ったときの位相のデータです
初期位置合わせはそのときのロータの位置によってすんなり終わる場合と少し時間がかかる場合があります
今回の波形は時間がかかったときで、電気角でほぼ1周期オープンループ制御で回転してからロータ位置を確定しています
青色が制御で使用しているPLL制御で補完した位相情報、オレンジ色が補完前のエンコーダパルスで検出した生の位相情報、緑色がそれらの偏差(位相誤差)です(いずれも電気角)
なお途中の歯抜けになっている部分は測定側(STM32CubeMonitor)側の問題できちんと取り込めていない部分だと思います

最後はなんちゃってサーボロックの波形です
回転数指令値は0rpmで運転開始してモータ軸を手で回そうとすると妨げる方向にトルクが発生します
オレンジ色が位相で青色がq軸電流指令値です
位相制御をしているわけではないのであくまでもなんちゃってですが、きちんと回転を妨げるようにトルクがかかっている様子が見て取れるかと思います
