Arduinoで制御プログラム(ソース)も自作しています。ある程度は制御できるようになってきましたので、まだまだ改良中ですがプログラムの中身を少しずつ紹介していきたいと思います。
今回は「モーターの回転制御」の部分、Arduinoでブラシレスモーターを制御する方法を少し詳しく紹介します。
▼ドローンテスト飛行▼
操縦が難しいです・・・。
▼これまでのドローン製作記録はこちらに纏めていってます▼
まずはプログラムの概要から・・
制御プログラム(アルゴリズム)の概要
流れはこんな感じです。なるべく簡素にしたかったのでループ制御のみで行ってます。データ送受信とモーター制御(PWM出力)もループの中で処理しているのでここら辺がネックで4ms(250Hz)の制御周期となってます。もう少し高速に処理したいところです・・。
今回紹介する「モーター制御」の部分は以前にも記事投稿したのですが、もう少し詳しく説明したいと思います。
ブラシレスモーターは普通のDCモーターと違い、通電すれば回転するというわけではないため、マイコンから制御するにはハード、ソフトともに工夫が必要です。がESCを使用すればハード、ソフトともに随分敷居が低くなるため、Arduino + ESC(Electronic Speed Controller)の組み合わせでブラシレスモーターを制御します。
回路
右のほうに4つ縦に並んでるのがESCです。モーター数分のESCが必要となります。
ArduinoとESCは、信号線とGNDを接続しておくだけでO.K。今回、信号線は3,5,6,9のPWM用のpinに接続してます。説明を簡単にするためで、このpinを使用しなくも制御できます。
ArduinoからESCへの制御信号
ESCへの制御信号ですが、最近ではいろいろなプロトコルがあるようです。今回はPWM信号で制御してみます。ラジコン等のサーボモーターと同様の考え方です。
ArduinoからESCへ制御信号を出力することでESCが信号に合わせてモーター回転をコントロールしてくれます。
▼一般的なサーボモーターの制御信号(PWM)は▼
このような感じです。ドローン(ラジコン)の場合は、パルス幅を1000μs~2000μsで可変させることでモーター回転の速度をコントロールしてます。
ただこの信号の場合、制御周期が50Hz(20ms)と遅いです。モーター最速(パルス幅2000μs)でもLow時間が18ms程度あり、無駄な時間が非常に長いです。ドローンの制御で50Hzというのは遅いため、周期を可能な限り短くして制御します。
パルス幅がモーター最速で2000μs必要となるため周期の最速はおのずと500Hz未満が限界となります。500Hz信号対応と謳っているESCはこのことだと思います。500Hz以上を出そうとすると波形が破綻します。
さらに今ではもっと進んだプロトコルがいろいろあり、Oneshot125というものではパルス幅をおよそ125μs~250μsにすることでさらに高速な制御を行っているようです。Oneshot42やMULTISHOTというのも、さらにパルス幅を短くしてより高速な制御を行えるもののようです。ここら辺はモーター回転の分解能を犠牲にしているのでしょうかね?。
またさらにDSHOTというプロトコルも開発されており、これは今まで、パルス幅のアナログ制御であったのに対して、デジタルで信号制御を行うもののようで~kHzとか実現しているようですね。
いくらモーター制御のスピード上げても姿勢制御の処理がそんな高速には私には書けません。ので、普通のPWM信号(パルス幅1000μs~2000μs)で制御を行いたいと思います・・。
Arduinoプログラム
Arduinoにはservo.hというサーボを制御するための便利なライブラリがありますが、こういったライブラリは便利な反面、かゆい所に手が届かないというか・・。融通が利かないところがあるため最終的には使用しませんでした。
servo.hのライブラリの中身を覗いてみたらやはり制御周期は20msでした。制御周期はいじれば修正できたのですが、さらに複数の信号を出力する場合(モーター4個分の制御)、どうも順番に処理しているような・・。ちょっと確認してみました。
▼ライブラリを使った制御信号▼
3つのpinからライブラリを使ってPWM出力しているところです。長いLow時間をうまく利用して、順番にパルス幅出力してます。
これではモーター4個とも最速(2000μs)出力した場合、125Hz未満が制御周期の限界となってしまい、遅いです。ここの部分修正しようとすると非常に大がかりというかほとんどライブラリの原型くずしてしまうため、ライブラリを使う意味がありません。
ということでライブラリ使わずにPWM信号を作ります。
▼ソースはこんな感じです▼
//PWM 3,5,6,9pin => HIGH digitalWrite(3, HIGH); digitalWrite(5, HIGH); digitalWrite(6, HIGH); digitalWrite(9, HIGH); //PWMパルス幅カウンターセット ESCLoopTimer = micros(); ESC1_timer = 1000 + ESCLoopTimer; ESC2_timer = 1250 + ESCLoopTimer; ESC3_timer = 1500 + ESCLoopTimer; ESC4_timer = 2000 + ESCLoopTimer; //PWM 3,5,6,9pin => LOW while (digitalRead(3) + digitalRead(5) + digitalRead(6) + digitalRead(9) > 0) { ESCLoopTimer = micros(); if (ESC1_timer <= ESCLoopTimer)digitalWrite(6, LOW); if (ESC2_timer <= ESCLoopTimer)digitalWrite(3, LOW); if (ESC3_timer <= ESCLoopTimer)digitalWrite(9, LOW); if (ESC4_timer <= ESCLoopTimer)digitalWrite(5, LOW); }
ドローンを前提としているためモーター(ESC)4個分のPWM出力用のソースです。最初に4pinすべてを「HIGH」にします。
その後、時間を確認しておき、各pinのパルス幅(1000~2000μs)をμs単位でセットします。ドローンを制御するには実際にここでセットするパルス幅は姿勢制御(PID)、スロットル操作などから算出された値となります。
最後に、セットした時間(パルス幅)になったらそのpinを「LOW」にします。すべてのpinがLOWになるまでループさせてます。
この考え方でパルス幅生成してます。HIGHにしてからLOWになるまでの間で必ず1ms(1000μs)の無駄な時間が発生するため、その間に1ms以下で処理できる内容を入れてみてもいいかと思います。
上のソースでは説明を簡単にするため、IDEの関数(digitalWrite/Read)使ってますが、処理に時間が掛かるのと、一度にpin操作できないため、実際のプログラムではポートを直接制御してます。
▼例えば▼
PORTD |= B11110000;
こんな感じで記述すれば4、5、6、7pinを同時にHIGHにできますし、digitalWrite()使用するより圧倒的に処理速度が速いです。
今回は姿勢制御プログラムのモーター制御部分を紹介しました。またそのうち他の部分を紹介していきたいと思います。
コメント
はじめまして。
何かインクルードされているものはありますか?
サイト拝見下さり有難う御座います。
#include <Wire.h>
だけですね。検証用で
#include <MadgwickAHRS.h>
を入れてますが、実際の姿勢制御には使用してません。これくらいですかね。