3. 交通信号灯状态机控制

交通信号灯状态机控制 学习卡片

任务说明

实现一个交通信号灯状态机控制器,管理红、黄、绿三种灯的正常时序切换,并支持紧急模式(紧急车辆通过时强制红灯,结束后恢复原状态)。本案例使用 Python 实现,不依赖第三方库,可直接运行验证。

状态定义与转换逻辑

  • 正常模式:绿(5s) → 黄(2s) → 红(5s) → 绿,循环切换
  • 紧急模式:任意状态收到紧急信号后立即进入红灯;紧急解除后回到紧急前的状态,并重新计时

完整实现

import time
from enum import Enum

class LightState(Enum):
    RED = "红灯"
    YELLOW = "黄灯"
    GREEN = "绿灯"

class TrafficLightFSM:
    def __init__(self):
        self.state = LightState.RED
        self.remaining_time = 5
        self.emergency = False
        self.prev_state = None
        self.prev_remaining = 0
        self._state_durations = {
            LightState.RED: 5,
            LightState.YELLOW: 2,
            LightState.GREEN: 5,
        }

    def _next_normal_state(self):
        order = [LightState.GREEN, LightState.YELLOW, LightState.RED]
        return order[(order.index(self.state) + 1) % 3]

    def tick(self, dt=1):
        """推进时间,dt为经过的秒数"""
        if self.emergency:
            return  # 紧急模式下不推进正常时序

        self.remaining_time -= dt
        if self.remaining_time <= 0:
            self.state = self._next_normal_state()
            self.remaining_time = self._state_durations[self.state]

    def trigger_emergency(self):
        """进入紧急模式:强制红灯"""
        if not self.emergency:
            self.emergency = True
            self.prev_state = self.state
            self.prev_remaining = self.remaining_time
            self.state = LightState.RED
            self.remaining_time = 999  # 紧急模式持续期间红灯常亮

    def release_emergency(self):
        """解除紧急模式:恢复紧急前状态并重新计时"""
        if self.emergency:
            self.emergency = False
            self.state = self.prev_state
            self.remaining_time = self._state_durations[self.prev_state]

    def get_status(self):
        return {
            "当前灯": self.state.value,
            "剩余秒数": self.remaining_time if not self.emergency else "紧急中",
            "紧急模式": self.emergency,
        }

# 最小验证闭环
if __name__ == "__main__":
    fsm = TrafficLightFSM()
    print("初始:", fsm.get_status())

    # 模拟正常时序:红灯5秒后变绿
    for _ in range(5):
        fsm.tick()
    print("5秒后:", fsm.get_status())

    # 触发紧急模式
    fsm.trigger_emergency()
    print("紧急触发:", fsm.get_status())

    # 紧急期间tick不应改变状态
    fsm.tick()
    fsm.tick()
    print("紧急2秒后:", fsm.get_status())

    # 解除紧急,应回到红灯并重新计时5秒
    fsm.release_emergency()
    print("紧急解除:", fsm.get_status())

    # 再走5秒应切换到绿灯
    for _ in range(5):
        fsm.tick()
    print("再5秒后:", fsm.get_status())

运行与验证

  1. 将代码保存为 traffic_light_fsm.py
  2. 运行 python traffic_light_fsm.py
  3. 预期输出(确定性逻辑推导):
初始: {'当前灯': '红灯', '剩余秒数': 5, '紧急模式': False}
5秒后: {'当前灯': '绿灯', '剩余秒数': 5, '紧急模式': False}
紧急触发: {'当前灯': '红灯', '剩余秒数': '紧急中', '紧急模式': True}
紧急2秒后: {'当前灯': '红灯', '剩余秒数': '紧急中', '紧急模式': True}
紧急解除: {'当前灯': '红灯', '剩余秒数': 5, '紧急模式': False}
再5秒后: {'当前灯': '绿灯', '剩余秒数': 5, '紧急模式': False}

通过标准:程序无异常退出,输出与上述顺序一致,且紧急模式期间状态不随 tick 变化,解除后正确恢复。

绿灯 5秒 黄灯 2秒 红灯 5秒 5秒后 2秒后 5秒后 紧急模式:任意状态 → 红灯(常亮) 解除后 → 恢复紧急前状态并重新计时 实线:正常时序转换 虚线:紧急模式转换

关键设计说明

  • 状态枚举:使用 LightState 枚举限定合法状态,避免非法赋值。
  • 紧急模式处理:通过 prev_state 和 prev_remaining 保存现场,解除时恢复并重置完整时长,保证时序正确。
  • tick 驱动:外部每秒调用一次 tick() 模拟时间推进,紧急模式下 tick 不改变任何状态。