モーターを回せるようになったので、プラモの飛行機のプロペラを回すプログラムを作ってみたよ。(動画を貼る予定だったのだが、うまく貼れませんでした。)
この飛行機、エンジンがむき出しでプロペラの色も塗られていませんね。
飛行機は製作中なのである。
で、これ、どうやってやったのですか?
それが今回の内容なのだ。
さっそく行ってみよ~ぅ!
プロペラの動き
まず初めに、どのボタンを押すとプロペラがどのように動くかを説明しよう。
ボタンを押して動かす、という訳ですね。
プロペラが止まっている状態で「Aボタン」を押すと、プロペラがゆっくり回る。
なぜゆっくりなのですか?
エンジンが始動する前にプロペラがセルモーターで回っている状態を表しているのだ。
セルモーター?ですか??
例えば、車のエンジンをかけるときはどんな音がするかな?
「ギュイギュイギュイバウゥ~~ン!」
その「ギュイギュイギュイ」の部分がセルモーターで、「バウゥ~~ン!」の部分がエンジンで動いている状態なのだ。
なるほど。では、次はエンジンで動いている状態になるのですね?
その通り。もう一度「Aボタン」を押すと、エンジン始動、ということで、プロペラが速く回るのだ。
「Bボタン」はどう使うのですか?
「Bボタン」を押すと停止するようになっている。分かったかな?
イエ~ス
どんなプログラムを作ったのか?
次はプログラムですか?
その通り!ただ、今回作ったプログラムは、これまで見てきたものより長い。
そうなんですか?トマトの僕にも理解できるのかなぁ?
心配するな。実際のプログラムを見る前に、おおざっぱな動きを説明しよう。説明についてきてくれよ。
分かりました。頑張ります!
まず、先ほど説明したプロペラの動きには、3つの種類があることは分かるかな?
止まっているのと、セルモーターでゆっくり回っているやつ、エンジンで速く回っているやつですね?
その通りだ。そして、それぞれの動きをしているときに、マイクロビットのボタンが押されると、別の動きに変化する、ということは分かるかな?
ゆっくり回っているセルモーターのときに「Aボタン」が押されると、プロペラが速く回るエンジンの状態になる、ということですか?
その通りだ!止まっている状態(停止の状態)、セルモーターの状態、エンジンの状態をまとめてみるとこうなる。
状態 | 動き | Aボタン | Bボタン |
停止 | プロペラが止まっている。 | セルモーターの状態になる。 | 停止の状態のまま |
セルモーター | プロペラがゆっくり回っている。 | エンジンの状態になる。 | 止まる(停止の状態になる) |
エンジン | プロペラが速く回っている。 | エンジンの状態のまま | 止まる(停止の状態になる) |
ふむふむ・・・
今回作ったプログラムでは、ボタンによりこれらの状態が切り替わるようになっているのだ。
なんと!で、それは一体どういうことなのでしょうか???
状態が切り替わる、とは?
では、プロペラの状態の切り替わりについて説明しよう。この絵を見てくれたまえ。
なんだかややこしそうな絵ですね。
この絵の中に丸く囲った部分が3つあるのは分かるかな?
「停止の状態」、「セルモーターの状態」、「エンジンの状態」と書かれているやつですか?
そのとぉ~り!そして、「停止の状態」の丸の左上に「電源オン」と書かれており、そこから矢印が伸びているだろう。
コレはどういうことなんですか?
これは、マイクロビットの電源がオンされると、プロペラが止まった状態となることを表しているのだ。
な、なるほど・・・では、矢印と「Aボタン」とか、「Bボタン」とか書かれているのが、ボタンで状態が変わるということを表している・・とか?
よくわかったな!その通りだぞ!
えぇっ、本当ですか!ビックリ仰天ですよ!
これをプログラムにするには?
実際にプログラムを作るときのポイントは、以下の2つだ。
- プロペラの状態を切り替える。
- ボタンが押されるのを待つ。
ようやくプログラムにたどり着いたぞ。
まず、マイクロビットがそれぞれの状態を区別できるように番号を付ける。
状態 | 番号 |
停止の状態 | 0 |
セルモーターの状態 | 1 |
エンジンの状態 | 2 |
番号はこの通りでなくても構わないが、各状態に別の番号を割り当ててくれたまえ。
同じ番号だと、マイクロビットが区別できない、ということですね。
そうなのだ。そして、我々も後で分からなくならないようにするため、これらの番号を変数に入れておこう。
- 3行目 STATE_STOP = 0
- 4行目 STATE_CELL_MOTOR = 1
- 5行目 STATE_ENGINE = 2
「STATE」というのはどういうことですか?
「STATE」とは「状態」という意味の英語だ。変数名なので、自分たちで決めればよいのだ。
番号を変数に入れておかなくてもよいのですか?
もちろんだ。ただし、どの番号をどの状態に割り当てたかをしっかり覚えておかないといけなくなるのだ。
分かりやすい変数名にしておくのが良さどうですね。
そうなのだよ。次に、今はどの状態なのかを格納しておくため、「state」という名前の変数を用意する。
- 51行目 state = STATE_STOP
「state」には、「STATE_STOP」を入れておくのですか?
イェース。電源をオンした時はプロペラを停止させておくので、「state」には「STATE_STOP」を入れておく。
電源を入れたとたんにプロペラが回ったら、ビックリしちゃいますしね。
それぞれの状態の動きは、「関数」にまとめておくことにする。関数については、以下を見て思い出してくれたまえ。
それぞれの状態の関数の名前は、下のように決めたのだ。これも自分たちで決めることができるのだ。
状態 | 番号 | 関数の名前 |
停止の状態 | 0 | StateStop |
セルモーターの状態 | 1 | StateCellMotor |
エンジンの状態 | 2 | StateEngine |
いろいろと決まってきましたね。
プロペラの状態を切り替える部分
ところで、マイクロビットのプログラムには、無限ループを組み込む必要がある、ということは覚えているかい?
そういえば、そんなこともあったような・・・
状態を切り替える部分は、この無限ループの中に組み込んである。
- 3行目 STATE_STOP = 0
- 4行目 STATE_CELL_MOTOR = 1
- 5行目 STATE_ENGINE = 2
:
- 51行目 state = STATE_STOP
:
- 57行目 while True:
- 58行目 if state == STATE_CELL_MOTOR:
- 59行目 state = StateCellMotor()
- 60行目 elif state == STATE_ENGINE:
- 61行目 state = StateEngine()
- 62行目 else:
- 63行目 state = StateStop()
57行目以降が無限ループの部分だ。58行目、60行目、62行目により、変数「state」の中身に応じてそれぞれの状態の関数が呼び出されるようになっている。
「state」に「STATE_STOP」が入っているので、「StateStop」が呼び出されるのですね?ほかの関数はどのようにして呼び出されるのですか?
それを理解するには、「StateStop」の中身を見る必要がある。
ボタンが押されるのを待つ部分
「StateStop」は、次のような動作をするように作られている。
- プロペラを止める。
- ボタンが押されるのを待つ。
- Aボタンが押されたら、「次はセルモーターである」ということを知らせる。
「関数」の中で、ボタンが押されるのを待つのですか?
そうなのだ。そのために、「関数」の中にもループを組み込んであるのだ。
- 11行目 def StateStop():
- 12行目 nextState = STATE_STOP
- 13行目 display.show(‘S’)
- 14行目 pin1.write_analog(0)
- 15行目 pin13.write_digital(0)
- 16行目 while True:
- 17行目 if button_a.get_presses():
- 18行目 nextState = STATE_CELL_MOTOR
- 19行目 break
- 20行目 if button_b.get_presses():
- 21行目 nextState = STATE_STOP
- 22行目 return nextState
ええと、「関数」は、「def」で始まるのでしたね。
思い出してきたようだね。12行目は、「nextState」という変数を用意している。この変数は、22行目で関数の呼び出し元に返す「お知らせ」の役割をする。
「次はセルモーターだよ」というのを知らせるのですね?
ウイ。次の14行目と15行目でモーターを止めている。
あ、これは前にやったやつだ。
16行目から21行目までが、ボタンが押されるのを待っている部分だ。16行目の無限ループにより、17行目から21行目が繰り返されるのだ。
ふむふむ・・・
- 16行目 while True:
- 17行目 if button_a.get_presses():
- 18行目 nextState = STATE_CELL_MOTOR
- 19行目 break
- 20行目 if button_b.get_presses():
- 21行目 nextState = STATE_STOP
- 22行目 return nextState
「Aボタン」が押されると、17行目の「if」文の条件が成り立つ。
うむむむ・・・
18行目で「nextState」に「STATE_CELL_MOTOR」が格納される。そして、19行目の「break」で無限ループから抜けて22行目に移るのだ。
なんと!22行目は「return」文なので、呼び出しもとに「STATE_CELL_MOTOR」がお知らせされるのですね!
その通りだ!
呼び出し元に戻った後は・・・
「StateStop」は63行目で呼び出されている。
そうでしたね。
- 57行目 while True:
- 58行目 if state == STATE_CELL_MOTOR:
- 59行目 state = StateCellMotor()
- 60行目 elif state == STATE_ENGINE:
- 61行目 state = StateEngine()
- 62行目 else:
- 63行目 state = StateStop()
63行目は「state = StateStop()」となっている。この「=」のおかげで、「StateStop」から戻ってくるときの「お知らせ」が「state」に格納されるのだ。
な、なんと!・・・無限ループなので、そのあと57行目に戻るのでしたね・・・
そうなのだ、この時には「state」には「STATE_CELL_MOTOR」が格納されている。
と、いうことは?もしかすると・・・
- 58行目 if state == STATE_CELL_MOTOR:
- 59行目 state = StateCellMotor()
そうだ!58行目の「if」文により「StateCellMotor」が呼び出されるのだ!
ウッシャーァ!
Bボタンが押されたときはどうなる?
ところで、「StateStop」で、「Bボタン」が押された場合はどうなるのですか?
プロペラの動きは止まったままだ。
状態 | 動き | ボタンA | ボタンB |
停止 | プロペラが止まっている。 | セルモーターの状態になる。 | 停止の状態のまま |
プログラムを見てみると・・・
- 16行目 while True:
- 17行目 if button_a.get_presses():
- 18行目 nextState = STATE_CELL_MOTOR
- 19行目 break
- 20行目 if button_b.get_presses():
- 21行目 nextState = STATE_STOP
- 22行目 return nextState
20行目の「if」文の条件が成り立ち、21行目が実行される。
「nextState」の中身はもともと「STATE_STOP」ですね。何も変わらないのでは?
その通り。実質的には、何も変わらない。そして、「プロペラは停止したまま」となるのだ。
では、この部分は無くてもよいのですか?
そうとも言い切れないのだ。が、ややこしい説明が続いたので、続きは次回説明することにしようと思う。
残り2つの関数「StateCellMotor」と「StateEngine」も次回ですね。
まとめ
今回のまとめは・・・
- 複数の状態を切り替えることで、マイクロビットにつないだものにいろいろな動きをさせられる。
- それぞれの状態の中に無限ループを組み込み、ボタンなどの操作を待つようにする。
という感じでしょうか。
今回作ったプログラムの全文は、以下の記事を見てね。(新しいタブで開きます。)
【マイクロビット応用】[2.1] プラモの飛行機のプロペラのプログラム:最初のバージョン
つづく
コメント