Arduino で ブラシレスDCモータ 用 ESC を作る ~ オープンループ制御編 ~

Blog

こんにちは。このブログを運営するサークルにおいて、絵描き担当の雫です。

趣味でドローンをやっているのですが、自分が扱うようなドローンは、100g 未満の機体で 5A とかの大きな電流を制御してブラシレスモーターを高速で回転させて飛行しています。

ロジックICやマイコンでキャッキャするような電子工作しかしてこなかった自分からだと、1A とかでも結構怖いのに、もう 5A もぶち流れるとすべてが燃えてしまいそうな気がしてきます。

とか考えてたら自分で作りたくなってきちゃったので、原理調べてブラシレスモーターを動かしてみようと思います。

ざっくり原理

ブラシレスDCモーターについて

こんな感じの見た目をしています。

回路的には、コイル(電磁石)が Y結線 で3つ入っていて、その周りにネオジム等の強力な永久磁石がついている、回転子があります。

回路図にすると以下のような感じです。

まさに Y結線 って感じの見た目をしていますね。

一応説明すると、3相交流を突っ込んで、回転磁界を作り、磁石でできた回転子を回します。
そのため、3相分のコイルがあります。

中性点とは、3つのコイルを束ねる個所です。

もう少し具体的に、ブラシレスモーターがどうなっているか図解してみました。

このようにコイルと磁石が並んでいて、一番外側の円が回転子になります(アウターロータ方式)。

わかりやすく中性点を書きましたが、実際のブラシレスモーターは3本しか線が出ていません。

これは、中性点は内部で結線されていて、3つのコイルの端のみが端子として出ているためです。

世の中には デルタ結線 のブラシレスモーターもありますが、ドローン用のモータはほとんど Y結線 なので、今回はスルーします。

ブラシレスDCモータを制御するには

先ほどの説明を見るとわかると思いますが、ブラシレスDCモータは、よくあるブラシ付きモータとちがい、ただ電流を流すだけでは回ってくれません。

実際、適当に2端子の間に電圧を印可すると、回転子がビク!!って動いて止まります。

じゃあどうやって回転させんのや!!

ブラシレスDCモータを回転させるには、ESC (Electronic Speed Controller) という制御装置を用います。

こんな感じの商品が結構出回っています。

Amazon.co.jp

この ESC というパーツが何をしているのかというと、超ざっくり、
「3相交流っぽい波形を作って、ブラシレスモータに突っ込む」
ってことをしています。

なんで3相交流???って理由は、東芝さんの動画が分かりやすかったです。

この3相交流の周波数を高くしたり低くしたりして、モータの速度を制御しています。

↑の動画では、センサを用いて適切な電流をコイルに流し込む前提で話されていますが、本記事では、そんなことしません。ただ波形作ってぶち込むだけです

こういう、自分勝手な制御方法を、オープンループ制御といいます。

今回の記事は、オープンループ制御 ESC を自作してみよう!の入門記事となります。

実際に作ってみた

ぐだぐだ言っててもつまんないので、本記事のいったん最終系ドーン

下の写真のように組んでみました。

電流がめっちゃ流れるので、ブレッドボードでは怖すぎますが、実験なのでまぁ目をつぶってください。

以下は動作している様子です。

回転位置を把握したりなど、何もしていないのでガンガン脱調しています

まぁでも風を起こすくらいはトルクが出せたのでまぁ良しとしましょう。。。

筆者は全くもって電子回路に精通していないので、計算もなんもせずに雰囲気で調整しています。
なので、変な箇所があると思いますがご容赦ください。(ツッコミコメントいただいても歓迎です…)

ESC の構成要素

さて、ざっくりどういう要素があるのかを解説していきます。下の画像をご覧ください。

構成要素は、

  • 制御マイコン
  • ゲートドライバ
  • 3相ブリッジ
  • ブラシレスモーター

の4つです。

このうち、制御マイコン+ゲートドライバ+3相ブリッジの組み合わせを ESC といいます。

この要素がそれぞれどういった役割なのかを説明します。

制御マイコン

ESC は、ブラシレスモータのために、高い電圧・多い電流で3相交流に近い波形を生成しなければなりません。

波形を作る手段はいろいろあるのですが、マイコンでタイミングを計算しながら波形を作ってしまえば、周波数の変更など、いろいろ融通が利きそうです。

しかし、マイコンは大きな電力を扱えないので、もっとパワフルな部品 (MOSFETやIGBT) を介してモータを制御しないといけません。なので、ESCのマイコンは、パワフルな部品を使って3相交流っぽい波形を作れるように、制御信号を作ることに専念します。

