[ev3dev×Python]   超音波センサ

この記事はPythonでev3を操作してみたい人のための記事です。
今回は超音波センサを使っていろいろな操作をしていきたいと思います。


#目次
0 . 用意するもの
1 . 超音波センサのプログラム





#0.用意するもの
◯ ev3(タンク) と超音波センサ
◯ パソコン(VSCode)
◯ bluetooth
◯ microSD
◯ [資料](https://buildmedia.readthedocs.org/media/pdf/python-ev3dev/latest/python-ev3dev.pdf)(これをみながら進めていくのがオススメです。)



#1.超音波センサのプログラム(資料p.35)







###1-0 . 障害物との距離としきい値を比較するプログラム 

○障害物との距離が３０cmより大きい間は直進するプログラムです。

```ultrasonicsensor00.py
#!/usr/bin/env python3

#モジュールから必要なものだけをimportする
ev3dev2.sensor.lego import UltrasonicSensor
from ev3dev2.motor import MoveSteering,OUTPUT_A,OUTPUT_B,SpeedPercent

#インスタンスの生成
us = UltrasonicSensor()
steering_drive = MoveSteering(OUTPUT_A,OUTPUT_B)

#超音波センサの値が30より大きい間実行されるループ
while us.distance_centimeters > 30:
    steering_drive.on(0,SpeedPercent(75))
#ループが終了したら停止する
steering_drive.stop()
#プログラム を終了する
exit()
```

**Point** : しきい値についての参考記事
[しきい値とは](https://wa3.i-3-i.info/word15002.html)

**Point** : distance_centimeters
超音波センサの値を格納する変数

---


###1-1 . ものとの距離を表示するプログラム
```ultrasonicsensor01.py

#!/usr/bin/env python3

#モジュールから必要なものだけをimportする
from ev3dev2.display import Display
ev3dev2.sensor.lego import UltrasonicSensor
from time import sleep

#インスタンスの生成
dsp = Display()
us = UltrasonicSensor()

#無限ループ
while True:
    dsp.update()
    #round()で四捨五入する
    distance = round(us.distance_centimeters)
    dsp.text_pixels(str(distance) + 'cm',True,0,52,font = 'helvB' + '24')
    sleep(0.1)
```

**Point** : 超音波センサの値を表示し続けるプログラム



---




###1-2 . 手動と自動の切り替えプログラム

○障害物が20cmより近くにない時は、手動でラジコン操作が出来ます。
しかし、障害物が20cmより近くにある場合は、障害物との距離が30cmより遠くになるまで自動で後ろに逃げて緊急回避します。

```ultrasonicsensor02.py
#!/usr/bin/env python3
#モジュールから必要なものだけをimportする
from ev3dev2.motor import OUTPUT_A,OUTPUT_B,MoveTank
from ev3dev2.sensor.lego import TouchSensor,UltrasonicSensor
from ev3dev2.sensor import INPUT_1,INPUT_2,INPUT_3

#インスタンスの生成
tank_drive = MoveTank(OUTPUT_A,OUTPUT_B)
us = UltrasonicSensor(INPUT_3)
ts_1 = TouchSensor(INPUT_1)
ts_2 = TouchSensor(INPUT_2)

#無限ループ
while True:
    #超音波センサの値が20より大きい間実行するループ
    while us.distance_centimeters > 20:
        #ts_1が押された
        if ts_1.is_pressed:
            #ts_1が押された、かつ、ts_2が押された
            if ts_2.is_pressed:
                tank_drive.on(100,100)
            #ts_1が押された、かつ、ts_2が押されていない
            else:
                tank_drive.on(40,100)
        #ts_1が押されていない
        else:
            #ts_1が押されていない、かつ、ts_2が押された
            if ts_2.is_pressed:
                tank_drive.on(100,40)
            #ts_1が押されていない、かつ、ts_2が押されていない
            else:
                tank_drive.stop()
    #超音波センサの値が20より大きい間実行するループ
    while us.distance_centimeters < 30:
        tank_drive.on(-80,-80)
```

**Point** : スクラッチで例えるとこんな仕組み(内容は同じ)↓
![スクリーンショット 2020-06-19 16.59.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/83a2c949-9f63-eae1-57c2-b8b382ddc701.png)

**Point** : **〜まで繰り返す**　と　**〜の間繰り返す**

**〜まで繰り返す** : 条件が真でなくなるまで繰り返す
**〜の間繰り返す** : 条件が真の間は繰り返す


---



###1-3 . 並列処理のプログラム

○障害物が30cmより近くにない場合は、直進します。
しかし、障害物が30cmより近くにある場合は、障害物との距離が50cmより大きくなる(ひらけたところを見つける)までその場で回転するルンバのようなプログラムです。
そして、走行と同時に障害物との距離を表示します。

```ultrasonicsensor03.py
#!/usr/bin/env python3

#モジュールから必要なものだけをimportする
from ev3dev2.motor import OUTPUT_A,OUTPUT_B,MoveTank
from ev3dev2.display import Display
from ev3dev2.sensor.lego import UltrasonicSensor
from time import sleep
from threading import Thread

#インスタンスの生成
tank_drive = MoveTank(OUTPUT_A,OUTPUT_B)
dsp = Display()
us = UltrasonicSensor()

#distance_display()という関数の定義
def distance_display():
    #loop = Trueの間繰り返す
    while loop:
        dsp.update()
        distance = us.distance_centimeters
        dsp.text_pixels(str(distance) + 'cm',True,0,52,font = 'helvB' + '24')
        sleep(0.1)
#loopにTrueを代入してループ可能にする
loop = True
#Threadクラスのインスタンス t を生成する
t = Thread(target = distance_display)
#スレッドを開始する
t.start()

#10回繰り返す
for i in range(10):
    #超音波センサの値が30より大きい間は繰り返す
    while us.distance_centimeters > 30:
        tank_drive.on(10,10)
    tank_drive.stop()
    #超音波センサの値が50より小さい間は繰り返す
    while us.distance_centimeters < 50:
        tank_drive.on(5,-5)
tank_drive.stop()
#loopにFalseを代入してスレッドを停止する
loop = False
```


**Point** : 並列処理に関する参考記事
[Multithreading](https://sites.google.com/site/ev3python/learn_ev3_python/threads)




---




###1-4 . 並行処理のプログラム

○main.pyからsub.pyを呼び出して並行処理するプログラムです。
(処理が重いです)


```main.py
#!/usr/bin/env python3

#モジュールから必要なものだけをimportする
from ev3dev2.motor import OUTPUT_A,OUTPUT_B,MoveTank
from ev3dev2.sensor.lego import UltrasonicSensor
import subprocess

#インスタンスの生成
tank_drive = MoveTank(OUTPUT_A,OUTPUT_B)
us = UltrasonicSensor()

#新しいプロセスで子プログラム を開始する
subprocess.Popen(['python3','sub.py'])

#10回繰り返す
for i in range(10):
    while us.distance_centimeters > 30:
        tank_drive.on(10,10)
    tank_drive.stop()
    while us.distance_centimeters < 50:
        tank_drive.on(5,-5)
tank_drive.stop()
#クラスPopenのインスタンスを生成する
proc = subprocess.Popen(['python3','sub.py'])
#子プログラムを終了させる
proc.kill()
exit()
```

```sub.py
from ev3dev2.sensor.lego import UltrasonicSensor
from ev3dev2.display import Display
from time import sleep

dsp = Display()
us = UltrasonicSensor()

while True:
    dsp.update()
    distance = round(us.distance_centimeters)
    dsp.text_pixels(str(distance) + 'cm',True,0,52,font = 'helvB' + '24')
    sleep(0.5)
exit()
```

**Point** : 並行処理に関する参考記事
[Pythonにおける並行処理プログラミング入門](https://myenigma.hatenablog.com/entry/2016/04/09/184215)












---


#最後に

読んで頂きありがとうございました！！
次回はジャイロセンサについて書いていきたいと思います！

より良い記事にしていきたいので
　◯こうした方がわかりやすい
　◯ここがわかりにくい
　◯ここが間違っている
　◯ここをもっと説明して欲しい
などの御意見、御指摘のほどよろしくお願い致します。