291 lines
9.7 KiB
Markdown
291 lines
9.7 KiB
Markdown
|
|
# 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. 发送多个坐标点到PLC(D2000开始,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个点 |
|