ゲートドライバ

なんで必要なのかは、後にハーフブリッジの説明をしますが、その時に詳しく触れます。

ゲートドライバは、マイコンの制御信号通りに、
パワフルな部品 (MOSFETやIGBT) を駆動させるための部品です。

今回は楽をしたいので、専用のICを使っています。

3相ブリッジ

クソデカ電力を制御するための部品です。

これをいい感じに接続して、3相交流っぽい波形が出せるようにしてあります。

具体的にはハーフブリッジを3つ作ってあります。

ブラシレスモーター

さっき説明したので割愛

まずは1相だけで考えてみる

ブラシレスモーターを回すには、例えば +12 V から -12V までの間で120度ずつ位相がずれたサイン波=3相交流を作る必要があります。

いきなり3相交流を作ろうと考えると、理解が追い付かないので、一個ずつ理解していきましょう。

直流から交流に変換する

電源はバッテリーなどの直流電源しかありません。そのままでは正から負の電圧にかけての波が作れません。

直流からどうやって、正の電圧から負の電圧の波を作っているのか見ていきましょう。

ハーフブリッジ回路

使用されている部品は FET です。

このFETという部品は、S(ソース)よりも一定以上高い電圧G(ゲート)に加わると、D(ドレイン)とS(ソース)の間が導通するようになります。

つまり、G に電圧をかければONになるスイッチのように扱えます。(雑)

上の回路では、「HiサイドA」と「LoサイドA」が G に接続されています。ここに制御信号を突っ込んで、OUTの状態を変化させます。

1 = 5Vくらいを印可している状態として、こんな感じのパターンになります。

HiサイドALoサイドAOUTの電位
01GND
10+12V
11短絡してやばい
00どっちでもない浮いてる電位

下二つは今は考えません。

上二つのように、OUTの電位をGNDと+12Vにするような制御ができますね。

ブートストラップ回路

しかし、ここで一つ問題が発生します。

Hiサイド側のFETに注目してください。

先ほど説明した通り、FETは、S(ソース)よりも一定以上高い電圧G(ゲート)に加わると、D(ドレイン)とS(ソース)の間が導通するようになります。

OUTの電位と、Hiサイド側のFETの S の電位は同じなので、S の電位が定まらない問題があります。
これでは、G に何Vを印可すれば Hi サイドが制御できるかわからないので、困ってしまいます。

これを楽に解決するため、専用のゲートドライバIC (今回はIR2302) を使用します。

ゲートドライバIC一つと、電解コンデンサ1つ、あとはダイオードを一個追加しました。

重要なのは電解コンデンサです。

このように、LoサイドのFETを駆動中に、Hiサイドを駆動させるための電力を蓄電します。

Hiサイド駆動時にコンデンサとG-Sをつなぎ、放電させ、G-S間に、FETの駆動に必要な電位差を作り出します。

これを、ブートストラップ回路とか言います。

コンデンサを使用しているため、ずーっとHiサイドをONにし続けることができません。
そのため、これは比較的高速な切り替えをする前提の方式ですので注意してください。
といっても、ESCを作る=高速なスイッチングするので気にしなくていいんですが。

全部結線されているとみにくいので、ラベルで置き換えておきましょう。

IR2302 ゲートドライバ IC

ゲートドライバは、IR2302 というものを使用しました。理由はその辺に転がっていたからです。

SignalA には 1 (+5V) か 0 (GND) を入力します。

タイミング ダイアグラムは以下のような感じです。

シャットダウンピン (SD) がありますが、今回の記事では SD は 1 固定にします。

IR2302は、
IN が 1の時は、Hiサイドの FET を ON 、Lo サイドを OFF
IN が 0 の時は、Hiサイドの FET を OFF、Lo サイドを ON
にします。

INSDHiサイドFETLoサイドFET
11ONOFF
10OFFOFF
01OFFON
00OFFOFF

つまり、Hi と Lo が同時に ON になって短絡してやばいことにはならないようにしてくれます。

さらに、一本で Hi 側と Lo 側を楽に制御できますね。(Hi、Lo別々で制御したい場合のほうが普通だと思うけど、今回は楽なこと重視で)

2相や3相に増やして考えてみる

フルブリッジ

ハーフブリッジが大体わかったと思うので、次は同じものを2つ用意してみましょう。

A相B相を用意しました。

OUT と書かれている場所に流れる電流の方向を見てみます。
左から右に流れた場合 +12V逆は -12V ということです。

