跳转到内容

ARCS Modbus 使用指南

1. Modbus 协议介绍

  • Modbus是一种串行通信协议,最初由 Modicon 公司(现在的施耐德电气)在1979年为使用可编程逻辑控制器(PLC)的自动化设备设计。Modbus 已经成为工业领域通信协议的事实标准。Modbus 协议包括 Modbus RTU 和 Modbus TCP 两种形式。

  • Modbus RTU(Remote Terminal Unit):这是一种基于串行线(例如 RS-485、RS-422、RS-232)的二进制通信协议。在 Modbus RTU 中,数据以二进制形式传输,每个字节由两个十六进制字符表示。Modbus RTU 主要用于工业和系统自动化应用,其中设备之间的通信距离较长。

  • Modbus TCP(Transmission Control Protocol):这是一种基于以太网的通信协议。Modbus TCP 使用 TCP/IP 协议进行通信,因此可以利用现有的以太网基础设施。与 Modbus RTU 相比,Modbus TCP 可以支持更多的设备连接,并且通信速度更快。

  • Modbus RTU 与 Modbus TCP 两者的主要区别:

    • Modbus RTU 基于串行通信的方式,如 RS-485 接口,其传输速率受限于串行接口的性能。

    • Modbus TCP 基于 TCP/IP 协议栈,在网络上进行数据传输,支持更高的传输速率。

2. Modbus 主站

2.1 主站介绍

在 Modbus 通信网络中,主站(Master Station)是发起通信的设备,它负责控制和协调与从站(Slave Station)之间的通信过程。主站就像是一个指挥者,主动向从站请求数据或者向从站发送命令,以实现对整个网络的有效管理和数据交互。

2.2 主站用途

  • 在焊接、搬运、装配等操作中作为主站,它需要根据自身的任务流程和工作状态,有针对性地向 PLC 从站请求数据或发送指令。

    • 示例:在汽车零部件组装过程中,机器人可能需要从 PLC 获取零部件的位置信息,以便准确地抓取和安装。
  • 机器人主站往往具有较高的智能化程度,能够对获取的数据进行分析和处理,以做出合理的决策。

    • 示例:根据 PLC 提供的生产线上的设备状态信息,机器人可以调整自己的工作节奏和动作顺序,实现与其他设备的协同工作。

2.3 Modbus 入口

打开 遨博 STUDIO 软件主页,单击左侧导航栏“配置 > 现场总线 > Modbus”进入 【Modbus 客户端 IO设置】页面。

2.4 主站 Modbus TCP

  • 单元页面:在 【Modbus 客户端 IO设置】页面单击“单元 > 添加 Modbus 单元 > TCP模式”。

  • Modbus TCP 设备: 使用 TCP/IP 连接,不需要校验和计算,可配置“设备”、“名称”、“从站编号”、“IP 地址”、“端口”及“操作”。配置 IP 地址后可单击【测试】,弹出测试成功表示可以与目标设备进行通讯,反之则与目标设备不可进行通讯,需检查与目标设备是否在同一网段,防火墙是否关闭等。

    注意:

    请确保您的TCP设备与目标设备处于同一网段。

  • 信号页面:在 【Modbus 客户端 IO设置】页面单击“信号 > 添加 Modbus 信号”。

    • COIL STATUS(线圈状态):用于读取和控制远程设备的开关状态,通常用于控制继电器等开关设备。
    • INPUT STATUS(输入状态):用于读取远程设备的输入状态,通常用于读取传感器等输入设备的状态。
    • HOLDING REGISTER(保持寄存器):用于存储和读取远程设备的数据,通常用于存储控制参数、设备状态等信息。
    • INPUT REGISTER(输入寄存器):用于存储远程设备的输入数据,通常用于存储传感器等输入设备的数据。
    • 绿色表示为正常通讯,灰色,红色为不通讯,红色响应代码如下所示
      • E1 :非法函数(0x01)查询中接收到的函数代码不是服务器(或从服务器)允许的操作。
      • E2 :非法数据地址(0x02)在查询中收到的功能代码不是服务器(或从站)允许的操作,请检查输入的信号地址对应的远程 MODBUS 服务器的设置。
      • E3 :非法数据值(0x03)数据字段中包含的值对于服务器(或从服务器)是不允许的值,请检查信号值对于远程 MODBUS 服务器上的指定地址是否有效。
      • E4 :从属设备故障(0x04)当服务器(或从服务器)试图执行请求的操作时,发生了一个不可恢复的错误,请检查设备与接线是否损坏,并尝试重启设备。
      • E5 :应答(0x05)与发送到远程 MODBUS 单元的编程命令结合使用的专用功能。
      • E6 :从设备忙(0x06)与发送到远程 MODBUS 单元的编程命令一起使用,表示设备(服务器)现在无法响应,请等待或尝试重新连接,并排查机器人IP地址是否与同一局域网下其他设备IP地址一致,产生了冲突。

