Pythonロボティクスコース レッスン 14 *

テーマ.4-1 電子ベルの制作

加速度センサーで振動を検知してブザーを制御しよう

このレッスンで学ぶこと

このレッスンでは、Studuino:bitに内蔵されている「加速度センサー」を使用して、ブザーを制御する電子ベルを制作します。

新しいPython文法の学習

始めに、今回のレッスンで初めて扱うPythonの文法について学習しましょう。

2. 1 条件式を利用した変数への値の代入

ある条件によって、変数に代入する値を変えたいときに、これから紹介する「条件式」を使うと、コードを簡潔にまとめることができます。条件式は他の言語では三項演算子とも呼ばれます。

例えば、あるリストから先頭の要素を取得して、新しく用意した変数に代入する場合を考えます。リストの要素は「0」から始まる番号(インデックスともいいます)を指定して取得できるため、下のコードのように書くことができます。

【 サンプルコード 2-1-1 】

このとき、もしリストa1つも要素を持たない場合、要素を取得するときにエラーが発生します。

【 サンプルコード 2-1-2 】

このような場合でも、エラーを出さずに変数bへ代わりの値を入れるにはどのようにすれば良いでしょうか。1つの方法として、標準関数の len(~) で要素の数を調べ、リストが空かどうかを判断し、if文で処理を分けることが考えられます。

【 サンプルコード 2-1-3 】

上のコードでリスト a にいくつかの要素を入れたときと、空にしたときのどちらの場合でも、プログラムが上手く動作することを実際に確認してみましょう。(これではまだエラーが出ます)

この方法でも問題はありませんが、Pythonでは、条件式を使うと、同じ処理を1行にまとめることができます。

■ 条件式の書き方

条件式は次のルールで記述します。

変数名 = (条件式がTrueのときの値)if 条件式 else (条件式がFalseのときの値)

条件式を使い、【 サンプルコード 2-1-3 】を書き直したものが以下のコードです。

【 サンプルコード 2-1-4 】

リスト a にいくつかの要素を入れたときと、空にしたときのどちらの場合でも、プログラムが上手く動作することを確認してみましょう。

2. 2 プログラムの中で値が変わらない変数

長いプログラムを作成していると、ある決まった同じ値を使い回したい場面が出てきます。例として、Studuino:bitのLEDディスプレイを利用した簡単な迷路ゲームを作成するときを考えてみましょう。

<迷路ゲームの表示例>

上の例では、赤色に点灯するLEDで迷路の壁を表しています。このような迷路をいくつか用意するときに、どれもy座標が0の行とy座標が4の行は外壁として固定したとします。このとき、迷路の壁をより効率的に作るコードはどのように書くことができるでしょうか。

1つの方法として、外壁の部分のみをあらかじめ別のイメージを用意することが考えられます。実際にこの案で作成したプログラムが以下になります。

【 サンプルコード 2-2-1 】
※迷路は英語で「maze」といいます。

上のコードでは、外側の壁は固定のイメージで用意し、別で用意した内側の壁のイメージと合成することで、複数の迷路のイメージを作成しています。

しかしながら、作成者以外がこのコードを見ると、outer_wallsという変数も迷路を作成するときには編集するものだろうと考えてしまう可能性があります。実際は、outer_walls は 固定で表示する壁 です。そこで、この意図が伝わるように書き直しをします。

Pythonでは、プログラムの中で値が固定され、なおかつこれ以上変更がされることがない変数の名前を全て大文字で表す という習慣があります。これを踏まえて、【 サンプルコード 2-2-1 】を修正すると以下のようになります。

【 サンプルコード 2-2-2 】
変更【3行目、6行目、9行目】

このように全て大文字で表し、プログラムの中で値が変わらない変数のことを特別に定数と呼びます。もし、プログラム中に大文字のみで表される変数が出てきた場合はむやみに編集せず、「どんな意図で定数にしたのだろうか?」と考えるようにしましょう。

電子ベルの組み立て

組立説明書を開き、手順に沿って電子ベルを組み立てましょう。

3. 1 組み立てに必要なパーツ

  • Studuino:bit×1
  • 電池ボックス×1
  • ブロック基本四角(白)×1
  • ブロック三角(赤)×2
  • ブロックハーフB(グレー)×1
  • ブロックハーフB(赤)×2
  • ブロックハーフC(白)×6
  • ブロックハーフD(白)×2
  • ステー(白)×2
アーテックブロックの形状

3. 2 電子ベルの組立説明書

こちらから組み立て説明書を確認して、組み立てましょうここまでできたらクリック

