三、Modbus 通讯(Python)
本页对应 C++ 版。函数名与参数顺序与 C++ 完全一致(Python SDK 由 C++ 经 SWIG 生成),差异只在两处:
- 返回值形态:C++ 用引用参数回填数据;Python 的返回形态由 SWIG 绑定决定,逐接口实测,不按类型推断。
- 少数接口在 Python 中不可直接调用(绑定缺陷),页面内已逐个标注。
本页共 13 个接口,其中 11 个在 Python SDK 中存在。
数据结构
ModbusTCPParameter
TCP 通讯参数。
| 成员 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| IP | string | "192.168.1.13" | Modbus TCP 服务器 IP 地址 |
| port | int | 503 | Modbus TCP 端口号 |
Python 中定义:nrc_interface.ModbusTCPParameter(构造:nrc.ModbusTCPParameter())。
可用字段(共 2 个,实测 dir()):
IP、port
ModbusRTUParameter
RTU 通讯参数。
| 成员 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| slaveId | int | - | 从站 ID,范围 [0, 65535] |
| port | int | 1 | 串口端口号 |
| baudrate | int | 115200 | 波特率 |
| checkBit | string | "None" | 奇偶校验位;"None"(无校验)/ "Even"(偶校验)/ "Odd"(奇校验) |
| dataBit | int | 8 | 数据位;可选 5、6、7、8 |
| stopBit | int | 1 | 停止位;可选 1、2 |
Python 中定义:nrc_interface.ModbusRTUParameter(构造:nrc.ModbusRTUParameter())。
可用字段(共 6 个,实测 dir()):
baudrate、checkBit、dataBit、port、slaveId、stopBit
ModbusMasterParameter
Modbus 主站参数。
| 成员 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | string | "TCP" | 主站类型;"TCP" 或 "RTU" |
| startAddress | bool | false | 起始地址偏移;false 为地址自动 -1(起始为 1),true 为地址不变(起始为 0) |
| TCP | ModbusTCPParameter | - | TCP 通讯参数(type 为 TCP 时有效) |
| RTU | ModbusRTUParameter | - | RTU 通讯参数(type 为 RTU 时有效) |
Python 中定义:nrc_interface.ModbusMasterParameter(构造:nrc.ModbusMasterParameter())。
可用字段(共 4 个,实测 dir()):
RTU、TCP、startAddress、type
主站配置
modbus_set_master_parameter
设置主站参数(支持 TCP/RTU,最多 9 个工艺号)。
Result modbus_set_master_parameter(SOCKETFD socketFd, int id, const ModbusMasterParameter& param);def modbus_set_master_parameter(socketFd, id, param):返回值:int 结果码(0 成功,负数为错误码)。本接口无数据出参。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符,由 connect_robot 返回 |
| id | int | 工艺号,范围 [1, 9] |
| param | const ModbusMasterParameter& | 主站参数结构体 |
C++ 侧返回值描述:Result 结构体,result 为 true 时表示设置成功。
modbus_open_master
打开主站通讯连接。
Result modbus_open_master(SOCKETFD socketFd, int id);def modbus_open_master(socketFd, id):返回值:int 结果码(0 成功,负数为错误码)。本接口无数据出参。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
C++ 侧返回值描述:Result 结构体。
modbus_get_master_connection_status
获取主站连接状态。
Result modbus_get_master_connection_status(SOCKETFD socketFd, int id, int& status);def modbus_get_master_connection_status(socketFd, id, status):返回值:list,共 2 个元素,形如 [结果码, 数据...]。下标 0 是结果码,下标 1 是出参值。(实测为 list 而非 tuple,解包写法 ret, val = ... 同样可用。)
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| status | int& | 输出参数,连接状态;0 表示未连接,1 表示已连接 |
C++ 侧返回值描述:Result 结构体。
连接状态 ≠ 从站在线(现场经验,按版本复核)
status = 1 只说明主站这一侧的会话已建立。现场多次遇到:从站未上电或网线未插,本接口仍返回 1,随后的读写也不报错、只是数据不更新。 所以不要把它当成从站在线判据,建议:
- 周期读一个已知寄存器,用数据是否更新判断从站在线;
- 读写超时/失败在业务层累计计数,连续 N 次失败即判离线并重连;
- 恢复后重新确认该
id的配方参数没有被重置。
功能码 01H - 读线圈
modbus_read_coil_status
读取从站线圈状态(位操作,可读可写)。
Result modbus_read_coil_status(SOCKETFD socketFd, int id, int address, int quantity, std::vector<int>& data);def modbus_read_coil_status(socketFd, id, address, quantity, data):返回值:int 结果码(0 成功,负数为错误码)。数据通过出参容器原地填充——先创建 nrc.VectorInt() 传入,调用成功后用 list(obj) 读取。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 起始地址 |
| quantity | int | 读取数量;范围 [1, 2000] |
| data | std::vector<int>& | 输出参数,读取到的线圈状态数组;每个元素为 0 或 1 |
C++ 侧返回值描述:Result 结构体。
功能码 02H - 读输入状态
modbus_read_input_status
读取从站离散输入状态(位操作,只读)。
Result modbus_read_input_status(SOCKETFD socketFd, int id, int address, int quantity, std::vector<int>& data);def modbus_read_input_status(socketFd, id, address, quantity, data):返回值:int 结果码(0 成功,负数为错误码)。数据通过出参容器原地填充——先创建 nrc.VectorInt() 传入,调用成功后用 list(obj) 读取。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 起始地址 |
| quantity | int | 读取数量;范围 [1, 2000] |
| data | std::vector<int>& | 输出参数,读取到的输入状态数组;每个元素为 0 或 1 |
C++ 侧返回值描述:Result 结构体。
功能码 03H - 读保持寄存器
modbus_read_holding_registers
读取从站保持寄存器(16 位操作,可读可写)。
Result modbus_read_holding_registers(SOCKETFD socketFd, int id, int address, int quantity, std::vector<int>& data);def modbus_read_holding_registers(socketFd, id, address, quantity, data):返回值:int 结果码(0 成功,负数为错误码)。数据通过出参容器原地填充——先创建 nrc.VectorInt() 传入,调用成功后用 list(obj) 读取。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 起始地址 |
| quantity | int | 读取数量;范围 [1, 125] |
| data | std::vector<int>& | 输出参数,读取到的保持寄存器值数组;每个元素范围 [0, 65535] |
C++ 侧返回值描述:Result 结构体。
功能码 04H - 读输入寄存器
modbus_read_input_registers
读取从站输入寄存器(16 位操作,只读)。
Result modbus_read_input_registers(SOCKETFD socketFd, int id, int address, int quantity, std::vector<int>& data);def modbus_read_input_registers(socketFd, id, address, quantity, data):返回值:int 结果码(0 成功,负数为错误码)。数据通过出参容器原地填充——先创建 nrc.VectorInt() 传入,调用成功后用 list(obj) 读取。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 起始地址 |
| quantity | int | 读取数量;范围 [1, 125] |
| data | std::vector<int>& | 输出参数,读取到的输入寄存器值数组;每个元素范围 [0, 65535] |
C++ 侧返回值描述:Result 结构体。
功能码 05H - 写单个线圈
modbus_write_signal_coil_status
写单个线圈状态。
Result modbus_write_signal_coil_status(SOCKETFD socketFd, int id, int address, int data);def modbus_write_signal_coil_status(socketFd, id, address, data):返回值:int 结果码(0 成功,负数为错误码)。本接口无数据出参。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 线圈地址 |
| data | int | 写入值;0 或 1 |
C++ 侧返回值描述:Result 结构体。
功能码 06H - 写单个保持寄存器
modbus_write_signal_holding_registers
写单个保持寄存器。
Result modbus_write_signal_holding_registers(SOCKETFD socketFd, int id, int address, int data);def modbus_write_signal_holding_registers(socketFd, id, address, data):返回值:int 结果码(0 成功,负数为错误码)。本接口无数据出参。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 寄存器地址 |
| data | int | 写入值;范围 [0, 65535] |
C++ 侧返回值描述:Result 结构体。
功能码 0FH - 写多个线圈
modbus_write_multiple_coil_status
批量写入多个线圈状态。
Result modbus_write_multiple_coil_status(SOCKETFD socketFd, int id, int address, const std::vector<int>& data);def modbus_write_multiple_coil_status(socketFd, id, address, data):返回值:int 结果码(0 成功,负数为错误码)。本接口无数据出参。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 起始地址 |
| data | const std::vector<int>& | 写入的线圈值数组;每个元素为 0 或 1 |
C++ 侧返回值描述:Result 结构体。
功能码 10H - 写多个保持寄存器
modbus_write_multiple_holding_registers
批量写入多个保持寄存器。
Result modbus_write_multiple_holding_registers(SOCKETFD socketFd, int id, int address, const std::vector<int>& data);def modbus_write_multiple_holding_registers(socketFd, id, address, data):返回值:int 结果码(0 成功,负数为错误码)。本接口无数据出参。
参数说明(与 C++ 一致):
| 参数 | 类型 | 说明 |
|---|---|---|
| socketFd | SOCKETFD | 套接字文件描述符 |
| id | int | 工艺号,范围 [1, 9] |
| address | int | 起始地址 |
| data | const std::vector<int>& | 写入的寄存器值数组;每个元素范围 [0, 65535] |
C++ 侧返回值描述:Result 结构体。
完整使用示例
TCP 主站读写完整流程
#include "nrc_modbus.h"
void modbus_tcp_example(SOCKETFD socketFd) {
// 1. 设置主站参数(TCP 模式)
ModbusMasterParameter masterParam;
masterParam.type = "TCP";
masterParam.startAddress = false; // 起始地址为 1
masterParam.TCP.IP = "192.168.1.14";
masterParam.TCP.port = 503;
Result ret = modbus_set_master_parameter(socketFd, 1, masterParam);
if (!ret.result) {
printf("设置主站参数失败\n");
return;
}
// 2. 打开主站
ret = modbus_open_master(socketFd, 1);
if (!ret.result) {
printf("打开主站失败\n");
return;
}
// 3. 检查连接状态
int status = 0;
ret = modbus_get_master_connection_status(socketFd, 1, status);
if (ret.result && status == 1) {
printf("Modbus TCP 连接成功\n");
}
// 4. 读线圈(功能码 01H)
std::vector<int> coilData;
ret = modbus_read_coil_status(socketFd, 1, 0, 10, coilData);
if (ret.result) {
printf("读取线圈成功: ");
for (int v : coilData) printf("%d ", v);
printf("\n");
}
// 5. 写单个线圈(功能码 05H)
ret = modbus_write_signal_coil_status(socketFd, 1, 3, 1);
// 6. 读保持寄存器(功能码 03H)
std::vector<int> holdingReg;
ret = modbus_read_holding_registers(socketFd, 1, 200, 5, holdingReg);
if (ret.result) {
printf("读取保持寄存器成功: ");
for (int v : holdingReg) printf("%d ", v);
printf("\n");
}
// 7. 写多个保持寄存器(功能码 10H)
std::vector<int> writeReg = {1000, 2000, 3000};
ret = modbus_write_multiple_holding_registers(socketFd, 1, 400, writeReg);
}⚠️ 该接口在 Python SDK 中不存在。
nrc_interface中没有同名函数,调用会抛AttributeError。请使用 C++ SDK,或联系纳博特确认后续版本是否支持。
RTU 主站配置示例
ModbusMasterParameter rtuParam;
rtuParam.type = "RTU";
rtuParam.startAddress = false;
rtuParam.RTU.slaveId = 1;
rtuParam.RTU.port = 2;
rtuParam.RTU.baudrate = 115200;
rtuParam.RTU.checkBit = "Even";
rtuParam.RTU.dataBit = 8;
rtuParam.RTU.stopBit = 1;
Result ret = modbus_set_master_parameter(socketFd, 2, rtuParam);⚠️ 该接口在 Python SDK 中不存在。
nrc_interface中没有同名函数,调用会抛AttributeError。请使用 C++ SDK,或联系纳博特确认后续版本是否支持。