2.5 主站 Modbus RTU

  • 单元页面:在 【Modbus 客户端 IO设置】页面单击“单元 > 添加 Modbus 单元 > RTU模式”。

  • Modbus RTU 设备:可配置设备“名称”、“从站编号”、“串口号”、“波特率”、“奇偶校验”、“数据位”及“停止位”。

    注意:Modbus RTU 设备基于串行通信的方式,其传输速率受限于 RS-485 串行接口的性能。若通信不稳定,信号状态闪烁,可将波特率值调小,若不通讯时排查选择的串口是否符合,可使用 Modbus 串口助手进行排查,参考文档:

    78 RS485测试流程

    79 Modbus RTU 串口通信测试

  • Modbus RTU 通讯依赖于控制柜或机械臂末端的 RS-485 串口通讯,在 Modbus 的串口选择可以参考如下:

  • 控制 RS-485 串口号,控制 RS-485 包括末端 RS485 及 USB485。

2.6 Modbus 信号在配置中作为 IO 使用

在【配置】界面单击“一般 > I/O设置”可配置其 I/O 输入动作,除拖动示教外其余信号需要在联动模式下触发信号执行(也可通过 OEM 定制功能使其在手动模式或自动模式生效)。

进行此配置前需要用户在【配置】界面单击“ 现场总线 > Modbus > 信号”中添加信号类型为“寄存器输入”或“数字输入”的Modbus 信号。

  1. 为对应的 Modbus 信号配置输入动作。

  2. 为对应的 Modbus 信号配置输出动作。

  3. 用户可以在左侧导航栏单击“IO > Mobus”查看信号寄存器和数字信号的变化。

2.7 Modbus 信号在程序中使用

  • 设置节点: 可以设置 Modbus 信号的“数字输出”和“寄存器输出”以及数字信号的单脉冲参数。

提示

通常需配合“等待信号”做为校验,确保信号设置成功再执行后续流程。

  • 等待节点: 以 Modbus 信号为判断依据,待满足此信号后程序才继续运行,常与设置信号搭配使用。

  • 赋值节点: 以 Modbus 信号值赋值给变量,供后续流程调用。

  • 如果节点: 以 Modbus信号 做为判断条件,信号满足要求时,程序进入判断流程。

  • 循环节点: 以 Modbus 信号做为触发循环的条件,信号满足条件时,程序进入循环流程。

  • 用户可以在左侧导航栏单击“IO > Mobus”查看信号寄存器和数字信号的变化。

3. Modbus 从站

3.1 从站介绍

Modbus 从站的主要作用是响应主站(Master)的请求并执行相应的操作。实际应用中它可以用于连接和控制生产线上的各种设备,实现设备之间的信息交换和控制指令传递。

3.2 ARCS 从站的用途

  • 响应主站(Master)的请求,将机器臂的状态信息实时发送给主站。

  • 响应主站(Master)的请求,将控制器的信息发送给主站。

  • 测试调试时作为数据:

    • 将机器臂 I/O 信号的变化实时传递给主站。
    • 将主站自定义信号实时传递给机器臂。

注意:

通过 ARCS 的主站连接从站的方式,可能会存在信号延时,仅在调试时候使用,不可在程序中使用,若需要在程序中对从站进行寄存器的读写可以参考下文 3.4 通用寄存器的读写示例。

