前回から、ロボットカーに「数値制御」機構を拡張する取り組みを進めています。今回は、ロボットカー数値制御の完結編です。
通常PWMのdutyと、間欠的PWMのduty’を組み合わせ、総合PWMのDuty=duty×duty’でモータの回転を制御するアルゴリズムを検討して行きます。
プログラムで使用している変数で記したので、具体的なコーディングについては完成したプログラムで確認してください。
左右モータの進捗率偏差ncm_deviに対して、どの程度の偏差まで許容するか?を定数ncm_MAX_DEVIに設定します。
const int ncm_MAX_DEVI=5; // ncm: deviation tolerance
最適なncm_MAX_DEVI値が、どこかに見つかるはずですが、環境によって最適値が異なる可能性があります。各自の環境にて、色々なパタンで走行実験して見て、最適な数値を見つけ出してください。
数値制御を適応したプログラムを以下にリンクしておきます。
更新版プログラム:robot_car.ino
今回追加したシリアルモニタコマンドの仕様を以下に説明します。
数値制御シリアルモニタコマンド仕様:
その他のコマンドは、こちらをご参照ください。
今回追加した【nc*】系コマンドは、ブロッキング処理となります。コマンドを送信したら、当該コマンドの実行が終わるまで次の処理を実行できません。
また、【ncmov】、【ncrot】コマンドの実行中に、シリアルモニタに何らかのデータを受信した場合、コマンドの実行を中断します。コマンド実行を中断したくない場合、コマンドの実行が終わるまで次のコマンドを送信しないで下さい。
シリアルモニタコマンドは、M5StickC Plus ⇔ 328duino間の通信にも使用します。
【nc*】系コマンドはブロッキング処理なので、受け付けた【nc*】系コマンドの実行が終わるまで、M5StickC Plusからの次のコマンド送信を抑止する必要が生じます。【nc*】系コマンド実行中に、シリアルモニタに何らかのデータを送信してしまうと、「中断要求」と見なして、コマンド実行を中断する仕様のためです。
そこで、328duinoからRTS(Request To Send、負論理)信号をデジタル端子D16から出力するように拡張しました。対するM5StickC Plusには、CTS(Clear To Send、負論理)信号をG25端子で受ける様に拡張したので、この信号線を互いに接続して使用してください。
拡張した回路図やネットリストは、こちらから参照してください。
M5StickC PlusのCTSがネゲートされている時にシリアルモニタコマンドを送信しようとすると、エラーメッセージが表示されます。328duino側で【nc*】系コマンドの処理中と考えられるので、処理が終わるまで待ってから次のコマンドを送信してください。
尚、M5StickC Plusから328duinoへ、現在実行中の【nc*】系コマンドへ中断を要求するため、【ncclr】コマンドだけはCTSがネゲートされていたとしても送信可能となっています。
CTS制御に対応した、新しいM5StickC Plus制御プログラムを以下にリンクしておきます。
更新版プログラム:robot_car_rc.m5f
UIFlow開発環境のオンライン版で読み込んで、M5StickC Plusへ書き込みしてください。UIFlowの環境立ち上げに関しては、こちらを参照してください。
まずは、こちらの記事に従って、ロボットカーを組み立てます。
制御モジュールの328duinoには、こちらのプログラムをコンパイル&書き込みしてください。
M5StickC Plusへ書き込むプログラムと合わせて、こちらのページからもダウンロード可能です。
ただ最初は、328duinoにUSB⇔UART変換モジュール(FTDI等)を接続して、シリアルモニタからコマンドを送信しますので、M5StickC Plusとは接続せず、電源もUSB⇔UART変換モジュールから供給する様に構成してください。制御プログラムが意図した通りに動くのか、ロボットカーのタイヤを浮かして、ほぼ無負荷の状態で動作確認してみます(下図)。
グラフ化するデータを取得するため、デバッグ用の#defineマクロを有効化してコンパイル&書き込みしておきます。
#define DEBUG_PLOT
シリアルモニタから、【nc*】系コマンドを送信して動作を確認して見ましょう。
実験サンプル:【 】内は、シリアルモニタからの送信データ
「#define DEBUG_PLOT」有効でコンパイル&書き込みしたプログラムを使い、取得したデータをExcelで取り込んでグラフ化しました(下図)。
横軸にコマンド送信からの経過時間[ms]、縦軸にタコメータのカウンタを取ったグラフです。tcnt1(青色プロット)は左側タコメータのカウンタ(tch_cnt1)、tcnt2(橙色プロット)は右側タコメータのカウンタ(tch_cnt2)です。
tch_cnt1/tch_cnt2と左/右の対応については、モータドライバICと、左右DCモータとの接続次第で変わるため、各自の環境で読み替えて理解してください。
グラフより、左右モータが時折上下入れ替わりながら、進行している様子が見て取れます。時々、カウンタが増加せず、停止している時間帯もある様です。間欠的PWM制御が機能して、一瞬モータが停止しているのでしょう。
マクロにみると、ほぼ同じカウント数で増加しています。時間経過と共に、左右モータからのタコメータカウンタがほぼ同じ値を取りながら変化しており、直進しているであろうと思われます。……タイヤを浮かせているため、実際には走行しておらず、グラフからの類推ですが……。
と言っても、完全に(100%)同じ値では無いため、厳密には直進しておらず、多少左右に蛇行している様です。→ 制御の誤差範囲でしょう。
左右タイヤの走行距離をアンバランスに異なる値に設定して見ました(下図)。期待値としては、円弧を描き右側に曲がりながら走行するはずです。
時折、カウンタが増加せず、停止している期間が見られます。前節で直進させた時より、停止時間が長い期間もあります。時間の進行(横軸)に対してリニアに増加していない事とも併せて考えると、実際に走行させたとしたら恐らく、ギクシャクした動きになるものと推察できます。
左右の走行距離の比が3:1というアンバランスに指示したため、間欠的PWM(ON/OFF)制御によって、離散的な制御となったことが原因だと考えられます。
滑らかな走行を実現したい場合は、左右の走行距離差を、なるべく小さく指示することが求められる様です。
実際の走行状態に当てはめると、左右に曲がる時は大きな弧を描きながら曲がるか、いっその事、直角に近い角度で曲がったり、その場旋回で方向を変えた方が、滑らかに動きます。中途半端な弧を描いてカーブさせると、ギクシャクした動きになる可能性が高いです。
最終的な到達距離としては指定通り、左300mmと右100mmで回転できたことが確認できました。アンバランスな距離でも問題なしです。
その場で360°旋回させてみました(下図)。
タコメータのカウンタは、正転(前進する側)を正値、逆転(後退する側)を負値でカウントしています。その場旋回の場合、左右が互いに逆回転するため、上図の通りのグラフとなります。期待値通りです。左右とも、ほぼリニア、かつ、上下対称に変化しており、滑らかに旋回するであろう事が期待できます。
無負荷状態の実験で、ある程度期待通りに動くことが確認できました。次の段階として、タイヤを浮かせていた土台を取り除き、実際に走行させながらデータを取得してみましょう。
負荷が加わることで制御系パラメータが変化するので、無負荷の状態と変わりないかどうかを確認しておく事とします。
タイヤを地に付けて、実際に20cm直進させてみました(下図)。
USB⇔UART変換モジュールのケーブルがPCと接続された状態でデータ取りしていますので、机の上に20cmの走行余地がある事の他に、ケーブルが届く範囲で走行するように気を付けなくては、なりません。
実際に観察したところ、正確には計測しませんでしたが目視でおよそ20cm直進して停止しました。グラフで見ても、無負荷の場合と変わらない印象です。
本当は、実際に走行させた状態で、色々な走行データを取って試行したいところです。しかし、PCとケーブルで繋がった状態では、あまり派手に走行させることができません。ケーブルがねじれたりして受信データにゴミが乗る場合も有ります。データの取得が困難なので、上の一点だけで確認完了とします。
結論としては、負荷有り状態でも、負荷無しの場合と(ほとんど)変わらないデータが確認できたと思います。
と、言う事で、USB⇔UART変換モジュールを外してM5StickC Plusを接続し、更に充電池から電源を供給しながら、実際の走行状態を確認してみようと思います。
こちらの記事に従ってロボットカーを完成させます。以下図に実験中の様子を示します。
もう、グラフデータは必要ないので、プログラム中の「#define DEBUG_PLOT」もコメントするか、削除してからコンパイル&書き込みしてください。
ロボットカーに数値制御を実行させたデモ動画をご覧に入れます(以下リンク)。
実験の結果は上の動画より、実際の走行状態をご覧いただき、皆様の目でご確認ください。
以下考察を数値制御のまとめとします。
タコメータのスロットディスクは1回転で40カウントします。1回転で走行する距離は約18.8cmなので、その解像度は、約4.7[mm/カウント]です(解説はこちら)。
さらに、目標としていた距離の走行を確認した時点で、すぐさまDCモータの電源供給を絶っても、一度回転し始めたモータは、すぐには止まりません。実験では数カウント程、惰性で回転している様でした。
つまり、理論上の解像度約4.7[mm/カウント]と、惰性でオーバランしてしまう分が、数値制御の誤差となります。円運動や正方形に走行し続ける等、ずっと同じ動作を繰り返したとしても、誤差の蓄積によって、どんどん軌道がずれていくことは容易に予想できます。
現時点のプログラムでは、これは致し方ありません。
目標のカウンタに近づいたらデューティを絞って制動をかけ、目標カウンタぴったりで停止するようにプログラムを改訂すれば、もっと正確な数値制御も可能でしょう。……その辺りの改訂は、興味のある皆様にお譲り致しますm(1__)m。
数値制御できるようになれば、「ロボットカー🤖」と言っても恥ずかしくない機能を備えることができるのですがね……。なかなか難しい様です。