【マイクロビット応用】[4] プラモの飛行機のプロペラ(3)回転が徐々に遅くなって止まるように改造

マイクロビット

 飛行機のプロペラのプログラムだが、よりリアルな動きを追求するため、改造を施したよ。

 どんな改造を施したのですか?

 プロペラが止まるときに、いきなり止まるのではなく、徐々に回転が遅くなってから止まるようにしたのだ。

 リアルですね~

どんな改造を施したのか?

 これまで見てきたプログラムでは、「エンジンでプロペラが高速回転」の状態で「Bボタン」を押すと、いきなりプロペラが止まってしまうようになっていた。

高速回転中にBボタンを押すと
いきなり止まる。

 これを、徐々に回転が遅くなるように改造したのですね?

高速回転中にBボタンを押すと
プロペラの回転が徐々に遅くなり
停止する。

 うむ。その通り。これを実現するため、新たに「徐々に減速」という状態を追加したのだ。

状態プロペラの動きAボタンBボタンプロペラが減速完了
停止止まっている。セルモーターの状態になる。停止の状態のまま(減速しない)
セルモーターゆっくり回る。エンジンの状態になる。停止の状態になる(減速しない)
エンジン速く回る。エンジンの状態のまま徐々に減速の状態になる(減速しない)
徐々に減速徐々に遅くなる。徐々に減速のまま徐々に減速のまま停止の状態になる。

 前に出てきた表ですね。一番下に「徐々に減速」が追加されていますね。

 そうなのだ。そして、この「徐々に減速」では、他の状態と異なり、プロペラの回転速度が徐々にゆっくりに変化していくのが特徴なのである。

 「エンジン」の状態で「Bボタン」を押すと、この「徐々に減速」の状態になるのですね?

 修正前のプログラムでは、「停止」の状態に移行していたが、今回は「徐々に減速」の状態に移行するようにしたのだよ。

 「プロペラが減速完了」という列が増えていますね。これはどういうことですか?

 これは、状態を切り替えるためのきっかけが1つ増えた、ということなのだ。 

 「きっかけ」ですか???

 元のプログラムでは、「Aボタン」や「Bボタン」で状態が変わっていたのは覚えているね?

 ボタンを押すことが「きっかけ」ということですね?

 その通りだ。ところが、「徐々に減速」の状態では、ボタンはきっかけにならず、プロペラの減速が完了することがきっかけとなり、「停止」に状態が変わるのだ。

 ということは、減速中はボタンを押しても、何も起こらない、ということですか?

 うむ。今回は、そういうふうにプログラムを改造したのだよ。

 なるほど・・・

「徐々に減速」の動きを行うための関数を追加

 ところで、それぞれの状態の動きを行う部分を「関数」にまとめていたのは覚えているかい?

 「State何とか」というやつですね?

 うむ。そして、今回追加したのは、徐々に減速して停止を行っている最中ということで、「StateStopping」という名前にしてみた。

状態番号関数の名前
停止の状態StateStop
セルモーターの状態StateCellMotor
エンジンの状態StateEngine
徐々に減速の状態StateStopping

 4つある関数のうち、一番名前が長いですね!

 「徐々に減速」の状態に割り当てた番号は3、変数名はSTATE_STOPPINGとしたぞ。

  • 3行目 STATE_STOP = 0
  • 4行目 STATE_CELL_MOTOR = 1
  • 5行目 STATE_ENGINE = 2
  • 6行目 STATE_STOPPING =3

 「関数」が追加されたら、呼び出す部分も追加されるのですか?

 ヤ~。プログラムでは、下のようになるのだ。

 (ドイツ語できたぞ??)

  • 76行目 while True:
  • 77行目  if state == STATE_CELL_MOTOR:
  • 78行目   state = StateCellMotor()
  • 79行目  elif state == STATE_ENGINE:
  • 80行目   state = StateEngine()
  • 81行目  elif state == STATE_STOPPING:
  • 82行目   state = StateStopping()
  • 83行目  else:
  • 84行目   state = StateStop()

 赤の部分に「StateStopping()」の呼び出しが追加されているのが分かるね?

 ヤ~!

「徐々に減速」の状態の関数の内容

 これまでの流れから言って、次は関数の中身の説明ですね?

 うむ。「StateStopping」は、次のような動作をするように作られている。

  1. プロペラの回転数を徐々に遅くする。
  2. Aボタン、Bボタンが押された場合は現状維持とする。
  3. 減速が完了したら、「次は停止である」ということを知らせる。

 そして、これが「StateStopping」の中身だ。

  • 53行目 def StateStopping():
  • 54行目  rpm = RPM_ENGINE
  • 55行目  nextState = STATE_STOPPING
  • 56行目  display.show(‘:’)
  • 57行目  while True:
  • 58行目   if button_a.get_presses():
  • 59行目    nextState = STATE_STOPPING
  • 60行目   if button_b.get_presses():
  • 61行目    nextState = STATE_STOPPING
  • 62行目   rpm = rpm – D_RPM
  • 63行目   if rpm <= RPM_CELL:
  • 64行目    nextState = STATE_STOP
  • 65行目    break
  • 66行目   pin1.write_analog(rpm)
  • 67行目   sleep(200)
  • 68行目 return nextState

 回転数の設定値は、エンジンの状態の回転数RPM_ENGINEから徐々に小さくしていくことになる。まずは、54行目で回転数を保持するために「rpm」という変数を用意した。

 「変数」は、数字を入れておく箱でしたね。

 箱に入れてある数字を少しづつ小さくすることで、徐々に減速させるのだ。最初は高速回転しているので、この変数「rpm」に、RPM_ENGINEを入れておく。

 ふむふむ。

 この変数「rpm」に格納された値を、57行目以降のループの中の62行目で小さくする。

  • 62行目   rpm = rpm – D_RPM
  • 63行目   if rpm <= RPM_CELL:
  • 64行目    nextState = STATE_STOP
  • 65行目    break
  • 66行目   pin1.write_analog(rpm)
  • 67行目   sleep(300)

 そして、66行目でマイクロビットからモーター駆動回路に出力するのだ。モーター駆動回路については、以前の記事をご覧ください。

