- 选型指南
- 概述
- 入门指南
- 机械臂参数
- 示教器使用
-
二次开发
-
API(C++)
- 快速开始
- 接口说明
- 7000端口接口说明
- 使用示例
- 返回值说明
-
API(Python)
- 快速开始
- 接口说明
- 7000端口接口说明
- 使用示例
- 返回值说明
- ROS2开发
-
API(C++)
- 相关下载
Windows(x64)架构使用示例
1. Modbus Rtu 使用示例
Python
import nrc_interface as nrc
import time
def set_modbus_master_parameter(self, master_id: int, param) -> int:
"""
配置 Modbus 主站参数 (包含 RTU 串口/TCP 配置)
:param master_id: 主站 ID,取值范围 [0, 8]
:param param: 实例化的 nrc.ModbusMasterParameter 对象
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-1 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与失败返回值 -1
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 配置 Modbus 参数失败,未建立有效网络连接 (socket_fd 无效)。")
return -1
try:
# 调用底层核心接口
ret = nrc.modbus_set_master_parameter(self.socket_fd, master_id, param)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print(f"成功: Modbus 主站 [ID: {master_id}] 参数配置已成功下发。")
else:
print(f"错误: 配置 Modbus 主站参数失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 配置 Modbus 主站参数发生未知异常: {e}")
return -1
def open_modbus_master(self, master_id: int) -> int:
"""
打开指定的 Modbus 主站
:param master_id: 主站 ID,取值范围 [0, 8]
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-1 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与失败返回值 -1
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 打开 Modbus 主站失败,未建立有效网络连接 (socket_fd 无效)。")
return -1
try:
# 调用底层核心接口
ret = nrc.modbus_open_master(self.socket_fd, master_id)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print(f"成功: Modbus 主站 [ID: {master_id}] 已成功打开。")
else:
print(f"错误: 打开 Modbus 主站失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 打开 Modbus 主站发生未知异常: {e}")
return -1
def read_modbus_registers(self, master_id: int, address: int, quantity: int) -> list:
"""
批量读取多个 Modbus 保持寄存器
:param master_id: 主站 ID,取值范围 [0, 8]
:param address: 读取的目标寄存器起始地址
:param quantity: 需要连续读取的寄存器数量
:return: 成功返回读取到的整型数据列表,失败或断连返回空列表 []
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与失败返回值 []
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 批量读取 Modbus 寄存器失败,未建立有效网络连接 (socket_fd 无效)。")
return []
try:
# 实例化底层所需的 VectorInt 接收容器,并根据读取数量预分配缓冲空间
read_back = nrc.VectorInt()
for _ in range(quantity):
read_back.push_back(0)
# 调用底层核心接口
ret = nrc.modbus_read_holding_registers(self.socket_fd, master_id, address, quantity, read_back)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
res_list = list(read_back)
print(f"成功: Modbus 主站 [ID: {master_id}] 批量读取寄存器成功 -> 起始地址: {address}, 数量: {quantity}, 数据: {res_list}")
return res_list
else:
print(f"错误: 批量读取 Modbus 寄存器失败,起始地址: {address},底层错误码: {ret}")
return []
except Exception as e:
print(f"异常: 批量读取 Modbus 寄存器发生未知异常: {e}")
return []
def write_modbus_registers(self, master_id: int, address: int, data_list: list) -> int:
"""
批量写入多个 Modbus 保持寄存器
:param master_id: 主站 ID,取值范围 [0, 8]
:param address: 写入的目标寄存器起始地址
:param data_list: 待写入的 16 位整型数据列表
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-1 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与失败返回值 -1
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 批量写入 Modbus 寄存器失败,未建立有效网络连接 (socket_fd 无效)。")
return -1
try:
# 转换数据类型为底层所需的 VectorInt 类型
arm_data = nrc.VectorInt()
for val in data_list:
arm_data.push_back(int(val))
# 调用底层核心接口
ret = nrc.modbus_write_multiple_holding_registers(self.socket_fd, master_id, address, arm_data)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print(f"成功: Modbus 主站 [ID: {master_id}] 批量写入寄存器成功 -> 起始地址: {address}, 数据: {data_list}")
else:
print(f"错误: 批量写入 Modbus 寄存器失败,起始地址: {address},底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 批量写入 Modbus 寄存器发生未知异常: {e}")
return -1
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
# 【步骤 1】配置工具手的物理通信参数 (RTU 模式、串口 2、波特率 115200)
arm_param = nrc.ModbusMasterParameter()
arm_param.type = "RTU"
arm_param.startAddress = True
arm_param.RTU.slaveId = 2 # 工具手出厂默认站号 (根据实际说明书修改)
arm_param.RTU.port = 2 # 纳博特控制器物理串口 2
arm_param.RTU.baudrate = 115200
arm_param.RTU.checkBit = "None"
arm_param.RTU.dataBit = 8
arm_param.RTU.stopBit = 1
arm_master_id = 0
# 下发参数配置到内存
ret_config = nrc.modbus_set_master_parameter(arm_test.socket_fd, arm_master_id, arm_param)
if ret_config == 0:
# 【步骤 2】通电并打开 Modbus 主站通道
ret_open = arm_test.open_modbus_master(master_id=arm_master_id)
if ret_open == 0:
time.sleep(1) # 延时 1 秒,等待工具手协议栈握手稳定
# 【步骤 3】向 1135 地址写入控制指令 (例如: 驱使工具手闭合/张开)
arm_write_address = 1135
arm_control_data = [0, 0, 40000, 40000, 0] # 动作目标参数
ret_write = arm_test.write_modbus_registers(master_id=arm_master_id, address=arm_write_address, data_list=arm_control_data)
if ret_write == 0:
time.sleep(1) # 延时 1 秒,留出工具手物理动作执行时间
# 【步骤 4】从 1155 地址读取寄存器,验证工具手是否抓取成功或获取当前位置
arm_read_address = 1155
arm_quantity = 5
arm_test.read_modbus_registers(master_id=arm_master_id, address=arm_read_address, quantity=arm_quantity)
2. 关节实时跟踪 servoJ 使用示例
Python
import nrc_interface as nrc
import time
def open_servo_joint(self, max_v: float, max_a: float, max_j: float) -> int:
"""
打开标准关节跟踪模式 (精简中文输出版)
:param max_v: 所有关节统一的最大速度约束 (°/s)
:param max_a: 所有关节统一的最大加速度约束 (°/s²)
:param max_j: 所有关节统一的最大加加速度约束 (°/s³)
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与原代码返回值 -2
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 打开关节跟踪模式失败,未建立有效网络连接 (socket_fd 无效)。")
return -2
try:
# 1. 实例化 C++ 向量容器,用以承载多轴独立的动力学约束
vmax_vec = nrc.VectorDouble()
amax_vec = nrc.VectorDouble()
jmax_vec = nrc.VectorDouble()
# 2. 根据机械臂自由度 (dof) 动态填充各个关节的限制边界
for _ in range(self.dof):
vmax_vec.push_back(float(max_v))
amax_vec.push_back(float(max_a))
jmax_vec.push_back(float(max_j))
# 3. 调用底层核心控制原语,开启 ServoJ 通道
ret = nrc.open_servoJ(self.socket_fd, vmax_vec, amax_vec, jmax_vec)
# 【统一日志】工业级标准化前缀输出,扁平化分支
if ret == 0:
print("成功: 标准关节跟踪模式 (ServoJ) 已成功打开,系统进入高频流式监听状态。")
else:
print(f"错误: 打开标准关节跟踪模式失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 打开标准关节跟踪模式发生未知异常: {e}")
return -1
def close_servo_joint(self) -> int:
"""
在 7000 端口关闭标准关节跟踪模式
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐特定高频实时通道 (robotarm7000) 拦截流标准与原代码返回值 -2
if not self.robotarm7000 or self.robotarm7000 <= 0:
print("错误: 关闭关节跟踪模式失败,7000 端口未建立有效连接。")
return -2
try:
# 调用底层核心原语,显式传入 7000 端口句柄,注销 ServoJ 监听
ret = nrc.close_servoJ(self.robotarm7000)
# 【统一日志】工业级标准化前缀输出,扁平化分支
if ret == 0:
print("成功: 7000 端口标准关节跟踪模式已安全关闭,系统已恢复为常规轨迹就绪态。")
else:
print(f"错误: 关闭标准关节跟踪模式失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 关闭标准关节跟踪模式发生未知异常: {e}")
return -1
def set_servo_joint_position(self, joint_angles: list) -> int:
"""
在 7000 端口发送实时跟踪关节位置
:param joint_angles: 目标关节角度列表 (单位: °)
:return: 底层接口返回值 (0代表成功, 非0代表失败)
"""
if not self.robotarm7000 or self.robotarm7000 <= 0:
print("错误: 发送实时关节位置失败,7000 端口未建立有效连接。")
return -2
try:
# 1. 转换数据类型为底层所需的 VectorDouble
q_vec = nrc.VectorDouble()
for angle in joint_angles:
q_vec.push_back(float(angle))
# 2. 严谨处理特殊轴数补齐:如果是6轴机械臂且长度不足7,按照文档规范补0
if self.dof == 6 and len(joint_angles) == 6:
q_vec.push_back(0.0)
# 3. 核心传参:严格限定传入 7000 端口句柄 self.robotarm7000
ret = nrc.set_servoJ_pos(self.robotarm7000, q_vec)
if ret != 0:
print(f"错误: 发送实时关节位置失败。错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 发送实时关节位置发生异常: {e}")
return -1
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
# 步骤一:在 7000 端口打开跟踪模式
# 官方的约束很大(300°/s),代表不限制轴速,完全听从点位的移动增量
arm_test.open_servo_joint(max_v=300.0, max_a=3000.0, max_j=50000.0)
time.sleep(0.2)
# 步骤二:模拟官方的 while 递增发点逻辑,初始化
q = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
print("提示: 正在高频发送实时点位 (1轴 0° -> 60°)...")
try:
while q[0] < 60.0:
q[0] += 0.1 # 每次递增 1 度
# 核心发点(函数内部已封装:自动用 7000 端口,且自动把 6 轴补齐为 7 轴)
arm_test.set_servo_joint_position(q)
time.sleep(0.01) # 维持官方的 10ms (100Hz) 发送频率
except Exception as e:
print(f"警告: 发点循环中途发生异常: {e}")
# 保持 5 秒(对齐官方示例)
time.sleep(5.0)
# 步骤三:安全关闭关节跟踪模式(严格锁定 7000 端口)
arm_test.close_servo_joint()
print("=== 跟踪测试结束 ===")
3. 关节运动到目标点 robot_movej 使用示例
Python
import nrc_interface as nrc
import time
def move_joint(self, target_angles: list, velocity: int = 20, acc: int = 50, dec: int = 50, pl: int = 0) -> bool:
"""
实时运动控制:让机械臂立刻以关节运动(MoveJ)奔向目标角度!
:param target_angles: 目标关节角度列表,如 [10.0, 0.0, 0.0, 0.0, 0.0, 0.0]
:param velocity: 实时运动速度 (1 ~ 100)
:param pl: 实时到达平滑度
:return: 成功返回 True,失败返回 False
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与日志
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 机械臂未连接 (socket_fd 无效)。")
return False
try:
move_cmd = nrc.MoveCmd()
# 按照官方示例潜规则:实时指令通常固定开辟 7 个空间
# 前 6 位为本体轴,第 7 位为外部轴(没有外部轴则填 0)
cmd_len = 7
move_cmd.targetPosValue.resize(cmd_len)
# 逐个安全赋值,防止数组越界,不足 7 位的后面自动补 0.0
for i in range(cmd_len):
if i < len(target_angles):
move_cmd.targetPosValue[i] = target_angles[i]
else:
move_cmd.targetPosValue[i] = 0.0
# 设置实时运动必填参数
move_cmd.coord = 0 # 0: 关节空间模式
move_cmd.velocity = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = pl # 实时到达平滑度
# 核心底层知识:因为是直接发送裸数据给电机,不需要在示教器建表
# 所以这里不需要像之前那样设置 targetPosType=1 和 targetPosName
print("成功: 正在下发实时单步动作...")
# 调用官方实时关节运动接口
ret = nrc.robot_movej(self.socket_fd, move_cmd)
# 【统一日志】对齐 "成功/错误" 的工业级日志前缀
if ret == 0:
print(f"成功: 机械臂正奔向 -> {target_angles}")
return True
else:
print(f"错误: 实时运动指令下发失败,底层错误码: {ret} (提示: 请检查机械臂是否已正常上电)")
return False
except Exception as e:
print(f"异常: 实时运动异常: {e}")
return False
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
safe_target = [20.0, 10.0, 0.0, 0.0, 0.0, 0.0]
arm_test.move_joint(target_angles=safe_target)
4. 直线运动到目标位置 robot_movel 使用示例
Python
import nrc_interface as nrc
import time
def move_linear(self, target_coords: list, velocity: int = 20, acc: int = 50, dec: int = 50, pl: int = 0) -> bool:
"""
实时直线运动控制:让机械臂末端立刻沿直线奔向目标直角坐标!
:param target_coords: 目标直角坐标列表,如 [320.5, -45.0, 180.0, 3.14, 0.0, 0.0]
:param velocity: 实时运动速度百分比 (1 ~ 100)
:param pl: 轨迹平滑度等级 (0 代表精准到位)
:return: 成功返回 True, 失败返回 False
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 机械臂未连接 (socket_fd 无效)。")
return False
try:
move_cmd = nrc.MoveCmd()
# 遵照官方实时指令潜规则:固定开辟 7 个空间
# 前 6 位为直角坐标 [X, Y, Z, A, B, C],第 7 位为外部轴(填 0.0)
cmd_len = 7
move_cmd.targetPosValue.resize(cmd_len)
# 逐个安全赋值
for i in range(cmd_len):
if i < len(target_coords):
move_cmd.targetPosValue[i] = target_coords[i]
else:
move_cmd.targetPosValue[i] = 0.0
# 设置实时直线运动参数
move_cmd.coord = 0 # 0: 官方示例指定的基坐标系
move_cmd.velocity = velocity
move_cmd.velocitySync = velocity # 双保险控速参数
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = pl
print(f"成功: 正在下发实时直线动作,目标坐标: {target_coords[:6]}...")
# 调用官方实时直线运动接口
ret = nrc.robot_movel(self.socket_fd, move_cmd)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print("成功: 实时直线运动指令发送成功!")
return True
else:
print(f"错误: 实时直线运动下发失败,底层错误码: {ret}")
return False
except Exception as e:
print(f"异常: 实时直线运动异常: {e}")
return False
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
safe_cartesian_target = [220.0, -0.065, 143.139, 3.141, 0.0, 0.0]
arm_test.move_linear(target_coords=safe_cartesian_target)
5. 点动使用示例
Python
import nrc_interface as nrc
import time
def start_robot_jogging(self, axis: int, direction: int) -> bool:
"""
启动机械臂点动连续运动
:param axis: 轴号 (1~7 代表第 1~7 轴)
:param direction: 方向 (1: 正向, 0 或 -1: 反向)
:return: 成功返回True, 失败返回False
"""
try:
# 方向转换:1→正向(True),其他→反向(False)
is_positive = direction == 1
# 调用底层SDK接口
ret = nrc.robot_start_jogging(self.socket_fd, axis, is_positive)
if ret != 0:
raise RuntimeError(f"SDK接口返回错误码 {ret}")
print(f"成功:启动{axis}轴点动运动,方向:{'正向' if is_positive else '反向'}")
return True
except Exception as e:
print(f"错误:启动点动连续运动失败,原因:{e}")
return False
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
# 测试启动点动连续运动(速度控制每次转的角度)
for _ in range(75):
arm_test.start_robot_jogging(axis=4, direction=0)
time.sleep(0.04)
6. 作业文件插入指令使用示例
Python
import nrc_interface as nrc
import time
def open_job(self, job_name: str) -> bool:
"""
打开指定的作业文件 (相当于在示教器上选中并打开某个程序)
:param job_name: 作业文件的名称 (比如 "TEST" 或 "TEST.JOB")
:return: 成功返回 True, 失败返回 False
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与日志
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 机械臂未连接 (socket_fd 无效)。")
return False
try:
# 调用底层接口,告诉控制器我们要操作哪个文件
ret = nrc.job_open(self.socket_fd, job_name)
# 【统一日志】对齐 "成功/错误" 的工业级日志前缀
if ret == 0:
print(f"成功: 打开作业文件成功 -> {job_name}")
return True
else:
print(f"错误: 打开作业文件失败,底层错误码: {ret}")
return False
except Exception as e:
print(f"异常: 打开作业文件异常: {e}")
return False
def insert_job_moveJ(self, line: int = 1, target_angles: list = None, velocity: int = 5, acc: int = 20, dec: int = 20, pos_name: str = "P0001") -> bool:
"""
在作业文件指定行插入 MoveJ (关节运动) 指令 - 官方指定 P 变量模式
:param line: 插入的行号
:param target_angles: 目标关节角度列表
:param velocity: 运行速度
:param acc: 加速度
:param dec: 减速度
:param pos_name: 点位变量名,例如 "P0001"
:return: 成功返回 True,失败返回 False
"""
if not self.socket_fd or self.socket_fd <= 0:
print("未连接,无法插入指令")
return False
if target_angles is None:
target_angles = [0.0] * self.dof
try:
move_cmd = nrc.MoveCmd()
# 1. 官方指定的数组赋值方式
pos = nrc.VectorDouble(self.dof)
for i in range(min(self.dof, len(target_angles))):
pos[i] = target_angles[i]
move_cmd.targetPosValue = pos
# 2. 官方核心潜规则:使用点位变量 (P变量)
move_cmd.targetPosType = 1 # 1 代表使用变量名
move_cmd.targetPosName = pos_name # 给这个点位起个名字,比如 "P0001"
move_cmd.coord = 0 # 0 代表关节坐标系
# 3. 速度与平滑度设置
move_cmd.velocity = velocity
move_cmd.velocitySync = velocity # 官方同步速度
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0 # 精准到达先用 0
# 4. 下发指令
ret = nrc.job_insert_moveJ(self.socket_fd, line, move_cmd)
if ret == 0:
print(f"成功在第 {line} 行插入 MoveJ 指令!绑定点位: {pos_name}, 角度: {target_angles[:self.dof]}")
return True
else:
print(f"插入 MoveJ 指令失败,错误码: {ret}")
return False
except Exception as e:
print(f"插入 MoveJ 指令异常: {e}")
return False
def insert_job_moveL(self, line: int = 1, target_coords: list = None, velocity: int = 20, acc: int = 20, dec: int = 20, pos_name: str = "P0001") -> bool:
"""
在作业文件指定行插入 MoveL (笛卡尔空间直线运动) 指令 - 官方 P 变量版
:param pos_name: 点位变量名,例如 "P0002"
"""
if target_coords is None:
target_coords = [0.0] * 6
if self.socket_fd and self.socket_fd > 0:
try:
move_cmd = nrc.MoveCmd()
# 1. 官方指定的数组赋值方式
coord_len = len(target_coords)
pos = nrc.VectorDouble(coord_len)
for i in range(coord_len):
pos[i] = target_coords[i]
move_cmd.targetPosValue = pos
# 2. 官方核心潜规则
move_cmd.targetPosType = 1 # 使用点位变量
move_cmd.targetPosName = pos_name # 分配变量名
move_cmd.coord = 1 # 【关键】1 代表直角坐标系(笛卡尔)
# 3. 运动参数
move_cmd.velocity = velocity
move_cmd.velocitySync = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0
# 4. 下发指令
ret = nrc.job_insert_moveL(self.socket_fd, line, move_cmd)
if ret == 0:
print(f"✅ 成功在第 {line} 行插入 MoveL 指令!绑定点位: {pos_name}, 坐标: {target_coords}")
return True
else:
print(f"❌ 插入 MoveL 指令失败,错误码: {ret}")
return False
except Exception as e:
print(f"❌ 插入 MoveL 指令异常: {e}")
return False
print("未连接,无法插入指令")
return False
def insert_job_moveC(self, line: int = 1, target_coords: list = None, velocity: int = 20, acc: int = 20, dec: int = 20, pos_name: str = "P0003") -> bool:
"""
在作业文件指定行插入 MoveC (笛卡尔空间圆弧运动) 指令 - 官方 P 变量版
:param line: 插入的行号
:param target_coords: 目标直角坐标列表
:param velocity: 运行速度
:param acc: 加速度
:param dec: 减速度
:param pos_name: 点位变量名,圆弧建议传入 "P0003" (中间点) 或 "P0004" (终点)
:return: 成功返回 True,失败返回 False
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与日志
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 机械臂未连接 (socket_fd 无效)。")
return False
if target_coords is None:
target_coords = [0.0] * 6
try:
move_cmd = nrc.MoveCmd()
# 1. 官方指定的数组赋值方式
coord_len = len(target_coords)
pos = nrc.VectorDouble(coord_len)
for i in range(coord_len):
pos[i] = target_coords[i]
move_cmd.targetPosValue = pos
# 2. 官方核心潜规则
move_cmd.targetPosType = 1 # 使用点位变量
move_cmd.targetPosName = pos_name # 分配变量名
move_cmd.coord = 1 # 1 代表直角/笛卡尔坐标系
# 3. 运动参数
move_cmd.velocity = velocity
move_cmd.velocitySync = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0 # 圆弧通常要求精准过点,设为 0
# 4. 下发指令
ret = nrc.job_insert_moveC(self.socket_fd, line, move_cmd)
# 【统一日志】对齐 "成功/错误" 的工业级日志前缀
if ret == 0:
print(f"成功: 在第 {line} 行插入 MoveC 指令!绑定点位: {pos_name}, 坐标: {target_coords}")
return True
else:
print(f"错误: 插入 MoveC 指令失败,底层错误码: {ret}")
return False
except Exception as e:
print(f"异常: 插入 MoveC 指令异常: {e}")
return False
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
target_open_name = "TEST2"
arm_test.open_job(job_name=target_open_name)
# 测试在作业文件中插入 MoveJ 运动指令,在第 1 行插入一个指令
my_target_angles = [10.0, 10.0, 0.0, 0.0, 0.0, 0.0]
arm_test.insert_job_moveJ(line=1, target_angles=my_target_angles, velocity=10)
# 测试在作业文件中插入 MoveL 直线运动指令,[X, Y, Z, A, B, C],单位通常是 mm 和 rad(弧度)
my_coords = [320.5, -45.0, 0.0, 0, 3.14, 0.0]
arm_test.insert_job_moveL(line=1, target_coords=my_coords, velocity=20)
# 测试在作业文件中插入 MoveC 圆弧运动指令,作为圆弧的途经点或终点
arc_target_coords = [350.0, 0.0, 200.0, 3.14, 0.0, 0.0]
arm_test.insert_job_moveC(line=2, target_coords=arc_target_coords, velocity=20)
7. 队列运动指令使用示例
Python
import nrc_interface as nrc
import time
def set_queue_motion_status(self, status: bool) -> int:
"""
设置队列运动模式状态
:param status: True 为打开队列运动, False 为关闭队列运动
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-1 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与失败返回值 -1
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 机械臂未连接 (socket_fd 无效)。")
return -1
try:
# 调用标准底层接口
ret = nrc.queue_motion_set_status(self.socket_fd, status)
status_name = "打开" if status else "关闭"
# 【统一日志】工业级标准化前缀输出,扁平化分支逻辑
if ret == 0:
print(f"成功: 队列运动模式 [{status_name}] 执行完毕。")
else:
print(f"错误: 队列运动模式 [{status_name}] 失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 设置队列运动模式状态发生未知异常: {e}")
return -1
def execute_queue(self, size: int, is_continue: bool = False) -> int:
"""
将本地队列数据发送到控制器并执行
:param size: 要发送的队列大小, 0 代表发送全部指令,有效范围 [0, 31]
:param is_continue: 是否继续执行未完成的队列,默认为 False
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与原代码返回值 -2
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 激活队列执行失败,未建立有效网络连接 (socket_fd 无效)。")
return -2
try:
# 调用底层标准接口
ret = nrc.queue_motion_send_to_controller(self.socket_fd, size, is_continue)
# 【统一日志】工业级标准化前缀输出,扁平化逻辑分支
if ret == 0:
target_desc = "全部" if size == 0 else f"前 {size} 个"
print(f"成功: 已将 {target_desc} 队列数据发送至控制器并开始执行。")
else:
print(f"错误: 队列下发失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 激活队列执行发生未知异常: {e}")
return -1
def queue_moveJ(self, pos_list: list, velocity: int = 30, acc: int = 20, dec: int = 20, coord: int = 0) -> int:
"""
向本地运动队列尾部插入一条 MoveJ 指令
:param pos_list: 目标位置列表 (关节系为各轴度数,直角系为 X/Y/Z/RX/RY/RZ)
:param coord: 坐标系类型 (0: 关节坐标系, 1: 直角坐标系),默认 0
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与原代码返回值 -2
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 压入队列 MoveJ 指令失败,未建立有效网络连接 (socket_fd 无效)。")
return -2
try:
# 1. 将 Python 列表转换为底层所需的 VectorDouble 类型
pos = nrc.VectorDouble(len(pos_list))
for i, val in enumerate(pos_list):
pos[i] = float(val)
# 2. 实例化并配置底层的运动命令结构体
move_cmd = nrc.MoveCmd()
move_cmd.coord = coord
move_cmd.targetPosType = nrc.PosType_data # 固定为数据点位模式
move_cmd.targetPosValue = pos
move_cmd.velocity = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0 # 队列平滑过渡等级 (通常由队列机制自动融合)
# 3. 调用底层接口压入本地队列尾部
ret = nrc.queue_motion_push_back_moveJ(self.socket_fd, move_cmd)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print(f"成功: MoveJ 轨迹点已成功压入本地运动队列尾部 -> 目标点: {pos_list}")
else:
print(f"错误: 压入队列 MoveJ 指令失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 压入队列 MoveJ 发生未知异常: {e}")
return -1
def queue_moveL(self, pos_list: list, velocity: int = 10, acc: int = 20, dec: int = 20, coord: int = 1) -> int:
"""
向本地运动队列尾部插入一条 MoveL 直线指令
:param pos_list: 目标直角坐标列表 [X, Y, Z, RX, RY, RZ]
:param coord: 坐标系类型 (直线运动通常默认为 1: 基座直角坐标系)
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与原代码返回值 -2
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 压入队列 MoveL 指令失败,未建立有效网络连接 (socket_fd 无效)。")
return -2
try:
# 1. 将 Python 列表转换为底层所需的 VectorDouble 类型
pos = nrc.VectorDouble(len(pos_list))
for i, val in enumerate(pos_list):
pos[i] = float(val)
# 2. 实例化并配置底层的运动命令结构体
move_cmd = nrc.MoveCmd()
move_cmd.coord = coord
move_cmd.targetPosType = nrc.PosType_data # 固定为数据点位模式
move_cmd.targetPosValue = pos
move_cmd.velocity = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0 # 队列平滑过渡等级 (通常由队列机制自动融合)
# 3. 调用底层 MoveL 接口压入本地队列尾部
ret = nrc.queue_motion_push_back_moveL(self.socket_fd, move_cmd)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print(f"成功: MoveL 直线轨迹点已成功压入本地运动队列尾部 -> 目标点: {pos_list}")
else:
print(f"错误: 压入队列 MoveL 指令失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 压入队列 MoveL 发生未知异常: {e}")
return -1
def queue_moveC(self, pos_list: list, velocity: int = 10, acc: int = 20, dec: int = 20, coord: int = 1) -> int:
"""
向本地运动队列尾部插入一条 MoveC 三点圆弧指令
:param pos_list: 包含中间点和终点的 12 维直角坐标列表 [中间点 X/Y/Z/RX/RY/RZ, 终点 X/Y/Z/RX/RY/RZ]
:param coord: 坐标系类型 (圆弧运动通常默认为 1: 基座直角坐标系)
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与原代码返回值 -2
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 压入队列 MoveC 指令失败,未建立有效网络连接 (socket_fd 无效)。")
return -2
try:
# 1. 将 12 维 Python 列表转换为底层所需的 VectorDouble 类型
pos = nrc.VectorDouble(len(pos_list))
for i, val in enumerate(pos_list):
pos[i] = float(val)
# 2. 实例化并配置底层的运动命令结构体
move_cmd = nrc.MoveCmd()
move_cmd.coord = coord
move_cmd.targetPosType = nrc.PosType_data # 固定为数据点位模式
move_cmd.targetPosValue = pos
move_cmd.velocity = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0 # 队列平滑过渡等级 (通常由队列机制自动融合)
# 3. 调用底层 MoveC 接口压入本地队列尾部
ret = nrc.queue_motion_push_back_moveC(self.socket_fd, move_cmd)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print("成功: MoveC 圆弧轨迹点已成功压入本地运动队列尾部 -> 包含 12 维中间点与终点数据。")
else:
print(f"错误: 压入队列 MoveC 指令失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 压入队列 MoveC 发生未知异常: {e}")
return -1
def queue_moveS(self, pos_list: list, velocity: int = 10, acc: int = 20, dec: int = 20, coord: int = 1) -> int:
"""
向本地运动队列尾部插入一条 MoveS 样条曲线指令
:param pos_list: 目标直角坐标列表 [X, Y, Z, RX, RY, RZ]
:param coord: 坐标系类型 (曲线运动通常默认为 1: 基座直角坐标系)
:return: 底层接口返回值 (0 代表成功,非 0 代表失败错误码,-2 代表断连异常)
"""
# 【统一拦截】严格对齐常规指令通道 (socket_fd) 拦截流标准与原代码返回值 -2
if not self.socket_fd or self.socket_fd <= 0:
print("错误: 压入队列 MoveS 指令失败,未建立有效网络连接 (socket_fd 无效)。")
return -2
try:
# 1. 将 Python 列表转换为底层所需的 VectorDouble 类型
pos = nrc.VectorDouble(len(pos_list))
for i, val in enumerate(pos_list):
pos[i] = float(val)
# 2. 实例化并配置底层的运动命令结构体
move_cmd = nrc.MoveCmd()
move_cmd.coord = coord
move_cmd.targetPosType = nrc.PosType_data # 固定为数据点位模式
move_cmd.targetPosValue = pos
move_cmd.velocity = velocity
move_cmd.acc = acc
move_cmd.dec = dec
move_cmd.pl = 0 # 队列平滑过渡等级 (通常由队列机制自动融合)
# 3. 调用底层 MoveS 接口压入本地队列尾部
ret = nrc.queue_motion_push_back_moveS(self.socket_fd, move_cmd)
# 【统一日志】工业级标准化前缀输出
if ret == 0:
print(f"成功: MoveS 样条曲线路点已成功压入本地运动队列尾部 -> 目标点: {pos_list}")
else:
print(f"错误: 压入队列 MoveS 指令失败,底层错误码: {ret}")
return ret
except Exception as e:
print(f"异常: 压入队列 MoveS 发生未知异常: {e}")
return -1
if __name__ == '__main__':
# 1 地址通信
arm_test = RobotArmTest(ip="192.168.1.13", dof=6)
if arm_test._connect_robot() == 0:
# 1. 设置全局运动运行速度(安全低速)
nrc.set_speed(arm_test.socket_fd, 20)
time.sleep(1.0)
# 2. 步骤一:打开队列运动模式
# 此时控制器开始建立 FIFO 缓存,机械臂保持静止
arm_test.set_queue_motion_status(status=True)
time.sleep(2.0)
# 3. 步骤二:向本地队列不间断地"灌入"连续点位数据
# 这里的点位以 6 轴机械臂为例(如果是 7 轴请自行补齐一位),控制 A1 轴进行来回摆动
point_start = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # 起点(初始回零位置)
point_left = [30.0, 0.0, 0.0, 0.0, 0.0, 0.0] # 途经点A(A1轴转动30度)
point_right = [-30.0, 0.0, 0.0, 0.0, 0.0, 0.0] # 途经点B(A1轴转动-30度)
point_movel1 = [197.0, -115.0, 140.0, -3.14, 0.0, 0]
# 依次压入队列尾部,此时仅做数据写入,机械臂依然保持静止
arm_test.queue_moveJ(pos_list=point_start)
arm_test.queue_moveJ(pos_list=point_left)
arm_test.queue_moveJ(pos_list=point_right)
arm_test.queue_moveL(pos_list=point_movel1, velocity=20)
arm_test.queue_moveJ(pos_list=point_start) # 最终回到起点
# 4. 步骤三:批量发送数据并激活执行
# size=0 代表将当前写入缓冲区的 4 个点位指令全部一次性发送
arm_test.execute_queue(size=0, is_continue=False)
# 5. 步骤四:物理运动保持延时
# 队列下发后,Python 脚本会继续向下执行。为了防止脚本立刻关闭连接,
# 必须主观挂起线程,预留充足的时间给机器人硬件跑完这段连续轨迹。
print("提示: 机械臂正在执行连续队列运动")
time.sleep(40.0)
# 6. 步骤五:完成运动后清理并关闭队列模式
# 恢复常规控制模式,确保安全
arm_test.set_queue_motion_status(status=False)
关注天链机器人
公众号
视频号
抖音号
哔哩哔哩
新浪微博
今日头条
小红书
百度
1688店铺
这里是占位文字