SignalAHiALoASignalBHiBLoBOUT→
0010010V
110001+12V
001110-12V
110110は?

ハーフブリッジを2つ用いることで、こういったパターンで電流の方向が制御できるようになります。

この、ハーフブリッジを2つ合わせた回路を、フルブリッジとかHブリッジといいます。

3相ブリッジ

さて、1つのハーフブリッジから、2つ使ったフルブリッジまでをざっくりやってきました。

ここまで来たら、もう1相増やしてもやることは変わんないですね。

ちょっと収まりが悪かったのでレイアウトを変えました。

もうこれでほとんど ESC の駆動部分は完成です。あとは、ちょっとした補助部品を挟んで、狙った動きになるように調整していくだけです。

一応説明しておきますね。

ブラシレスモータは、以下のように接続します。

図の通りに、3つのコイルが接続された状態になります。

ブラシレスモータを動かすことを考え始める

さて、ついにブラシレスモータのことを考えられる段階まで来ました。

3相ブリッジに接続されたコイルをよく見てみましょう。

例えば、A相→B相に電流が流れるように、HiAを1、LoBを1とすると、AとBのコイルが磁化し、極性を帯びます。

すると、回転子についている永久磁石が引き寄せられて、回転子が回転します。

電流を流す方向と、回転子の移動の様子を簡易的な図にしてみました。

ブラシレスモータは、電磁石を放射状に配置しているため、回転子に影響を与える極性は、外側の極だけです。なので、内側の極は無視して考えます。

出っ張っているのがコイル = 電磁石を表しています。
緑色の矢印が、コイルに流す電流の向きです。
また、回転の様子が分かりやすいように、黄土色で方向と向きに印をつけました。
(実際には、回転子が回転しきるまえ(つまり図の状態になる前)に、次の状態に持っていくことで回転し続けさせます。)

この図はかなり省略して書いていて、実際は磁石やコイルの数はこれの4倍以上あります。でも、概念的にはこれと等価なので、理解するには有用かな~と。

いざ実装

さて、ここまで理解すれば、あとはもう現実世界で実装するだけです。

実際に電流を制御するハードウェアと、ハードウェアの制御をするソフトウェアを作っていきましょう。

ハードウェア編

先ほどまで紹介していた回路だけだと、動きはしますが実際動かしてみると、とてつもなくスカスカなトルクで悲しくなります

原因はいろいろあって、
モータを回すと、逆起電力 (BEMF) が生まれますが、こいつが本来流したい方向の電流を打ち消してしまったりします。
また、突発的な電力を賄いきれずに信号がなまったり逆に鋭い信号すぎてもまずい個所とかもあります。

こういった電気的な不具合をどうにかするために、いくつか部品を追加しましょう。

モータの逆起電力を逃がす

FETをOFFにした瞬間に、まだ回転子が慣性で回って動いているため、モータから逆起電力が発生します。

これを放っておくと、FETが耐圧以上の電圧を食らって壊れたり、逆起電力の流れ先がなくなって、モータにブレーキがかかってしまいます。

そこで、逆起電力を逃がすように、ショットキーバリアダイオードを使用します。

ショットキーバリアダイオードは、Vf (順方向電圧) が低いです。つまり、順方向の電流なら、高速でONになって電流を流してくれます。

FETには、構造的に、内部にダイオードが存在します。しかし、ただの PN 接合のため遅くVfが高く、発熱したりします。そのため、外付けで高速なショットキーバリアダイオードをつけます。

モータからの逆起電力を、内部にある遅いダイオードでせき止めずに、S から D 側へ逃げるようにしてあげます。

こうすることで、使用していないコイル等から発生した余計な逆方向のトルクを抑え、スムーズにモータを回すことができるようになります。

ゲートドライブの電源を強化

ゲート駆動用の出力 (HOとLOからの出力)を、意図したタイミング以内にしっかり立ち上げるために、十分な給電をしたいです。

そのため、ゲートドライブ IC の電源ラインに並列に、なるべく近くに 10 μF くらいのセラミックコンデンサを配置します。

(ついでに、シャットダウンピンも使えるように外に出しときました)

とりあえずブレッドボードで回路作成

これをブレッドボードに実装していきます

ゲートにプルダウン抵抗とかが刺さっていますが、いりませんでした。

ソフトウェア編

最初はメインループ void loop() {} 内で処理をしていましたが、生成できる波形の周波数の限界が、クロック周波数に対して低すぎるのと、割り込み等で波形が崩れるため、タイマ割込みで実装しなおしました。

#include <avr/io.h>