3.3 从站地址表更新位置

Modbus 从站地址表位于“钉盘-团队文件 > ARCS > 对外文件夹 > Modbus从站”中进行更新,若您是使用客户,可联系本公司技术服务部技术人员获取,若您是技术服务人员可自行获取。

Modbus 版本ARCS 版本修改日期修改内容
1.0.40.29.2-beta.102024-8-191. 增加控制工程。
2. 增加工程运行状态。
1.0.70.31.0-beta.3
0.32.0-alpha.23
2024-12-26更新机器人系列和机器人子型号。
1.0.80.29.4-rc.6
0.31.0-beta.5
0.32.0-alpha.32
2025-1-9增加 Modbus 从站输出操作模式和心跳。
1.0.90.29.5-rc.10
0.31.0-rc.12
0.32.0-alpha.73
2025-3-4增加读写工程运行速度百分比。
1.0.110.29.5-rc.21
0.31.0-rc.26
0.31.1-beta.7
0.32.0-alpha.117
2025-4-25增加 Modbus 从站解除保护性停止。
1.0.120.29.5-rc.22
0.29.6-rc.1
0.31.0-rc.28
0.32.0-alpha.136
2025-5-12增加 Modbus 从站清除错误弹窗,包括解除保护性停止和重置接口板。
1.0.130.31.1-beta.9
0.32.0-alpha.131
2025-5-15增加 bool 寄存器。
1.140.31.1-beta.10
0.32.0-alpha.139
2025-5-21增加切换工程。
1.140.31.1-beta.10
0.32.0-alpha.140
2025-5-221.增加操作模式支持输出联动模式。
2.增加输出 Modbus 版本号。

3.4 从站 Modbus TCP

在 【Modbus 客户端 IO设置】页面单击【从站】 打开“Modbus TCP”开关。

开启从站之后,可通过 PLC 或 modscan 等主站设备连接该从站,从站地址请参考 Modbus 从站协议中的定义。

3.5 从站 Modbus RTU

  • 在 【Modbus 客户端 IO设置】页面单击【从站】 打开“Modbus RTU”开关。

    注意:

    • Modbus RTU 从站需要先将串口参数配置完成才可开启。
    • 开启后串口参数不可修改,需关闭后再进行修改。

  • Modbus RTU 通讯依赖与控制柜或机械臂末端的 RS-485 串口通讯,不同设备的串口参数参考如下:

    注意:Modbus RTU 基于串行通信的方式,其传输速率受限于 RS-485 串行接口的性能。若通信不稳定,信号状态闪烁,可将波特率值调小,若不通讯时排查选择选择的串口是否符合,可使用 Modbus 串口助手进行排查,参考文档:

    78 RS485测试流程

    79 Modbus RTU 串口通信测试

  • 控制 RS-485 串口号,控制 RS-485 包括末端 RS485 及 USB485。

3.6 Modbus 从站通用寄存器读写接口应用示例

3.6.1 Modbus 从站通用寄存器介绍

为了方便用户使用自定义信号实现 PLC (主站)与控制器之间的通信,Modbus 从站提供了专用的可读写的通用寄存器,通用寄存器的地址为 300 ~ 525。

通用寄存器读写示例,两种典型的通用寄存器读写示例:

  • 使用 SDK 调用接口读写对应地址的通用寄存器信号。
  • 使用工程(Lua)脚本读写对应地址的通用寄存器信号。

3.6.2 Modbus TCP 读写通用寄存器

测试环境描述:

现采用 Modbus TCP 通信方式,用 Modbus 调试助手(Modbus Poll)来模拟 PLC 主站与 Modbus TCP 从站进行通信,Modbus 调试助手的相关地址信号设置如下:

