ロボティクス入門ゼミ 教材 2017-11-24
EV3の標準キットには、タッチセンサ、カラーセンサ、超音波センサ、 ジャイロセンサが含まれている。 これらに加え、モータ自身も「角度センサ」として使用することができる。
センサの細かな仕様については、
http://docs.ev3dev.org/projects/lego-linux-drivers/en/ev3dev-jessie/sensor_data.html
(ev3devのドキュメント)
を見るとよい。
センサは、1〜4のどのポートに接続してもかまわない。 また、モータと同様に、センサ類自身やそれら値などは、Linuxでは 「ディレクトリ」や「ファイル」として表されている。
まずセンサを接続していない状態で、次のようなセンサのディレクトリに 移動してみる。
robot@ev3dev:~$ cd /sys/class/lego-sensor/
センサを接続していない場合、このディレクトリが空であることを ls で確認する。
robot@ev3dev:/sys/class/lego-sensor$ ls
何も表示されければOK。
次にタッチセンサを接続する。 以下の例ではポート3に接続している(どのポートでもOK)。 接続後、再度 ls で確認。
robot@ev3dev:/sys/class/lego-sensor$ ls sensor1
新たに sensor1 というディレクトリができている。 sensor1の"1" という数字はポートの番号とは関係なく、 接続した順番にセンサに割り振られる。 実際に、一度センサを外し、再度接続すると sensor2 になる。
次にこのディレクトリに移動してどのようなファイルがあるか見てみる。 (cd s まで入力して tabキーを押せば残りは補完してくれるはず。)
robot@ev3dev:/sys/class/lego-sensor$ cd sensor1
ファイル一覧。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ ls address decimals mode subsystem value1 value6 bin_data device modes text_value value2 value7 bin_data_format direct num_values uevent value3 command driver_name poll_ms units value4 commands fw_version power value0 value5
以下、いくつかのファイルの中身を cat コマンドで見てみる。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat address in3
adress には接続ポートが格納されている。ポート3に接続しているので in3 になっている。
個々のセンサには「モード」があり、センサによっては複数のモードを切り替えて使用できる。 どのようなモードが指定可能であるかは modes というファイルに記述されている。 また現在のモードは、mode を見れば分かる
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat modes TOUCH robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat mode TOUCH
タッチセンサの場合は TOUCH というモードのみ。
タッチセンサの値は、value0 に格納されている。 タッチセンサを押していない場合は 0 である。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat value0 0
今度はタッチセンサを押しながらvalue0の値を表示させてみる。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat value0 1
タッチセンサが押されていれば value0 の値は 1 になる。
タッチセンサの場合、値は value0 の一つのみである。 value1からvalue7までのファイルは、ファイルとしては存在しているが、 これらの値を読むことはできない。 実際に、value1の値を読もうとするとエラーになる。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat value1 cat: value1: No such device or address
ちなみに、値の数は num_values に格納されている。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cat num_values 1
次に、カラーセンサも接続してみる。以下の例ではポート2に接続している。
一つ上のディレクトリに戻って、ファイル一覧を表示させる。
robot@ev3dev:/sys/class/lego-sensor/sensor1$ cd .. robot@ev3dev:/sys/class/lego-sensor$ ls sensor1 sensor2
センサが二つになっているのが分かる。
タッチセンサの時と同様に、中身を見てみる。
robot@ev3dev:/sys/class/lego-sensor$ cd sensor2 robot@ev3dev:/sys/class/lego-sensor/sensor2$ ls address decimals mode subsystem value1 value6 bin_data device modes text_value value2 value7 bin_data_format direct num_values uevent value3 command driver_name poll_ms units value4 commands fw_version power value0 value5
ディレクトリの構造自体はタッチセンサと同じである。 以下、address, mode, modes の値を表示してみる。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat address in2 robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat mode COL-REFLECT robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat modes COL-REFLECT COL-AMBIENT COL-COLOR REF-RAW RGB-RAW COL-CAL robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat num_values 1
上のように、デフォルトのモードは COL-REFLECT になっている。
このモードでは赤い光を発してその反射で明るさを測定している。 値はパーセント表示で 0〜100までの値を取る。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat value0 1
白い紙の上にカラーセンサを当てて値を読んでみる。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat value0 76
紙からの距離によって値は代わるが、70〜80辺りの値が得られるはずである。
モードを REF-RAW に変更して値を読んでみよう。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ echo REF-RAW > mode robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat num_values 2 robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat value0 value1 373 703 robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat value0 value1 634 662
これらの「生の」値が何を示しているのか仕様書からは正確に分からなかったが、 白い部分を測ると value0とvalue1はそれぞれ200と700くらいになり、 黒い部分を測るとそれぞれ600代半ばの値になる。
モードを RGB-RAW にすれば、色のRGBの値が得られる。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ echo RGB-RAW > mode robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat num_values 3 robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat value0 value1 value2 394 413 249
赤い部分を測定すると value0 が value1 と value2 に対して大きくなる。 いろいろな色を測ってみよう。
モードを COL-COLOR にすれば、7つの色を判別する。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ echo COL-COLOR > mode robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat num_values 1 robot@ev3dev:/sys/class/lego-sensor/sensor2$ cat value0 6
得られる数字は次の色を表す。
0 | none |
1 | black |
2 | blue |
3 | green |
4 | yellow |
5 | red |
6 | white |
7 | brown |
同様に超音波センサの値を読んでみる。 以下の例ではポート1に接続。
robot@ev3dev:/sys/class/lego-sensor/sensor2$ cd .. robot@ev3dev:/sys/class/lego-sensor ls sensor1 sensor2 sensor3 robot@ev3dev:/sys/class/lego-sensor$ cd sensor3 robot@ev3dev:/sys/class/lego-sensor/sensor3$ ls address decimals mode subsystem value1 value6 bin_data device modes text_value value2 value7 bin_data_format direct num_values uevent value3 command driver_name poll_ms units value4 commands fw_version power value0 value5
ポートとモードを確認。
robot@ev3dev:/sys/class/lego-sensor/sensor3$ cat address in1 robot@ev3dev:/sys/class/lego-sensor/sensor3$ cat mode US-DIST-CM robot@ev3dev:/sys/class/lego-sensor/sensor3$ cat modes US-DIST-CM US-DIST-IN US-LISTEN US-SI-CM US-SI-IN US-DC-CM US-DC-IN
デフォルトの US-DIST-CM は、連続的に距離を測り mm の単位で値が得られる。 それに対し、US-SI-CM は一度きり(single)の測定。 また US-DIST-IN と US-SI-IN は、距離を0.1インチ(2.54mm)の単位で得る。 US-LISTEN にすると距離は測らず赤いLEDを点滅させる。 US-DC-CM と US-DC-IN は US-DIST-CM と US-DIST-IN と同じように連続して距離を測定しているが、違いはよくわからない。
robot@ev3dev:/sys/class/lego-sensor/sensor3$ cat value0 150
この場合、対象物までの距離は15cm。また255cm以上離れた場合は常に2550という値になる。
ジャイロセンサは 以下の例ではポート4に接続。
robot@ev3dev:/sys/class/lego-sensor/sensor3$ cd .. robot@ev3dev:/sys/class/lego-sensor ls sensor1 sensor2 sensor3 sensor4 robot@ev3dev:/sys/class/lego-sensor$ cd sensor4 robot@ev3dev:/sys/class/lego-sensor/sensor3$ ls address decimals mode subsystem value1 value6 bin_data device modes text_value value2 value7 bin_data_format direct num_values uevent value3 command driver_name poll_ms units value4 commands fw_version power value0 value5
ポートとモードを確認。
robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat address in4 robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat mode GYRO-ANG robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat modes GYRO-ANG GYRO-RATE GYRO-FAS GYRO-G&A GYRO-CAL
デフォルトのモードでは現在の角度がvalue0で得られる。
robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat value0 62
少し角度を変えて測定してみる。
モードを GYRO-RATE にすると角速度(度/秒)が得られる。
robot@ev3dev:/sys/class/lego-sensor/sensor4$ echo GYRO-RATE > mode robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat value0 0
動かしていない場合や、平行移動している場合は 0 となる。
1秒間で半周くらいのスピードで回転させると180くらいの値になる。
robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat value0 192
もちろん回転させている途中で測る必要がある。
モードを GYRO-G&A にすると現在の角度と角速度が同時に得られる。
robot@ev3dev:/sys/class/lego-sensor/sensor4$ echo GYRO-G\&A > mode robot@ev3dev:/sys/class/lego-sensor/sensor4$ cat value0 value1 34 0
シェルのコマンドで & を入力する場合には、\& と入力しなければならないことに注意する (シェルで &マークは、コマンドをバックグランドで実行する、という意味になるので 通常の文字として扱うためには前に \ が必要。)
python-ev3 ではセンサー各種のクラスが用意されている。
次の例は、ポート3にタッチセンサを接続して、タッチセンサの値を1秒おきに出力するスクリプト。 センサの値は value() というメソッドで取得できる。
#!/usr/bin/env python3 from ev3dev.ev3 import * from time import sleep ts = TouchSensor('in3') # 接続ポートを指定してインスタンスを作る if __name__ == '__main__': while True: print(ts.value()) # value()で値が取得できる sleep(1)
この例では while True: の無限ループがあるのでプログラムがいつまでたっても終了しない。 強制的に終了するには、Contol + c を押す (コントロールキーを押しながら c を押す)。
次にポートに接続したカラーセンサの値を表示してみる。
#!/usr/bin/env python3 from ev3dev.ev3 import * from time import sleep ts = TouchSensor('in3') cs = ColorSensor('in2') # カラーセンサのインスタンスを作る cs.mode = 'COL-REFLECT' # modeを'COL-REFLECT'に設定 if __name__ == '__main__': while ts.value() == 0: # ts.value()が0の間だけ繰り返し print (cs.value()) sleep(1)
この例ではタッチセンサを停止ボタンとして使用し、タッチセンサが押されていれば while ループから抜けるようにしている。こうしておけば Control + c でプログラムを強制終了しなくてよい。
またこの例ではセンサのモードが'COL-REFLECT'なので値は一つだけであるが、 モードを 'RGB-RAW' にすると red,green,blue の3つの値が取得できる。 この場合、value(0), value(1), value(2) でそれぞれの値が取得できる。
#!/usr/bin/env python3 from ev3dev.ev3 import * from time import sleep ts = TouchSensor('in3') cs = ColorSensor('in2') cs.mode = 'RGB-RAW' # センサのモードを指定 if __name__ == '__main__': while ts.value() == 0: print (cs.value(0),cs.value(1),cs.value(2)) sleep(1)
【練習問題】 超音波センサのクラスは UntrasonicSensor() で与えられる。 上の例を参考に、一秒おきに超音波センサの値を表示するプログラムを作成しなさい。
超音波センサを使って、前にある物体との距離を20cmに保つロボットを作ってみる。 具体的には、実際の距離を測り、その距離が20cmからずれていれば、 そのずれに比例したスピードで前進または後進するようにする。 ただし、スピードの範囲は -700 〜 700 となるようにする。 つまり、 距離が10cm以下の時に最大のスピード700で後進、 距離が30cm以上の時に最大のスピード700で前進、となるように設定する。
#!/usr/bin/env python3 from ev3dev.ev3 import * from time import sleep mL = LargeMotor('outA') mR = LargeMotor('outB') ts = TouchSensor('in3') us = UltrasonicSensor('in1') if __name__ == '__main__': mL.reset() mR.reset() while ts.value() == 0: sp = (us.value() - 200) * 7 # 距離からスピードを計算してspに代入 (前進は正値、後進は負値) sp = 700 if sp > 700 else sp # spの値が700を超えたらspを700に設定 sp = -700 if sp < -700 else sp # spの値が-700より小さい時はspを-700に設定 mL.run_forever(speed_sp=sp) mR.run_forever(speed_sp=sp) sleep(0.001) mL.stop(stop_action="coast") # whileループを抜けた後、モータを止める mR.stop(stop_action="coast")
この例では sp の上限と下限を設定するために次のような条件演算子を使った。
x = a if cond else b # 条件condが成り立つ時には x に a を代入、そうでない場合は bを代入
通常のブロック形式では次のようになる。
if sp > 700: sp = 700 if sp < -700: sp = -700
【練習問題】 ジャイロセンサのクラスは GyroSensor() で与えられる。 上の例を参考に、一秒おきに超音波センサの値を表示するプログラムを作成しなさい。
【練習問題】 一定の半径で円を描いて動くロボットを作り、ちょうど1周したことをジャイロセンサで検知して停止するロボットを作りなさい。