.. include:: /index.rst
:start-after: start_hello_message
:end-before: end_hello_message
.. _py_fun_traffic_light:
4.9 信号機シミュレーション
==============================
**はじめに**
このプロジェクトでは、LED と 4 桁の 7 セグメントディスプレイを使用して、実際の信号機システムをシミュレーションします。LED は赤・黄・緑の信号灯を表し、7 セグメントディスプレイは各信号の残り時間をカウントダウン表示します。GPIO 制御、タイミング処理、7 セグメントディスプレイの使い方を、教育用途や試作環境で楽しく学べる内容になっています。
----------------------------------------------
**必要なもの**
このプロジェクトで必要なコンポーネントは以下のとおりです。
.. list-table::
:widths: 30 20
:header-rows: 1
* - COMPONENT INTRODUCTION
- PURCHASE LINK
* - :ref:`cpn_breadboard`
- |link_breadboard_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_led`
- |link_led_buy|
* - :ref:`cpn_4_digit`
- \-
* - :ref:`cpn_74hc595`
- |link_74hc595_buy|
* - :ref:`cpn_fusion_hat`
- \-
* - Raspberry Pi
- \-
----------------------------------------------
**回路図**
以下は、信号機シミュレーションプロジェクトの回路図です。
.. image:: img/fzz/4.1.9_sch.png
:width: 90%
:align: center
----------------------------------------------
**配線図**
コンポーネントの組み立ては、以下の配線図を参照してください。
.. image:: img/fzz/4.1.9_bb.png
:width: 80%
:align: center
----------------------------------------------
**サンプルの実行**
このチュートリアルで使用するすべてのサンプルコードは ``ai-lab-kit`` ディレクトリに含まれています。
以下の手順に従ってサンプルを実行してください。
.. raw:: html
.. code-block:: shell
cd ~/ai-lab-kit/python/
sudo python3 4.9_TrafficLight.py
----------------------------------------------
**コード**
以下は、信号機シミュレーションで使用する Python スクリプトです。
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
from fusion_hat.pin import Pin, Mode
import threading
# Setup GPIO pins for 74HC595 shift register
SDI = Pin(17,mode=Mode.OUT) # Serial Data Input
RCLK = Pin(4,mode=Mode.OUT) # Register Clock
SRCLK = Pin(27,mode=Mode.OUT) # Shift Register Clock
# Define GPIO pins for digit selection on the 7-segment display
placePin = [Pin(pin,mode=Mode.OUT) for pin in (23, 24, 25, 12)]
# Segment codes for numbers 0-9 on 7-segment display
number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90)
# Setup GPIO pins for traffic light LEDs
ledPinR = Pin(5,mode=Mode.OUT) # Red LED
ledPinG = Pin(6,mode=Mode.OUT) # Green LED
ledPinY = Pin(13,mode=Mode.OUT) # Yellow LED
# Duration settings for traffic lights
greenLight = 30
yellowLight = 5
redLight = 60
# Traffic light color names
lightColor = ("Red", "Green", "Yellow")
# Initialize state variables
colorState = 0
counter = 60
timer1 = None
def setup():
""" Initialize the traffic light system and start the timer. """
global timer1
timer1 = threading.Timer(1.0, timer)
timer1.start()
def clearDisplay():
""" Clear the 7-segment display. """
for _ in range(8):
SDI.high()
SRCLK.high()
SRCLK.low()
RCLK.high()
RCLK.low()
def hc595_shift(data):
""" Shift data to the 74HC595 shift register for digit display. """
for i in range(8):
SDI.value(0x80 & (data << i))
SRCLK.high()
SRCLK.low()
RCLK.high()
RCLK.low()
def pickDigit(digit):
""" Select a specific digit to display on the 7-segment display. """
for pin in placePin:
pin.low()
placePin[digit].high()
def timer():
""" Handle the timing for traffic light changes. """
global counter, colorState, timer1
timer1 = threading.Timer(1.0, timer)
timer1.start()
counter -= 1
if counter == 0:
counter = [greenLight, yellowLight, redLight][colorState]
colorState = (colorState + 1) % 3
print(f"counter : {counter} color: {lightColor[colorState]}")
def lightup():
""" Update the traffic light LED based on the current state. """
global colorState
ledPinR.low()
ledPinG.low()
ledPinY.low()
[ledPinR, ledPinG, ledPinY][colorState].high()
def display():
""" Display the current counter value on the 7-segment display. """
global counter
for i in range(4):
digit = counter // (10 ** (3 - i)) % 10
if i == 0 and digit == 0:
continue
clearDisplay()
pickDigit(i)
hc595_shift(number[digit])
def loop():
""" Main loop to continuously update display and lights. """
while True:
display()
lightup()
def destroy():
""" Clean up resources when the script is terminated. """
global timer1
timer1.cancel()
ledPinR.low()
ledPinG.low()
ledPinY.low()
try:
setup()
loop()
except KeyboardInterrupt:
destroy()
----------------------------------------------
**コードの解説**
1. **初期化:**
* シフトレジスタ、7 セグメントディスプレイ、および信号機用 LED の GPIO ピンを設定します。
* 各信号の点灯時間を定義し、状態変数を初期化します。
2. **7 セグメントディスプレイ用関数:**
* ``clearDisplay``: ディスプレイ上のすべてのセグメントを消灯します。
* ``hc595_shift``: 表示セグメントを制御するために、シフトレジスタへデータを送信します。
* ``pickDigit``: 多重化表示のために、特定の桁を有効にします。
3. **タイマー関数:**
* カウントダウンを処理し、信号の状態を切り替えます。
4. **信号機の制御:**
* 現在の状態に応じて LED を更新します。
5. **メインループ:**
* ディスプレイと LED を継続的に更新します。
6. **終了処理:**
* スクリプト終了時に、すべてのリソースが適切に解放されるようにします。
----------------------------------------------
**トラブルシューティング**
1. **信号灯が動作しない** :
- **原因** : 配線ミス、または LED の故障。
- **対処方法** :
- LED が GPIO5(赤)、GPIO6(緑)、GPIO13(黄)に正しく接続されていることを確認してください。
- 簡単な GPIO 制御スクリプトで各 LED を個別にテストしてください。
2. **7 セグメントディスプレイにカウントダウンが表示されない**:
- **原因** : 配線ミス、またはシフトレジスタ設定の誤り。
- **対処方法** :
- シフトレジスタの ``SDI`` 、 ``RCLK`` 、 ``SRCLK`` ピンが、それぞれ GPIO17、GPIO4、GPIO27 に正しく接続されていることを確認してください。
- 桁選択ピンが ``placePin`` の設定と一致していることを確認してください。
3. **カウントダウンタイマーが停止する**:
- **原因** : タイマースレッドが正しく再起動していません。
- **対処方法** : ``timer()`` 関数内で ``timer1.start()`` が呼び出され、タイマースレッドが再開されていることを確認してください。
4. **信号の点灯時間が正しくない** :
- **原因** : 時間設定値、または状態遷移の誤り。
- **対処方法** :
- ``redLight`` 、 ``greenLight`` 、 ``yellowLight`` の値を確認してください。
- ``timer()`` 関数内のロジックが、正しく状態を切り替えていることを確認してください。
----------------------------------------------
**拡張アイデア**
1. **歩行者用横断機能**: 歩行者ボタンを追加し、信号サイクルを一時的に中断して安全に横断できるようにします。
.. code-block:: python
from fusion_hat import Pin
pedestrian_button = Pin(22, Pin.IN, Pin.PULL_DOWN)
def handle_pedestrian():
global colorState, counter
if colorState == 1: # If Green Light
counter = 5 # Shorten green light duration
pedestrian_button.when_activated = handle_pedestrian
2. **適応型タイミング制御** : リアルタイムの交通量に応じて、各信号の点灯時間を動的に調整します。
3. **イベントログ記録** : 信号状態の変化とタイムスタンプをファイルに保存して分析できるようにします。
.. code-block:: python
with open("traffic_log.txt", "a") as log_file:
log_file.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - {lightColor[colorState]} light\n")
----------------------------------------------
**まとめ**
このプロジェクトでは、信号機システムをシミュレーションすることで、GPIO 制御、シフトレジスタ、7 セグメントディスプレイの使い方を実践的に学ぶことができます。実際のアプリケーションを模した、楽しく教育的な電子工作プロジェクトです。さらに機能を追加して、よりインタラクティブなシステムへ発展させてみてください。