3.6.2.1 SDK 读写通用寄存器
  • 读取通用寄存器:

    • 通过 SDK 读取 Modbus 信号的核心步骤:

      1. 调用 modbusAddSignal 添加对应地址的信号。

      2. 使用 modbusGetSignalStatus 获取对应地址的信号值。

      3. 使用 modbusDeleteSignal 删除该信号。

    • 使用示例:使用 SDK 读取 Modbus 从站中地址为 300、301、303 的通用寄存器,具体代码逻辑如下:

      c++
      // 读通用寄存器
      void exampleModbusSlaveRead(RpcClientPtr impl)
      {
          // 根据从站地址新建对应地址的保持寄存器信号
          impl->getRegisterControl()->modbusAddSignal(
              MODBUS_SLAVE_IP, 1, 300, 0x03, "READ_HOLDING_REGISTER_300", true);
          impl->getRegisterControl()->modbusSetSignalUpdateFrequency(
              "READ_HOLDING_REGISTER_300", 10);
      
          impl->getRegisterControl()->modbusAddSignal(
              MODBUS_SLAVE_IP, 1, 301, 0x03, "READ_HOLDING_REGISTER_301", true);
          impl->getRegisterControl()->modbusSetSignalUpdateFrequency(
              "READ_HOLDING_REGISTER_301", 10);
      
          impl->getRegisterControl()->modbusAddSignal(
              MODBUS_SLAVE_IP, 1, 303, 0x03, "READ_HOLDING_REGISTER_303", true);
          impl->getRegisterControl()->modbusSetSignalUpdateFrequency(
              "READ_HOLDING_REGISTER_303", 10);
      
          std::this_thread::sleep_for(std::chrono::seconds(1));
      
          int i = 30;
          while (i--) {
               // 获取对应地址的保持寄存器信号的值
              auto ret0 = impl->getRegisterControl()->modbusGetSignalStatus(
                  "READ_HOLDING_REGISTER_300");
              std::cout << "READ_HOLDING_REGISTER_300:" << ret0 << std::endl;
      
              auto ret1 = impl->getRegisterControl()->modbusGetSignalStatus(
                  "READ_HOLDING_REGISTER_301");
              std::cout << "READ_HOLDING_REGISTER_301:" << ret1 << std::endl;
      
              auto ret3 = impl->getRegisterControl()->modbusGetSignalStatus(
                  "READ_HOLDING_REGISTER_303");
              std::cout << "READ_HOLDING_REGISTER_303:" << ret3 << std::endl;
      
              std::this_thread::sleep_for(std::chrono::seconds(1));
          }
          // 结束后删除信号
          impl->getRegisterControl()->modbusDeleteSignal("READ_HOLDING_REGISTER_300");
          impl->getRegisterControl()->modbusDeleteSignal("READ_HOLDING_REGISTER_301");
          impl->getRegisterControl()->modbusDeleteSignal("READ_HOLDING_REGISTER_303");
      }
    • 读取的结果如下:

  • 写入通用寄存器:

    • 通过 SDK 写入 Modbus 通用寄存器的步骤:

      1. 使用 SDK 调用 modbusAddSignal 添加对应地址的信号。

      2. 使用 modbusSetOutputSignal 写入对应地址的信号值。

      3. 使用 modbusDeleteSignal 删除该信号。

    • 使用示例:使用 SDK 写入 Modbus 从站中地址为 302 的通用寄存器,具体代码逻辑如下:

      // 写保持寄存器
      void exampleModbusSlaveWrite(RpcClientPtr impl)
      {
          // 根据从站地址新建对应地址的保持寄存器信号
          impl->getRegisterControl()->modbusAddSignal(
              MODBUS_SLAVE_IP, 1, 302, 0x03, "WRITE_HOLDING_REGISTER_302", true);
      
          std::this_thread::sleep_for(std::chrono::seconds(1));
      
          // 写入对应地址保持寄存器的值
          impl->getRegisterControl()->modbusSetOutputSignal(
              "WRITE_HOLDING_REGISTER_302", 25);
      
          std::this_thread::sleep_for(std::chrono::seconds(1));
      
          // 结束后删除信号
          impl->getRegisterControl()->modbusDeleteSignal(
              "WRITE_HOLDING_REGISTER_302");
      }
    • 实现效果:

3.6.2.2 工程脚本读写通用寄存器
  • 读取通用寄存器:

    • 实现目标:使用 Modbus 调试助手,设置 Modbus 从站中地址为 300 的通用寄存器值为 10。

    • 示例代码:

      --建立 modbus 信号,(ip,站号,寄存器起始地址,功能码名,字)     
      modbusAddSignal("127.0.0.1,502",1,300,0x03,"READ_HOLDING_REGISTER_300",true)   
      -- 获取 modbus 的寄存器的值,并赋值给变量,赋值给变量是为了方便在示教器上查看   
      tmp0=modbusGetSignalStatus("READ_HOLDING_REGISTER_300")   
      -- 删除指定名称的信号      
      modbusDeleteSignal("READ_HOLDING_REGISTER_300")
    • 实现效果:在示教器中通过编写脚本,获取地址为 300 的信号值,可以看到获取的值 tmp0 为10。

  • 写入通用寄存器:

    • 实现目标:在示教器中通过编写脚本,将地址为 302 的信号值设置为 88。

    • 示例代码:

      --建立modbus信号,(ip,站号,寄存器起始地址,功能码名,字)
      modbusAddSignal("127.0.0.1,502",1,300,0x03,"WRITE_HOLDING_REGISTER_300",true)   
      --写入modbus的值,并赋值给变量,赋值给变量是为了方便在示教器上查看
      tmp0 = modbusSetOutputSignal("WRITE_HOLDING_REGISTER_300",88)
      --删除指定名称的信号
      modbusDeleteSignal("WRITE_HOLDING_REGISTER_300")
    • 实现效果:使用 Modbus 调试助手可以看到地址为 302 的通用寄存器值为 88。

3.6.3 Modbus RTU 读写通用寄存器

测试环境描述:

  • 现使用 Modbus RTU 通信方式,用编程调用接口方式和 Modbus RTU 从站进行通信。

    由于串口通信时,Modbus RTU 从站不支持同时连接多个 Modbus 主站,所以此处不使用 Modbus 调试助手来辅助测试,而是通过调用接口获取相应地址的信号值来查看信号变化是否正确。

  • 选择两个可以通信的串口号,本次测试使用的是 /dev/ttyS0/dev/ttyS1/dev/ttyS1 分配给 Modbus RTU 从站使用,/dev/ttyS0在编程调用接口时使用。

  • 开启 Modbus RTU 从站,相关配置如下图:

重要:

  • 进行串口通信时,请确保所用两个串口号能够正常通信,可以使用 cutecom 等调试助手来辅助测试确认。

  • 同一串口号不能同时被多个主站或从站使用。

3.6.3.1 SDK 读写通用寄存器
  • 通过 SDK 读写通用寄存器示例流程:

    1. 调用 modbusAddSignal 添加对应地址的信号。
    2. 调用 modbusGetSignalStatus 读取对应地址的信号值,查看地址存储的初始值。
    3. 调用 modbusSetOutputSignal 写入对应地址的信号值。
    4. 调用 modbusGetSignalStatus 读取对应地址的信号值。
    5. 最后使用 modbusDeleteSignal 删除该信号。
  • 下面使用 SDK 读写 Modbus 从站里地址为 302 的通用寄存器,具体代码逻辑如下:

    c++
    // 使用 Modbus RTU 读写保持寄存器
    #define MODBUS_SERIAL_PORT "/dev/ttyS0,115200,N,8,1"
    void exampleModbusRtu(RpcClientPtr impl)
    {
        // 根据从站地址新建对应地址的保持寄存器信号
        impl->getRegisterControl()->modbusAddSignal(
            MODBUS_SERIAL_PORT, 1, 302, 0x03, "HOLDING_REGISTER_302", true);
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        // 获取对应地址的保持寄存器信号的值
        auto ret0 = impl->getRegisterControl()->modbusGetSignalStatus(
            "HOLDING_REGISTER_302");
        std::cout << "读取 --> HOLDING_REGISTER_302:" << ret0 << std::endl;
    
        // 写入对应地址保持寄存器的值
        impl->getRegisterControl()->modbusSetOutputSignal("HOLDING_REGISTER_302",
                                                          66);
        std::cout << "将 66 写入 HOLDING_REGISTER_302 的值" << std::endl;
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        // 获取对应地址的保持寄存器信号的值
        auto ret1 = impl->getRegisterControl()->modbusGetSignalStatus(
            "HOLDING_REGISTER_302");
        std::cout << "读取 --> HOLDING_REGISTER_302:" << ret1 << std::endl;
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        // 写入对应地址保持寄存器的值
        impl->getRegisterControl()->modbusSetOutputSignal("HOLDING_REGISTER_302",
                                                          88);
        std::cout << "将 88 写入 HOLDING_REGISTER_302 的值" << std::endl;
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        // 获取对应地址的保持寄存器信号的值
        auto ret2 = impl->getRegisterControl()->modbusGetSignalStatus(
            "HOLDING_REGISTER_302");
        std::cout << "读取 --> HOLDING_REGISTER_302:" << ret2 << std::endl;
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
    
        // 结束后删除信号
        impl->getRegisterControl()->modbusDeleteSignal(
            "WRITE_HOLDING_REGISTER_302");
    }
  • 从下面的输出结果里可以看到,地址为 302 的通用寄存器的初始值为 0。写入 66 后,获取的值为 66。写入 88后,获取的值为 88 。说明 SDK 可以正常读写 Modbus 从站里的通用寄存器。