チャプター4電子ベルのプログラム作成

これから製作する電子ベルは次の機能を備えています。

  1. 振ると音が鳴る
  2. もう一度振ると順番に音が変わり、続けると1つの曲が流れる
  3. ボタン操作で曲のテンポを変えられる

これらの機能を順番に実装し、電子ベルのプログラムを完成させましょう。

4. 1 振ると音が鳴る機能の作成

始めに、電子ベルを振ると音が鳴る機能を作成します。

■ 振っているときの加速度センサーの値を調べる

電子ベルが振られたかどうかを判定するために、加速度センサーのZ軸の値を利用します。

加速度は初期設定で-19.6~19.6m/s2の範囲で検出されるようになっていますが、set_fs()メソッドを使うと、その範囲を変えることができます。

StuduinoBitAccelerometer.set_fs(value)
・・・センサーの測定範囲を'2g'、'4g'、'8g'、'16g'から選択して設定します。
   初期設定では'2g'が選択されています。

それぞれの設定の検出範囲は以下の通りです。

  • ‘2g’ = -19.6~19.6m/s2
  • ‘4g’ = -39.2~39.2m/s2
  • ‘8g’ = -78.4~78.4m/s2
  • ‘16g’ = -156.8~156.8m/s2
※1gが重力加速度の9.8m/s2を表しており、その倍数で測定範囲を設定しています。

電子ベルを振ると、初期設定の「2g」の範囲を超える加速度が検出されるため、ここではset_fs()メソッドの引数に「8g」を指定して、範囲を「-78.4~78.4m/s2」に変更します。

また、テーマ.3-2で使用したget_values()メソッドは、X軸、Y軸、Z軸の3つの軸方向の加速度を(x, y, z)のタプルで返すメソッドでした。しかし、ここではz軸方向の値だけを取得すればよいので、代わりにget_z()メソッドを使います。

StuduinoBitAccelerometer.get_x()
・・・X軸方向の加速度を取得します。
StuduinoBitAccelerometer.get_y()
・・・Y軸方向の加速度を取得します。
StuduinoBitAccelerometer.get_z()
・・・Z軸方向の加速度を取得します。

以上を踏まえて、下のプログラムを作成し、加速度センサーのZ軸の値の変化を調べてみましょう。

【 サンプルコード 4-1-1 】

プログラムの実行中は振り上げ、振り下ろしの動作を繰り返します。値の変化が小さい場合は、少し強めに振ってください。

※USBケーブルを接続した状態で確認してください。
【 ターミナルの表示例 】

大きいときで、20(m/s2)以上の値が、小さいときでは-40(m/s2)以下の値が検出されることが分かります。これらの値を基準として、振ったことを判定する処理を作成します。

■ 振ったことを判定する

ベルを振る動作は「振り上げる」動作と「振り下ろす」動作が連続しています。このときの連続して変化する加速度センサーの値から、ベルを1回振ったという判定はどのようにして行うことができるでしょうか。

まず、振り上げや振り下ろすときの加速度の変化について考えてみます。振り上げ始めはZ軸の-方向の加速度が増えていきます。そして、速さが最大になったところから、今度は減速するために、Z軸+方向への加速度が増えることになります。

振り下ろすときも同様に、振り下ろし始めはZ軸+方向の加速度が増えていきますが、速さが最大になったところで、減速するためにZ軸-方向の加速度が増えることになります。

この一連の動作を1回行うときの加速度センサーZ軸の値の変化をグラフに表すと、次のようになります。

このグラフから、加速度センサーの値が20m/s2より大きくなったときがベルを振り上げた状態を表し、-40m/s2より小さくなっているときがベルを振り下ろした状態を表していることがわかります。そのため、以下のコードでベルの状態の変化を検知することができます。

しかし、このコードだけでは1回振ったという判定はできません。そこで、目印を付けて、振り上げから振り下ろしへの変化が起きたことを捉え、その瞬間に1回だけ振ったと判定するようにします。このときの目印のことを「フラグ(flag)」といいます。

フラグにはブール値(True、False)もしくは数値が利用されることが多いです。ここでは、flag_accelという名前の変数を用意し、振り上げを検知したときに「1」を、振り下ろしを検知したときに「0」を記録して、次のコードで判定を行います。

このコードでは変数flag_accelの値が「1」から「0」に変化した瞬間を振ったと判定しています。

この判定方法を使い、振ると音が鳴る機能は次のコードで実現できます。実際に、このプログラムを実行して動作を確認しましょう。

【 サンプルコード 4-1-2 】

4. 2 続けて振ると順番に音が変わり1つの曲が流れる機能の作成

