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

決められた条件の成否で動作をわける「分岐処理」について学ぼう

このレッスンで学ぶこと

テーマ.2-1では「順次処理」、「反復処理」について学習しました。プログラムには、これら2つの他に、もう1つ「分岐処理」という大事な制御処理があります。このレッスンでは分岐処理の基本を学び、Studuino:bitに搭載されているセンサーを利用して、LEDディスプレイを制御する課題に取り組みます。

条件式とブール値

分岐処理は、ある条件式が成り立つときと、そうでないときで処理を分ける制御方法です。そのため、分岐処理を学習する前に、まずは条件式について理解する必要があります。

2. 1 条件式で使う比較演算子と比較演算の結果

テーマ.2-1のwhile文の説明でも少し紹介しましたが、条件式は次の比較演算子を使って作成します。

比較演算子の記号使い方意味
==a == baとbが同じ
!=a != baとbは異なる
<a < baがbより小さい(a==bは含まない)
>a > baがbより大きい(a==bは含まない)
<=a <= baがb以下(a==bを含む)
>=a >= baがb以上(a==bを含む)

この比較演算子を使った条件式を実行すると、ある結果が返ってきます。どういった結果が返ってくるのか、実際に==!=の比較演算子を使った以下のコードを、ターミナルで実行して確認しましょう。

>>> 1 == 1
True
>>> 1 != 1
False

条件式の比較演算の結果は True と False の2つの値のみをもつ「 ブール(bool)型 」のデータで返ります。True は日本語で「真(しん)」を意味し、条件式が正しく成り立っていることを表しています。一方で False は「偽(ぎ)」を意味し、条件式が成り立っていないことを表しています。

ブール型とは?
https://e-words.jp/w/%E3%83%96%E3%83%BC%E3%83%AB%E5%9E%8B.html

TrueFalseの先頭の文字が大文字であることに注意してください。truefalseと書くと、エラーになります。

ここで、while文について振り返ると、その処理は条件式が成り立つときは内部のコードを繰り返し実行し、成り立たないときは繰り返しを抜けるというものでした。

これをブール型を用いて説明すると、条件式を評価(比較演算)して、True が返ってきた場合は内部のコードを繰り返し実行し、False が返ってきた場合は繰り返しを抜けるということになります。

そのため、以下のようにwhile True:とすることで、内部の処理をずっと繰り返す「 永久ループ 」を実現することもできます。

while True:
    内部の処理コード
    .
    .
    .

また、True や False を整数型に変換すると、それぞれ「1」と「0」になります。

>>> int(True)
1
>>> int(False)
0

反対に、整数値をbool型に変換すると、「0」は False に、「0」以外の数値はすべて True に変換されます。

>>> bool(0)
False
>>> bool(1)
True
>>> bool(10)
True

文字列も同様に変換でき、空文字列の場合は False に、それ以外は True になります。

>>> bool(”)
False
>>> bool(‘a’)
True
>>> bool(‘b’)
True
>>> bool(‘ ‘)
True

このため、ある処理を行い、その結果が「0や空文字列」かどうかを調べたい場合は bool(結果) == False とし、「0以外の値」の場合は bool(結果) == True で確認することができます。

>>> bool(1-1) == False
True
>>> bool(10-2) == True
True
>>> bool(10/3) == True
True

int関数とは?
https://jp-seemore.com/iot/python/10657/

2. 2 複数の条件式をつなぐ論理演算子

私達は普段何かを購入するときに、「暖かくて かつ 値段が手ごろな洋服」や「チョコレート または クッキーをトッピングしたアイスクリーム」など、複数の条件を組み合わせて考えた上で意思決定をしています。プログラムの世界でも同様に、複数の条件式を組み合わせて処理を分けることがあります。そのときに使うのが 論理演算子 です。

論理演算子は「and」「or」「not」の3つがあり、このうちの「and」と「or」には複数の条件式をつなぐ役割があります。

■ and演算子

and演算子は、以下のように書くことで複数の条件式をつなぎます。

条件式1 and 条件式2

and演算子は2つの条件式の結果がどちらもTrueの場合だけTrueを返し、それ以外の場合はFalseを返します。

条件式1の結果条件式2の結果and演算の結果
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse

