3. 电梯控制器

电梯控制器 学习卡片

任务目标

实现一个电梯控制器的有限状态机(FSM),管理空闲、运行、开门、关门四个核心状态,并响应外部楼层请求与内部指令。电梯在空闲时等待请求,收到请求后运行至目标楼层,到达后自动开门,延时后关门并回到空闲。

状态定义与转移逻辑

当前状态触发事件动作下一状态
IDLE(空闲)request(floor)记录目标楼层,开始移动MOVING(运行)
MOVING(运行)到达目标楼层停止,开门DOOR_OPEN(开门)
DOOR_OPEN(开门)延时结束(3秒)关门DOOR_CLOSED(关门)
DOOR_CLOSED(关门)关门完成清空目标,回到待命IDLE(空闲)

若电梯在MOVING状态收到新请求,仅当新楼层与当前运行方向一致且更近时更新目标;否则暂存请求,待空闲后处理。

完整实现(Python)

from enum import Enum
import time

class State(Enum):
    IDLE = 1
    MOVING = 2
    DOOR_OPEN = 3
    DOOR_CLOSED = 4

class ElevatorFSM:
    def __init__(self, start_floor=1):
        self.state = State.IDLE
        self.current_floor = start_floor
        self.target_floor = None
        self.pending_floors = set()
        self.door_open_time = 3  # 秒

    def request(self, floor):
        """外部或内部请求电梯到指定楼层"""
        if floor == self.current_floor:
            return  # 已在当前楼层,无需响应
        if self.state == State.IDLE:
            self.target_floor = floor
            self.state = State.MOVING
            print(f"请求楼层 {floor},电梯从 {self.current_floor} 出发")
        elif self.state == State.MOVING:
            # 同方向且更近则更新目标,否则暂存
            if self._is_on_way(floor):
                self.target_floor = floor
                print(f"更新目标楼层为 {floor}")
            else:
                self.pending_floors.add(floor)
                print(f"暂存请求楼层 {floor}")
        else:
            # 开门或关门中,暂存请求
            self.pending_floors.add(floor)
            print(f"暂存请求楼层 {floor}")

    def _is_on_way(self, floor):
        """判断新请求是否在当前运行路径上"""
        if self.target_floor is None:
            return False
        direction = 1 if self.target_floor > self.current_floor else -1
        return (floor - self.current_floor) * direction > 0

    def tick(self):
        """模拟一个时间步的推进"""
        if self.state == State.MOVING:
            # 向目标楼层移动一层
            step = 1 if self.target_floor > self.current_floor else -1
            self.current_floor += step
            print(f"运行中,当前楼层 {self.current_floor}")
            if self.current_floor == self.target_floor:
                self.state = State.DOOR_OPEN
                print("到达目标楼层,开门")
        elif self.state == State.DOOR_OPEN:
            # 模拟延时后自动关门
            time.sleep(self.door_open_time)
            self.state = State.DOOR_CLOSED
            print("关门")
        elif self.state == State.DOOR_CLOSED:
            self.state = State.IDLE
            self.target_floor = None
            print("关门完成,回到空闲")
            # 处理暂存请求
            if self.pending_floors:
                next_floor = self.pending_floors.pop()
                self.request(next_floor)

    def run_until_idle(self, max_steps=100):
        """驱动电梯运行直到回到空闲状态"""
        steps = 0
        while self.state != State.IDLE and steps < max_steps:
            self.tick()
            steps += 1
        return self.state == State.IDLE

# 最小验证闭环
if __name__ == "__main__":
    # 场景1:单次请求
    print("=== 场景1:从1楼到5楼 ===")
    e = ElevatorFSM(start_floor=1)
    e.request(5)
    e.run_until_idle()
    assert e.current_floor == 5, "电梯应停在5楼"
    assert e.state == State.IDLE, "电梯应回到空闲"
    print("场景1通过\n")

    # 场景2:运行中收到同向更近请求
    print("=== 场景2:从1楼到5楼,途中收到3楼请求 ===")
    e = ElevatorFSM(start_floor=1)
    e.request(5)
    e.tick()  # 到2楼
    e.request(3)  # 同向更近,应更新目标
    e.run_until_idle()
    assert e.current_floor == 3, "电梯应停在3楼"
    print("场景2通过\n")

    # 场景3:运行中收到反向请求,暂存后处理
    print("=== 场景3:从1楼到5楼,途中收到2楼请求(反向) ===")
    e = ElevatorFSM(start_floor=1)
    e.request(5)
    e.tick()  # 到2楼
    e.tick()  # 到3楼
    e.request(2)  # 反向,应暂存
    e.run_until_idle()
    assert e.current_floor == 2, "电梯最终应处理暂存请求到2楼"
    print("场景3通过\n")

    print("所有验证场景通过")

运行方式

python elevator_fsm.py

验证方法与判定标准

  • 场景1:电梯从1楼出发,运行至5楼后开门、关门、回到空闲。控制台输出应依次显示“请求楼层 5”“运行中…”“到达目标楼层,开门”“关门”“关门完成,回到空闲”。
  • 场景2:电梯在去5楼途中(2楼时)收到3楼请求,因同向且更近,目标更新为3楼,最终停在3楼。
  • 场景3:电梯在去5楼途中(3楼时)收到2楼请求,因反向被暂存;完成5楼任务回到空闲后,自动处理暂存请求,最终停在2楼。
  • 程序退出码为0且打印“所有验证场景通过”即判定实现正确。

关键设计说明

本实现采用时间步推进(tick())模拟电梯逐层移动,而非真实时间驱动,便于确定性验证。开门延时使用time.sleep模拟,实际工程中应替换为定时器回调。状态转移完全由tick()和request()触发,无外部直接修改状态字段,保证状态机封装性。