3.6.3.2 工程脚本读写通用寄存器
  • 实现目标:在示教器中通过编写脚本来实现以下流程,且每次获取的信号值都赋值给 tmp0。

    1. 调用 modbusGetSignalStatus 获取地址为 300 的信号值,
    2. 调用 modbusSetOutputSignal 将地址为 300 的信号值设置为 88。
    3. 调用 modbusGetSignalStatus 获取地址为 300 的信号值。
    4. 调用 modbusSetOutputSignal 将地址为 300 的信号值设置为 66。
  • 示例代码:

    --建立modbus信号,(设备信息,站号,寄存器起始地址,功能码,名,字)     
    modbusAddSignal("/dev/ttyS0,115200,N,8,1",1,300,0x03,"HOLDING_REGISTER_300",true)  
    -- 获取modbus的寄存器的值,并赋值给变量,赋值给变量是为了方便在示教器上查看   
    tmp0=modbusGetSignalStatus("HOLDING_REGISTER_300")
    --写入modbus的值,并赋值给变量,赋值给变量是为了方便在示教器上查看
    modbusSetOutputSignal("HOLDING_REGISTER_300",88)
    -- 获取modbus的寄存器的值,并赋值给变量,赋值给变量是为了方便在示教器上查看   
    tmp0=modbusGetSignalStatus("HOLDING_REGISTER_300")
    --写入modbus的值,并赋值给变量,赋值给变量是为了方便在示教器上查看
    modbusSetOutputSignal("HOLDING_REGISTER_300",66)
    -- 获取modbus的寄存器的值,并赋值给变量,赋值给变量是为了方便在示教器上查看   
    tmp0=modbusGetSignalStatus("HOLDING_REGISTER_300")
    -- 删除指定名称的信号      
    modbusDeleteSignal("READ_HOLDING_REGISTER_300")
  • 实现效果:可以看到 tmp0 的值在 66 和 88 之间变化。

4. 接口应用

4.1 modbusSendCustomCommand 接口功能说明 & 注意事项

  • 将用户指定的命令发送到指定 IP 地址上的 Modbus 单元。
  • 由于不会接收到响应,因此不能用于请求数据,读数据的功能码暂不可用。
  • 用户负责提供对所提供的功能码有意义的数据。
  • 内置函数负责构建 Modbus 帧,因此用户不需要关心命令的长度,不需要输入 CRC 格式的数据。

4.2 参数定义及格式

c++
// 接口定义
int modbusSendCustomCommand(const std::string &device_info,int slave_number, int function_code, const std::vector<uint8_t> &data);