実際に次のコードをターミナルで実行して、結果を確認しましょう。

>>> 5 < 10 and ‘a’ == ‘a’
True
>>> 5 < 10 and ‘a’ == ‘A’
False
>>> 5 > 10 and ‘a’ == ‘a’
False
>>> 5 > 10 and ‘a’ == ‘A’
False

■ or演算子

or演算子は、以下のように書くことで複数の条件式をつなぎます。

条件式1 or 条件式2

or演算子は2つの条件式のうち、どちらか一方でも結果がTrueの場合はTrueを返し、どちらもFalseの場合のみFalseを返します。

条件式1の結果条件式2の結果or演算の結果
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse

こちらも、実際に次のコードをターミナルで実行して、結果を確認しましょう。

>>> 5 < 10 or ‘a’ == ‘a’
True
>>> 5 < 10 or ‘a’ == ‘A’
True
>>> 5 > 10 or ‘a’ == ‘a’
True
>>> 5 > 10 or ‘a’ == ‘A’
False

■ not演算子

not演算子は条件式の結果を反転させる役割があります。つまり、 not True は False になり、 not False は True になります。実際に次のコードをターミナルで実行して、結果を確認しましょう。

>>> not 5 < 10
False
>>> not 5 > 10
True

分岐処理

分岐処理で使うのが if-else文 です。if-else文は、次の形式で書きます。

if 条件式:
	条件式が成り立つときに実行するコード
	.
	.
else:
	条件式が成り立たないときに実行するコード
	.
	.
	.

条件式が成り立つときのみ、特定の処理を実行したい場合は、else文以下は省略できます。まずは、簡単なプログラムを通してこのif-else文の使い方を確認していきましょう。

3. 1 得点によって合否を振り分けるプログラム

語学の検定試験や自動車の運転免許試験など、世の中にある試験では知識やスキルがある一定の水準に達しているかどうかを、あらかじめ設定した合格点によって判断します。これらの試験は多くの人が受けるため、採点や合否の判定をコンピューターによって自動化し、効率的に運用する仕組みが整えられています。ここでは、複数の受験者の合否をそれぞれの得点から振り分けるプログラムを作成します。

■ 作成するプログラムの処理の流れ

受験者を探索し、得点が合格基準点の「60点」に達している場合は合格者リストに追加し、そうでない場合は不合格者のリストに追加します。そして、すべての探索を終えた後に合格者リストと不合格者リストをそれぞれ表示します。

■ プログラムの作成

始めに、振り分けの対象として次の5名の受験者のデータを用意します。

受験番号得点
No.0172
No.0256
No.0386
No.0445
No.0563

データ(data)はキーを受験番号に、値(要素)を得点にした辞書型で作成しましょう。

  1. data = {‘No.01′:72,’No.02′:56,’No.03′:86,’No.04′:45,’No.05’:63}

次に、合格者(successful)と不合格者(unsuccessful)を管理する2つの空のリストを用意します。

追加【2行目~3行目】
  1. data = {‘No.01′:72,’No.02′:56,’No.03′:86,’No.04′:45,’No.05’:63}
  2.  
  3. successful = []
  4. unsuccessful = []

続けて、受検者の合否を繰り返し判定する処理を作成します。for~in文を使うと、リストと同様に辞書も要素を順番に取り出すことができます。ただし、辞書の場合は値ではなく、キーが取り出されることに注意してください。

for キー in 辞書:
	繰り返し実行したいコード
	.
	.

ここでは、キーとなっている受験番号を取り出して変数numberに格納し、data[number] と指定することで値(得点)を取得するようにします。そして、条件式で得点を評価し、if-else文で60点以上の場合とそうでない場合に分け、合格者のリストsuccessfulと不合格者のリストunsuccessfulにそれぞれappend()メソッドで受験番号を追加します。

追加【6行目~10行目】
  1. data = {‘No.01′:72,’No.02′:56,’No.03′:86,’No.04′:45,’No.05’:63}
  2.  
  3. successful = []
  4. unsuccessful = []
  5.  
  6. for number in data:
  7.   if data[number] >= 60:
  8.     successful.append(number)
  9.   else:
  10.     unsuccessful.append(number)