【プログラミング応用】(1)モーターを動かしてみよう。

 ループの中にあるので、どんどん遅くなっていく、という訳ですね。

 そうだね。また、67行目で少し待つことで、遅くなる具合を調整している。

 「減速が完了したら・・・」の部分はどこですか?

 それは63~65行目の部分だ。

  • 63行目   if rpm <= RPM_CELL:
  • 64行目    nextState = STATE_STOP
  • 65行目    break

 モーターの回転数がセルモーターの時の回転数「RPM_CELL」以下になったら、減速完了と判断して、「次は停止」というお知らせを用意して、ループを抜けるのだ。

 「break」でループを抜けるのでしたね。

 ループを抜けると、「return」があるので、この関数の呼び出しもとに「お知らせ」が届くことになるのだ。

  • 68行目 return nextState

 58行目から61行目は、ボタンについての部分ですね。後で問題が起こらないようにするために、ここでボタンが押されたかどうかを見ているのでしたね。

 これは前回説明したところだね。詳しくは、前回の記事をご覧ください。

【プログラミング応用】(3)プラモの飛行機のプロペラ(2)

「エンジンの状態」の改造

 改造はこれで全てですか?何か忘れているような気がしますが・・・

 関数「StateEngine」の改造が残っているぞ。「Bボタン」を押した後に、「停止」の状態ではなく、「徐々に減速」の状態に切り替わるようにしないといけないのだ。

 思い出した!そういえば、こんな表がありましたね。

状態プロペラの動きAボタンBボタンプロペラが減速完了
停止止まっている。セルモーターの状態になる。停止の状態のまま(減速しない)
セルモーターゆっくり回る。エンジンの状態になる。停止の状態になる(減速しない)
エンジン速く回る。エンジンの状態のまま徐々に減速の状態になる(減速しない)
徐々に減速徐々に遅くなる。徐々に減速のまま徐々に減速のまま停止の状態になる。

 なんだか、大変そうな予感が・・・

 いや、心配はいらない。「StateEngine」からのお知らせを「次は停止状態」から「次は徐々に減速」に変更すればよいのだ。

  • 40行目 def StateEngine():
  • 41行目  nextState = STATE_ENGINE
  • 42行目  display.show(‘E’)
  • 43行目  pin1.write_analog(RPM_ENGINE)
  • 44行目  pin13.write_digital(1)
  • 45行目  while True:
  • 46行目   if button_a.get_presses():
  • 47行目    nextState = STATE_ENGINE
  • 48行目   if button_b.get_presses():
  • 49行目    nextState = STATE_STOPPING
  • 50行目    break
  • 51行目 return nextState

 「StateEngine」の中の49行目を変更するだけで良い。

 なんと!意外と簡単でしたね!

「状態切り替え」方式のプログラムは改造しやすい。

 プロペラのプログラムを改造してみたのだが、元のプログラムにはあまり手を加えていないことには気が付いたかな?

 新しく作った関数「StateStopping」の呼び出し部分の追加と、後は「エンジン」の状態から切り替わるときのお知らせを変更したぐらいですね。

 新たに関数「StateStopping」を作ることで、今回の改造はほとんど終わったと言えるだろう。

 なるほど・・・何か秘訣があるのですか?

 うむ。「状態切り替え方式」でプログラムを作っていることが秘訣なのだ。

 そうだったのですか!でも、まだピンときませんが・・・

 では、説明しよう。元のプログラムでは、三つの状態がある。そして、それぞれの動きを関数にまとめてある。

 ここに、新しい動作を加える場合は、その動作を新しい状態として追加すればよいのだ。

 追加した状態の動きを新しい関数にまとめて追加すればよく、状態の切り替わり方は「お知らせ」を変えるだけで済むのだ。

 「徐々に減速」の状態の関数を作るのは大変ではないですか?

 確かにそこは大変だが、他の状態の関数はほとんど手を加えていない。追加したい機能のみに集中してプログラムを改造することができるのだ。

 ほかの部分をあまりいじらなくてよいのは助かりますね。

 このように、「状態切り替え」方式でプログラムを作っておけば、後で改造するのが楽、ということは分かったかな?

 ヤー!

まとめ

 今回のまとめデース

  • 「状態切り替え」方式のプログラムは改造しやすい。
  • 状態を切り替えるきっかけはボタンでなくてもよい。

 改造したプログラムの全文は、以下の記事をご覧ください。(新しいタブで開きます。)

【プログラミング応用】[4.1] プラモの飛行機のプロペラのプログラム:回転が徐々に遅くなって止まるバージョン

つづく

コメント

タイトルとURLをコピーしました