- 为 ExecuteFlyShotTraj 补齐 wait 语义,并让 move_to_start 先完成临时 PTP 运动后再启动正式飞拍轨迹 - 将 J519 命令发送改为由机器人 UDP status sequence 驱动, 避免在未收到状态包时主动发周期命令 - 将 10010 状态通道关节字段统一按 JointRadians 命名, 同步更新运行时读取逻辑与协议测试 - 新增 FANUC 10010 状态帧、流运动手册和 Python client 逆向文档,并更新 README 与兼容需求说明 - 补充兼容层编排测试与 HTTP 集成测试,覆盖 wait 和 move_to_start 串行化行为
8.7 KiB
Python ControllerClient 接口逆向记录
背景
本记录用于确认旧 PyControllerClient 对 Python 暴露了哪些接口,尤其确认是否能通过 Python client 直接查询或设置旧服务端运行态 JointLimits。
复核对象:
../flyshot-uaes-interface/lib/PyControllerClient.cpython-37m-x86_64-linux-gnu.so
../FlyingShot/FlyingShot/Lib/PyControllerClient.cpython-37m-x86_64-linux-gnu.so
../flyshot-uaes-interface/lib/libControllerClient.so
../FlyingShot/FlyingShot/Lib/libControllerClient.so
../FlyingShot/FlyingShot/Include/ControllerClient/ControllerClient.h
../FlyingShot/FlyingShot/Include/ControllerClient/Types.h
../flyshot-uaes-interface/UseControllerClient.py
../flyshot-uaes-interface/main.py
两份 Python 扩展与两份底层 client 库哈希一致:
PyControllerClient.cpython-37m-x86_64-linux-gnu.so
SHA256=648CC23CBC6DF83822B58AC4A10211EE1DF8029AD8933D31032187748DF7F4BC
libControllerClient.so
SHA256=6D6FD3F20F0791F1CF11EEE5B1D479E2DCB6A1A2C8AB00A1165575BAB4B62813
因此 flyshot-uaes-interface/lib 与 FlyingShot/FlyingShot/Lib 中的 Python client 可视为同一份接口。
暴露的 Python 类型
PyControllerClient 暴露以下类型:
| 类型 | 来源 | 说明 |
|---|---|---|
ControllerClient |
ControllerClient.h |
TCP JSON client,高层控制入口 |
JointPositions |
Types.h |
关节位置容器,可用 6 维列表构造,也支持下标读写 |
Pose |
Types.h |
TCP/末端位姿容器,C++ 侧为 7 元数组 |
JointLimits |
Types.h |
关节上下限、速度、加速度、jerk 容器 |
IOType |
Types.h |
IO 枚举 |
IOType 的枚举值:
IOType.kIOTypeDI = 1
IOType.kIOTypeDO = 2
IOType.kIOTypeRI = 8
IOType.kIOTypeRO = 9
ControllerClient 暴露方法
二进制字符串和 C++ 公开头文件交叉确认,Python client 暴露的方法为:
| Python 方法 | 典型调用 | 返回形态 | 说明 |
|---|---|---|---|
ConnectServer |
c.ConnectServer(server_ip="127.0.0.1", port=50001) |
bool |
连接旧 50001/TCP+JSON 服务端 |
GetServerVersion |
c.GetServerVersion() |
str |
Python 包装层把 C++ out 参数折叠成返回值 |
GetClientVersion |
c.GetClientVersion() |
str |
获取 client 版本 |
SetUpRobot |
c.SetUpRobot("FANUC_LR_Mate_200iD") |
bool |
按机器人名称初始化服务端机器人模型 |
SetUpRobotFromEnv |
c.SetUpRobotFromEnv(env_file) |
bool |
从环境文件初始化 |
IsSetUp |
c.IsSetUp() |
bool |
判断服务端是否已经初始化机器人 |
SetShowTCP |
c.SetShowTCP(is_show=True, axis_length=0.1, axis_size=2) |
bool |
仿真显示 TCP 坐标系 |
GetName |
c.GetName() |
str |
获取机器人名称 |
GetDoF |
c.GetDoF() |
int |
获取自由度 |
SetActiveController |
c.SetActiveController(sim=True) |
bool |
切换仿真/真实控制器 |
Connect |
c.Connect("192.168.10.101") |
bool |
连接机器人控制器 |
Disconnect |
c.Disconnect() |
bool |
断开机器人控制器 |
EnableRobot |
c.EnableRobot() / c.EnableRobot(8) |
bool |
使能机器人,参数为 buffer size |
DisableRobot |
c.DisableRobot() |
bool |
下使能 |
GetSpeedRatio |
c.GetSpeedRatio() |
float |
获取执行速度倍率 |
SetSpeedRatio |
c.SetSpeedRatio(0.8) |
bool |
设置执行速度倍率 |
GetTCP |
res, tcp = c.GetTCP() |
(bool, Pose) |
获取 TCP |
SetTCP |
c.SetTCP(tcp) |
bool |
设置 TCP |
GetIO |
res, value = c.GetIO(port=1, io_type=IOType.kIOTypeDI) |
(bool, bool) |
读取 IO |
SetIO |
c.SetIO(port=1, value=True, io_type=IOType.kIOTypeDO) |
bool |
写 IO |
StopMove |
c.StopMove() |
bool |
停止运动 |
GetJointPosition |
res, joints = c.GetJointPosition() |
(bool, JointPositions) |
获取当前关节角 |
GetPose |
res, pose = c.GetPose() |
(bool, Pose) |
获取当前末端位姿 |
GetNearestIK |
res, ik = c.GetNearestIK(pose, joint_seed=joints) |
(bool, JointPositions) |
按 seed 求最近 IK |
MoveJoint |
c.MoveJoint(joint_positions) |
bool |
关节运动 |
ExecuteTrajectory |
c.ExecuteTrajectory(waypoints=[...], method="icsp", save_traj=True) |
bool |
执行普通轨迹 |
UploadFlyShotTraj |
c.UploadFlyShotTraj(name, waypoints, shot_flags, offset_values, addrs) |
bool |
上传飞拍轨迹 |
DeleteFlyShotTraj |
c.DeleteFlyShotTraj(name) |
bool |
删除飞拍轨迹 |
ListFlyShotTraj |
c.ListFlyShotTraj() |
list[str] |
列出已上传飞拍轨迹 |
ExecuteFlyShotTraj |
c.ExecuteFlyShotTraj(name, move_to_start=True, method="icsp", save_traj=True) |
bool |
执行飞拍轨迹 |
SaveTrajInfo |
c.SaveTrajInfo(name, method="icsp") |
bool |
保存规划结果到 ~/Rvbust/Data |
IsFlyShotTrajValid |
valid, time = c.IsFlyShotTrajValid(name, method="icsp", save_traj=True) |
(bool, float) |
检查飞拍轨迹是否合法并返回规划时长 |
没有暴露的关键接口
本轮重点确认:Python client 暴露方法中没有看到:
GetJointLimits
SetJointLimits
_GetJointLimits
_SetJointLimits
虽然 PyControllerClient 绑定了 JointLimits 类型,并且 libControllerClient.so 中存在 JointLimits 的输出运算符符号,但公开 ControllerClient 方法表中没有任何接收或返回 JointLimits 的 client 入口。
这和旧服务端二进制不同。旧服务端 ControllerServer.cpython-37m-x86_64-linux-gnu.so 中能看到:
ControllerServer.ControllerServer._GetJointLimits
ControllerServer.ControllerServer._SetJointLimits
ControllerServer.ControllerServer._IsWaypointInJointLimits
ControllerServer.ControllerServer._IsTrajInJointLimits
ControllerServer.ControllerServer._IsTrajInJerkLimits
因此当前判断是:
Python client 公开 API 不能直接抓 runtime JointLimits;
runtime JointLimits 查询能力存在于旧服务端内部,而不是 PyControllerClient 公开接口中。
UAES Python 服务实际使用的接口
../flyshot-uaes-interface/main.py 只使用了公开 client 方法:
ConnectServerSetUpRobotIsSetUpEnableRobotDisableRobotSetActiveControllerConnectGetNameGetServerVersionGetDoFGetSpeedRatioSetTCPGetTCPSetIOGetJointPositionMoveJointListFlyShotTrajUploadFlyShotTrajExecuteFlyShotTrajSetSpeedRatioDeleteFlyShotTrajGetPose
其中 /execute_flyshot/ 调用:
c.ExecuteFlyShotTraj(name=name, move_to_start=True, method="icsp", save_traj=True)
/set_speedRatio/ 调用:
c.SetSpeedRatio(speed)
没有看到 UAES 服务通过 Python client 设置或查询 JointLimits。
2026-04-30 追加 50001/TCP+JSON 抓包复核后,这个判断进一步收敛。all-50001-plan.pcap 中已经抓到两次真实规划/执行请求:
{"cmd":"SetSpeedRatio","ratio":0.5}
{"cmd":"ExecuteFlyShotTraj","method":"icsp","move_to_start":true,"name":"UTTC_MS11_TEST01","save_traj":true,"use_cache":false,"wait":true}
{"cmd":"SetSpeedRatio","ratio":1.0}
{"cmd":"ExecuteFlyShotTraj","method":"icsp","move_to_start":true,"name":"UTTC_MS11_TEST01","save_traj":true,"use_cache":false,"wait":true}
请求中仍没有 JointLimits / acc_limit / jerk_limit / velocity / acceleration / jerk。因此公开 Python client 与公开 50001 JSON 都没有把规划限制作为参数传给 ExecuteFlyShotTraj。
另外,main.py 的 /execute_trajectory/ 中出现:
c.yrxm(waypoints=joint_positions, method='icsp', save_traj=True)
yrxm 不在 PyControllerClient 暴露方法表中,按上下文应是 ExecuteTrajectory 的笔误;这条不影响飞拍主路径 /execute_flyshot/。
对当前时长差异调查的含义
如果要抓旧系统规划时使用的 effective vel/acc/jerk,优先级应调整为:
- 在旧服务端进程内直接调用或插桩
_GetJointLimits。 - 或者逆向
50001/TCP+JSON的 hidden command envelope,再尝试发送GetJointLimits/_GetJointLimits。 - 不应指望现有
PyControllerClient.ControllerClient直接提供GetJointLimits。
如果短期内无法进入旧服务端内部,新系统不再继续等待这份不可见状态;设计上使用 replacement-only 的内部规划约束参数补齐,优先限制规划加速度,例如 planning_acceleration_scale。该参数必须标注为新系统校准值,不能写成旧 Python client 或旧 50001 JSON 的公开字段。
最小现场验证脚本可以先确认 Python client 暴露面:
from PyControllerClient import ControllerClient
c = ControllerClient()
names = [x for x in dir(c) if "Limit" in x or "limit" in x]
print(names)
按当前二进制逆向,预期不会出现 GetJointLimits / SetJointLimits。