最後に、それぞれのリストの中身をprint()関数で表示します。print()関数は、,(カンマ)で区切って複数の引数を指定することができ、この場合は1文に合成して表示されます。

【サンプルコード 3-1-1】
追加【12行目~13行目】
  1. data = {‘No.01′:72,’No.02′:56,’No.03′:86,’No.04′:45,’No.05’:63}
  2.  
  3. successful = []
  4. unsuccessful = []
  5.  
  6. for number in data:
  7.   if data[number] >= 60:
  8.     successful.append(number)
  9.   else:
  10.     unsuccessful.append(number)
  11.  
  12. print(‘successful:’, successful)
  13. print(‘unccessful:’, unsuccessful)

完成したプログラムを画面上の実行ボタンを押して実行し、結果を確認しましょう。

successful: [‘No.03’, ‘No.01’, ‘No.05’]
unccessful: [‘No.02’, ‘No.04’]

■ 複数の条件式で処理を分岐する方法

if文はある条件式が「成り立つとき」「成り立たないとき」の2択だけではなく、「ある条件式が成り立つとき」「ある条件式は成り立たないが、別の条件式なら成り立つとき」「どの条件式も成り立たないとき」のように3つ以上に処理を分岐することができます。

例えば、先ほどのプログラムでは、60点以上を合格、60点未満を不合格としていましたが、ここに新たに補欠合格を設け、60点未満でも55点以上なら補欠合格者リストsubstituteに追加することにします。これを実現する方法の1つは、if文またはelse文の中に、さらに別のif文-else文を書くことです。以下のように【サンプルコード 3-1-1】を変更して実行結果を確認してみましょう。

【サンプルコード 3-2-1】
追加・変更【5行目、11行目~14行目、18行目】
  1. data = {‘No.01′:72,’No.02′:56,’No.03′:86,’No.04′:45,’No.05’:63}
  2.  
  3. successful = []
  4. unsuccessful = []
  5. substitute = []
  6.  
  7. for number in data:
  8.   if data[number] >= 60:
  9.     successful.append(number)
  10.   else:
  11.     if data[number] >= 55:
  12.       substitute.append(number)
  13.     else:
  14.       unsuccessful.append(number)
  15. print(‘successful:’,successful)
  16. print(‘unccessful:’,unsuccessful)
  17. print(‘substitute:’,substitute)
(実行結果)

successful: [‘No.03’, ‘No.01’, ‘No.05’]
unccessful: [‘No.04’]
substitute: [‘No.02’]

上のプログラムでは、最初の if data[number] >= 60: で「点数が60点以上かどうか」を調べ、60点未満だった場合は、さらにその中の if data[number] >= 55 で「点数が55点以上かどうか」を判定しています。

この書き方以外にも「 elif文 」を使ってまとめることもできます。最初のif文の条件式が成立しなかった場合は、次のelif文の条件式を判定するようになっており、また、elif文はif文とelse文の間にいくつでも入れることができます。

if 条件式1:
	条件式1が成り立つときに実行するコード
	.
	.
elif 条件式2:
	条件式1は成り立たないが、条件式2が成り立つときに実行するコード
	.
	.
elif 条件式3:
	条件式1と条件式2は成り立たないが、条件式3が成り立つときに実行するコード
	.
	.
else:
	すべての条件式が成り立たないときに実行するコード
	.
	.

【サンプルコード 3-2-1】を、elif文を使って書き直すと以下のようになります。

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

変更【11行目~14行目】
  1. data = {‘No.01′:72,’No.02′:56,’No.03′:86,’No.04′:45,’No.05’:63}
  2.  
  3. successful = []
  4. unsuccessful = []
  5. substitute = []
  6.  
  7. for number in data:
  8.   if data[number] >= 60:
  9.     successful.append(number)
  10.   elif data[number] >= 55:
  11.     substitute.append(number)
  12.   else:
  13.     unsuccessful.append(number)
  14. print(‘successful:’,successful)
  15. print(‘unccessful:’,unsuccessful)
  16. print(‘substitute:’,substitute)

このように、同じ結果となる場合でも、プログラムの書き方は1通りとは限りません。混同してしまい誤ったプログラムを書いてしまうこともよくあるので、慣れないうちは図などを使って処理の流れを整理してからプログラムを書くようにしましょう。

