1. 项目背景与需求分析
在智能仓储和自动化停车领域,立体车库系统正面临前所未有的效率挑战。传统单PLC控制系统在应对大规模车位管理时,往往受限于单一品牌的功能局限。我们最近完成的104号立体车库项目,通过创新性地整合西门子S7-1200和三菱FX5U双PLC系统,配合MCGS人机界面,成功将300平方米的占地面积转化为800个智能车位的运营能力。
这个项目的核心挑战在于:如何让两个不同品牌的工业控制器实现毫秒级的数据同步?西门子的工艺对象在垂直运动控制上具有精度优势,而三菱的定位模块在水平轴向移动时响应更快。通过Modbus TCP协议建立通信桥梁,我们不仅保留了双方的优势特性,还实现了1+1>2的系统效果。
2. 硬件架构设计
2.1 设备选型与功能分配
-
西门子S7-1200(6ES7215-1AG40-0XB0):
- 负责垂直升降轴控制
- 配置TM Pulse 2HS计数模块(6ES7223-1QH32-0XB0)用于高度定位
- 使用工艺对象实现S曲线加减速控制
-
三菱FX5U-32MT/ES:
- 专管水平横移控制
- 扩展FX5-40SSC-S定位模块
- 内置直线插补功能实现多轴同步
-
MCGS TPC7062KT人机界面:
- 7寸触摸屏
- 双网口配置
- 运行嵌入式Windows CE系统
2.2 网络拓扑设计
采用星型网络架构,关键配置参数:
network复制交换机:赫斯曼MS30-0800SA
IP分配:
- 西门子PLC:192.168.1.10/24
- 三菱PLC:192.168.1.20/24
- HMI:192.168.1.100/24
端口设置:
- 端口1:HMI(全双工,100Mbps)
- 端口2:西门子(开启Port Trunking)
- 端口3:三菱(开启QoS优先级)
关键经验:工业交换机必须开启IGMP Snooping功能,避免Modbus TCP广播风暴
3. 通信协议实现
3.1 Modbus TCP数据映射表
| 功能描述 | 西门子地址 | 三菱地址 | 数据类型 | 刷新周期 |
|---|---|---|---|---|
| 急停信号 | %DB5.DBX0.0 | M8000 | BOOL | 10ms |
| 升降轴当前位置 | %DB10.DBD0 | D100-D103 | REAL | 50ms |
| 横移目标位置 | %DB10.DBD4 | D200 | INT | 50ms |
| 系统故障代码 | %DB20.DBW0 | D500 | WORD | 100ms |
3.2 协议转换Lua脚本优化版
lua复制-- 带校验的浮点转换函数
function convertFloatWithCheck(siemensAddr, mitsubishiAddr)
local rawData = mb_read(siemensAddr, 502, 0, 4, "FLOAT")
if not rawData then
syslog("ERR", "Modbus读取超时")
return false
end
-- IEEE754浮点解析
local sign = rawData[1] > 0 and 1 or 0
local mantissa = math.floor(math.abs(rawData[1]) * 100)
local exponent = math.floor(math.log(math.abs(rawData[1]))/math.log(10))
-- 写入三菱寄存器
local success = com.write_to_plc(
string.format("D%d=%d,D%d=%d,D%d=%d",
mitsubishiAddr, mantissa,
mitsubishiAddr+1, exponent,
mitsubishiAddr+2, sign),
"fx5u")
-- 回读校验
if success then
local check = com.read_from_plc(
string.format("D%d,D%d,D%d",
mitsubishiAddr, mitsubishiAddr+1, mitsubishiAddr+2),
"fx5u")
return check and check[1]==mantissa
end
return false
end
-- 带重试机制的定时任务
timer.create(200, function()
local retry = 0
while retry < 3 do
if convertFloatWithCheck("192.168.1.10", 100) then break end
retry = retry + 1
sys.sleep(50)
end
end)
调试发现:三菱FX5U的D寄存器写入延迟可能达到5-8ms,关键数据需采用"写入-回读-比对"机制
4. 运动控制实现细节
4.1 西门子升降轴控制逻辑
ST复制// 在OB35循环中断组织块中(周期2ms)
IF #升降使能 THEN
// 带负载补偿的速度计算
#实际速度 := LIMIT(
MIN := 0.0,
MAX := #最大速度,
IN := #基准速度 * (1.0 - (#负载重量 / 5000.0))
);
// 安全条件联锁
IF #松闸信号 AND #限位正常 AND NOT #急停激活 THEN
Axis_MoveVelocity(
Axis := "升降轴",
Velocity := #实际速度,
Direction := #运动方向);
ELSE
Axis_Stop(Axis := "升降轴", Mode := 1);
END_IF;
// 跨系统状态同步
MCGS_WriteTag("CurrentHeight", #当前位置);
MCGS_WriteTag("WeightAlarm", #负载重量 > 2500.0);
END_IF;
4.2 三菱定位控制参数
parameter复制[FX5-40SSC-S参数]
1轴加速度时间 = 300ms
1轴S曲线比率 = 30%
插补周期 = 0.88ms
到位判定带宽 = 0.5mm
振动抑制增益 = 45%
[电子齿轮设置]
1轴分子 = 10000
1轴分母 = 360
4.3 速度耦合算法
在MCGS中实现的动态速度调整:
javascript复制function syncSpeed() {
// 获取西门子侧实时速度
let liftSpeed = GetTag("LiftSpeed");
// 计算三菱横移基准速度
let baseMoveSpeed = liftSpeed * 1.2;
// 动态调整系数(0.8-1.2)
let factor = GetTag("CouplingFactor");
// 写入三菱PLC
SetTag("MoveSpeed", baseMoveSpeed * factor);
// 超速保护
if(baseMoveSpeed * factor > 500) {
AlarmTrigger("SpeedOverLimit");
SetTag("EmergencyStop", 1);
}
}
// 每50ms执行一次同步
setInterval(syncSpeed, 50);
5. HMI界面优化技巧
5.1 动画性能优化方案
| 优化前 | 优化后 | 实现方法 |
|---|---|---|
| 全屏刷新15fps | 局部刷新60fps | 脏矩形算法 |
| 直接颜色绑定 | 预编译颜色表 | LUT转换 |
| 同步数据请求 | 异步分批加载 | 数据分页 |
5.2 车位状态显示逻辑
javascript复制class ParkingSlot {
constructor(ctx, x, y) {
this.ctx = ctx;
this.pos = {x, y};
this.lastStatus = null;
}
update() {
let status = GetTag(`Slot_${this.id}_Status`);
let weight = GetTag(`Slot_${this.id}_Weight`);
// 状态未变化时不重绘
if(status === this.lastStatus) return;
// 动态颜色映射
let colorMap = {
'empty': '#CCCCCC',
'reserved': '#FFFF00',
'occupied': weight > 2000 ? '#FF0000' : '#00AAFF',
'fault': this.getFaultColor()
};
this.drawRect(colorMap[status]);
this.lastStatus = status;
}
getFaultColor() {
// 呼吸灯效果
let phase = (Date.now() % 2000) / 2000;
let alpha = Math.sin(phase * Math.PI) * 0.5 + 0.5;
return `rgba(255,165,0,${alpha})`;
}
}
6. 系统可靠性设计
6.1 双看门狗机制
-
硬件看门狗:
- 西门子:通过OB35周期检测(2ms)
- 三菱:内置看门狗定时器(500ms)
-
软件心跳包:
lua复制-- 在MCGS中实现的心跳检测
local last_siemens = 0
local last_mitsubishi = 0
timer.create(1000, function()
-- 西门子心跳检测
local siemens_ok = mb_read("192.168.1.10", 502, 0x5000, 1)
if siemens_ok then last_siemens = os.time() end
-- 三菱心跳检测
local mitsubishi_ok = com.read_from_plc("M9000", "fx5u")
if mitsubishi_ok then last_mitsubishi = os.time() end
-- 超时处理
if os.time() - last_siemens > 3 then
EmergencyStop("SIEMENS_TIMEOUT")
end
if os.time() - last_mitsubishi > 3 then
EmergencyStop("MITSUBISHI_TIMEOUT")
end
end)
6.2 接地抗干扰措施
- 通讯电缆:采用双层屏蔽双绞线(Belden 3106A)
- 接地电阻:<1Ω(实测0.78Ω)
- 滤波器配置:
- 电源输入端:Schaffner FN2070
- PLC输出端:TDK ZJYS51R5
现场经验:Modbus信号异常时,先用示波器检查RS485差分电压(应≥1.5V)
7. 压力测试方案
7.1 测试脚本增强版
python复制from pyModbusTCP.client import ModbusClient
import random
import time
class StressTester:
def __init__(self):
self.client = ModbusClient(host='192.168.1.100', timeout=2)
self.operation_count = 0
self.error_log = []
def random_operation(self):
cmd = random.choice(['store', 'retrieve'])
slot = random.randint(1, 800)
try:
# 写入操作命令
self.client.write_single_coil(0x5000, cmd == 'store')
self.client.write_register(0xD200, slot)
# 等待响应(超时3秒)
start = time.time()
while not self.client.read_coils(0x6000):
if time.time() - start > 3:
raise TimeoutError()
time.sleep(0.1)
self.operation_count += 1
except Exception as e:
self.error_log.append(f"{time.ctime()} | 车位{slot} | 错误:{str(e)}")
self.client.write_single_coil(0x7000, True)
if __name__ == "__main__":
tester = StressTester()
for _ in range(10000):
tester.random_operation()
time.sleep(random.uniform(0.05, 0.2))
print(f"测试完成,成功率:{(tester.operation_count/10000)*100:.2f}%")
with open("error_log.txt", "w") as f:
f.write("\n".join(tester.error_log))
7.2 性能优化成果
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 吞吐量 | 500次/小时 | 2000次/小时 |
| 响应延迟 | 300-500ms | 80-120ms |
| 故障恢复时间 | >30s | <5s |
通过指令缓冲队列和预读取策略,三菱FX5U的Modbus处理能力提升4倍。实测在800个车位的存取操作中,平均响应时间控制在120ms以内,完全满足商业运营需求。
