GrabBag/App/WorkpieceHole/Doc/MODBUS_PROTOCOL.md
2026-02-01 14:51:16 +08:00

291 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WorkpieceHole 工件孔定位 - Modbus TCP 通信协议
## 1. 系统架构
```
┌─────────────────┐ Modbus TCP ┌─────────────────────┐
│ │◄────────────────────►│ │
│ 3D视觉系统 │ 192.168.0.88 │ 汇川PLC-easy320 │
│ (Modbus客户端) │ :502 │ (Modbus服务端) │
│ │ │ │
└─────────────────┘ └─────────────────────┘
```
## 2. 网络配置
| 设备 | IP地址 | 端口 | 角色 |
|------|--------|------|------|
| 3D视觉系统 | - | - | Modbus TCP 客户端 |
| 汇川PLC-easy320 | 192.168.0.88 | 502 | Modbus TCP 服务端 |
## 3. 地址映射规则
汇川PLC D寄存器与Modbus保持寄存器地址映射关系
```
代码协议地址 = D寄存器地址 + 1
示例:
D1000 -> 代码协议地址 1001
D1002 -> 代码协议地址 1003
D2000 -> 代码协议地址 2001
```
## 4. 寄存器地址定义
### 4.1 控制寄存器
| PLC寄存器 | 代码协议地址 | 类型 | 读/写 | 说明 |
|-----------|------------|------|-------|------|
| D1000 | 1001 | uint16 | R/W | 拍照请求标志1=请求拍照) |
| D1002 | 1003 | uint16 | W | 数据输出完成标志1=完成) |
### 4.2 坐标数据寄存器D2000开始最多10个点
每个点包含6个float值X, Y, Z, Pitch, Roll, Yaw每个float占用2个寄存器大端序共12个寄存器/点。
| 点序号 | PLC寄存器范围 | 代码协议地址范围 | 说明 |
|--------|--------------|-----------------|------|
| 点0 | D2000-D2011 | 2001-2012 | 第1个点坐标 |
| 点1 | D2012-D2023 | 2013-2024 | 第2个点坐标 |
| 点2 | D2024-D2035 | 2025-2036 | 第3个点坐标 |
| 点3 | D2036-D2047 | 2037-2048 | 第4个点坐标 |
| 点4 | D2048-D2059 | 2049-2060 | 第5个点坐标 |
| 点5 | D2060-D2071 | 2061-2072 | 第6个点坐标 |
| 点6 | D2072-D2083 | 2073-2084 | 第7个点坐标 |
| 点7 | D2084-D2095 | 2085-2096 | 第8个点坐标 |
| 点8 | D2096-D2107 | 2097-2108 | 第9个点坐标 |
| 点9 | D2108-D2119 | 2109-2120 | 第10个点坐标 |
### 4.3 单点坐标数据布局以点0为例
| PLC寄存器 | 代码协议地址 | 类型 | 说明 |
|-----------|------------|------|------|
| D2000-D2001 | 2001-2002 | float (大端) | X坐标 (mm) |
| D2002-D2003 | 2003-2004 | float (大端) | Y坐标 (mm) |
| D2004-D2005 | 2005-2006 | float (大端) | Z坐标 (mm) |
| D2006-D2007 | 2007-2008 | float (大端) | Pitch角度 (°) |
| D2008-D2009 | 2009-2010 | float (大端) | Roll角度 (°) |
| D2010-D2011 | 2011-2012 | float (大端) | Yaw角度 (°) |
> **注意**:
> - 每个float值占用2个寄存器采用IEEE 754单精度浮点数格式
> - 大端序Big-Endian高位字在低地址寄存器低位字在高地址寄存器
> - 最多支持10个点共120个寄存器10 × 6 × 2 = 120
## 5. 通信流程
```
时序图:
3D视觉系统 汇川PLC
│ │
│ 轮询读取D1000(地址1001) │
│◄─────────────────────────────│
│ │
│ D1000=1 (拍照请求) │
│◄─────────────────────────────│
│ │
│ 写0到D1000(地址1001) │
│─────────────────────────────►│
│ │
│ [执行拍照和算法处理] │
│ │
│ 写坐标到D2000(地址2001)开始│
│─────────────────────────────►│
│ │
│ 写1到D1002(地址1003) │
│─────────────────────────────►│
│ │
```
### 5.1 详细流程说明
1. **轮询拍照请求**
- 3D系统持续轮询读取PLC的D1000寄存器代码协议地址1001
- 轮询间隔100ms可配置
- 使用边沿检测只在0→1变化时触发
2. **拍照执行**
- 检测到D1000=1后立即写0到D1000清除请求
- 触发相机拍照
- 执行工件孔定位算法
3. **坐标输出**
- 算法处理完成后将坐标数据写入PLC的D2000开始的寄存器
- 代码协议地址2001-2012单点12个寄存器6个float值
- 数据格式IEEE 754单精度浮点数大端序
4. **完成通知**
- 坐标数据写入成功后写1到D1002代码协议地址1003
- 通知PLC数据输出完成
## 6. 连接管理
### 6.1 自动重连机制
- 初始化时尝试连接PLC
- 连接失败时自动启动重连定时器
- 重连间隔3000ms可配置
- 持续重连直到连接成功或软件关闭
### 6.2 优雅退出
- 设置关闭标志,阻止新的重连尝试
- 停止所有定时器(轮询、重连)
- 断开Modbus连接
- 释放资源
## 7. 错误处理
| 错误类型 | 处理方式 |
|----------|----------|
| 连接失败 | 自动重连,发送错误信号 |
| 读取失败 | 记录日志,下次轮询重试 |
| 写入失败 | 记录日志,返回失败状态 |
| 超时 | 默认1秒超时触发重连 |
## 8. 配置文件
配置文件路径:`config/config.xml`
```xml
<TcpServerConfig
plcServerIp="192.168.0.88"
plcServerPort="502"
robotServerIp=""
robotServerPort="502"/>
```
> **注意**: robotServerIp 留空表示不使用机械臂直连
## 9. 代码接口
### 9.1 PLCModbusClient 类
```cpp
// 寄存器地址默认值(代码协议地址 = D寄存器 + 1
static constexpr int DEFAULT_ADDR_PHOTO_REQUEST = 1001; // D1000: 拍照请求
static constexpr int DEFAULT_ADDR_DATA_COMPLETE = 1003; // D1002: 数据完成
static constexpr int DEFAULT_ADDR_COORD_DATA_START = 2001; // D2000: 坐标数据起始
// 每个点占用的寄存器数量6个float × 2寄存器/float = 12寄存器
static constexpr int REGS_PER_POINT = 12;
// 最大点数
static constexpr int MAX_POINTS = 10;
// 坐标数据结构float类型大端序
struct CoordinateData {
float x = 0.0f; // X坐标 (mm)
float y = 0.0f; // Y坐标 (mm)
float z = 0.0f; // Z坐标 (mm)
float pitch = 0.0f; // Pitch角度 (°)
float roll = 0.0f; // Roll角度 (°)
float yaw = 0.0f; // Yaw角度 (°)
};
// 初始化连接
bool Initialize(const std::string& plcIP, int plcPort = 502, const RegisterConfig& regConfig = RegisterConfig());
// 关闭连接
void Shutdown();
// 启动/停止轮询
void StartPolling(int intervalMs = 100);
void StopPolling();
// 设置拍照触发回调
void SetPhotoTriggerCallback(PhotoTriggerCallback callback);
// 清除拍照请求写0到D1000
bool ClearPhotoRequest();
// 发送单个坐标数据到PLC写入D2000开始
bool SendCoordinateToPLC(const CoordinateData& coord, int pointIndex = 0);
// 发送多个坐标数据到PLC
bool SendCoordinatesToPLC(const std::vector<CoordinateData>& coords);
// 通知数据输出完成写1到D1002
bool NotifyDataComplete();
// 连接状态查询
bool IsPLCConnected() const;
```
### 9.2 信号
```cpp
// 拍照请求信号
void photoRequested(int cameraIndex);
// 连接状态变化
void connectionStateChanged(bool plcConnected);
// 正在重连
void reconnecting(const QString& deviceName, int attemptCount);
// 错误发生
void errorOccurred(const QString& errorMsg);
```
## 10. 使用示例
```cpp
// 创建客户端
PLCModbusClient* client = new PLCModbusClient(this);
// 从配置读取IP并初始化只连接PLC
PLCModbusClient::RegisterConfig regConfig;
regConfig.addrPhotoRequest = 1001; // D1000
regConfig.addrDataComplete = 1003; // D1002
regConfig.addrCoordDataStart = 2001; // D2000
client->Initialize(
config.plcRobotServerConfig.plcServerIp,
config.plcRobotServerConfig.plcServerPort,
regConfig
);
// 设置拍照回调
client->SetPhotoTriggerCallback([this, client](int cameraIndex) {
// 1. 清除拍照请求
client->ClearPhotoRequest();
// 2. 执行拍照和算法
auto results = doDetection(cameraIndex);
// 3. 发送多个坐标点到PLCD2000开始float大端序
std::vector<PLCModbusClient::CoordinateData> coords;
for (const auto& result : results) {
PLCModbusClient::CoordinateData coord;
coord.x = result.x; // float (mm)
coord.y = result.y; // float (mm)
coord.z = result.z; // float (mm)
coord.pitch = result.pitch; // float (°)
coord.roll = result.roll; // float (°)
coord.yaw = result.yaw; // float (°)
coords.push_back(coord);
}
client->SendCoordinatesToPLC(coords);
// 4. 通知完成
client->NotifyDataComplete();
});
// 启动轮询
client->StartPolling(100);
// 程序退出时
client->Shutdown();
```
## 11. 版本历史
| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2025-01 | 初始版本支持PLC和机械臂 |
| 1.1 | 2025-01 | 移除机械臂直连坐标数据输出到PLC |
| 1.2 | 2025-01 | 坐标数据改为float大端序支持最多10个点 |