ここでは例として、「きらきら星」の8小節の音が順番に鳴るようにプログラムを作成します。

【 きらきら星の楽譜 】

■ 音符の情報をまとめたタプルを用意する

音符の形は音の長さを表しており、四部音符の長さを基準として次のようにそれぞれの長さが決められています。

また、楽譜の7小節目にある点のついた音符は「付点八部音符」です。付点が付いた場合、元の音符の1.5倍の長さとなります。

そこで、四部音符の長さを600ミリ秒とし、それぞれの音符の長さを定数として次のように定義します。ただし、後で使用するStuduinoBitBuzzerクラスのon()メソッドで鳴らす時間を指定するときは、引数に整数値しか渡せないため、結果が浮動小数点数となる割り算が含まれる場合は、標準関数の「int()」や「round()」を使って整数値に変換する必要があります。ここでは小数点以下が切り捨てられるint()で変換します。

追加【3行目~6行目】

これらの定数を使い、曲を次の入れ子になったタプルで表します。

( 
  (1番目の音符の高さ, 1番目の音符の長さ), 
  (2番目の音符の高さ, 2番目の音符の長さ),
  .
  .
  .
)

内側のタプルが1つの音符情報を表し、外側のタプルがそれらの音符情報をまとめた1つの曲を表しています。この形式で楽譜の8小節をまとめたものが以下のコードです。

追加【8行目~24行目】

■ 音を順番に鳴らす

上で定義した曲のタプルから音符の情報を順番に取り出すために、ベルを振った回数をカウントする処理を追加します。また、その回数によってタプルの要素の番号(インデックス)を指定します。下のコードが完成プログラムです。

【サンプルコード 4-2-1】
変更・追加【28行目、36行目~38行目】

28行目のcount = 0は、カウント数を0に初期化する処理です。他に追加した36行目~38行目に追加・変更した3行のコードについても詳しく見ていきましょう。

36行目の count = count+1 if count < len(melody) else 1は、変数countに振った回数を記録する処理で、条件式を利用して1行にまとめています。これを通常のif-else文で表すと次のようになります。

countの値からmelodyのインデックスを指定するため、回数が増え続けないようにmelodyの長さで制限を掛けています。また、melodyの最後のインデックスまで到達すると回数をリセットして、1から数えるようにしています。

37行目のnote = melody[count-1]は、countmelodyのインデックスを指定して変数noteに値をひもづけています。melody[count-1]としているのは、回数は1から数えるのに対し、タプルのインデックスは0から始まるためです。

38行目のbuzzer.on(note[0], duration=note[1])で音を鳴らしています。タプルの0番目が音の高さを、1番目が音の長さを表しているため、このように書くことができます。

4. 3 ボタン操作でテンポを変更する機能の作成

ボタンAとボタンBを押すと、ディスプレイに表示された数字が1ずつ変わり、この倍数だけ曲のテンポを速める機能を追加します。

■ ボタンA・Bが押されたことを調べる

ボタンが押されているかどうかを調べるメソッドは、StuduinoBitButtonクラスのis_pressed()メソッドのほかにwas_pressed()メソッドがあります。

StuduinoBitButton.was_pressed()
・・・ボタンが過去に押されていたらTrueを返し、押されていないときはFalseを返します。
   一度呼び出されると、過去の情報をリセットします。

例えば、is_pressed()メソッドを使った下のプログラムを実行すると、ボタンAを押している間、連続してターミナルに1ずつ増える変数numの値が出力されます。

※ 実際に動作を確認する場合は、プログラムを新規作成し、そこに以下のコードを貼り付けて実行してください。

一方で、was_pressed()メソッドを使った下のプログラムでは、ボタンAを長押ししても、1回だけしかnumの値は出力されません。ボタンAをはなして、もう一度押すと1増えたnumの値が出力されます。

今回のようにボタンを押すたびに数を1ずつ増やしたり、減らしたりしたい場合は、was_pressed()メソッドを使います。

■ ボタンA・Bが押されるとテンポを変える

【 サンプルコード 4-2-1 】に、ボタンAが押されると、変数tempoを1減らし、ボタンBが押されると変数tempoを1増やすプログラムを追加します。また、この変数tempoによってブザーを鳴らす時間の長さが変わるように計算式を追加します。この2点を追加したコードが以下になります。

【 サンプルコード 4-3-1 】
変更・追加【1行目、29・30行目、40行目、42行目~47行目】

40行目では、引数durationに渡せるのが整数のみであるため、標準関数のint()で計算結果が必ず整数となるようにしています。

