- 选型指南
- 概述
- 入门指南
- 机械臂参数
- 示教器使用
-
二次开发
-
API(C++)
- 快速开始
- 接口说明
- 7000端口接口说明
- 使用示例
- 返回值说明
-
API(Python)
- 快速开始
- 接口说明
- 7000端口接口说明
- 使用示例
- 返回值说明
- ROS2开发
-
API(C++)
- 相关下载
拖拽示教与轨迹记录/回放示例
拖拽示教与轨迹记录/回放示例
Python
#!/usr/bin/env python3
#
# ex_track_queue_drag.py
# @brief 测试 track_record_playback 接口 ------ 轨迹记录与回放
# @attention
# - 确保机械臂供电正常、网络通信正常
# - 默认控制器 IP 为 192.168.1.13
# - 需要在安全环境下运行,回放时机械臂会自动运动
# - 操作流程:
# 示教模式 → set_darg_mode(1)力矩 → set_teach_type(1)拖拽
# → track_record_start → 手拖机械臂 → track_record_stop
# → set_teach_type(0)恢复 → track_record_save → track_record_playback
# - 运行: python3 ex_track_queue_drag.py
#
import sys
import os
import platform
import time
_script_dir = os.path.dirname(os.path.abspath(__file__))
if platform.system() == "Windows":
sys.path.append(os.path.join(_script_dir, "../../lib/windows/python"))
_dll_dir = os.path.join(_script_dir, "../../lib/windows")
os.add_dll_directory(_dll_dir)
else:
sys.path.append(os.path.join(_script_dir, "../../lib/linux/x86/python"))
from tl_interface import *
# ============================================================
# 工具函数
# ============================================================
def print_ok(msg):
print(" [OK] " + msg)
def print_fail(msg, ret):
print(" [FAIL] " + msg + ",错误码: " + str(ret))
def print_title(title):
print("\n" + "=" * 50)
print(" " + title)
print("=" * 50)
def enable_servo(sock):
"""伺服上电(含状态检查,对齐 liuxin1.cpp 的 enable_servo)"""
print("--- 检查伺服状态 ---")
clear_error(sock)
time.sleep(0.3)
set_servo_poweroff(sock)
time.sleep(0.3)
state = -1
ret, state = get_servo_state(sock, state)
if ret != SUCCESS:
print(" [ERROR] 获取伺服状态失败: %d" % ret)
return False
print(" [信息] 当前伺服状态: %d (0=停止 1=就绪 2=报警 3=运行)" % state)
if state == 2:
print("[ERROR] 伺服处于报警状态,无法上电,请排查报警原因后重试")
return False
if state == 3:
print("[INFO] 机械臂已在使能上电状态")
return True
if state == 0:
print(" [信息] 伺服处于停止状态,设置就绪...")
ret = set_servo_state(sock, 1)
if ret != SUCCESS and ret != OPERATION_NOT_ALLOWED:
print("[ERROR] 设置伺服就绪失败: %d" % ret)
return False
time.sleep(0.5)
print(" [信息] 上电使能...")
ret = set_servo_poweron(sock)
if ret != SUCCESS:
print("[ERROR] 上电失败: %d" % ret)
return False
time.sleep(2)
ret, state = get_servo_state(sock, state)
if state == 3:
print("[INFO] 机械臂使能上电成功(servo_state = %d)" % state)
return True
else:
print("[ERROR] 机械臂使能上电失败(servo_state = %d)" % state)
return False
def disable_servo(sock):
"""伺服下电(对齐 liuxin1.cpp 的 disable_servo)"""
state = -1
get_servo_state(sock, state)
if state == 1:
print("[INFO] 机械臂已使能下电")
elif state == 3:
set_servo_poweroff(sock)
get_servo_state(sock, state)
print("[INFO] 机械臂使能下电成功(servo_state = %d)" % state)
else:
print("[INFO] 机械臂使能下电失败(servo_state = %d)" % state)
def wait_playback_done(sock, timeout=120):
"""轮询等待回放完成(用 get_robot_running_state 替代,x86 SWIG 不支持 bool&)"""
time.sleep(0.1)
for _ in range(timeout * 2):
running_state = -1
ret, running_state = get_robot_running_state(sock, running_state)
if ret == SUCCESS and running_state == 0: # 0=停止,回放完成
return True
time.sleep(0.5)
return False
# ============================================================
# 主函数
# ============================================================
def main():
print_title("track_record_playback 接口测试(对齐 liuxin1.cpp)")
print("""
流程概览:
1. 上电 → 示教模式
2. set_darg_mode(1)力矩 → set_teach_type(1)拖拽
3. 开启轨迹记录
4. 手动拖拽机械臂走一段轨迹
5. 停止记录 → set_teach_type(0)恢复 → 保存轨迹
6. 回放轨迹(不同速度,轮询等待完成)
7. 清除轨迹数据
""")
# ---- 连接 ----
sock = connect_robot("192.168.1.13", "6001")
if sock <= 0:
print("[ERROR] 连接失败")
return -1
print("[INFO] 连接成功 (socket=%d)" % sock)
# ---- 清错 + 上电 ----
print_title("清错 & 上电")
if not enable_servo(sock):
print("[ERROR] 伺服上电失败,程序退出")
disconnect_robot(sock)
return -1
# ---- 示教模式 ----
print_title("切换示教模式")
ret = set_current_mode(sock, 0)
print_ok("set_current_mode(0) 示教模式") if ret == SUCCESS else print_fail("set_current_mode", ret)
time.sleep(0.3)
pass_count = 0
fail_count = 0
# ================================================================
# 测试1: 查询初始记录状态
# ================================================================
print_title("测试1: 查询初始记录状态")
recordStart = False
ret, recordStart = get_track_record_status(sock, recordStart)
# 注意: x86 Linux SWIG 可能无法正确传出 bool& 参数,以 ret 为准
if ret == SUCCESS:
print_ok("初始状态: %s (ret=%d)" % ("记录中" if recordStart else "未记录", ret))
pass_count += 1
else:
print_fail("get_track_record_status", ret)
fail_count += 1
# ================================================================
# 测试2: 开启拖拽模式(对齐 liuxin1.cpp: darg_mode=1 力矩,需在 teach_type 前)
# ================================================================
# mode: 0=无 1=力矩模式 2=位置(参考 liuxin1.cpp 实际映射)
print_title("测试2: set_darg_mode(1) 力矩模式")
ret = set_darg_mode(sock, 1)
if ret == SUCCESS:
print_ok("set_darg_mode(1) 力矩模式已开启")
pass_count += 1
else:
print_fail("set_darg_mode(1)", ret)
fail_count += 1
# set_teach_type 必须在 set_darg_mode 之后(对齐 liuxin1.cpp)
print_title("测试2b: set_teach_type(1) 切换到拖拽")
ret = set_teach_type(sock, 1)
if ret == SUCCESS:
print_ok("已切换到拖拽模式")
pass_count += 1
else:
print_fail("set_teach_type(1)", ret)
fail_count += 1
# 确认
teach_type = -1
ret, teach_type = get_teach_type(sock, teach_type)
if ret == SUCCESS:
name = {0: "点动", 1: "拖拽"}.get(teach_type, "未知")
print_ok("确认: teach_type=%d (%s)" % (teach_type, name))
# ================================================================
# 测试3: track_record_start(开始记录)
# ================================================================
print_title("测试3: 开始轨迹记录")
# 参数对齐 liuxin1.cpp: maxSamplingNum=500, samplingInterval=0.1
MAX_SAMPLES = 500
SAMPLE_INTERVAL = 1
ret = track_record_start(sock, MAX_SAMPLES, SAMPLE_INTERVAL)
if ret != SUCCESS:
print_fail("track_record_start", ret)
fail_count += 1
# 尝试备选参数
print(" [信息] 尝试备选参数 (1000, 0.1)...")
ret = track_record_start(sock, 1000, 1)
if ret != SUCCESS:
print_fail("track_record_start (备选参数)", ret)
set_teach_type(sock, 0)
set_darg_mode(sock, 0)
set_servo_poweroff(sock)
disconnect_robot(sock)
return -1
print_ok("轨迹记录已开始 (maxSamples=%d, interval=%.2fs)" % (MAX_SAMPLES, SAMPLE_INTERVAL))
# 验证记录状态(注意: x86 SWIG 可能无法正确传出 bool&,以 track_record_start 返回值判断)
recordStart = False
ret, recordStart = get_track_record_status(sock, recordStart)
if ret == SUCCESS:
print_ok("记录状态验证: %s" % ("正在记录" if recordStart else "状态查询成功(ret=%d),以上一步 start 返回值为准" % ret))
pass_count += 1
else:
print_fail("记录状态验证失败", ret)
fail_count += 1
# ================================================================
# 用户手动拖拽
# ================================================================
print("\n" + "=" * 50)
print(" [操作] 机械臂已进入拖拽状态,请手动拖拽机械臂走一段轨迹")
print(" [操作] 完成后按回车键停止记录...")
print("=" * 50)
try:
input()
except (EOFError, KeyboardInterrupt):
pass
# ================================================================
# 测试4: track_record_stop(停止记录)
# ================================================================
print_title("测试4: 停止轨迹记录")
ret = track_record_stop(sock)
if ret == SUCCESS:
print_ok("track_record_stop")
pass_count += 1
else:
print_fail("track_record_stop", ret)
fail_count += 1
# 验证停止状态
recordStart = True
ret, recordStart = get_track_record_status(sock, recordStart)
if ret == SUCCESS:
print_ok("记录状态验证: %s" % ("已停止" if not recordStart else "状态查询成功(ret=%d),以上一步 stop 返回值为准" % ret))
pass_count += 1
else:
print_fail("记录状态验证失败", ret)
fail_count += 1
# ---- 退出拖拽模式,切回点动(对齐
# liuxin1.cpp,回放前需切回点动)----
print_title("退出拖拽模式")
ret = set_teach_type(sock, 0)
print_ok("set_teach_type(0) 已切回点动模式") if ret == SUCCESS else print_fail("切回点动", ret)
time.sleep(0.3)
# ================================================================
# 测试5: track_record_save(保存轨迹)
# ================================================================
print_title("测试5: 保存轨迹")
# 按示教器格式生成轨迹名(对齐 liuxin1.cpp)
TRAJ_NAME = time.strftime("轨迹名-%m月%d日%H时%M分%S", time.localtime())
ret = track_record_save(sock, TRAJ_NAME)
if ret == SUCCESS:
print_ok("轨迹已保存为: %s" % TRAJ_NAME)
pass_count += 1
else:
print_fail("track_record_save('%s')" % TRAJ_NAME, ret)
fail_count += 1
# ================================================================
# 测试6: track_record_playback(回放)------ 核心测试
# ================================================================
print_title("测试6: 轨迹回放 (track_record_playback)")
print(" [警告] 机械臂将自动回放记录的轨迹!请确保周围安全!")
print(" 按回车键开始回放...")
try:
input()
except (EOFError, KeyboardInterrupt):
pass
# --- 用例A: 低速回放 vel=20 ---
print("\n [用例A] 低速回放 (vel=20)")
ret = track_record_playback(sock, 20)
if ret == SUCCESS:
print_ok("低速回放已开始,等待完成...")
if wait_playback_done(sock, timeout=120):
print_ok("低速回放完成")
pass_count += 1
else:
print(" [WARN] 低俗回放等待超时")
fail_count += 1
else:
print_fail("低俗回放", ret)
fail_count += 1
# --- 用例B: 中速回放 vel=50(对齐 liuxin1.cpp 的默认速度)---
print("\n [用例B] 中速回放 (vel=50)")
print(" 按回车键继续...")
try:
input()
except (EOFError, KeyboardInterrupt):
pass
ret = track_record_playback(sock, 50)
if ret == SUCCESS:
print_ok("中速回放已开始,等待完成...")
if wait_playback_done(sock, timeout=120):
print_ok("中速回放完成")
pass_count += 1
else:
print(" [WARN] 中速回放等待超时")
fail_count += 1
else:
print_fail("中速回放", ret)
fail_count += 1
# --- 用例C: 高速回放 vel=100 ---
print("\n [用例C] 高速回放 (vel=100)")
print(" 按回车键继续...")
try:
input()
except (EOFError, KeyboardInterrupt):
pass
ret = track_record_playback(sock, 100)
if ret == SUCCESS:
print_ok("高速回放已开始,等待完成...")
if wait_playback_done(sock, timeout=120):
print_ok("高速回放完成")
pass_count += 1
else:
print(" [WARN] 高速回放等待超时")
fail_count += 1
else:
print_fail("高速回放", ret)
fail_count += 1
# --- 用例D: 边界值测试 ---
print_title("测试7: playback 边界值测试")
for vel, desc in [(0, "vel=0"), (150, "vel=150"), (200,
"vel=200")]:
ret = track_record_playback(sock, vel)
if ret == SUCCESS:
print(" vel=%d (%s): 返回成功" % (vel, desc))
else:
print(" vel=%d (%s): 返回错误码 %d(可能是正常范围外)" % (vel, desc, ret))
time.sleep(1)
# ================================================================
# 测试8: track_record_delete(清除轨迹缓冲区)
# ================================================================
print_title("测试8: 清除轨迹数据")
ret = track_record_delete(sock)
if ret == SUCCESS:
print_ok("track_record_delete")
pass_count += 1
else:
print_fail("track_record_delete", ret)
fail_count += 1
# ================================================================
# 收尾
# ================================================================
print_title("收尾")
set_darg_mode(sock, 0)
set_teach_type(sock, 0)
disable_servo(sock)
disconnect_robot(sock)
print("[INFO] 测试完毕")
# ---- 报告 ----
print_title("测试报告")
total = pass_count + fail_count
print(" 通过: %d, 失败: %d, 总计: %d" % (pass_count, fail_count, total))
return 0 if fail_count == 0 else -1
if __name__ == "__main__":
exit(main())
