ラズパイ4で歩行者用信号（押ボタン式）を作る

# 目的
歩行者用信号を作ることで、
- LEDの光らせ方
- ボタンの入力の受け取り方

を学習します。


# 注意
　製作には[このキット](https://www.sunfounder.com/products/raphael-kit?_pos=1&_sid=e78196ab0&_ss=r)に含まれている、T型GPIO拡張ボード、40ピンケーブルを使用しています。LEDやケーブルなども、このキットに含まれているものです。
　回路に関しての知識が未熟なため、配線が最適でないかもしれません。壊れても責任はおいかねます。


# 使用するもの
- 2 * LED
- 2 * Resistor(220R)
- 1 * Resistor(10KR)
- 1 * Button


# 目次
1. LEDを光らせる
1. ボタンの入力を受け取る
1. 歩行者用信号を作る
1. 総括
1. 参考

# 補足
　実行する際は、コードをファイルに書いて、次のように実行します。
```
$ sudo python3 ファイル名.py
```


# 1. LEDを光らせる
　GPIO17と18を、赤と緑のLEDに接続します。このとき、LEDのピンの短い方（カソード）であることに気をつけます。長い方（アノード）には、Resistor(220R)を接続します。
![01.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884269/e99c3c05-5a93-b662-824f-1b92543093f0.png)

 
　接続できたら次のコードで、LEDを点滅させます。
 ```
 import RPi.GPIO as GPIO
import time

# 番号をわりあてる
LedPin = 17
GreenPin = 18

def setup():
	# モードを出力にして、初期値をHIGHにする
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(LedPin, GPIO.OUT, initial=GPIO.HIGH)
	GPIO.setup(GreenPin, GPIO.OUT, initial=GPIO.HIGH)

def main():
	while True: # 1秒間隔で光る
		# 光る
		print("光る")
		GPIO.output(LedPin, GPIO.LOW)
		GPIO.output(GreenPin, GPIO.LOW)
		time.sleep(0.2)
		# 消える
		print("消える")
		GPIO.output(LedPin, GPIO.HIGH)
		GPIO.output(GreenPin, GPIO.HIGH)
		time.sleep(1.0) # 1秒待つ
		
def destroy():
	# 終了時にLEDを消す
	GPIO.output(LedPin, GPIO.HIGH)
	GPIO.output(GreenPin, GPIO.HIGH)
	GPIO.cleanup()

if __name__ == "__main__":
	setup()
	try:
		main()
	except KeyboardInterrupt:
		destroy()
 ```
　setup()の後に、main()が実行されます。main()では、１秒間隔で光らせています。ctrl + Cで停止すると、destroy()が実行されます。destroy()では、光を消した後、使用したピンの記録を消しています。


# 2. ボタンの入力を受け取る
　GPIO27をButtonに接続します。さらに、ButtonにはResistor(10KR)とGNDも接続します。
 ![02.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884269/4c3b4584-91a0-4c24-3cae-64f677a9bffd.png)

　接続できたら次のコードで、Buttonを押したときにメッセージを表示させます。
 ```
 import RPi.GPIO as GPIO
import time

# 番号をわりあてる
ButtonPin = 27

def setup():
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(ButtonPin, GPIO.IN)

def push(ev=None):
	print("押された")

def main():
	GPIO.add_event_detect(ButtonPin, GPIO.FALLING, callback=push)
	while True:
		time.sleep(1)
		
def destroy():
	GPIO.cleanup()

if __name__ == "__main__":
	setup()
	try:
		main()
	except KeyboardInterrupt:
		destroy()
 ```
　ボタンが押されると、push()が呼び出されます。pushではコメントを表示するため、ボタンを押すたびに、「押された」と表示されます。
　実行した時に`Failed to add edge detection`というエラーが出るかもしれません。その時は、次のコマンドを入力します。
```
$ sudo apt remove python3-rpi.gpio
$ sudo apt update
$ sudo apt install python3-rpi-lgpio
```
https://raspberrypi.stackexchange.com/questions/147332/rpi-gpio-runtimeerror-failed-to-add-edge-detection


# 3. 歩行者用信号を作る
　先ほど学んだことを応用して、歩行者用信号を作ります。仕様は次のように定義します。
1. 起動時は、赤が光って、緑が消えている
2. ボタンが押されると以下の内容が実行される
    - 赤が消えて、緑が光る
    - 緑が点滅する
    - 緑が消えて、赤が光る

　先ほど作成した回路（LEDとButton）をそのまま使用します。次のコードで、歩行者用信号が動きます。
 ```
 import RPi.GPIO as GPIO
import time

LedPin = 17
GreenPin = 18
ButtonPin = 27

def setup():
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(LedPin, GPIO.OUT, initial=GPIO.HIGH)
	GPIO.setup(GreenPin, GPIO.OUT, initial=GPIO.HIGH)
	GPIO.setup(ButtonPin, GPIO.IN)

def changeGreen(ev=None):
	print("ボタンが押されました")
	time.sleep(2.0)
	# 赤が消えて、緑が光る
	GPIO.output(LedPin, GPIO.HIGH)
	GPIO.output(GreenPin, GPIO.LOW)
	time.sleep(2.0)
	# 緑が点滅する
	for i in range(0,5):
		GPIO.output(GreenPin, GPIO.LOW)
		time.sleep(0.2)
		GPIO.output(GreenPin, GPIO.HIGH)
		time.sleep(0.2)
	# 緑が消えて、赤が光る
	GPIO.output(GreenPin, GPIO.HIGH)
	GPIO.output(LedPin, GPIO.LOW)

def main():
	GPIO.output(LedPin, GPIO.LOW) # 最初は赤を光らせる
	GPIO.add_event_detect(ButtonPin, GPIO.FALLING, callback=changeGreen)
	while True:
		time.sleep(1)
		
def destroy():
	GPIO.output(LedPin, GPIO.HIGH)
	GPIO.output(GreenPin, GPIO.HIGH)
	GPIO.cleanup()
	
	
if __name__ == "__main__":
	setup()
	try:
		main()
	except KeyboardInterrupt:
		destroy()

 ```
　起動時は赤が光っています。ボタンが押されると、changeGreen()が呼び出されます。changeGreen()では、緑だけを光らせた後5回点滅させて、再び、赤だけ光らせます。

# 4. 総括
　今回は、LEDの光らせ方と、ボタンの入力について学びました。回路を使うプログラミングは、Webと全く異なります。

# 5. 参考
　勉強には、キットについていた、オンラインドキュメントを使いました。キットに含まれるものを使って、開発ができます。電子工作の初心者である筆者には、非常に参考になりました。

https://www.sunfounder.com/products/raphael-kit?_pos=1&_sid=e78196ab0&_ss=r