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

9.7 KiB
Raw Blame History

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

<TcpServerConfig
    plcServerIp="192.168.0.88"
    plcServerPort="502"
    robotServerIp=""
    robotServerPort="502"/>

注意: robotServerIp 留空表示不使用机械臂直连

9. 代码接口

9.1 PLCModbusClient 类

// 寄存器地址默认值(代码协议地址 = 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 信号

// 拍照请求信号
void photoRequested(int cameraIndex);

// 连接状态变化
void connectionStateChanged(bool plcConnected);

// 正在重连
void reconnecting(const QString& deviceName, int attemptCount);

// 错误发生
void errorOccurred(const QString& errorMsg);

10. 使用示例

// 创建客户端
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个点