前回は、二つのマイクロビットを使って無線機能を使ってみた。
「リモコン」のマイクロビットを使って、「プロペラ」のマイクロビットを動かしましたね。
今回はもう少し踏み込んで、チャンネル指定と双方向通信を行ってみようと思う。
?????
行ってみよ~ゥ!
チャンネル指定とは?
なんか、強引に始まってしまいましたが、チャンネルって言いましたね?リモコンでチャンネルってことは、テレビも操作できるとか・・・
残念ながら、テレビの操作はできない。
では、とういうことですか?
マイクロビットがたくさんあった時に、通信する相手の組み合わせを決める機能なのだ。
チャンネル1の「リモコン」の「Aボタン」を押すと、チャンネル1の飛行機のプロペラが回るのだ。そして、チャンネル2の飛行機では何も起こらない。
なんかわかったような気がしますが、これができるとどんないいことがあるのですか?
そうだね、例えば飛行機の代わりに戦車をリモコンで動かすとしよう。
フムフム。
二つのリモコンと二台の戦車を用意して、チャンネルを分けておけば二台を別々に走らせることができる。例えば二人で競争させて遊ぶこともできるようになるのだ。
おぉ、これは楽しそうですね!
プロペラのプログラムにチャンネル機能を組み込む。
では、組み込んだものを見てみよう。まずは、「リモコン」のプログラムの修正箇所から見よう。赤い文字の部分を追加したのだ。
- 1行目 import radio
- 2行目 from microbit import *
- 3行目
- 4行目 radio.config(channel=1)
- 5行目 radio.on()
- 6行目
修正したのは、1行だけですか?
ウム。この1行により、チャンネルを指定したのだ。
もしかして、プロペラ側も1行修正しただけとかですか?
鋭いな。その通りナ~のだ。
- 98行目 state = STATE_STOP
- 99行目
- 100行目 pin14.write_digital(1)
- 101行目 pin1.write_analog(RPM_STOP)
- 102行目 pin12.write_digital(0)
- 103行目
- 104行目 radio.config(channel=1)
- 105行目 radio.on()
- 106行目
- 107行目 while True:
radio.config()関数とは?
ちなみに、この「radio.config()」という関数を使うと、チャンネルのほかにもいろいろと無線の設定を変更することができる。
項目 | 内容 | 初期値 |
length | 1回の通信で送ることができる文字の数 | 32 |
queue | 受信したデータをためておく箱の数 | 3 |
channel | チャンネル番号 | 7 |
power | 無線電波の強さ | 6 |
address | 電波を送り届けるマイクロビットを指定するために使う「住所」 | 0x75626974 |
group | addressと組み合わせて、電波を送り届けるマイクロビットを指定する | 0 |
data_rate | 1秒間に送るデータの数 | radio.RATE_1MBIT |
特に指定しなければ、「初期値」が使われるようになっている。
「address」とか、[group」とか、よくわからない奴がありますが・・・?
今回のところは、「色々変えられるんだな」ぐらいに覚えておいてくれたまえ。
(・・・もしかして、まだよく調べていないんだな?)
詳しくは、「BBC micro:bit MicroPython documentation」を見て下サ~イ。
英語版:https://microbit-micropython.readthedocs.io/en/latest/
日本語版:https://microbit-micropython.readthedocs.io/ja/latest/index.html
「TUTORIALS」の「Radio」には基本的な使い方が、「API REFERENCE」の「Radio」には「config()」関数などの詳しい解説が載っていますね。
リモコンのプロペラの状態を表示する。
これまでは、「リモコン」から「プロペラ」に、一方的に通信を送っていただけだったが、次は、「プロペラ」のマイクロビットからも送ってみようと思う。
もしかしてこれが「双方向通信」っていうやつですか?
ィエ~ス!双方向に通信を行うので、「双方向通信」なのだね。
そういうことか。なんだか「そのまんま」ですね。で、「プロペラ」からは何を送るのですか?
「プロペラ」のマイクロビットからは、プロペラの回転状態を送ることにした。
プロペラの状態 | 送るデータ | 表示 |
停止 | stp | S |
セルモーター | cel | C |
エンジン | eng | E |
停止のための減速 | spg | : |
これを「リモコン」が受けて、LEDに表示するのですね?
その通り!電池切れなどで「リモコン」の電源を入れ直した時にも「プロペラ」の状態がきちんと表示されるようにしたのだ。
おお、なんか便利そうな予感!(でも、プロペラそのものを見ればいいのか。)
そのためには、一定周期でプロペラの状態を送信する必要がある。
そうか。いつ「リモコン」の電池が切れるか分からないですからね。
ここで使うのが、「utime」というライブラリなのデ~ス!
「プロペラ」側のプログラム
今回は、「プロペラ」側から見ていこう。
- 1行目 import radio
- 2行目 import utime
- 3行目 from microbit import *
「utime」を使うため、プログラムの先頭でインポートしたのですね。で、この「utime」って、どんなライブラリなのですか?
これは、時間を扱うためのライブラリなのだ。この中から三つの関数を使ってみたョ。
関数 | 機能 |
tics_ms() | 現在をミリ秒であらわす値を取得する。 |
tics_add(tics, delta) | 時間を表す値の足し算を行う。 |
tics_diff(tics1, tics2) | 時間を表す値の引き算を行う。 |
これらの三つの関数を使って、一定間隔でプロペラの状態を送るようにしたのだ。
フムフム。ところで、「tics_ms()」の説明で、「現在をミリ秒であらわす値」と書いてあるのですが、どういうことですか?
マイクロビットを動かして調べてみたのだが、プログラムが動き始めてから何ミリ秒経過したがを示しているようだったョ。
「何時何分何秒」という感じではなさそうですね。
実際にプログラムで見てみよう。例えば「停止状態」の部分を見てみるよ。
「停止状態」の動きを行わせる関数ですね。
- 29行目 def StateStop():
- 30行目 nextState = STATE_STOP
- 31行目 display.show(‘S’)
- 32行目 pin1.write_analog(RPM_STOP)
- 33行目 pin13.write_digital(0)
- 34行目 deadline = utime.ticks_ms()
- 35行目 while True:
- 36行目 data = UserInput()
- 37行目 if data == ‘a’:
- 38行目 nextState = STATE_CELL_MOTOR
- 39行目 break
- 40行目 if utime.ticks_diff(utime.ticks_ms(), deadline) > 0:
- 41行目 radio.send(“stp”)
- 42行目 deadline = utime.ticks_add(utime.ticks_ms(), SEND_TS)
- 43行目 return nextState
34行目でさっそく「utime.ticks_ms()」が出てきましたね。これは何をしているのですか?
これは「deadline」という変数に、現在の時刻を取り込んでいるのだ。
- 34行目 deadline = utime.ticks_ms()
現在の時刻をメモしているようなものですね。変数「deadline」がメモ帳ってことですね。
そして、35行目以降のループの中の40行目で、「deadline」にメモしておいた時刻と、その時点での現在時刻を比べて、現在時刻の方が後ならばプロペラの状態を送信する。
フムフム、フムフム。
- 40行目 if utime.ticks_diff(utime.ticks_ms(), deadline) > 0:
- 41行目 radio.send(“stp”)
- 42行目 deadline = utime.ticks_add(utime.ticks_ms(), SEND_TS)
42行目は、次の送信タイミングを決めるための処理だ。
と、言いますと・・・
メモ帳の「deadline」に、現在の時刻から少し後の時刻をメモするのだ。「SEND_TS」が「少し後」を示す変数だ。あらかじめプログラムの上の方で用意してあるのだョ。
- 15行目 SEND_TS = 10000
なるほど。
これらの処理はループの中にあるので、繰り返し実行される。
そういうことか!プロペラの状態を送信した後、少し後の時刻をメモしておいて、その時間になったら次の送信を行って、また少し後の時刻をメモして、というのを繰り返すのですね。
ウム。その通りだ!理解できたようだね。では、動かしてみよう。
初めはプロペラが止まっているので、「リモコン」に「S」が表示されましたね!
「Aボタン」を押すと・・・プロペラが回って、「C」が表示された。
もう一回「Aボタン」を押すと、プロペラが高速回転して「E」が表示された。
そして「Bボタン」で「:」が表示されてプロペラが減速していき・・・
止まった!成功です、青木鳥隊長!
tick_ms()とticks_us()があるようなのですが・・・
ところで赤トマト君、現在の時刻を取得するためには、「ticks_ms()」のほかに「ticks_us()」も使うことができる。
ムムムムム、何が違うのですか?
「ticks_ms()」はミリ秒、「ticks_us()」はマイクロ秒の値が得られるのだ。
それで、それで?
この先は、次回のお楽しみだ!
ギャホーン!
まとめ
今回のまとめデ~ス
- チャンネルを指定することで、無線で通信する相手を指定することができる。
- 関数「radio.config()」により、チャンネルなどの無線機能の設定を行うことができる。
- ライブラリ「utime」を組み込むことで、時間を扱うことができるようになる。
今回のプログラムの全文はこちらをご覧ください。(新しいタブで開きます。)
【マイクロビット応用】[6.1] プラモの飛行機のプロペラのプログラム:無線のチャンネル指定と双方向通信
次は「utime」について、もう少し踏み込んでみます。次回も見てね!
つづく
コメント