#define PWM_FREQ 62500
#define SAMPLES 256
#define TIMER_INTERRUPT_FREQ 4000

uint8_t outputSinStep = SAMPLES / 4;
const int pinA=3;
const int pinB=5;
const int pinC=11;

uint16_t WP_A = 0;  
uint16_t WP_B = SAMPLES *2/ 3;
uint16_t WP_C = SAMPLES / 3;

float sinwave[SAMPLES]={0};

void setupPWM(uint8_t pin, uint32_t frequency) {
    uint8_t prescalerBits = 0b010; // default divide by 8
    uint16_t prescalerVal = 8;

    if (frequency >= 62500) {
      prescalerBits = 0b001; prescalerVal = 1;
    } else if (frequency >= 31250) {
      prescalerBits = 0b010; prescalerVal = 8;
    } else if (frequency >= 15625) {
      prescalerBits = 0b011; prescalerVal = 64;
    } else if (frequency >= 3906) {
      prescalerBits = 0b100; prescalerVal = 256;
    } else {
      prescalerBits = 0b101; prescalerVal = 1024;
    }

    switch (pin) {
      case pinA:
        pinMode(pinA, OUTPUT);
        TCCR2A |= (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);
        TCCR2B = (TCCR2B & 0b11111000) | prescalerBits;
        break;

      case pinC:
        pinMode(pinC, OUTPUT);
        TCCR2A |= (1 << COM2A1) | (1 << WGM21) | (1 << WGM20);
        TCCR2B = (TCCR2B & 0b11111000) | prescalerBits;
        break;

      case pinB:
        pinMode(pin, OUTPUT);
        TCCR0A |= (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
        TCCR0B = (TCCR0B & 0b11111000) | prescalerBits;
        break;

      default:
        break;

    }
}

void changeDuty(uint8_t pin, uint8_t d) {
    switch (pin) {
        case pinA:
            OCR2B = d;
            break;
        case pinB:
            OCR0B = d;
            break;
        case pinC:
            OCR2A = d;
            break;
    }
}

void analogMode() {
  WP_A = (WP_A + outputSinStep) % SAMPLES;
  WP_B = (WP_B + outputSinStep) % SAMPLES;
  WP_C = (WP_C + outputSinStep) % SAMPLES;

  changeDuty(pinA, sinwave[WP_A]);
  changeDuty(pinB, sinwave[WP_B]);
  changeDuty(pinC, sinwave[WP_C]);
}

void setupTimer1Interrupt(unsigned int freq) {
  TIMSK1 &= ~(1 << OCIE1A);

  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  unsigned int compareMatch = (16000000 / (8 * freq)) - 1;

  OCR1A = compareMatch;
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS11);
  TIMSK1 |= (1 << OCIE1A);

  TIMSK1 |= (1 << OCIE1A);
}
 
void setup() {
  int pwmLimit = 15;
  for (int i = 0; i < SAMPLES; i++) {
    sinwave[i] = sin(2.0 * PI * i / SAMPLES) * (127.0 - pwmLimit) + (128.0);
  }
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);

  setupPWM(pinA, PWM_FREQ);
  setupPWM(pinB, PWM_FREQ);
  setupPWM(pinC, PWM_FREQ);

  setupTimer1Interrupt(TIMER_INTERRUPT_FREQ);
}

ISR(TIMER1_COMPA_vect) {
  analogMode();
}
 
void loop() {
  float val = analogRead(A0) / 1024.0;
  unsigned int step = (unsigned int)(val * SAMPLES/4 - 1) + 1;

  outputSinStep = step;
}

ざっくりコードをの動きを説明すると、「3相 sin 波を PWM で出力するプログラム」です。

arduino の D3, D5, D11 ピンを使用しています。

また、正弦波をどれくらい細かく再現するかを決めるために、 A0 ピンのアナログピンを使用しています。

ISR(TIMER1_COMPA_vect) で sin になるように デューティー比を変更しています。

上部にある、以下の定数

#define PWM_FREQ 62500
#define SAMPLES 256
#define TIMER_INTERRUPT_FREQ 4000

これらを調整して実験できるようにしてあります。

例えば、#define TIMER_INTERRUPT_FREQ 4000 とすると、かなりゆっくりモータを回すことができたりします。

最後に

以上で、arduino で作る ESC のオープンループ制御編は終わりとなります。

ほんとはソフト側が一番試行錯誤したのですが、この後書こうと思っているセンサレス制御編のほうが重要なのであんまり語らないようにしておきますw

では、また~!

コメント

タイトルとURLをコピーしました