1. 项目背景与挑战
凌晨两点的实验室里,六部电梯的仿真界面在显示器上闪烁着蓝光。这是我们团队为2021年西门子杯工业自动化挑战赛开发的六部十层电梯控制系统,项目代号"电梯侠"。作为机械专业的学生,这次比赛让我们完成了从机械制图到PLC编程的硬核转型。
这个项目的核心挑战在于实现六部电梯的高效协同调度。与普通单梯控制不同,多电梯系统需要解决几个关键问题:
- 如何合理分配新到达的乘梯请求?
- 怎样避免多部电梯响应同一楼层造成的资源浪费?
- 当系统负载激增时,如何防止电梯群出现"死锁"或"饥饿"现象?
我们使用的硬件平台是西门子S7-1200 PLC,编程环境为TIA Portal V15。选择这个组合是因为它既满足比赛要求,又具有良好的仿真调试功能——这对我们这些PLC新手至关重要。
2. 系统架构设计
2.1 状态机模型
每部电梯都被建模为一个独立的状态机,包含以下基本状态:
- 空闲态(IDLE):电梯静止且无任务
- 上行态(UP):电梯正在向上运行
- 下行态(DOWN):电梯正在向下运行
- 停靠态(DOCKED):电梯停靠楼层并开门
状态转换遵循严格的优先级规则:
- 当前方向上的目标楼层优先响应
- 同方向的外部呼叫次优先
- 反向呼叫最后处理
这种设计保证了电梯运行的高效性,避免了无谓的方向切换。
2.2 数据结构设计
我们为每部电梯定义了状态结构体:
st复制TYPE ELEVATOR_STATUS :
STRUCT
CurrentFloor : INT; // 当前楼层(1-10)
Direction : INT; // 运行方向(-1/0/+1)
TargetFloors : ARRAY[1..10] OF BOOL; // 内部目标楼层
CallUp : ARRAY[1..10] OF BOOL; // 上行外呼
CallDown : ARRAY[1..10] OF BOOL; // 下行外呼
DoorStatus : BOOL; // 门状态(开/关)
Overload : BOOL; // 超载报警
Moving : BOOL; // 运动状态
END_STRUCT
END_TYPE
这个结构体看似简单,却包含了调度决策所需的全部信息。特别说明几个设计考量:
- 使用三个独立的数组分别存储内部目标、上行外呼和下行外呼,便于快速查询
- Direction字段用-1/0/+1表示方向,比布尔量更易扩展
- Moving字段用于区分停靠和运行中的静止状态
3. 核心调度算法
3.1 成本计算模型
当新的乘梯请求到达时,调度器会为每部电梯计算响应成本:
st复制FUNCTION CalculateCost : INT
VAR_INPUT
elevator : ELEVATOR_STATUS;
callFloor : INT;
callDir : INT;
END_VAR
VAR
distanceCost : INT := ABS(elevator.CurrentFloor - callFloor);
directionScore : INT := 0;
loadFactor : REAL := 0.0;
END_VAR
// 方向匹配度计算
IF elevator.Direction = callDir THEN
directionScore := (callDir = 1) ? (10 - callFloor) : callFloor;
ELSIF elevator.Direction = 0 THEN
directionScore := 5;
ELSE
directionScore := -10;
END_IF
// 负载因子计算
loadFactor := COUNT_ENABLED(elevator.TargetFloors) / 10.0;
// 综合成本计算
RETURN distanceCost * 2 - directionScore + INT(loadFactor * 20);
这个成本函数包含三个关键因素:
- 距离成本:电梯与呼叫楼层的物理距离
- 方向得分:运行方向与呼叫方向的匹配程度
- 负载因子:电梯当前任务量的影响
经过实测,这个模型在响应速度和系统吞吐量之间取得了良好平衡。
3.2 动态权重调整
在比赛准备阶段,我们发现固定权重的成本函数难以适应不同负载场景。于是引入了动态调整机制:
st复制// 根据系统负载动态调整权重
IF totalPendingCalls > 15 THEN // 高负载
distanceWeight := 3;
directionWeight := 2;
ELSE // 常规负载
distanceWeight := 2;
directionWeight := 3;
END_IF
高负载时优先考虑距离因素,确保快速响应;常规负载时则侧重方向匹配,提高运行效率。
4. 关键问题解决方案
4.1 死锁预防机制
在早期测试中,我们遇到了典型的"电梯震荡"问题:多部电梯在相邻楼层间来回响应同一批请求,导致系统吞吐量骤降。解决方案是引入心跳检测:
st复制// 每5秒检查一次电梯状态
IF heartbeatTimer.Q THEN
FOR i := 1 TO 6 DO
IF NOT elevators[i].Moving AND
(COUNT_ENABLED(elevators[i].TargetFloors) > 0 OR
COUNT_ENABLED(elevators[i].CallUp) > 0 OR
COUNT_ENABLED(elevators[i].CallDown) > 0) THEN
// 触发任务重新分配
ReallocateTasks(i);
END_IF
END_FOR
heartbeatTimer(IN:=TRUE);
END_IF
这个机制就像给电梯系统安装了心脏起搏器,当检测到某部电梯异常停滞时,会自动重新分配其任务。
4.2 负载均衡策略
为避免某些电梯过度繁忙而其他闲置,我们实现了负载均衡算法:
-
实时计算系统平均负载:
st复制totalLoad := 0; FOR i := 1 TO 6 DO totalLoad := totalLoad + COUNT_ENABLED(elevators[i].TargetFloors); END_FOR avgLoad := totalLoad / 6; -
对于新请求,优先分配给负载低于平均值的电梯
-
当负载差异超过阈值时,触发任务迁移
5. 调试与优化经验
5.1 仿真测试技巧
-
压力测试场景设计:
- 早高峰模式:集中生成1层上行请求
- 午间模式:随机生成各楼层双向请求
- 晚高峰模式:集中生成高层下行请求
-
关键指标监控:
- 平均响应时间
- 最长等待时间
- 电梯利用率
- 能耗指标
5.2 性能优化记录
通过多次迭代优化,我们将系统性能从最初的82%提升到97%:
- 第一轮优化:改进成本函数权重 (+8%)
- 第二轮优化:添加动态负载均衡 (+5%)
- 第三轮优化:优化状态机转换逻辑 (+2%)
6. 实用调试技巧
-
可视化调试工具:
- 使用TIA Portal的Trace功能记录关键变量
- 在HMI上显示电梯运行轨迹热力图
- 用Excel分析日志数据,找出性能瓶颈
-
常见问题排查:
- 电梯不响应呼叫:检查方向标志是否更新
- 多部电梯聚集同一楼层:调整成本函数的方向权重
- 系统响应变慢:检查负载均衡机制是否生效
-
编程规范建议:
- 为所有状态机定义明确的状态转换图
- 关键算法添加详细注释
- 重要变量使用有意义的命名
这个项目让我们深刻体会到,好的控制系统就像交响乐团——每个部件都要各司其职,又要默契配合。虽然最终提交的版本仍有改进空间,但那段在实验室通宵调试的日子,确实让我们对实时控制系统有了全新的认识。