// device_info: 设备信息
     * 设备信息是 RTU 格式,
     * 例如:"serial_port,baud,parity,data_bit,stop_bit" 
     * (1)serial_port 参数指定串口的名称,
     * 例如,在 Linux 上为"/dev/ttyS0""/dev/ttyUSB0",在Windows上为"\.\COM10"
     * (2)baud 参数指定通信的波特率,例如 96001920057600115200 等 。
     * (3)parity 参数指定奇偶校验方式,N 表示无校验,E 表示偶校验,O表示奇校验。
     * (4)data_bit 参数指定数据位数,允许的值为5、67和8。
     * (5)stop_bit 参数指定停止位数,允许的值为1和2。
     *
     * 设备信息是 TCP 格式,例如:"ip address,port" 
     * (1)ip address 参数指定服务器的IP地址 
     * (2)port 参数指定服务器监听的端口号
         
// slave_number: 指定用于自定义命令的从站号

// function_code: 指定自定义命令的功能码
     * MODBUS_FC_READ_COILS                0x01   // 读线圈寄存器
     * MODBUS_FC_READ_DISCRETE_INPUTS      0x02   // 读离散输入状态
     * MODBUS_FC_READ_HOLDING_REGISTERS    0x03   // 读保持寄存器
     * MODBUS_FC_READ_INPUT_REGISTERS      0x04   // 读输入寄存器
     * MODBUS_FC_WRITE_SINGLE_COIL         0x05   // 写单线圈
     * MODBUS_FC_WRITE_SINGLE_REGISTER     0x06   // 写单寄存器
     * MODBUS_FC_READ_EXCEPTION_STATUS     0x07   // 读异常状态(限串行线)
     * MODBUS_FC_WRITE_MULTIPLE_COILS      0x0F   // 写多线圈
     * MODBUS_FC_WRITE_MULTIPLE_REGISTERS  0x10   // 写多个寄存器
     * MODBUS_FC_REPORT_SLAVE_ID           0x11   // 报告丛机ID(限串行线)
     * MODBUS_FC_MASK_WRITE_REGISTER       0x16   // 带屏蔽字写入寄存器
     * MODBUS_FC_WRITE_AND_READ_REGISTERS  0x17   // 读&写寄存器

// data: 必须是有效的字节值(0-255)
     * { 0x00, 0x02, 0x00, 0x0F }
     * { 0x06, 0x0A, 0x0F, 0x08, 0x00, 0x0F }

4.3 调用示例

c++
// 定义IP
#define MODBUS_IP          "172.16.3.111,502"    
// 建立对象
RpcClientPtr impl;
// 发送自定义数据
impl->getRegisterControl()->modbusSendCustomCommand(MODBUS_IP, 1, 0x06, { 0x00, 0x02, 0x00, 0x0F });

5. 问题处理

Modbus TCP信号通信失败

修复流程:

  • 排查设备与机器人之间网络是否能正常通信,首先查看是否关闭设备的防火墙,然后使用ping命令检查网络是否能正常通信。
  • 排查主站建立的信号地址在从站中是否存在,主站新建的信号对应地址在从站中必须存在,信号才能正常通信。
  • 排查机器人 IP 地址是否与同一局域网下其他设备 IP 地址一致,是否产生了冲突。

Modbus RTU信号通信失败

  • 修复流程:

    • 排查设备与机器人之间串口通信是否正常,可以使用设备与机器人中的串口调试助手来测试串口通信状态。

    • 排查主站建立的信号地址在从站中是否存在,主站新建的信号对应地址在从站中必须存在,信号才能正常通信。

  • 操作步骤:

    1. 在机器人控制柜中使用命令安装 cutecom
    2. 打开cutecom,并设置“串口号”、“波特率”、“奇偶校验”、“数据位”及“停止位”。
    3. 若设备端是 PLC,则用 cutecom 直接连接 PLC 测试,若设备是本机电脑,可在电脑中安装串口调试助手,例如:XCOM
    4. 如果 cutecomPLC/XCOM 能够相互发送数据,表示能正常通信,串口通信线路没有问题,反之,需要检查通信线路连接情况。

6. 常见问题

Q1. 在用无线示教器时,使用路由器来桥接网络,可能会出现 IP 能 ping 通,但是 Modbus 主站信号不通。

解决方案: 检查路由器是否配置端口转发,如果没有配置,需将 Modbus TCP 使用的端口号配置上。