はじめに
前回のの続きです。
電流センサ ACS712 を追加します。
ACS712について
SimpleFOCは、基本的に電流センサがなくてもモーターは指示したとおりに動いてくれます。センサがあればもっと精度がよくなるのでしょう。閉ループ制御を謳った業務用モジュールでは、多くは電流センシングできるようです。というわけで電流センサを導入しました。(速度起電圧を利用することでセンサレスにできるそうです。)
まずはSimpleFOCShield v3.2が採用しているACS712にしました。AmazonやAliExplessなどで購入できるため入手性もよく、一個200~400円くらいで安くて助かります。スタートとしてはよいのではと思います。
購入時の注意点として、多くのチップと同様にACS712はバリエーションがあります。計測できる電流最大値が5A、20A、30Aがあります。つかっているブラシレスモーターは5Aで十分です。20A、30Aでも使えないことはありませんが、分解能の低下が懸念されます。ちなみに私は間違えて20Aを買ってしまって、あとから5Aを買い直しました。
写真のように、2列目に ELC-05B と印字されているかで確認できます。
今回は3相ブラシレスモーターを1つにつき電流センサは2個使います。3相なので3つ使うこともできますが、理論的には2個あればよいそうです。
接続
モーターにつながる電流する方法が3つあります。
- ハイサイド電流センシング
- ローサイド電流センシング
- インライン電流センシング
それぞれの仕組みについてはドキュメントを参照してもらえればと思います。SimpleFOCMiniではインライン電流センシングのみ可能です。
接続場所は、モーター線M1・M2・M3のうち2本を使い、間にセンサを入れます。
RCサーボでよく使うJR(日本遠隔制御)配色の3線ケーブルで製作しました。両端にQIコネクタをつけます。
ACS712を取り付けるため、3線の途中を剥がし切断し被覆を剥きます。2個の電流センサの干渉をさけるため、切断位置を少しずらしています。
つぎにセンサ出力と電源を接続するケーブルを作成します。VCCは5Vです。Arduino Uno R4 Minimaには5V出力ソケットが1箇所しかありません。磁気センサにも電力供給しなくてはいけませんので、5Vを3つに分岐させる必要があります。
私は分岐ケーブルを自作することにしました。BECを作るとか、ブレッドボードを使う手も考えましたが、今回はケーブルのほうが邪魔じゃなくていいかなと思いました。
こんな感じで作りました。赤5V、黒GND、白が電流センシングしたアナログ値になります。
赤・黒は5VとGNDにつなぎます。白はANALOG INのA0とA1につなぎました。モーター線のM1・M2の順番どおりに接続しましょう。間違えたらモーターが動きませんでした。
コーディング
グローバルにインスタンスを作成します。
先に引数の2番目、3番目はSimpleFOCMiniのコネクタM1、M2につなげた電流センサのOUTにつながるアナログイン番号を指定します。
電流センサを3つつけたときは、A0, A1, A2
のように書きます。デフォルトは_NC
で未使用という意味になります。
InlineCurrentSense current_sense = InlineCurrentSense(185.0f, A0, A1);
引数1番目はA(アンペア)あたりのmVです。ACS712データシートによるとTpy. 185 mV/Aとあるので、そのまま185.0fを指定します。
グラフを見ると、0Aのとき2.5Aが出力されます。実際には誤差があるので、current_sense.init()で初期化するときに0Aのときの測定値を使います。
-5Aから+5Aまできれいな比例になっています。
温度による変化は小さそうなので無視してよさそうです。
セットアップを行います。BLDCMotor::init()
をコールする前にBLDCMotor::linkCurrentSense()
で登録を済ませます。
void setup() {
...
current_sense.linkDriver(&driver);
current_sense.init();
motor.linkCurrentSense(¤t_sense);
motor.init();
motor.initFOC();
...
}
loop関数では特にやることはありません。ライブラリ内部で実行されます。
ジンバルモーター、SimpleFOCで動かす(4) - Teleplotでグラフ表示で紹介したTeleplotで電流センサ値を表示する場合は、REG_CURRENT_A, REG_CURRENT_B
を登録します。
uint8_t reg[] = { REG_TARGET, REG_ANGLE, REG_VELOCITY, REG_CURRENT_A, REG_CURRENT_B };
telemetry.setTelemetryRegisters(5, reg);
または、メンバ関数でも値を取ってこれるので、シリアル出力などお好みに合わせて利用できます。
PhaseCurrent_s currents = current_sense.getPhaseCurrents();
float current_magnitude = current_sense.getDCCurrent();
Renesas RA4M1のADC14bit読み込み
記事を書いている2024年7月時点のマニュアルによると、Arduino Uno R4は未対応(TDB)となっています。とはいえ、Arduinoライブラリがハードウェアの違いを吸収してくれるのでアナログ値を問題なく読み込むことができます。
この場合、ADCは10bit精度、つまり0~1023の値になります。
Arduino Uno R4のRenesas RA4M1は、ADCを最大14bitで読むことができます。せっかくなら使いたいところです。
ビット数の変更は簡単で、analogReadResolution(14)
とコールするだけで変更できます。
InlineCurrentSenseクラスが内部でハードウェア依存部分としてコールする_configureADCInline()
をコーディングします。
なお、インライン電流センシングのみになります。ローサイドのときは同期するためにタイマ割り込みするので、さくっとコーディングとはいきません。
動作確認するとちゃんと動いてくれました。14bitの分解能が活きているような気はしないですけど😅
#include <current_sense/hardware_api.h>
#if defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA)
#define _ADC_VOLTAGE 5.0f
#define _ADC_RESOLUTION_BIT 14
#define _ADC_RESOLUTION 16384.0f
// function reading an ADC value and returning the read voltage
void* _configureADCInline(const void* driver_params, const int pinA,const int pinB,const int pinC){
_UNUSED(driver_params);
analogReadResolution(_ADC_RESOLUTION_BIT);
if( _isset(pinA) ) pinMode(pinA, INPUT);
if( _isset(pinB) ) pinMode(pinB, INPUT);
if( _isset(pinC) ) pinMode(pinC, INPUT);
GenericCurrentSenseParams* params = new GenericCurrentSenseParams {
.pins = { pinA, pinB, pinC },
.adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION)
};
return params;
}
#endif
おわりに
次回、SimpleFOCStudioについて書いてみたいと思います。