課題:センサーを利用した制御

センサーは人の五感(視覚・聴覚・触覚・味覚・嗅覚)と同じように、周囲の環境から情報を集める働きがあります。現在の家電製品やロボットの多くは何かしらのセンサーが使われていて、周囲の環境に合わせて自動で動作するようになっています。

例えば、エアコンには温度センサーが使われており、設定した温度と室温が一致するように制御されています。

また、新しい製品モデルでは人を感知するセンサーも搭載されており、人が居ないときは自動で停止したり、人がいる方向へ風を送ったりするなど多機能化しています。

レッスンの最後に課題として、Studuino:bitに搭載されているセンサーを使って、センサーで読み取った周囲の情報から処理を分けるプログラムを作成していきましょう。

4. 1 Studuino:bitに搭載されているセンサー

Studuino:bitには、「光センサー」「温度センサー」「ボタン」「モーションセンサー」の4つのセンサーが搭載されています。このレッスンでは、この中から光センサーを使います。

センサー名役割
光センサー周囲の明るさを調べる
温度センサー周囲の温度を調べる
ボタン押されているかどうかを調べる
モーションセンサー加速度、ジャイロ(角速度)、磁気の3つを測定する

4. 2 光センサーで周囲の明るさを調べる

明るさや温度などは本来コンピュータ上で直接扱うことができないアナログなデータです。そのため、センサーで取得したアナログデータはコンピュータが扱えるディジタルデータに変換されます。ディジタルデータとはつまり数値データで、Studuino:bitに搭載されているセンサーが取得したデータは全て数値で表されます。

では、光センサーを使い、周りの明るさがどのような数値データとして表れるのか、プログラムを書いて確認しましょう。

■ プログラムの作成

始めに、エディタエリアに以下の2行のコードをコピーして貼りつけます。

  1. from pystubit.board import lightsensor
  2. import time

1行目のコードでは、光センサーからデータを取得するためのオブジェクト ligntsensorを呼び出し、2行目のコードでは、プログラムの中で時間を制御するタイムオブジェクトtimeを呼び出して利用できるようにしています。

次に、光センサーのデータを500ミリ秒おきに繰り返し取得するコードを書きます。 レッスンの始めの方で紹介した while True: の永久ループを使いましょう。

追加【4行目】
  1. from pystubit.board import lightsensor
  2. import time
  3.  
  4. while True:

明るさの取得には、光センサーのオブジェクトlightsensorの get_values()メソッドを使います。このメソッドは戻り値として、明るさを表す整数値を返します。この戻り値を変数 value に格納し、print()関数でターミナルに表示するようにしましょう。また、次の取得までに500ミリ秒間をあけるために、タイムオブジェクトtimesleep_ms()メソッドを最後の行に追加しましょう。

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

追加【5行目~7行目】
  1. from pystubit.board import lightsensor
  2. import time
  3.  
  4. while True:
  5.     value = lightsensor.get_value()
  6.     print(value)
  7.     time.sleep_ms(500)
※7行目のtime.sleep_ms(500)で指定する時間を短くし過ぎると、print()関数の実行による表示処理が重くなり、Muがビジー状態となって操作できなくなることがあるので注意してください。

■ プログラムの実行

【サンプルコード 4-2-1】を実行して、表示された値が「光センサーが露出しているとき」と「光センサーを手で覆い隠したとき」とで、どのように変わるのかを確認しましょう。

(光センサーが露出しているときの表示例)
(手で光センサーを覆い隠したときの表示例)

光センサーで取得した周囲の明るさは、「0~4095」の範囲の整数値で表されます。数値が小さいほど暗く、数値が大きいほど明るいことを意味しています。

4. 3 周囲の明るさで処理を分ける

では、光センサーで取得した周囲の明るさを利用して処理を分けるプログラムを作成します。ここでは例として、周りが暗くなると自動で点灯するセンサー式ライトをイメージして、光センサーの値がある値を下回ると、一定時間LEDディスプレイが点灯するようにコードを書いていきましょう。

■ プログラムの処理の流れ

このプログラムの処理の流れは次の図のようになります。この図からも分かるように、ずっと繰り返し周囲の明るさを調べることで、いつ明るさが変化してもすぐに反応し、自動でLEDディスプレイを点灯できるようになります。

