1. 项目背景与需求解析
在工业称重领域,托利多地磅(Toledo scale)作为全球知名的称重设备品牌,被广泛应用于物流仓储、生产制造等场景。传统的地磅数据采集通常依赖人工记录或本地串口直连,这种方式存在效率低下、数据易丢失等问题。我们最近接到一个需求:某物流园区需要将20台托利多地磅的实时称重数据自动上传到中央管理系统,用于货物跟踪和结算。
这个项目的核心挑战在于:
- 地磅设备仅提供RS-232/485串口输出
- 现场分布在不同仓库,距离最远达500米
- 需要实现秒级数据采集和断网缓存
- 现有系统基于MQTT协议进行数据交换
经过方案对比,我们最终选择"串口网关+MQTT"的架构,具体实现路径是:
- 通过串口网关采集地磅数据
- 解析托利多特有协议格式
- 转换为JSON格式数据
- 通过MQTT发布到服务器
关键提示:托利多设备通常使用SBI协议或MT协议,不同型号的波特率(常见9600/19200)、数据位(7/8)、停止位(1/2)等参数可能不同,需提前确认。
2. 硬件选型与连接方案
2.1 串口网关选型要点
市面上的串口网关主要分为三类:
- 通用型串口转网络网关(如MOXA NPort)
- 工业物联网专用网关(如研华UTX-3115)
- 开源硬件方案(如树莓派+串口模块)
我们最终选择工业级网关,主要考虑因素:
| 指标 | 通用型网关 | 工业网关 | 开源方案 |
|---|---|---|---|
| 稳定性 | ★★★☆ | ★★★★★ | ★★☆ |
| 协议支持 | ★★★☆ | ★★★★★ | ★★★☆ |
| 扩展性 | ★★☆ | ★★★★☆ | ★★★★★ |
| 成本 | ¥800-1500 | ¥2000-4000 | ¥300-600 |
工业网关的优势在于:
- 内置看门狗和断网重连机制
- 支持-40~75℃宽温工作
- 提供完整的协议栈支持
- 具备数据缓存功能(通常1万条以上)
2.2 物理连接实操
典型接线示意图:
托利多地磅(RS-232) → 串口网关(COM1) │ ├─ Ethernet → 交换机 │ └─ 12V电源具体接线步骤:
- 确认地磅接口类型(DB9母头或接线端子)
- 制作串口线(重点注意引脚定义):
- 托利多常用2-3-5接线法(RX-TX-GND)
- 部分型号需要短接RTS-CTS
- 连接电源和网线
- 通过Web界面检查连接状态
避坑指南:曾遇到因RTS/CTS流控未正确配置导致数据不稳定的情况,建议先用串口调试工具验证物理层通信正常。
3. 协议解析与数据转换
3.1 托利多协议解析
托利多设备常见两种协议格式:
SBI协议示例:
STX 02 W S 1 2 3 4 . 5 6 ETX 0D │ │ └──┬──┘ │ └┬┘ │ │ │ │ └─ 小数部分 │ │ │ └─ 小数点位置 │ │ └─ 整数部分 │ └─ 稳定标志(S=稳定) └─ 重量单位(W=kg)MT协议示例:
01 03 00 00 00 06 01 00 00 00 00 00 │ │ └──┬──┘ └──────┬──────┘ │ │ │ └─ 数据域 │ │ └─ 数据长度 │ └─ 功能码 └─ 设备地址我们开发的解析算法逻辑:
def parse_toledo(data): if data.startswith(b'\x02'): # SBI协议 stable = data[3] == ord('S') integer = data[4:8].decode().strip() decimal_pos = data[8] - ord('0') decimal = data[9:11].decode() weight = float(f"{integer}.{decimal}") return {'weight': weight, 'stable': stable} elif len(data) == 12: # MT协议 addr = data[0] value = int.from_bytes(data[6:10], 'big') return {'weight': value/1000, 'addr': addr}3.2 JSON格式转换
转换后的MQTT消息示例:
{ "device_id": "scale_001", "timestamp": "2023-08-20T14:25:30Z", "weight": 1234.56, "unit": "kg", "stable": true, "metadata": { "gateway": "GW-01", "rssi": -65 } }关键处理逻辑:
- 添加设备唯一标识符
- 使用ISO 8601时间格式
- 保留原始协议中的稳定状态标志
- 添加网关自身状态信息
4. MQTT服务端配置
4.1 Mosquitto服务器配置
推荐的生产环境配置(mosquitto.conf):
listener 1883 allow_anonymous false password_file /etc/mosquitto/passwd persistence true persistence_location /var/lib/mosquitto/ log_dest file /var/log/mosquitto/mosquitto.log用户权限管理:
# 创建密码文件 mosquitto_passwd -c /etc/mosquitto/passwd gateway_user # 设置ACL规则(/etc/mosquitto/acl) user gateway_user topic readwrite scales/+/data4.2 网关端MQTT客户端配置
工业网关通常提供MQTT配置界面,关键参数:
- Broker地址:mqtt.example.com:1883
- Client ID:gateway_001(需唯一)
- 主题格式:scales/{device_id}/data
- QoS级别:1(至少一次交付)
- 保持连接:60秒心跳
- 遗言消息:scales/gateway_001/status offline
实测发现:设置clean_session=false可避免网络抖动导致的消息丢失,但需要服务端支持持久会话。
5. 系统调试与优化
5.1 常见问题排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无数据上报 | 串口参数不匹配 | 核对波特率/数据位/停止位 |
| 数据断续 | 流控配置错误 | 检查RTS/CTS/DTR信号线 |
| MQTT连接频繁断开 | 心跳间隔设置过短 | 调整keepalive至60-120秒 |
| 数据延迟超过5秒 | 网络带宽不足 | 限制单包大小(建议<1KB) |
| 小数位精度丢失 | 协议解析算法错误 | 检查小数点位置处理逻辑 |
5.2 性能优化技巧
- 批量上报机制:
# 每10条数据或1秒间隔批量发送 buffer = [] last_send = time.time() def on_scale_data(data): buffer.append(data) if len(buffer) >= 10 or time.time() - last_send > 1: mqtt.publish(json.dumps(buffer)) buffer.clear() last_send = time.time()数据压缩:对JSON数据启用gzip压缩(可减少70%流量)
本地缓存:配置网关在断网时保存数据到SD卡
QoS策略:
- 重量数据使用QoS1
- 状态信息使用QoS0
6. 安全增强措施
6.1 通信安全方案
传输层加密:
# mosquitto.conf listener 8883 certfile /etc/ssl/certs/mosquitto.crt keyfile /etc/ssl/private/mosquitto.key设备认证:
- 每个网关使用唯一Client ID
- 基于证书的双向认证
数据校验:
def verify_checksum(data): # SBI协议校验和验证 if data[-2] != (sum(data[1:-2]) % 256): raise ValueError("Checksum error")
6.2 运维监控实现
Prometheus监控指标示例:
# HELP scale_weight Current weight measurement # TYPE scale_weight gauge scale_weight{device="scale_001"} 1234.56 # HELP gateway_status Gateway connection status # TYPE gateway_status gauge gateway_status{id="gw_01"} 1Grafana看板关键面板:
- 实时重量曲线图
- 网关在线状态矩阵
- 数据延迟热力图
- 异常事件统计
经过三个月的实际运行,这个方案在日均处理10万+条称重数据的压力下保持了99.99%的可用性。最大的收获是:工业现场一定要选择带隔离保护的串口网关,我们曾因电源干扰损失过一批数据,后来改用带光电隔离的网关再未出现类似问题。