Pythonロボティクスコース レッスン 15 *
テーマ.4-2 車の運転支援システムの制作
超音波距離センサーを使って衝突を未然に防ぐ運転支援システムをつくろう
チャプター1
このレッスンで学ぶこと
このレッスンでは、「超音波距離センサー」の特性について詳しく見ていき、正面にある物体との距離によって車型ロボットを自動制御します。
チャプター2
新しいPython文法の学習
始めに、今回のレッスンで初めて扱うPythonの文法について学習しましょう。
これからレッスンを先へ進めていくにつれて、記述するコードの量は次第に増えていきます。慣れないうちは、書くコードの量に比例して、エラーが起きる回数も多くなってしまいます。エラーが起きたときは、その原因となるバグ(プログラムの不具合)を探し、修正を行います。
このバグを探す方法としてよく用いられるのが、プログラムをいくつかのステップに分けて、各ステップごとに現在のデータを出力する方法です。特に、構造が複雑なプログラムを作成するときは、自分自身でバグを発見する方法の1つとしてよく用いられています。
データを出力するときは、そのまま数値や文字列を表示するのではなく、どこにある何のデータを表しているのかを分かりやすくするために見た目の加工を行います。ここでは、そのための方法を紹介します。
2. 1 `format()`メソッドによる文字列へのデータの埋め込み
テーマ.1-4でも少し紹介しましたが、文字列オブジェクトの format()
メソッドを使用すると、文字列中の波括弧 {}
を format()
メソッドに渡す引数に置き換えた新しい文字列データを作成することができます。復習として、ターミナルに次のコードを書いて、実行してみましょう。
>>> '{}, {}, {}'.format(1, 2, 3) '1, 2, 3'
{}
の部分を 置換フィールド といい、通常は、{}
の中に フィールドネーム を書きます。フィールドネームは上のコードのように省略することもでき、その場合、format()
メソッドの引数の先頭から順に置き換えられていきます。フィールドネームを付けた場合は、以下のようにキーワード引数として指定します。
>>> '{a}, {b}, {c}'.format(a=1, c=3, b=2) '1, 2, 3'
また、フィールドネームに続けて「:
(コロン)」を書くと、フォーマットの書式を指定することもできます。例えば、:f
を指定すると小数点以下の桁数が固定された固定小数点数として表示されます。
>>> '{a:f}, {b:f}, {c:f}'.format(a=1,c=3,b=2) '1.000000, 2.000000, 3.000000'
このとき、f
の前に .~
を付けると、表示する小数点以下の桁数を ~
の数字で指定することもできます。
>>> '{a:.3f}, {b:.2f}, {c:.1f}'.format(a=1, c=3, b=2) '1.000, 2.00, 3.0'
この他にも、format()
メソッドには次のような書式があります。
- 数値に対して符号を付ける
記号 | 意味 |
---|---|
+ | 符号の使用を、正の数と負の数の両方に対して行うことを指定します。 |
– | 符号の使用を、負の数のみに対して行うことを指定します。 |
(空白)半角スペース | 正の数の場合は空白を前に付け、負の数の場合は負号 - を前に付けることを指定します。 |
>>> '{a:+}, {b:-}, {c: }'.format(a=1, c=3, b=2) '+1, 2, 3'
- 数値をパーセンテージで表記する
記号 | 意味 |
---|---|
% | 数値は100倍され、f と同じく固定小数点数のフォーマットで、パーセント記号が付けられます。 |
>>> '{a:0.0%}, {b:0.1%}, {c:0.2%}'.format(a=1, c=3, b=2) '100%, 200.0%, 300.00%'
- フィールド幅を指定する
:
の後に数字を続けて書くと、その大きさでフィールドの幅を固定して出力します。
>>> '{:15}'.format('python') 'python '
- フィールド幅内での位置を指定する
固定されたフィールド幅内での位置(左寄せ、中央寄せ、右寄せ)を指定することができます。
記号 | 意味 |
---|---|
< | 左寄せを指定します。ほとんどのオブジェクトにおいては、左寄せがデフォルトになっています。 |
> | 右寄せを指定します。 |
^ | 中央寄せを指定します。 |
>>> '{:<16}'.format('python') 'python ' >>> '{:^16}'.format('python') ' python ' >>> '{:>16}'.format('python') ' python'
書式について一部のみを紹介しましたが、詳細を知りたい場合は、以下のPython公式ガイドを参照してください。
チャプター3
車型ロボットの組み立て
組立説明書を開き、手順に沿って車型ロボットを組み立てましょう。
3. 1 組み立てに必要なパーツ
- Studuino:bit×1
- ロボット拡張ユニット×1
- 電池ボックス×1
- DCモーター×1
- 超音波距離センサー×1
- センサー接続コード(3芯15cm)×1
- ブロック基本四角(グレー)×5
- ブロック基本四角(赤)×1
- ブロックハーフA(グレー)×1
- ブロックハーフB(グレー)×2
- ブロックハーフC(白)×5
- ブロックハーフD(白)×1
- ステー×1
- 丸(目玉)×1
- ギヤ大×2
- ギヤ用タイヤゴム×2
【 アーテックブロックの形状 】
【 組み立て説明書 】
チャプター4
運転支援システムの制作
テレビ広告でもおなじみになった自動ブレーキ機能や、高速道路で車線を認識して自動で走行する機能など、ドライバーの運転を支援するシステムが多くの自動車に搭載されるようになりました。また、コンピュータが無人で運転を行う、完全な自動運転技術の開発も既に様々な国や地域で実証試験が進められていて、その実現がより身近なものになってきています。
こういった技術が実現できた背景には、レーダーやカメラを利用したセンシング技術の発展があります。例えば、ミリ波レーダーは電波の反射を利用して、歩行者や車両の有無やその距離を検出できます。ミリ波レーダー以外にも、カメラの画像から同様に歩行者や車両、標識や白線などを認識する技術も既に開発されています。こういった技術は年々進化しており、自動運転の実現に大きく貢献しています。
そこで、このレッスンでは次の2つの機能をもつ運転支援システムを作成します。
- 一定距離以内に歩行者や車両、障害物などを検知するとブザー音で注意を促す機能
- 衝突の恐れがある場合に、自動でブレーキをかけて停止する機能
上記の機能を実現するために、超音波距離センサーを使用します。超音波距離センサーの使い方はテーマ.3-1で簡単に紹介しましたが、今回はその特性をより詳しく見ていきましょう。
4. 1 超音波距離センサーの値を調べる
超音波距離センサーを使い、様々な環境で距離を計測してみましょう。
■ 計測プログラムの作成
P0に接続した超音波距離センサーからget_distance()メソッドで1秒ごとに距離を取得する次のプログラムを作成し、Studuino:bitで実行します。
【 サンプルコード 4-1-1 】
from pyatcrobo2.parts import UltrasonicSensor
import time
us = UltrasonicSensor('P0')
while True:
print('{}cm'.format(us.get_distance()))
time.sleep_ms(1000)
超音波距離センサーは一度計測してから、10msの間は音波を検出できない仕様になっています。そのため、短い時間で連続して値を取得すると、-0.03のような正常でない数値が検出されます。必ず次の計測との間に15ms以上の時間をあけるようにしてください。
■ 天井や壁との距離を調べる
超音波距離センサーは、およそ3cm~250cmの範囲で距離を計測することができます。実際に、近くの天井や壁、床、机、箱の側面などに超音波距離センサーを向け、最大で計測できる距離を確認しましょう。
※PCとStuduino:BitをUSBケーブルで接続し、確認を行ってください。
※USBケーブルが短いため、遠くは天井、近くは机の平らな面に向けて計測すると良いでしょう。
また、キットの箱の側面に向けて近づけていき、距離が短い(3cm以下)と正確な距離が取得できないことも確認しておきましょう。
■ 計測可能な範囲を確認する
超音波距離センサーは真正面から左右に15°の範囲にある物体を検出することができます。ブロックのかたまりを用意して、実際に確認しましょう。
■ 複数の物体がある場合の計測
計測範囲内に複数の物体がある場合、最も近くにあるものとの距離が計測されます。実際にブロックのかたまりを2つ用意して確認しましょう。
■ 面が小さい物体の検出
超音波距離センサーは壁や箱の側面のように面が広く、平らで音波が反射されやすいものは検出できますが、ペンのように細く面が狭いものはうまく検出できません。実際に、超音波距離センサーの正面にペンや細めの物体を置き、距離が取得できるか確認しましょう。
※ペンを持っている手が検出されないように、真上から近づけましょう。
他にも、布やスポンジのように柔らかく、音波を吸収しやすいものも正確に距離を計測できません。
■ 物体の向きと音波の反射方向の関係
平らな面をもつ物体でも、超音波距離センサーに対して斜めに配置されていると、音波が別方向に反射され、反射波が届かないため、検出することができません。実際にキットの箱を、超音波距離センサーに対しておよそ45度の向きに設置すると、実際とは異なる距離が取得されることを確認しましょう。
また、次のように箱の先に別の物体がある場合は、その物体までの片道の道のりが距離として計測されます。
■ 超音波距離センサーの特性のまとめ
上で確認した特性に注意して、超音波距離センサーを利用してください。
- およそ3cm~250cmの範囲で物体との距離を計測できる。
- 真正面から左右におよそ15°の範囲内にある物体との距離が計測できる。
- 計測範囲内に2つ以上の物体がある場合、最も近い物体との距離が計測される。
- 面が小さい物体や音波を吸収する物体との距離は計測できない。
- センサーに対して、物体の表面が斜め(45度前後)を向いている場合、音波が別方向に反射されるため、距離が計測できない。
4. 2 一定の距離以内に障害物があると警告音を鳴らす機能の作成
実際の自動車でも、自動でブレーキをかける前に、前方の車両と距離が近づきすぎたり、周囲に衝突の危険があるものがあれば、ドライバーに対し音で注意を促す機能が搭載されています。ここでは、超音波距離センサーを使い10cm以内に物体を検出すると、ブザー音を鳴らすという仕様でプログラムを作成しましょう。
■ ボタンAを押すと前進するプログラムの作成
車のアクセルの操作のように、ボタンAを押すと前進し、はなすとゆっくりと止まるプログラムを用意します。次のコードを書きましょう。
【 サンプルコード 4-2-1 】
from pystubit.board import button_a
from pyatcrobo2.parts import DCMotor
dcm = DCMotor('M1')
dcm.power(100)
while True:
if button_a.is_pressed():
dcm.cw()
else:
dcm.stop() #ブレーキをかけずにゆっくりと止めます。
■ 一定距離以内に障害物を検出したらブザーを鳴らすプログラムの作成
超音波距離センサーで物体との距離が10cm未満になったら、注意喚起のために、ブザーから短く音を3回鳴らします。このブザーを鳴らす動作を関数にまとめて呼び出せるようにしましょう。【 サンプルコード 4-2-1 】から次のようにコードを変更・追加します。
変更・追加【1行目、5行目~8行目】
from pystubit.board import button_a, buzzer
from pyatcrobo2.parts import DCMotor
import time
def alarm(): # alarmには英語で危険を知らせるという意味があります。
for i in range(3):
buzzer.on('C7', duration=50) # 耳につくように、高い音を鳴らします。
time.sleep_ms(50)
dcm = DCMotor('M1')
dcm.power(100)
while True:
if button_a.is_pressed():
dcm.cw()
else:
dcm.stop()
次に、超音波距離センサーで距離を取得し、10cm未満なら関数alarmを実行するコードを追加します。このとき、超音波距離センサーは測定に失敗すると「-0.03」を返すため、この場合を除くように分岐処理(if文)の条件を用意する必要があります。
【 サンプルコード 4-2-2 】
変更・追加【2行目、10行目、16行目~18行目】
from pystubit.board import button_a, buzzer
from pyatcrobo2.parts import DCMotor, UltrasonicSensor
import time
def alarm():
for i in range(3):
buzzer.on('C7', duration=50)
time.sleep_ms(50)
us = UltrasonicSensor('P0')
dcm = DCMotor('M1')
dcm.power(100)
while True:
if button_a.is_pressed():
distance = us.get_distance()
if distance > 0 and distance < 10: # -0.03の場合を除くため、条件にdistance > 0 を追加しています。
alarm()
dcm.cw()
else:
dcm.stop()
上のプログラムを実行して、動作を確認しましょう。
4. 3 衝突の恐れがある場合に自動で停止する機能の作成
さらに、前方との距離が5cm未満まで近づくと、衝突の恐れが高くなったと判断して、ボタンAを押している場合でも強制的にブレーキをかけて停止するようにします。【 サンプルコード 4-2-2 】から以下のコードを変更・追加しましょう。
【 サンプルコード 4-3-1 】
変更・追加【19行目~22行目】
from pystubit.board import button_a, buzzer
from pyatcrobo2.parts import DCMotor, UltrasonicSensor
import time
def alarm():
for i in range(3):
buzzer.on('C7',duration=50)
time.sleep_ms(50)
us = UltrasonicSensor('P0')
dcm = DCMotor('M1')
dcm.power(100)
while True:
if button_a.is_pressed():
distance = us.get_distance()
if distance > 0 and distance < 10:
alarm()
if distance < 5:
dcm.brake()
else:
dcm.cw()
else:
dcm.stop()
これでプログラムの完成です。実行して動作を確認しましょう。
チャプター5
課題:机から落ちない車の制作
超音波距離センサーを下の図のように机に向けた取り付け方に変更します。
【 サンプルコード 4-3-1 】を参考にして、前進中に机から落ちそうになると、自動で停止するようにプログラムを作成しましょう。
※このプログラムではボタンAで車を操作せず、常に前進するようにしておきましょう。
5. 1 プログラムの作成例
上記のように超音波距離センサーを取り付けた場合、平らな机から超音波距離センサーまでの距離はおよそ7cmほどになります。そこで、下のサンプルコードでは、余裕を見て検出した距離が8cmよりも短い場合は前進し、そうでない場合は停止するようにしています。ただし、センサーの値はバラツキがあるため、実際に【 サンプルコード 4-1-1 】で机からの距離と床からの距離を計測してからif文の条件を決めるようにしてください。
【 サンプルコード 5-1-1 】
from pyatcrobo2.parts import DCMotor, UltrasonicSensor
us = UltrasonicSensor('P0')
dcm = DCMotor('M1')
dcm.power(100)
while True:
distance = us.get_distance()
if distance > 0 and distance < 8 : # 実際に計測した値から条件を決めます。
dcm.cw()
else:
dcm.brake()
チャプター6
おわりに
6. 1 このレッスンのまとめ
このレッスンでは新たに次のことを学習しました。
- 文字列のフォーマット
- 超音波距離センサーの特性
- 超音波距離センサーを利用した車型ロボットの制御方法
超音波距離センサーはロボット制作において欠かせないセンサーの1つですので、特性をしっかりとおさえた上で今後も活用していきましょう。
6. 2 次のレッスンについて
次のレッスンでは、赤外線フォトリフレクタとカラーセンサーの2つのセンサーを利用した電子ギターを制作します。