クローズドループ正弦波駆動 その1 ーブラシレスモータ駆動への道5ー
前回はオープンループでのブラシレスモータ正弦波駆動を確認しました。
矩形波駆動では出来なかった低速回転が実現され大変満足した次第です。
ここからはセンサを用いてモータの回転位置をフィードバックしたクローズドループ正弦波駆動に挑戦したいと考えております。
目次
オープンループ正弦波駆動 BLE制御
クローズドループにとりかかる前に復習をかねて、BLEで回転速度や正転・逆転切り替えをできるようにしました。
正弦波駆動によってセンサレス矩形波駆動では実現できなかった低速回転が実現されています。
最新版のBlynkではBLEが使用できないので、以前のバージョンのBlynkレガシーを使用してBLE通信しています。
磁気エンコーダ
クローズドループに向けてモータの回転位置を把握するために磁気エンコーダ AS5048 を購入したしました。
AS5048はインターフェースがSPIで付属の磁石の回転を1周 14 bit (16384)でエンコードします。
付属の磁石は面の上下が磁極になっていました。
以下では磁石の磁場をマグネットビューアシートでみています。
専用の磁気エンコーダケースを設計し3Dプリントしてロータに磁石をつけてブラシレスモータと一体化しました。
ブラシレスモータは以下を使用。極数は14。
エンコーダ動作
エンコーダの電源とSPI配線をESP32に接続して、動作確認しました。
以下は手回し。
磁気エンコーダ
回転位置を把握できる人になった
#ブラシレスモータ駆動への道 pic.twitter.com/eLJ8hhnOU6
— HomeMadeGarbage (@H0meMadeGarbage) May 5, 2022
AS5048のライブラリとして以下を使用しました。
https://github.com/eborghi10/AS5048A
オープンループで回して、エンコーダ値を見てみました。
エンコーダ値が1巡 (モータが1回転) する間にブラシレスモータのu, v, w相にはそれぞれ7周期の正弦波が印可されています。
これはロータの磁石が14個 (7ペア)のモータを使用したためです。
クローズドループ検討
矩形波駆動の時のように速度を指定して回転させる制御を実施したかったのですが現状うまくいっておらず勉強中のため、ここではモータの回転位置を可変抵抗で指定してモータを動かしてみました。
構成
前回のものに磁気エンコーダ AS5048 を追加した構成となります。
Arduinoコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
#include <AS5048A.h> AS5048A angleSensor(SS, false); #define periodPin 36 #define ampPin 39 #define uHin 25 #define vHin 26 #define wHin 27 int uPWMCH = 0; int vPWMCH = 1; int wPWMCH = 2; float uSine, vSine, wSine; int period, amp; float K; unsigned long oldTime = 0, nowTime, rotTime; int State = 0; uint16_t rotData; int u = 0, v, w; int i = 0; int diff; //Core0 void rotPosition(void *pvParameters) { for (;;){ rotData = angleSensor.getRawRotation() >> 5; } } void setup() { Serial.begin(115200); angleSensor.begin(); Blynk.setDeviceName("motor"); Blynk.begin(auth); ledcSetup(uPWMCH, 20000, 10); ledcAttachPin(uHin, uPWMCH); ledcWrite(uPWMCH, 0); ledcSetup(vPWMCH, 20000, 10); ledcAttachPin(vHin, vPWMCH); ledcWrite(vPWMCH, 0); ledcSetup(wPWMCH, 20000, 10); ledcAttachPin(wHin, wPWMCH); ledcWrite(wPWMCH, 0); //回転位置検出 タスク xTaskCreatePinnedToCore( rotPosition , "rotPosition" // A name just for humans , 4096 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 1 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL , 0); } void loop() { period = 511 - (analogRead(periodPin) >> 3); K = analogRead(ampPin) /300.0; diff = period - rotData; if(diff > 0){ u++; }else if(diff < 0){ u--; } v = u + 512.0 * 2.0 / 3.0; w = u + 512.0 / 3.0; u = u % 512; v = v % 512; w = w % 512; amp = abs(diff) * K; amp = constrain(amp, 0, 1023); uSine = amp *(1.0 + sin(2.0 * PI / (512.0 / 7.0) * u)) / 2.0; vSine = amp *(1.0 + sin(2.0 * PI / (512.0 / 7.0) * v)) / 2.0; wSine = amp *(1.0 + sin(2.0 * PI / (512.0 / 7.0) * w)) / 2.0; ledcWrite(uPWMCH, int(uSine)); ledcWrite(vPWMCH, int(vSine)); ledcWrite(wPWMCH, int(wSine)); Serial.print(K); Serial.print(", "); Serial.print(rotData); Serial.print(", "); Serial.println(period); } |
疑似正弦波を生成するためにドライバ駆動ピン(IO25~27)はledcWriteを用いて20kHz PWM出力します。分解能は10ビット(0~1023) (L. 44-52)。
モータの回転位置rotData をデュアルコアのcore0で検出しています。
1周の分解能を14bitから9bit (512)にしています (L. 32)。
可変抵抗でモータの位置period を0~511で指定します (L. 67)。
指定した位置とエンコーダによる実際の位置の差diff を導出し (L. 71)、その正負によって回転させるための正弦波のU相の位相のインクリメント・デクリメントを決定します(L. 73-77)。
V相とW相はそれぞれ120°づつ位相をずらします (L. 79, 80)。
正弦波の振幅は回転位置の差diffに比例させて定めます(P制御) (L. 86, 87)。
比例係数Kはもう一方の可変抵抗で調整できるようにしました (L. 68)。
上位の位相と振幅に従って正弦波を生成します (L. 89-95)。
正弦波の周期はモータが1周(分解能512)する間に7周期となるようにしています。
動作
動作は以下の通り、可変抵抗で指定した位置にモータが移動します。
手でずらしても指定の位置に戻ります。
比例係数Kは2.5ほどで安定動作しました。
クローズドループ正弦波駆動
一旦回転制御はあきらめて、角度指定検証
P制御でいい感じでございます。#ブラシレスモータ駆動への道 pic.twitter.com/YVsYwAzmBa— HomeMadeGarbage (@H0meMadeGarbage) May 23, 2022
参考
おわりに
ここでは磁気エンコーダを用いたクローズドループ正弦波駆動で位置指定による回転追従動作を確認いたしました。
回転速度を指定した回転動作は現在猛勉強中ですので、後日できましたら報告したいと考えております。
こんにちは、趣味でBLDCモータドライバを作っている者です。
手でずらして、その位置で保持した時のモータの挙動を教えていただきたいです。