また、30行目、44行目、47行目のコードでは、StuduinoBitDisplayクラスのshow()メソッドの1番目の引数に数値データが渡せないため、標準関数のstr()を使い、文字列に変換してから渡しています。

プログラムをStuduino:bitに保存して実行する方法

作成したプログラムはMuの「実行」ボタンを押して実行する以外に、Studuino:bitに保存して実行する方法があります。Studuino:bitにプログラムを保存した場合、USBケーブルでパソコンと接続していなくても、プログラムを動作させることができます。以下の手順で実際にStuduino:bitに保存してプログラムを動かしてみましょう。

5. 1 Studuino:bitへのプログラムの保存手順

  1. 始めに、作成したプログラムをファイルとして保存します。画面上部の「保存」をクリックして、表示されたウィンドウで好きな名前を付けて保存しましょう。保存したファイルには、Pythonのプログラムファイルを表す「.py」の拡張子が自動的に付与されます。
  2. 画面上部の「転送」をクリックします。
  3. Studuino:bitには0~9の番号を選択して、プログラムを転送・保存する機能があります。表示された小さなウィンドウで、0番を選び、「Transfer」ボタンをクリックして、プログラムを転送しましょう。※ 転送が完了するまで少し時間が掛かります。
  4. 転送が終わると、画面の左下に「Transfer success」というメッセージが表示されます。このメッセージが表示された数秒後に、転送したプログラムが自動的に実行されます。Studuino:bitに電子ボックスが接続されていれば、このままUSBケーブルを抜いてもプログラムの実行状態が保たれます。

5. 2 保存したプログラムの中から番号を選択して実行する方法

上記の方法で転送したプログラムは、Studuino:bitの電源がOFFになっても、上書きされるまで、そのまま内部に残り続けます。そのため、この方法では最大で10個までプログラムを保存することができます。

プログラムの転送後は、自動的に直前に転送したプログラムが実行されるようになっています。また、リセットボタンを押したり、一度電源をOFFにして再びONに戻したりした後も、このプログラムが自動的に実行されるようになっています。

もし、他の番号に保存したプログラムを実行したい場合は、次の手順でStuduino:bitを操作します。

  1. Studuino:bitのボタンAを押したまま、リセットボタンを1回押す。リセットボタンから指を離したあとも、ボタンAは押したままにしておきます。
  2. 数秒して、LEDディスプレイに緑色で数字が表示されたら、ボタンAから指を離します。この数字は、プログラムの番号を表しています。
  3. ボタンAを押すたびに、数字が0から9まで順番に切り替わります。実行したいプログラムの番号に数字を合わせましょう。
  4. ボタンBを押すと、その番号のプログラムが実行されます。一度実行した番号はStuduino:bit内に記録されていて、リセットボタンを押したり、再び電源をONにしたりしたときにも、自動的にこのプログラムが実行されるようになります。

課題:電子ベルから流れる曲の変更

きらきら星に代わり、次の曲が電子ベルから流れるように、【 サンプルコード 4-3-1 】を変更する課題に取り組みましょう。

【 大きな古時計 】
※ヒント:八部音符は四部音符の半分の長さ、最後の付点二分音符(dotted half note)は二分音符の1.5倍の長さ(四部音符の3倍の長さ)となります。新しくこれらの定数を定義して、上の5小節目の途中までの音符情報をタプルにまとめましょう。

6. 1 プログラムの作成例

楽譜上で使われている「四部音符」「付点半音符」「八部音符」定数として定義し、タプルmelodyに、各音の情報をまとめればプログラムの完成です。

【 サンプルコード 6-1-1 】
変更・追加【2行目~4行目、7行目~28行目】

おわりに

7. 1 このレッスンのまとめ

このレッスンでは、Pythonの新たな構文として、「条件式」と
定数」について学びました。

  • 条件式
    条件によって、変数にひもづける値を変えたい場合、次の書式で1行にまとめることができる。
変数名 =(条件式がTrueのときの値)if 条件式 else(条件式がFalseのときの値)
  • 定数
    プログラムの中で値が固定され、さらに別の値に変更されることを想定していない場合は変数名を全て大文字で表す。

また、これらの構文と加速度センサーを利用して、振ると順番に音が鳴る電子ベルを制作しました。

そして、最後に確認した、プログラムをStuduino:bitに保存して実行する方法はこれから先も使用していきますので、改めてもう一度手順を確認しておきましょう。

7. 2 次のレッスンについて

次のレッスンでは、超音波距離センサーを利用して事故を未然に防ぐ車の運転支援システムを制作します。

TOP