- 选型指南
- 概述
- 入门指南
- 机械臂参数
- 示教器使用
-
二次开发
-
API(C++)
- 快速开始
- 接口说明
- 7000端口接口说明
- 使用示例
- 返回值说明
-
API(Python)
- 快速开始
- 接口说明
- 7000端口接口说明
- 使用示例
- 返回值说明
- ROS2开发
-
API(C++)
- 相关下载
Modbus 主站通信综合示例
Modbus 主站通信综合示例
Python
# /**
# * ex_modbus.py
# * @brief Modbus 主站通信综合示例(TCP + RTU 双模式)
# * @attention
# * - 确保控制器网络通信正常
# * - TCP 模式需在 PC 上启动虚拟 Modbus 从站模拟器(端口 5000):
# * python3 -c "from pymodbus.server import StartTcpServer
# * from pymodbus.datastore import ModbusSlaveContext, ModbusSequentialDataBlock
# * store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [0]*100),
# * co=ModbusSequentialDataBlock(0, [0]*100),
# * hr=ModbusSequentialDataBlock(0, [0]*100),
# * ir=ModbusSequentialDataBlock(0, [0]*100))
# * StartTcpServer(context=store, address=('0.0.0.0', 5000))"
# * - RTU 模式用于灵巧手(通过 RS485 串口连接控制器)
# * 从站 ID = 2,波特率 115200,串口号根据实际接线修改
# * - 灵巧手寄存器地址(4X 保持寄存器):
# * 力阈值: 1115\~1119(5 指) 速度: 1125\~1130(6 关节)
# * 目标位置: 1135\~1140(6 关节) 实际位置反馈: 1155\~1160
# * @note 运行步骤
# * 1. TCP 模式需先启动虚拟从站模拟器
# * 2. 运行: python3 ex_modbus.py
# */
import sys
import os
import platform
import time
# 基于脚本所在目录构建 SDK Python 绑定的绝对路径
_script_dir = os.path.dirname(os.path.abspath(__file__))
# 自动检测平台,添加对应 SDK Python 绑定路径
if platform.system() == "Windows":
sys.path.append(os.path.join(_script_dir, "../../lib/windows/python"))
elif platform.machine() in ("aarch64", "arm64"):
sys.path.append(os.path.join(_script_dir, "../../lib/linux/arm64/python"))
else:
sys.path.append(os.path.join(_script_dir, "../../lib/linux/x86/python"))
# Windows: 将 tl_host.dll 所在目录加入 DLL 搜索路径
if platform.system() == "Windows":
_dll_dir = os.path.join(_script_dir, "../../lib/windows")
os.add_dll_directory(_dll_dir)
from tl_interface import *
# 灵巧手寄存器地址(Modbus 4X 保持寄存器)
REG_FORCE_LIMIT = 1115 # 手指力阈值(5 个)
REG_SPEED = 1125 # 手指速度(6 个)
REG_POS_TARGET = 1135 # 目标位置(6 个)
REG_POS_FEEDBACK = 1155 # 实际位置反馈(6 个)
# ============================================================
# 工具函数
# ============================================================
def print_result(msg, ret):
"""@brief 打印操作结果"""
if ret == SUCCESS:
print(" [成功] %s" % msg)
else:
print(" [失败] %s,错误码: %d" % (msg, ret))
def print_separator(title):
"""@brief 打印分隔标题"""
print("\n========== %s ==========" % title)
def read_with_retry(sock, id, addr, qty, desc):
"""@brief 带重试的读取:最多尝试 3 次,每次间隔 500ms"""
for attempt in range(1, 4):
data = VectorInt()
ret = modbus_read_holding_registers(sock, id, addr, qty, data)
if ret == SUCCESS:
print(" [成功] %s(第%d次)" % (desc, attempt))
return ret, data
print(" [重试] %s 第%d次失败,500ms后重试..." % (desc, attempt))
time.sleep(0.5)
print(" [失败] %s,错误码: %d(重试3次均失败)" % (desc, ret))
return ret, VectorInt()
# ============================================================
# 主函数
# ============================================================
def main():
# ---- 获取 SDK 版本 ----
version = get_library_version()
print("[信息] SDK 版本: %s" % version)
# ---- 连接控制器 ----
print_separator("连接控制器")
sock = connect_robot("192.168.1.13", "6001")
if sock < 0:
print("[ERROR] 连接控制器失败")
return -1
print("[信息] 连接成功 (socket = %d)" % sock)
# ===========================================================
# 第一部分:Modbus TCP 模式(master ID = 0)
# 覆盖功能码 01H\~06H + 10H
# ===========================================================
print_separator("第一部分:Modbus TCP 模式")
# 1.1 设置 TCP 主站参数
param = ModbusMasterParameter()
param.type = "TCP"
param.startAddress = True # 起始地址 0
param.TCP.IP = "192.168.1.100" # 从站 IP(PC 端 Modbus 模拟器)
param.TCP.port = 5000 # 从站端口
ret = modbus_set_master_parameter(sock, 0, param)
print_result("modbus_set_master_parameter (id=0, TCP)", ret)
if ret != SUCCESS:
disconnect_robot(sock)
return -1
print(" 类型: %s, IP: %s, 端口: %d" % (param.type, param.TCP.IP, param.TCP.port))
# 1.2 打开 Modbus 主站
ret = modbus_open_master(sock, 0)
print_result("modbus_open_master (id=0)", ret)
if ret != SUCCESS:
disconnect_robot(sock)
return -1
time.sleep(0.5)
# 1.3 功能码 05H: 写单线圈
print_separator("TCP --- 05H 写单线圈")
ret = modbus_write_signal_coil_status(sock, 0, 0, 0xFF00)
print_result("modbus_write_signal_coil_status (addr=0, ON)", ret)
time.sleep(0.2)
# 1.4 功能码 01H: 读线圈状态(验证 05H 写入)
print_separator("TCP --- 01H 读线圈状态")
read_data = VectorInt()
ret = modbus_read_coil_status(sock, 0, 0, 1, read_data)
print_result("modbus_read_coil_status (addr=0, qty=1)", ret)
if ret == SUCCESS and len(read_data) > 0:
print(" 线圈[0] = %d" % read_data[0])
# 1.5 功能码 02H: 读输入状态
print_separator("TCP --- 02H 读输入状态")
read_data = VectorInt()
ret = modbus_read_input_status(sock, 0, 0, 4, read_data)
print_result("modbus_read_input_status (addr=0, qty=4)", ret)
if ret == SUCCESS:
print(" 输入状态: ", end="")
for i in range(len(read_data)):
print("%d" % read_data[i], end=" ")
print()
# 1.6 功能码 06H: 写单寄存器
print_separator("TCP --- 06H 写单寄存器")
ret = modbus_write_signal_holding_registers(sock, 0, 0, 5678)
print_result("modbus_write_signal_holding_registers (addr=0, val=5678)", ret)
# 1.7 功能码 03H: 读保持寄存器(验证 06H 写入)
print_separator("TCP --- 03H 读保持寄存器")
read_data = VectorInt()
ret = modbus_read_holding_registers(sock, 0, 0, 3, read_data)
print_result("modbus_read_holding_registers (addr=0, qty=3)", ret)
if ret == SUCCESS:
print(" 保持寄存器[0\~2]: ", end="")
for i in range(len(read_data)):
print("%d" % read_data[i], end=" ")
print()
if len(read_data) > 0 and read_data[0] == 5678:
print(" [验证] 06H 写入与 03H 读取一致")
# 1.8 功能码 04H: 读输入寄存器
print_separator("TCP --- 04H 读输入寄存器")
read_data = VectorInt()
ret = modbus_read_input_registers(sock, 0, 0, 3, read_data)
print_result("modbus_read_input_registers (addr=0, qty=3)", ret)
if ret == SUCCESS:
print(" 输入寄存器: ", end="")
for i in range(len(read_data)):
print("%d" % read_data[i], end=" ")
print()
# 1.9 功能码 10H: 写多个保持寄存器
print_separator("TCP --- 10H 写多个保持寄存器")
write_data = [100, 200, 300]
ret = modbus_write_multiple_holding_registers(sock, 0, 10, write_data)
print_result("modbus_write_multiple_holding_registers (addr=10)", ret)
if ret == SUCCESS:
print(" 写入数据: %d, %d, %d" % (write_data[0], write_data[1], write_data[2]))
# 1.10 03H 回读验证批量写入
read_data = VectorInt()
ret = modbus_read_holding_registers(sock, 0, 10, 3, read_data)
print_result("modbus_read_holding_registers (addr=10, qty=3) 回读验证", ret)
if ret == SUCCESS and len(read_data) >= 3:
match = (read_data[0] == 100 and read_data[1] == 200 and read_data[2] == 300)
print(" 批量读写一致性验证: %s" % ("通过" if match else "失败"))
# ===========================================================
# 第二部分:Modbus RTU 模式(master ID = 1)
# 灵巧手控制示例
# ===========================================================
print_separator("第二部分:Modbus RTU 模式(灵巧手控制)")
# 2.1 设置 RTU 主站参数
param_rtu = ModbusMasterParameter()
param_rtu.type = "RTU"
param_rtu.startAddress = True
param_rtu.RTU.slaveId = 2 # 灵巧手从站 ID
param_rtu.RTU.port = 1 # 控制器串口号(根据接线修改)
param_rtu.RTU.baudrate = 115200 # 波特率
param_rtu.RTU.checkBit = "None"
param_rtu.RTU.dataBit = 8
param_rtu.RTU.stopBit = 1
ret = modbus_set_master_parameter(sock, 1, param_rtu)
print_result("modbus_set_master_parameter (id=1, RTU slaveId=2)", ret)
if ret != SUCCESS:
disconnect_robot(sock)
return -1
print(" 从站ID: %d(灵巧手)" % param_rtu.RTU.slaveId)
# 2.2 打开 Modbus 主站
ret = modbus_open_master(sock, 1)
print_result("modbus_open_master (id=1)", ret)
if ret != SUCCESS:
disconnect_robot(sock)
return -1
time.sleep(0.5)
# 2.3 03H 读灵巧手寄存器(目标位置 + 实际位置)
print_separator("RTU --- 03H 读保持寄存器")
ret_tgt, tgt_data = read_with_retry(sock, 1, REG_POS_TARGET, 6, "读目标位置 1135\~1140")
if ret_tgt == SUCCESS:
print(" 目标位置: ", end="")
for i in range(len(tgt_data)):
print("%d" % tgt_data[i], end=" ")
print()
ret_fb, fb_data = read_with_retry(sock, 1, REG_POS_FEEDBACK, 6, "读实际位置 1155\~1160")
if ret_fb == SUCCESS:
print(" 实际位置: ", end="")
for i in range(len(fb_data)):
print("%d" % fb_data[i], end=" ")
print()
# 2.4 06H 设置手指力阈值
print_separator("RTU --- 06H 写单寄存器(力阈值)")
ret = modbus_write_signal_holding_registers(sock, 1, REG_FORCE_LIMIT, 500)
print_result("写力阈值 (addr=%d, val=500)" % REG_FORCE_LIMIT, ret)
time.sleep(0.2)
# 2.5 06H 设置手指速度
print_separator("RTU --- 06H 写单寄存器(速度)")
ret = modbus_write_signal_holding_registers(sock, 1, REG_SPEED, 200)
print_result("写速度 (addr=%d, val=200)" % REG_SPEED, ret)
time.sleep(0.2)
# 2.6 05H 写单线圈(测试)
print_separator("RTU --- 05H 写单线圈")
ret = modbus_write_signal_coil_status(sock, 1, 0, 0xFF00)
print_result("modbus_write_signal_coil_status (addr=0, ON)", ret)
time.sleep(0.2)
# 2.7 01H 读线圈状态(验证)
print_separator("RTU --- 01H 读线圈状态")
coil_data = VectorInt()
for at in range(3):
ret = modbus_read_coil_status(sock, 1, 0, 1, coil_data)
if ret == SUCCESS:
break
time.sleep(0.5)
print_result("modbus_read_coil_status (addr=0, qty=1)", ret)
if ret == SUCCESS and len(coil_data) > 0:
print(" 线圈[0] = %d" % coil_data[0])
# 2.8 02H 读输入状态
print_separator("RTU --- 02H 读输入状态")
in_status = VectorInt()
for at in range(3):
ret = modbus_read_input_status(sock, 1, 0, 4, in_status)
if ret == SUCCESS:
break
time.sleep(0.5)
print_result("modbus_read_input_status (addr=0, qty=4)", ret)
if ret == SUCCESS:
print(" 输入状态: ", end="")
for i in range(len(in_status)):
print("%d" % in_status[i], end=" ")
print()
# 2.9 04H 读输入寄存器
print_separator("RTU --- 04H 读输入寄存器")
in_reg = VectorInt()
for at in range(3):
ret = modbus_read_input_registers(sock, 1, 0, 3, in_reg)
if ret == SUCCESS:
break
time.sleep(0.5)
print_result("modbus_read_input_registers (addr=0, qty=3)", ret)
if ret == SUCCESS:
print(" 输入寄存器: ", end="")
for i in range(len(in_reg)):
print("%d" % in_reg[i], end=" ")
print()
# 2.10 06H 设置手指目标位置(张开:所有手指 0)
print_separator("RTU --- 06H 设置目标位置(张开)")
# 手势"张开"位置 [0, 0, 0, 0, 0, 728]
pos = [0, 0, 0, 0, 0, 728]
for i in range(6):
ret = modbus_write_signal_holding_registers(sock, 1, REG_POS_TARGET + i, pos[i])
if ret != SUCCESS:
print(" [失败] 写位置[%d] 错误码: %d" % (i, ret))
time.sleep(0.05)
print(" [成功] 手指已张开(位置全0,拇指728)")
# ===========================================================
# 第三部分:六维力传感器通讯参数
# ===========================================================
print_separator("第三部分:六维力传感器通讯参数")
force_param = SixDimensionalForceCommunicationParams()
force_param.sensorCommunicationType = 0 # 0: EtherCAT
force_param.startupAutoConnectSensor = True # 启动自动连接传感器
force_param.sensorDragEnable = True # 传感器拖拽使能
force_param.etherCat_mapNum = 1
force_param.YDirection = -1
force_param.ZDirection = -1
ret = set_six_dimensional_force_communication_params(sock, force_param)
print_result("set_six_dimensional_force_communication_params", ret)
if ret == SUCCESS:
print(" 传感器通信类型: EtherCAT")
print(" 拖拽使能: %s" % ("开启" if force_param.sensorDragEnable else "关闭"))
# ===========================================================
# 断开连接
# ===========================================================
print_separator("断开连接")
disconnect_robot(sock)
print("[信息] 已断开连接")
print("\n[信息] Modbus 综合示例程序运行完毕")
return 0
if __name__ == "__main__":
main()