■ しきい値の設定

プログラムを作成する前に、ひとつ考えなければならないことがあります。「周りが暗い」とはコンピュータ上でどのように判定すれば良いでしょうか?

コンピュータ上では明るさは数値データとして扱いました。そのため、暗いかどうかの判定も取得した数値データをある基準となる値と比較することで行う必要があります。

このようにある状態とそうでない状態を分けるための基準値のことを「しきい(閾)値」といいます。この場合のしきい値には明確な決め方はありません。自分で調べた光センサーの数値を元にして、どれくらいの暗さが(数値の大きさが)LEDディスプレイを点灯するのに相応しいのかを考えて決めてください。

■ プログラムの作成

それでは、決めたしきい値を使って目的のプログラムを作ります。プログラムは、光センサーの値を調べたときのものから変更していきます。

まずは、LEDディスプレイを利用するためのコードを追加します。下のコードから追加した3行(2行目~3行目、6行目)をコピーして、エディタエリアの同じ場所に貼り付けましょう。

追加【2行目~3行目、6行目】
  1. from pystubit.board import lightsensor
  2. from pystubit.board import display
  3. from pystubit.board import Image
  4. import time
  5.  
  6. image = Image(‘11111:11111:11111:11111:11111:’)
  7.  
  8. while True:
  9.     value = lightsensor.get_value()
  10.     print(value)
  11.     time.sleep_ms(500)

6行目で作成しているimageは、LEDの点灯パターン情報を持つイメージオブジェクトです。ここでは、全てのLEDが点灯するパターン情報を持つように用意しています。

続いて、while文の中に分岐処理のコードを追加します。これも10行目のif文の条件式を除いて、そのまま書き写しましょう。

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

追加・変更【10行目~13行目】
  1. from pystubit.board import lightsensor
  2. from pystubit.board import display
  3. from pystubit.board import Image
  4. import time
  5.  
  6. image = Image(‘11111:11111:11111:11111:11111:’)
  7.  
  8. while True:
  9.     value = lightsensor.get_value()
  10.     if value < 1000: #「1000」の代わりに決めたしきい値を書きます。
  11.         display.show(image)
  12.         time.sleep_ms(1000)
  13.         display.clear()

10行目のif value < 1000:では、さきほど自分で決めたしきい値で処理を分岐させます。

次の11行目のdisplay.show(image)では、LEDディスプレイのオブジェクトdisplayが持つshow()メソッドでイメージオブジェクトimageのパターンでLEDを点灯させています。show()メソッドは、これまで何度か使用したscroll()メソッドと同じくLEDディスプレイの表示を制御します。show()メソッドは指定された文字列の文字を1つずつ切り替えながら表示させたり、今のようにイメージオブジェクトの持つ点灯パターンを表示させたいときに使います。

そして、最後の13行目で、LEDディスプレイのオブジェクトdisplayが持つclear()メソッドを実行し、点灯した全てのLEDを消灯しています。

■ プログラムの実行

【サンプルコード 4-3-1】を実行し、光センサーの周りを手で覆うとのLEDディスプレイが赤色に点灯することを確認しましょう。

おわりに

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

このレッスンでは、条件式と分岐処理について以下のことを学びました。

  • 条件式は比較演算子を使って作成すること。
  • 論理演算子(「and」や「or」)で複数の条件式をつなぐことができること。
  • 比較演算の結果はブール値(「True」もしくは「False」)であること。
  • if-else文を使うと、条件式を評価した結果によって処理を分けることができること。
  • if-else文を入れ子にしたり、elif文を使うことで、さらに複数の条件によって処理を分岐できること。

テーマ.2-1で学んだ「反復処理」と、今回の「分岐処理」を理解することで、「順次処理」だけではできない複雑な動作が実現できます。

また、Studuino:bitの光センサーの使い方についても見てきました。このレッスンで紹介したセンサー以外にも社会では様々なセンサーが活用されており、私達の生活を支えています。Studuino:bitの残りのセンサーについては、他のレッスンで使い方を詳しく紹介します。

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

次回のレッスンでは、オブジェクトの作成に必要な型である「クラス」について学習します。

TOP