328duinoやM5StickC Plusを使って組み立て・拡張中のロボットカーに、タコメータ(速度計)という機能を追加したいと思います。タコメータの中身は、遮断型赤外線センサと、スロットディスクの2種類です(下図)。
そう、前回までの2回に渡って、遮断型赤外線センサの試行をしてきたので準備万端なのです。
「#30-1 遮断型赤外線センサ」
「#30-2 パンチカードリーダ」
では早速、もう一つの部品であるスロットディスク💿とは何か?から解説して行きましょう。
スロットディスク(下図)には、円周状に規則的なスロット(穴)が開いています。
数えてみると、一周当たり20個のスロットが開いていました。また、ディスクには、真ん中に意味深な穴も開いています。ただの丸い穴ではなく、円の一部が削れて平らになった部分がありますね。
実はこの形状、ギア付ブラシDCモータの回転軸の断面と同じ形状をしています。つまり、ギア付ブラシDCモータの回転軸に取り付けて使う部品なのです。モータを回転させるとスロットディスクも一緒に回転します。
さてさて、このスロットディスクを挟み込む様に遮断型赤外線センサを設置すると、どうなるでしょうか?
スロットディスクには、20個のスロットが開いているのだから、出力信号OUTのLOW⇔HIGHトグル回数をカウントしたら、スロットディスクが何回転したか、ひいてはモータの回転軸が何回転したのか?を知ることができるのです。
モータの回転数が判ったら、その回数だけ、モータに取り付けたタイヤも回転するのだから、回転数×タイヤ一回転分の移動距離を計算すると、ロボットカーの移動距離が判るという寸法です。
タイヤ一回転分の移動距離は、タイヤの直径をD[cm]とすると、その円周長に当たるので、以下式で求められます。
タイヤ一回転で進む距離=D×π[cm]
タイヤの直径は、定規などを使って測定しておいてください。
タイヤと地面の間がスリップして空回りしない限り、上の様に求めたロボットカーの走行距離は正しいと考えられます。同時に、モータが一回転するのに要した時間を測定しておけば、距離÷時間で速さ[cm/s]も計算できます。
※余談ですが、メカナムホイールを搭載したロボットカーの場合には、スリップすることが前提となっているため、モータの回転数から移動距離を求めることは困難だと思われます。
なお、この方式のタコメータでは、前進しようと後退しようと、認知できるのは速さだけです。進行方向は知ることができません。別途、今、モータを正回転させているのか、逆回転させているのか?についての情報を保持しておくことで、タコメータでカウントしたスロット数が、正回転なのか、逆回転なのかを判定する必要があります。
ロボットカーにスロットディスクを組み込むため、一旦、ロボットカーを分解して、ギア付ブラシDCモータにアクセスできるようにしなくてはなりませんでした。
分解したら、ギア付ブラシDCモータの回転軸にスロットディスクを取り付けます(下図)。
ギアボックスの両サイドに伸びた回転軸の内、一方にはタイヤが取り付けてあるので、その逆側にスロットディスクを取り付けます。2個のモータに同じ様に取り付けたら、そのまま、ロボットカーの筐体を組み上げます。
ロボットカー筐体に空いた十字穴(左右二か所)が、遮断型赤外線センサの取り付け穴なので、その中央位置にスロットディスクが来るように、回転軸への取り付け位置を微調整してください(下図)。
スロットディスクを挟み込む様にして、十字穴に遮断型赤外線センサを取り付けます。
筐体にも、センサボードにも、M3サイズのネジ穴が開いているので、本当は、ネジで取り付けて固定したいところでした。だがしかし、ショボい中華品質の性で、センサと基板が斜めにはんだ付けされていたため、ネジが通りませんでした。→ 中華品質!ブーイング。
十字穴が、結構ピッタリサイズで開いているので、ネジで固定しなくても、何とかなりそうでは、あります……。最悪は、結束ワイヤなどで固定して使おうと思います。
ちゃんとはんだ付けされたモジュールを入手できた方は、ねじ止めする事を推奨します。
この時スロットディスクが、回転によってセンサとぶつからない様に、また、センサに対して平行になる様に位置調整しておいてください。
センサのピンヘッダから、20cmくらいのデュポンワイヤ(オス→メスタイプ)で配線を引き出したら、最後までロボットカーの筐体を組み立ててしまいましょう。
※本ページで組み立て中のロボットカーは2輪駆動なので、各モータの回転数を知るためには、タコメータが2組必要でした。単に走行速さだけを知るのではなく、今後、各モータ毎に回転数を知って、より精密な制御を実行するためです。4輪駆動なら4組必要となります。
前回までに、センサ自体の試用(お試し)は済んでいますので、電源(3.3V)、GNDを接続したら、後はデジタル出力信号OUTを制御モジュールの328duinoへ繋げば良いだけです。
ロボットカー制御プログラム中の処理とは非同期(無関係)にモータは回転するので、センサ出力信号OUTの変化は割り込みを使って処理します。ロボットカーシステムに使っている328duinoは、DCモータの制御に加え、RGB LEDパネル、パッシブブザーなどの制御にもI/Oポートを使っており、残りの未使用I/Oポートから、左/右タコメータ用のデジタル入力(2本)を受ける必要があります。
328duino(ATmega328)で、割り込みを受付可能な端子機能には、INT0,INT1,PCINT0〜23が、あります。INT0,INT1だと、立ち上がり/立ち下がりエッジで割り込みを受けることができて使い易そうだったのですが、あいにく、既に別機能へ割り当て済みで埋まっていました。
PCINT(端子変化割り込み)を使う事にしましょう。端子変化割り込みは、PCINT0〜23端子まで使用可能ですが、割り込み要因としてはPCINT0〜2の3要因に縮退しています。
※ATmega328データシートのまま記載していますが、端子名PCINT0〜23と、割り込み要因名PCINT0〜2が一部重複していて紛らわしいです。筆者の性ではないので、苦情はMicrochip社の方へ。
PCINT端子と割り込み要因の対応を以下表に示します。
割り込み要因名 | 割り込み端子名 | 対応するI/Oポート |
PCINT0 | PCINT0〜7 | D8〜D13,XTAL1,XTAL2 |
PCINT1 | PCINT8〜14 | A0〜A5[D14〜D19],RESET |
PCINT2 | PCINT16〜23 | D0〜D7 |
※ただし、PCINT15端子は欠番。
ロボットカーシステムに於いて、現在までに、D0〜D8までのI/Oポートには、別機能を割り当て済みでしたので、少なくとも、割り込み要因PCINT2の端子は使用できません。残った端子で割り込み受付可能な割り込み要因は、PCINT0とPCINT1の2要因です。
タコメータは、左/右2個のモータから信号を受け取るので、それぞれ、PCINT0とPCINT1割り込み要因の中から1本づつ端子を選んで接続します。
選択した端子:
新たに追加する、タコメータモジュールの回路を以下図に示します。
前節の回路設計で検討した通り、タコメータの出力は、328duinoの端子変化割り込みで受け付けます(以下コード)。
static volatile int tch_cnt1; // tch: tachometer counter
static volatile int tch_cnt2;
ISR (PCINT0_vect)
{
// PCINT0: PCINT4 (D12)
// tachometer #1 (left blushed DC motor)
tch_cnt1 += sgn (mtr_duty1);
}
ISR (PCINT1_vect)
{
// PCINT1: PCINT11 (A3[D17)
// tachometer #2 (right blushed DC motor)
tch_cnt2 += sgn (mtr_duty2);
}
これだけで終了です。簡単だったでしょう?
カウンタtch_cnt*をグローバル変数宣言しておいて、割り込みが発生した時に、モータ駆動用PWMデューティ値を保持した変数mtr_duty*の符号(sgn()関数)で回転方向を知り、正回転ではカウンタを+1、逆回転では−1しています。
※「*」には、1または2の数字が、モータ#1(左)/#2(右)に従って入ります。
なお、PCINTは「端子変化割り込み」なので、端子がLOW→HIGHに変化した時と、HIGH→LOWへ変化した時の両ケースで割り込みが発生します。スロットディスクには一周当たり20個のスロットが開いているので、スロットディスク一回転で40回割り込みが発生します。
言い換えると、tch_cnt*が40カウントすると、モータの回転軸が一回転します。
端子変化割り込みはsetup()関数で初期設定して有効化します(以下コード)。
// PCINT setting
PCMSK0=(1<<(pin_TACH1 - 8)); // PCINT4 select
PCMSK1=(1<<(pin_TACH2 - 14)); // PCINT11 select
PCIFR=0x07; // flag clear
PCICR=0x03; // PCINT0, 1 interrupt enable
端子変化割り込みは、Arduinoのコアライブラリ(※)ではサポートされていないため、上コードの通り、ATmega328のI/Oレジスタを直接叩いて設定する必要があります。
※サードパーティが提供しているライブラリは、探せば見つかると思います。わざわざライブラリをインストールしなくても、上コードの通り簡単な設定で使えるので、本ページでは使いませんでした。
RGB LEDパネルを使った電飾動作モードに「タコメータモード」を追加しました。
【pix,-6】
このモードでは、タコメータの出力(端子変化割り込み)から回転速度を計測し、その速さに従って、以下の通りRGB LEDパネルを点灯します。
以下に、改定してタコメータに対応したプログラムをリンクしておきます。
改定版プログラム:robot_car.ino
ロボットカーの制御モジュールに使用する328duinoへコンパイル&書き込んでお使いください。シリアルモニタから受け付けられるコマンドは、こちらをご参照ください。
こちらに従って、ロボットカーを組み立ててください。更に、タコメータモジュールを以下表の通りに接続します。
UNO 3.3V化328duino | 接続 | タコメータモジュール |
Vdd(3.3V) | → | Vdd |
GND | ⇔ | GND |
D12(PCINT4) | ← | TCHO1 |
A3[D17](PCINT11) | ← | TCHO2 |
ロボットカーは走行させない方が確認し易いので、タイヤを浮かせて実験しましょう。以下、実験中の様子です。
追加したスロットディスクと遮断型赤外線センサは筐体や電池ボックスに隠れているのですが、何とか、少しだけ見切れるアングルで撮影しました。タコメータが追加されています。
実験はM5StickC Plusと連携したスマートホンの制御画面から行います。M5StickC PlusのTFTディスプレイに表示されたQRコード等から、スマホの制御画面を開いてください。
以下図の様に、スマホの制御画面をスワイプして、下の方に配置してあるコマンド送信フィールドから328duinoへ、シリアルモニタコマンドを送信して実験を進めましょう。
コマンド送信フィールドにコマンドを入力して、その下にある「>>」ボタンを押すと、スマホ → WiFi → M5StickC Plus → UART → 328duinoと、コマンドが送信・伝達されます。
実験サンプル:【 】内はスマホからの送信データ
【pix,-6】
(OK: pix -6, 0,0,0) …… (※)
電飾動作モードをタコメータモードに設定しました。
※328duino.TXO → M5StickC Plus.RXDを接続しておくと、応答メッセージを確認することができます。
【mtr1,255】
(OK: motor #1 duty=255 turn=1)
モータ#1をPWMデューティ255で駆動して回転させました。RGB LEDパネルが緑色に光りましたか?
【stp】
(OK: stop motor)
【mtr2,128】
(OK: motor #2 duty=128 turn=1)
一旦、モータの回転を止めて、モータ#2をPWMデューティ128で駆動して回転させました。RGB LEDパネルが青色に光りましたか?先程の【mtr1,255】の緑色発光と比べて、PWMデューティを半分の128で回転させたので、点灯したピクセル数は少なかったはずです。
モータを駆動するPWMデューティを変えて、モータの回転速度を変化させると、以下図の様にRGB LEDパネルの点灯ピクセル数が、回転速度に応じて変化する事を確認して見てください。
単に「指定したデューティ値に従ってピクセル数を変化している」のではなくて、「タコメータで回転速度を実測し、その速さに従ってピクセル数を変えている」ことに注目してください。実際の回転速度が反映されているのです。例え、デューティを255に設定していても、タイヤを手で押さえる等して回転が停止すれば、速さ=0を表す「全8ピクセル消灯」と、なります。
【mtr1,255】
(OK: motor #1 duty=255 turn=1)
再び、モータ#1をPWMデューティ255で駆動して回転させました。RGB LEDパネルが緑色と水色に光りましたか?
この程度が確認できたら、実験は終了(成功)です。
凄く単純な仕組みなのですが、だいぶ正確に走行距離を計測する事ができます。ただ、こちらで簡易計算した通り、入手した遮断型赤外線センサモジュールは消費電力が大きいので、本当は、ロボットカーの様に充電池(バッテリ)で動作させるアプリケーションには不向きなのでした。そこが少し残念です。