今回は、飛行機のプロペラを回すプログラムの続きを説明しようと思う。
プロペラが止まっている状態、ゆっくり回転している状態、高速回転の状態を切り替えるのでしたね。
はじまりマ~ス
前回のおさらい
前回の内容を覚えているかい?
「Aボタン」でプロペラが回り、「Bボタン」で止まるのでしたね。プロペラは「Aボタン」で「ゆっくり回転」から「高速回転」に、回る速さも変わりましたね。
これを実現するために、「状態」を切り替えるプログラムを作成したのだ。
状態 | 動き | Aボタン | Bボタン |
停止 | プロペラが止まっている。 | セルモーターの状態になる。 | 停止の状態のまま |
セルモーター | プロペラがゆっくり回っている。 | エンジンの状態になる。 | 止まる(停止の状態になる) |
エンジン | プロペラが速く回っている。 | エンジンの状態のまま | 止まる(停止の状態になる) |
それぞれを「関数」にするんでしたっけ?「StateStop」という関数があったような・・・
イエ~ス。それぞれの「状態」の「関数」に番号と名前を付けた。
「StateStop」は、プロペラが停止している状態の「関数」ということですね。番号は何のために必要なんでしたっけ?
状態 | 番号 | 関数の名前 |
停止の状態 | 0 | StateStop |
セルモーターの状態 | 1 | StateCellMotor |
エンジンの状態 | 2 | StateEngine |
マイクロビットが「状態」を区別できるようにするためだね。そして、我々がこの番号を間違えないようにするため、「変数」に入れて使うことにした。
- 3行目 STATE_STOP = 0
- 4行目 STATE_CELL_MOTOR = 1
- 5行目 STATE_ENGINE = 2
ふむふむ・・・
停止状態の関数「StateStop」が具体的に何をしているのかを覚えているかい?
えーと、プロペラを止めて、「Aボタン」が押されたら「次はセルモーターだよ」とお知らせするんでしたっけ?
いいぞ、その調子だ。今回のプログラムは、次にどの「状態」に切り替えるのかをお知らせするように作られている。
あとは・・・「Aボタン」が押されるのを「ループ」の中で待つのでしたね?
うむ、その通りだ!大丈夫なようだね。
いろいろ思い出してきました。(分からなくなった場合は、前回の記事を見直してみてね。)
【プログラミング応用】プラモの飛行機のプロペラのプログラム:最初のバージョン
では、残り2つの「関数」を見ていこう。
ふむむむ・・・
セルモーターの状態の関数
「セルモーター」の状態の関数「StateCellMotor」は、次のような動作をするように作られている。
- プロペラをゆっくり回転させる。
- ボタンが押されるのを待つ。
- Aボタンが押されたら、「次はエンジンである」ということを知らせる。
- Bボタンが押されたら、「次は停止である」ということを知らせる。
「お知らせ」が2種類あるのですね。
そうなのだ。「Aボタン」を押された場合と「Bボタン」を押された場合で動きが異なるので、押されたボタンごとに異なる内容を「お知らせ」するのだ。
ナ~るほど。
これが「StateCellMotor」の中身だ。
- 24行目 def StateCellMotor():
- 25行目 nextState = STATE_CELL_MOTOR
- 26行目 display.show(‘C’)
- 27行目 pin1.write_analog(350)
- 28行目 pin13.write_digital(1)
- 29行目 while True:
- 30行目 if button_a.get_presses():
- 31行目 nextState = STATE_ENGINE
- 32行目 break
- 33行目 if button_b.get_presses():
- 34行目 nextState = STATE_STOP
- 35行目 break
- 36行目 return nextState
25行目は、「nextState」という変数を用意している。これが36行目で「お知らせ」として関数の呼び出し元に返される。
27行目と28行目はプロペラをゆっくり回す部分ですね。モーターを回すのは、以前にやりましたね。
【プログラミング応用】(1)モーターを動かしてみよう。のことだね。
31行目で「nextState」に「STATE_ENGINE」が格納されていますね。でも、34行目では「STATE_STOP」が格納されていますよ。実際にはどっちが格納されるのですか?
それは、「Aボタン」、「Bボタン」のどちらが押されたかによってきまるのさ。
あ、そうか。30行目、33行目の「if」文で切り替わるのですね?
その通り。「Aボタン」が押された場合は「STATE_ENGINE」、「Bボタン」なら「STATE_STOP」が格納される。
- 30行目 if button_a.get_presses():
- 31行目 nextState = STATE_ENGINE
- 32行目 break
- 33行目 if button_b.get_presses():
- 34行目 nextState = STATE_STOP
- 35行目 break
- 36行目 return nextState
そして、32行目または35行目の「break」でループを抜けて、36行目で「return nextState」とすることで、次にエンジンまたは停止のどちらの状態となるかをお知らせするのだ。
押されたボタンによって「nextState」に格納するものを変えることで、違う動きをさせることができるのですね。
そういうことなのだよ。
エンジンの状態の関数
残るは「エンジン」の状態の関数「StateEngine」ですね。
うむ。「StateEngine」は、次のような動作をするように作られている。
- プロペラを高速回転させる。
- ボタンが押されるのを待つ。
- Aボタンが押された場合は現状維持とする。
- Bボタンが押されたら、「次は停止である」ということを知らせる。
そして、これが「StateEngine」の中身だ。
- 38行目 def StateEngine():
- 39行目 nextState = STATE_ENGINE
- 40行目 display.show(‘E’)
- 41行目 pin1.write_analog(950)
- 42行目 pin13.write_digital(1)
- 43行目 while True:
- 44行目 if button_a.get_presses():
- 45行目 nextState = STATE_ENGINE
- 46行目 if button_b.get_presses():
- 47行目 nextState = STATE_STOP
- 48行目 break
- 49行目 return nextState
41行目で「pin1.write_analog()」のカッコの中の数字を950とすることで、プロペラを高速回転させている。
「StateCellMotor」では350でしたね。
- 24行目 def StateCellMotor():
- 25行目 nextState = STATE_CELL_MOTOR
- 26行目 display.show(‘C’)
- 27行目 pin1.write_analog(350)
先ほどの「StateCellMotor」と大きく異なるのは、44行目、45行目だ。
- 44行目 if button_a.get_presses():
- 45行目 nextState = STATE_ENGINE
えーと、あ!「break」がないですね?「break」を入れ忘れたのですか?
いや、ここには、「break」は必要ない。「エンジン」の状態では、「Aボタン」が押されても現状維持で、何もしないからね。
あ!そうか!!でも、それなら44行目、45行目もいらないのでは?
では、44行目、45行目をコメントアウトして試してみよう。
「ボタンが押されたかどうか」を見るのをやめるとどうなる?
コメントアウトは、「#」を入力するのでしたね。出来ました!
- 44行目 # if button_a.get_presses():
- 45行目 # nextState = STATE_ENGINE
では、動かしてみてごらん。
「Aボタン」をおして・・・プロペラがゆっくり回って・・・もう一回「Aボタン」をおして・・・プロペラが高速回転しました!
この状態で「Aボタン」を押すと、どうなるかな?
何も起こらないですね。「StateEngine」では、「Aボタン」を押しても、現状維持で何も起こらない、ということですね?
そうだね。では、「Bボタン」を押すとどうなるかな?
ええと、「Bボタン」だからプロペラが止まるのでは・・・あれれ??・・プロペラがゆっくり回っている!どうなっているの?
何もしないのに「ボタンが押されたかどうか」を見るのはなぜ?
これは、「StateEngine」の状態で「Bボタン」を押す前に押された「Aボタン」に反応してしまっている、ということなのだ。
な、なんですって?それは一体どういうことなんですか??
「StateEngine」の状態で「Aボタン」を押したときはどうなったかな?
「現状維持」で、プロペラが高速回転のまま何も起こらなかったですね。
そして、マイクロビットの中では、「Aボタンが押されました」という情報がセットされたのだ。
ふむふむ。
この「Aボタンが押されました」という情報は、「button_a.get_presses()」が呼び出されると、「True」となってマイクロビットの中から取り出される。
うむむむ。そうか。「True」となるので、「if」に反応するのですね。
- 43行目 while True:
- 44行目 if button_a.get_presses():
- 45行目 nextState = STATE_ENGINE
- 46行目 if button_b.get_presses():
- 47行目 nextState = STATE_STOP
- 48行目 break
- 49行目 return nextState
その通り。そして、マイクロビットの中では「Aボタンは押されていません」という情報がセットされる。
「Aボタンは押されていません」なので、「button_a.get_presses()」は「False」になるのですね?
イェス、その通りだ。関数「StateEngine」では、44行目で「button_a.get_presses()」が呼び出されている。
そうですね。
この44行目をコメントアウトする前のプログラムでは、「Aボタン」が押されて、マイクロビットの中で「Aボタンが押されました」となったとしても、すぐに「Aボタンは押されていません」に戻るのは分かるかな?
そうか、ループの中に「button_a.get_presses()」があるので、すぐにこれが呼び出されてしまうのですね。
そのとおり。そして、この44行目をコメントアウトしてしまうと、マイクロビットの中では「Aボタンが押されました」のままになってしまうのだ。ここまでは大丈夫かな?
何とかついてきています!
次に、「Bボタン」が押されるとする。
さっきやった操作ですね。「StateEngine」が「次は停止状態」というお知らせを返すので、「StateStop」が呼び出されるのですね。
うむ。ここで、44行目がコメントアウトされている場合と、されていない場合では、マイクロビットにセットされている情報が異なる。
44行目のコメントアウト | マイクロビットにセットされる情報 |
する | 「Aボタンが押されました」 |
しない | 「Aボタンは押されていません」 |
えーと、あ、そうか!
44行目がコメントアウトされていると、マイクロビットに「Aボタンが押されました」がセットされたまま「StateStop」が呼び出されてしまう。
なので、「StateStop」の中で「Aボタンが押されました」となって、「次はセルモーター」のお知らせが返されてしまう、ということなのですね!
ちょっと難しかったかな?
トマトの知能の限界を超えてしまったような気がしますョ。ところで、45行目はなぜ必要なのですか?
- 43行目 while True:
- 44行目 if button_a.get_presses():
- 45行目 nextState = STATE_ENGINE
- 46行目 if button_b.get_presses():
- 47行目 nextState = STATE_STOP
- 48行目 break
- 49行目 return nextState
44行目が「if」文なのだが、「if」文の後ろには「ブロック」を置かないといけないのだ。
「ブロック」・・・インデントで字下げしたやつでしたね。
なので、実質意味はないが、変数「nextState」に値を入れるだけの文を入れておいたのさ。
プロペラの回転数を調整しやすくしました
ここまでの説明では、モーターの回転数を調整するための「pin1.write_analog()」のカッコの中に、350などの数字を直接書き込んでいた。
14行目、27行目、41行目、54行目などのことですね。
この数字を変数に入れておくと、後で回転数を調整するのが楽になるよ。
楽になるのはよいですね!どうやってやるのですか?
まず、プログラムの冒頭で350などの数字を変数に入れてまとめておく。
- 7行目 RPM_STOP = 0
- 8行目 RPM_CELL = 350
- 9行目 RPM_STOP = 950
「RPM」っていうのは?
「回転数」ということだ。各自、分かりやすい名前を付ければよいぞ。
「KAITENSUU_STOP」でもいいのですね。「RPM_STOP」は、短くて良いですね。
そして、「pin1.write_analog()」のカッコには、数字ではなくこの変数を入れておく。
- 14行目 pin1.write_analog(RPM_STOP)
- 27行目 pin1.write_analog(RPM_CELL)
- 41行目 pin1.write_analog(RPM_ENGINE)
- 54行目 pin1.write_analog(RPM_STOP)
こうしておけば、モーターの回転数を調整するときに、修正する場所をすぐに見つけられるようになるのだ。
ちょっとした工夫ってわけですね。
まとめ
今回のまとめは・・・
- ボタンが押されたかどうかの確認はプログラムの各所でこまめに行うようにしよう。
- 回転数などの値は、変数に入れてまとめておくとよいですよ。
プログラムの全文は、以下の記事を見てね。(新しいタブで開きます。)
【マイクロビット応用】プラモの飛行機のプロペラのプログラム:最初のバージョン
つづく
コメント