1. 电梯控制系统状态机建模

电梯控制系统状态机建模 学习卡片

任务目标

使用有限状态机(FSM)为单部电梯建立控制模型,覆盖停止(Idle)、运行(Moving)、开门(DoorOpen)、关门(DoorClosed)四个核心状态,并处理来自楼层的外部请求与电梯内部的楼层选择请求。模型需正确响应请求、按方向运行、到站停靠并开关门。

状态定义与转移逻辑

当前状态触发事件条件下一状态动作
Idlerequest(floor)floor > currentFloorMoving方向=向上,加入请求队列
Idlerequest(floor)floor < currentFloorMoving方向=向下,加入请求队列
Idlerequest(floor)floor == currentFloorDoorOpen开门
Movingarrived(floor)floor == 目标楼层Idle停止,清除该请求
DoorOpentimeout(3s)—DoorClosed关门
DoorClosedrequest(floor)floor > currentFloorMoving方向=向上
DoorClosedrequest(floor)floor < currentFloorMoving方向=向下

关键完整代码(Python)

from enum import Enum
from collections import deque

class State(Enum):
    IDLE = "idle"
    MOVING = "moving"
    DOOR_OPEN = "door_open"
    DOOR_CLOSED = "door_closed"

class ElevatorFSM:
    def __init__(self, total_floors=10):
        self.state = State.IDLE
        self.current_floor = 1
        self.direction = None  # "up" / "down"
        self.total_floors = total_floors
        self.requests = set()  # 待处理的楼层请求
        self.log = []

    def _log(self, msg):
        self.log.append(msg)

    def request(self, floor):
        """外部或内部请求到达指定楼层"""
        if floor < 1 or floor > self.total_floors:
            raise ValueError(f"无效楼层: {floor}")
        self.requests.add(floor)
        self._handle_request()

    def _handle_request(self):
        if self.state == State.IDLE:
            if self.current_floor in self.requests:
                self.requests.remove(self.current_floor)
                self.state = State.DOOR_OPEN
                self._log(f"到达请求楼层 {self.current_floor},开门")
            else:
                self._start_moving()
        elif self.state == State.DOOR_CLOSED:
            self._start_moving()

    def _start_moving(self):
        if not self.requests:
            return
        # 选择方向:优先当前方向,否则按最近请求决定
        if self.direction is None:
            if any(f > self.current_floor for f in self.requests):
                self.direction = "up"
            else:
                self.direction = "down"
        self.state = State.MOVING
        self._log(f"开始运行,方向={self.direction},当前楼层={self.current_floor}")

    def step(self):
        """模拟电梯运行一个时间单位(移动一层)"""
        if self.state != State.MOVING:
            return
        if self.direction == "up":
            self.current_floor += 1
        else:
            self.current_floor -= 1
        self._log(f"运行至楼层 {self.current_floor}")
        # 检查是否到达某个请求楼层
        if self.current_floor in self.requests:
            self.requests.remove(self.current_floor)
            self.state = State.IDLE
            self.direction = None
            self._log(f"到达楼层 {self.current_floor},停止")
            # 若还有同向请求,继续运行;否则开门
            if self.requests:
                self._start_moving()
            else:
                self.state = State.DOOR_OPEN
                self._log("开门")

    def door_timeout(self):
        """模拟3秒超时后关门"""
        if self.state == State.DOOR_OPEN:
            self.state = State.DOOR_CLOSED
            self._log("关门")
            if self.requests:
                self._start_moving()

    def run_until_idle(self, max_steps=100):
        """持续运行直到无请求且门关闭"""
        steps = 0
        while steps < max_steps:
            if self.state == State.IDLE and not self.requests:
                break
            if self.state == State.MOVING:
                self.step()
            elif self.state == State.DOOR_OPEN:
                self.door_timeout()
            elif self.state == State.DOOR_CLOSED and self.requests:
                self._start_moving()
            steps += 1
        return self.log

运行与验证

# 实例化并模拟:初始1楼,请求5楼和2楼
elev = ElevatorFSM(total_floors=10)
logs = elev.run_until_idle()  # 空转,无请求

# 添加请求并运行
elev = ElevatorFSM(total_floors=10)
elev.request(5)
elev.request(2)
logs = elev.run_until_idle()

# 打印运行日志
for line in logs:
    print(line)

# 验证断言
assert elev.current_floor == 2, f"最终应在2楼,实际在{elev.current_floor}"
assert elev.state == State.DOOR_OPEN, "最终应停在开门状态(等待超时关门)"
print("状态机验证通过")

验证方法与判定标准

  1. 运行方式:将上述代码保存为 elevator_fsm.py,在Python 3.8+环境中执行 python elevator_fsm.py。
  2. 预期输出(确定性逻辑推导):日志依次显示“开始运行,方向=up”→“运行至楼层2”→“运行至楼层3”→“运行至楼层4”→“运行至楼层5”→“到达楼层5,停止”→“开门”→“关门”→“开始运行,方向=down”→“运行至楼层4”→“运行至楼层3”→“运行至楼层2”→“到达楼层2,停止”→“开门”。最终 current_floor == 2,状态为 DOOR_OPEN。
  3. 通过条件:程序无异常退出,断言全部通过,且日志顺序与上述预期一致。若请求楼层包含当前楼层(如1楼请求1楼),状态应直接从IDLE转为DOOR_OPEN。

常见问题

  • 方向选择策略:本实现采用“当前方向优先”的简化策略,未实现电梯调度中的“顺路接单”优化。若需完整SCAN/LOOK算法,需在 _start_moving 中增加对同向请求的筛选。
  • 门超时:实际系统中门超时后需检测障碍物,本模型以 door_timeout() 模拟3秒定时器触发,未加入传感器输入。
  • 多请求同时到达:requests 使用 set 去重,同一楼层多次请求只处理一次,符合实际电梯逻辑。