✨ feat: 实现 ControllerClient HTTP 兼容层及 FANUC 运行时
- 新增 Flyshot.ControllerClientCompat 兼容层模块 - 新增 Flyshot.Runtime.Fanuc 运行时模块 - 新增 LegacyHttpApiController 暴露 HTTP 兼容 API - 补充 RuntimeOrchestrationTests 等测试覆盖 - 补充 docs/ 兼容性需求与逆向工程文档 - 更新 Host 注册、配置及解决方案引用 变更概览: - Flyshot.ControllerClientCompat — 旧 ControllerClient 语义的 HTTP 适配 - Flyshot.Runtime.Fanuc — IControllerRuntime 的 FANUC 真机实现 - LegacyHttpApiController — HTTP API 兼容旧 SDK - docs/ — 兼容性需求与逆向工程分析文档 - 测试:RuntimeOrchestrationTests、LegacyHttpApiCompatibilityTests
This commit is contained in:
135
docs/controller-client-api-compatibility-requirements.md
Normal file
135
docs/controller-client-api-compatibility-requirements.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# ControllerClient API 兼容逆向约束
|
||||
|
||||
> 记录时间:2026-04-24
|
||||
> 适用仓库:`flyshot-replacement`
|
||||
> 当前阶段:已落地 HTTP-only `ControllerClientCompat` 服务,并已将轨迹执行接入规划、触发时间轴和最小运行时骨架;不实现 `50001/TCP+JSON` 监听
|
||||
|
||||
## 1. 当前目标
|
||||
|
||||
本轮目标不是直接实现 `50001/TCP+JSON` 兼容网关,而是先把旧 `ControllerClient` 暴露的公开 API 做成可执行的逆向合同。
|
||||
|
||||
本轮交付物固定为两份文档:
|
||||
|
||||
- `docs/controller-client-api-compatibility-requirements.md`
|
||||
- `docs/controller-client-api-reverse-engineering.md`
|
||||
|
||||
后续继续扩展 `Flyshot.ControllerClientCompat` 的方法覆盖、兼容测试矩阵或真实控制器联动时,必须以这两份文档为准,不再重新口头约定接口语义。
|
||||
|
||||
## 2. 范围边界
|
||||
|
||||
本轮只覆盖 `../FlyingShot/FlyingShot/Include/ControllerClient/ControllerClient.h` 中的 32 个公开方法。
|
||||
|
||||
分组如下:
|
||||
|
||||
- 传输与版本:`ConnectServer`、`GetServerVersion`、`GetClientVersion`
|
||||
- 机器人初始化:`SetUpRobot`、`SetUpRobotFromEnv`、`IsSetUp`、`SetShowTCP`、`GetName`、`GetDoF`
|
||||
- 控制器状态:`SetActiveController`、`Connect`、`Disconnect`、`EnableRobot`、`DisableRobot`、`StopMove`
|
||||
- 参数与 IO:`GetSpeedRatio`、`SetSpeedRatio`、`GetTCP`、`SetTCP`、`GetIO`、`SetIO`
|
||||
- 运动与求解:`GetJointPosition`、`GetPose`、`GetNearestIK`、`MoveJoint`、`ExecuteTrajectory`
|
||||
- 飞拍轨迹:`UploadFlyShotTraj`、`DeleteFlyShotTraj`、`ListFlyShotTraj`、`ExecuteFlyShotTraj`、`SaveTrajInfo`、`IsFlyShotTrajValid`
|
||||
|
||||
明确不在本轮范围内:
|
||||
|
||||
- `ControllerServer` 内部所有未公开 `_Xxx` 方法的完整实现复原
|
||||
- `50001` 网关代码、TCP server、JSON parser、命令路由实现
|
||||
- 真机 `10010 / 10012 / 60015` 联调
|
||||
- 抓包、hook、反汇编级协议完全坐实
|
||||
- 把当前 replacement 仓库的实现约束误写成旧系统事实
|
||||
|
||||
## 3. 证据源优先级
|
||||
|
||||
逆向结论必须按以下优先级交叉确认:
|
||||
|
||||
1. `../FlyingShot/FlyingShot/Include/ControllerClient/ControllerClient.h`
|
||||
2. `../FlyingShot/FlyingShot/Example/UseControllerClient.cpp`
|
||||
3. `../FlyingShot/FlyingShot/Example/UseControllerClient.py`
|
||||
4. `../FlyingShot/FlyingShot/Example/UseRealRobot.py`
|
||||
5. `../FlyingShot/FlyingShot/Docs/用户手册/FANUC飞拍软件及SDK用户手册.md`
|
||||
6. `../analysis/ControllerServer_analysis.md`
|
||||
7. `../analysis/CommonMsg_protocol_analysis.md`
|
||||
8. `../analysis/Trajectory_generation_algorithm_analysis.md`
|
||||
9. `../FlyingShot/FlyingShot/Lib/libControllerClient.so` 与 `../FlyingShot/FlyingShot/Python/ControllerServer/ControllerServer.cpython-37m-x86_64-linux-gnu.so` 的字符串证据
|
||||
|
||||
使用规则:
|
||||
|
||||
- 头文件负责定义“公开合同”:方法名、参数名、默认值、返回类型。
|
||||
- 示例和手册负责定义“典型调用方式”:调用顺序、Python 包装形态、用户侧常见用法。
|
||||
- 逆向分析文档和二进制字符串负责定义“服务端映射”和“协议线索”:`_Xxx` 方法名、错误文本、命令名、部分字段顺序。
|
||||
- 不能从当前 replacement 仓库的未来设计反推旧系统事实。
|
||||
|
||||
## 4. 文档填写规则
|
||||
|
||||
主归档文档 `docs/controller-client-api-reverse-engineering.md` 对每个 API 必须固定填写以下项目:
|
||||
|
||||
- C++ 公开签名
|
||||
- Python 包装形态
|
||||
- 服务端归属
|
||||
- 协议 / 命令线索
|
||||
- 返回值与默认值
|
||||
- 典型工作流位置
|
||||
- 证据来源
|
||||
- 置信度
|
||||
- 待确认点
|
||||
|
||||
填写约束:
|
||||
|
||||
- 只要精确 JSON 包结构还未恢复,就明确写成“命令名已知,JSON envelope 未恢复”。
|
||||
- 只要 Python 失败路径没有样例,就不能假装已经确认失败时的返回形态。
|
||||
- `GetServerVersion` 这类没有显式 `_GetServerVersion` 的接口,必须标成“协议分发层行为”,不能伪造一个服务端实现名。
|
||||
- `ConnectServer` 与 `GetClientVersion` 必须明确标成客户端侧行为,不写进服务端命令表。
|
||||
- 对 `GetJointPosition -> _GetJointPositions` 这种命名不一致,要单独注明。
|
||||
- 当同一结论同时来自头文件、示例和字符串时,置信度可标为“高”;只有示例间接体现时,最多“中”。
|
||||
|
||||
## 5. 验收条件
|
||||
|
||||
本轮逆向归档完成时,至少满足:
|
||||
|
||||
- 32 个公开方法全部覆盖,且每个方法只出现一次
|
||||
- 29 个服务端相关 API 有明确映射或明确写成协议分发层行为
|
||||
- `ConnectServer`、`GetClientVersion` 两个客户端侧行为被明确排除在服务端命令表外
|
||||
- 四条工作流附录完整:
|
||||
- 初始化工作流
|
||||
- 控制器状态工作流
|
||||
- 普通轨迹工作流
|
||||
- 飞拍轨迹工作流
|
||||
- 已知高置信协议字段至少记录:
|
||||
- `GetSpeedRatio`
|
||||
- `SetSpeedRatio`
|
||||
- `GetIO`
|
||||
- `SetIO`
|
||||
- 仍未恢复的部分必须进入“待确认问题”清单,不能被静默略过
|
||||
|
||||
## 6. 当前已确认摘要
|
||||
|
||||
当前已确认的高价值结论如下:
|
||||
|
||||
- `ControllerClient.h` 中共有 32 个公开方法。
|
||||
- 其中 29 个方法可与 `ControllerServer` 的公开 `_Xxx` 方法一一对齐。
|
||||
- `GetServerVersion` 能看到明确字符串证据,但未恢复到显式 `_GetServerVersion` 实现,更接近 `_ClientCB` / `_IsJsonValid` 所在的协议分发层。
|
||||
- `ConnectServer` 是客户端建立到 `127.0.0.1:50001` 的传输层动作。
|
||||
- `GetClientVersion` 更像客户端库自身版本查询,不进入服务端命令表。
|
||||
- `GetSpeedRatio` / `SetSpeedRatio`、`GetIO` / `SetIO` 已有较高置信度的底层字段顺序与 `MsgID` 证据。
|
||||
- `UploadFlyShotTraj`、`ListFlyShotTraj` 存在额外字符串线索:
|
||||
- `StartUploadFlyShotTraj`
|
||||
- `EndUploadFlyShotTraj`
|
||||
- `GetNextListFlyShotTraj`
|
||||
- `ExecuteFlyShotTraj`、`IsFlyShotTrajValid`、`SaveTrajInfo` 在工作流上有清晰分工,不能混成一个“执行轨迹”接口。
|
||||
|
||||
## 7. 下轮实现约束
|
||||
|
||||
当前 HTTP-only 兼容层已经可以承接公开 API 的主要服务端语义,并且 `ExecuteTrajectory` / `ExecuteFlyShotTraj` 已经进入 replacement 自身的规划与运行时链路。后续扩展必须遵守:
|
||||
|
||||
- 先以逆向合同建命令表,再写 `TCP + JSON` 入口
|
||||
- 先做兼容测试矩阵,再补最小命令桩
|
||||
- 区分“旧系统事实”和“replacement 当前策略”
|
||||
- 真机未接通前,允许实现层返回稳定错误或模拟状态,但不能反过来污染逆向文档
|
||||
|
||||
## 8. 当前 replacement 实现状态
|
||||
|
||||
以下内容是当前新实现的状态,不反推为旧系统事实:
|
||||
|
||||
- `Flyshot.ControllerClientCompat` 继续作为 HTTP 控制器后端兼容服务,不启动 `50001/TCP+JSON` 监听。
|
||||
- `ExecuteTrajectory` 会先通过 `ICspPlanner` 规划普通轨迹,再把 `TrajectoryResult` 和最终关节位置交给 `IControllerRuntime`。
|
||||
- `ExecuteFlyShotTraj` 会从上传轨迹目录取出轨迹,通过 `SelfAdaptIcspPlanner` 规划并用 `ShotTimelineBuilder` 生成 `ShotEvent` / `TrajectoryDoEvent`。
|
||||
- `Flyshot.Runtime.Fanuc` 当前只保存连接、使能、速度、IO、TCP、关节位置和执行结果状态;真实 `10010 / 10012 / 60015` Socket 通讯尚未落地。
|
||||
- `MoveJoint` 仍保持旧兼容语义中的直接运动接口,但状态写入已经统一经过运行时,而不是由兼容服务自己维护关节数组。
|
||||
561
docs/controller-client-api-reverse-engineering.md
Normal file
561
docs/controller-client-api-reverse-engineering.md
Normal file
@@ -0,0 +1,561 @@
|
||||
# ControllerClient API 全量逆向归档
|
||||
|
||||
> 记录时间:2026-04-24
|
||||
> 适用仓库:`flyshot-replacement`
|
||||
> 目标:为后续 `50001/TCP+JSON` 兼容网关实现提供只读合同
|
||||
|
||||
## 1. 总览
|
||||
|
||||
本次归档覆盖 `../FlyingShot/FlyingShot/Include/ControllerClient/ControllerClient.h` 中全部 32 个公开方法。
|
||||
|
||||
当前分类结果:
|
||||
|
||||
- 29 个 API 可与 `ControllerServer` 公开 `_Xxx` 方法一一映射
|
||||
- 1 个 API 属于协议分发层行为:`GetServerVersion`
|
||||
- 2 个 API 属于客户端侧行为:`ConnectServer`、`GetClientVersion`
|
||||
|
||||
本文档中的“协议 / 命令线索”有两个层次:
|
||||
|
||||
- 命令名:已从头文件、字符串或逆向文档坐实,例如 `SetUpRobot`、`GetIO`
|
||||
- JSON envelope:请求 JSON 的精确键名、必填规则、整体结构;当前大多仍未完全恢复
|
||||
|
||||
因此,除 `GetSpeedRatio` / `SetSpeedRatio` / `GetIO` / `SetIO` 等已在命令通道层坐实字段顺序的接口外,其余接口默认只写“命令名已知,精确 JSON 包结构待确认”。
|
||||
|
||||
置信度定义:
|
||||
|
||||
- 高:头文件 + 示例/手册 + 字符串/逆向文档三方交叉确认
|
||||
- 中:头文件 + 示例,或头文件 + 字符串,缺少第三方交叉
|
||||
- 低:仅有间接线索,未达到本轮归档主结论标准
|
||||
|
||||
## 2. 传输与版本
|
||||
|
||||
### `ConnectServer`
|
||||
|
||||
- C++ 公开签名:`bool ConnectServer(const std::string &server_ip = "127.0.0.1", unsigned port = 50001);`
|
||||
- Python 包装形态:`c.ConnectServer(server_ip="127.0.0.1", port=50001) -> bool`
|
||||
- 服务端归属:客户端传输层行为,不进入 `ControllerServer._Xxx` 命令表
|
||||
- 协议 / 命令线索:建立到 `127.0.0.1:50001` 的 TCP 连接;JSON 负载只发生在连接建立之后
|
||||
- 返回值与默认值:默认 `server_ip="127.0.0.1"`、`port=50001`;成功返回 `true`
|
||||
- 典型工作流位置:所有远程 API 的前置步骤
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`UseRealRobot.py`
|
||||
- 置信度:高
|
||||
- 待确认点:重连、超时、握手细节未恢复
|
||||
|
||||
### `GetServerVersion`
|
||||
|
||||
- C++ 公开签名:`bool GetServerVersion(std::string &version);`
|
||||
- Python 包装形态:样例中表现为 `controller.GetServerVersion() -> str`
|
||||
- 服务端归属:协议分发层行为;当前未恢复到显式 `_GetServerVersion`
|
||||
- 协议 / 命令线索:命令名字符串 `GetServerVersion` 已坐实;服务端存在 `GetServerVersion success: {}.` 日志;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:C++ 为 `bool + out string`;Python 样例把结果当作直接字符串使用
|
||||
- 典型工作流位置:`ConnectServer` 之后、机器人初始化前后均可读取的元信息接口
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`libControllerClient.so`、`ControllerServer.cpython-37m-x86_64-linux-gnu.so`
|
||||
- 置信度:高
|
||||
- 待确认点:Python 失败路径的返回形态未看到样例;请求 JSON 的精确字段未恢复
|
||||
|
||||
### `GetClientVersion`
|
||||
|
||||
- C++ 公开签名:`bool GetClientVersion(std::string &version);`
|
||||
- Python 包装形态:未见公开样例;从包装库字符串看接口存在
|
||||
- 服务端归属:客户端本地行为,不进入服务端命令表
|
||||
- 协议 / 命令线索:`libControllerClient.so` 与 `PyControllerClient` 都有 `GetClientVersion` 符号;未见 `ControllerServer` 对应 `_Xxx`
|
||||
- 返回值与默认值:C++ 为 `bool + out string`;Python 侧返回形态待确认
|
||||
- 典型工作流位置:客户端自检或 SDK 版本上报,不依赖服务端状态
|
||||
- 证据来源:`ControllerClient.h`、`libControllerClient.so`、`PyControllerClient.cpython-37m-x86_64-linux-gnu.so`
|
||||
- 置信度:高
|
||||
- 待确认点:实际版本字符串来源与 Python 包装失败行为未恢复
|
||||
|
||||
## 3. 机器人初始化
|
||||
|
||||
### `SetUpRobot`
|
||||
|
||||
- C++ 公开签名:`bool SetUpRobot(const std::string &robot_name);`
|
||||
- Python 包装形态:`c.SetUpRobot("FANUC_LR_Mate_200iD") -> bool`
|
||||
- 服务端归属:`ControllerServer._SetUpRobot`
|
||||
- 协议 / 命令线索:命令名 `SetUpRobot` 已坐实;参数高概率是 `robot_name`;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:创建客户端并连上 `50001` 后首先调用;旧说明明确它是最先执行的服务端初始化动作
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:请求字段键名是否为 `robot_name` 仍需抓包或 hook 坐实
|
||||
|
||||
### `SetUpRobotFromEnv`
|
||||
|
||||
- C++ 公开签名:`bool SetUpRobotFromEnv(const std::string &env_file);`
|
||||
- Python 包装形态:未见公开样例;服务端与客户端字符串均存在
|
||||
- 服务端归属:`ControllerServer._SetUpRobotFromEnv`
|
||||
- 协议 / 命令线索:命令名 `SetUpRobotFromEnv` 已坐实;参数高概率是环境文件绝对路径;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:与 `SetUpRobot` 二选一;当现场通过环境文件而不是型号名初始化时使用
|
||||
- 证据来源:`ControllerClient.h`、`ControllerServer_analysis.md`、`ControllerServer` 字符串、`libControllerClient.so`
|
||||
- 置信度:高
|
||||
- 待确认点:环境文件路径是否必须为绝对路径由注释可见,但服务端是否做额外归一化未恢复
|
||||
|
||||
### `IsSetUp`
|
||||
|
||||
- C++ 公开签名:`bool IsSetUp();`
|
||||
- Python 包装形态:`c.IsSetUp() -> bool`
|
||||
- 服务端归属:`ControllerServer._IsSetUp`
|
||||
- 协议 / 命令线索:命令名 `IsSetUp` 已坐实;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:直接返回布尔值
|
||||
- 典型工作流位置:`SetUpRobot` 或 `SetUpRobotFromEnv` 之后的状态确认
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:服务端返回是否仅受机器人对象存在性控制,还是还依赖模型/控制器更深层状态,当前未完全恢复
|
||||
|
||||
### `SetShowTCP`
|
||||
|
||||
- C++ 公开签名:`bool SetShowTCP(bool is_show = true, double axis_length = 0.1, size_t axis_size = 2);`
|
||||
- Python 包装形态:`c.SetShowTCP(is_show=True, axis_length=0.1, axis_size=2) -> bool`
|
||||
- 服务端归属:`ControllerServer._SetShowTCP`
|
||||
- 协议 / 命令线索:命令名 `SetShowTCP` 已坐实;字符串中可见 `SetShowTCP is_show success/failed`;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:默认 `is_show=true`、`axis_length=0.1`、`axis_size=2`
|
||||
- 典型工作流位置:初始化完成后、切换控制器前的仿真显示配置
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`ControllerServer_analysis.md`、`ControllerServer` 字符串
|
||||
- 置信度:高
|
||||
- 待确认点:仅仿真控制器生效还是真实控制器也接受该命令,当前未见明确负例
|
||||
|
||||
### `GetName`
|
||||
|
||||
- C++ 公开签名:`std::string GetName();`
|
||||
- Python 包装形态:`c.GetName() -> str`
|
||||
- 服务端归属:`ControllerServer._GetName`
|
||||
- 协议 / 命令线索:命令名 `GetName` 已坐实;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:直接返回机器人名称字符串
|
||||
- 典型工作流位置:完成机器人初始化后读取名称确认
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:失败时是返回空串还是异常/默认值,Python 样例未覆盖
|
||||
|
||||
### `GetDoF`
|
||||
|
||||
- C++ 公开签名:`int GetDoF();`
|
||||
- Python 包装形态:`c.GetDoF() -> int`
|
||||
- 服务端归属:`ControllerServer._GetDoF`
|
||||
- 协议 / 命令线索:命令名 `GetDoF` 已坐实;精确 JSON envelope 未恢复
|
||||
- 返回值与默认值:直接返回自由度整数
|
||||
- 典型工作流位置:完成机器人初始化后读取自由度
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:失败时的客户端行为未恢复
|
||||
|
||||
## 4. 控制器状态
|
||||
|
||||
### `SetActiveController`
|
||||
|
||||
- C++ 公开签名:`bool SetActiveController(bool sim = true);`
|
||||
- Python 包装形态:`c.SetActiveController(sim=True) -> bool`;真机样例使用 `sim=False`
|
||||
- 服务端归属:`ControllerServer._SetActiveController`
|
||||
- 协议 / 命令线索:命令名 `SetActiveController` 已坐实;字符串中可见 `SetActiveController sim success/failed`
|
||||
- 返回值与默认值:默认 `sim=true`
|
||||
- 典型工作流位置:机器人初始化后、`Connect` 前,用于在仿真控制器和真实控制器之间切换
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`UseRealRobot.py`、SDK 手册、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:切换控制器时是否会隐式断开旧控制器,当前只有 `_DisconnectAll` 的间接线索
|
||||
|
||||
### `Connect`
|
||||
|
||||
- C++ 公开签名:`bool Connect(const std::string &robot_ip);`
|
||||
- Python 包装形态:`c.Connect("192.168.10.101") -> bool`
|
||||
- 服务端归属:`ControllerServer._Connect`
|
||||
- 协议 / 命令线索:命令名 `Connect` 已坐实;字符串中可见 `Connect ip success/failed`
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:选定活动控制器后,通知服务端连接真实机器人 IP
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`UseRealRobot.py`、SDK 手册、`ControllerServer_analysis.md`、`FANUC_realtime_comm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 键名是否为 `ip` 或 `robot_ip` 未恢复;仿真模式下是否接受同一命令仍需实现侧验证
|
||||
|
||||
### `Disconnect`
|
||||
|
||||
- C++ 公开签名:`bool Disconnect();`
|
||||
- Python 包装形态:`c.Disconnect() -> bool`
|
||||
- 服务端归属:`ControllerServer._Disconnect`
|
||||
- 协议 / 命令线索:命令名 `Disconnect` 已坐实;字符串中可见 `Disconnect success/failed`
|
||||
- 返回值与默认值:直接返回布尔值
|
||||
- 典型工作流位置:真实控制器断开或工作流结束时调用
|
||||
- 证据来源:`ControllerClient.h`、`ControllerServer_analysis.md`、`ControllerServer` 字符串、`libControllerClient.so`
|
||||
- 置信度:高
|
||||
- 待确认点:是否同步清理状态通道 / 命令通道 / 伺服通道,当前只在 FANUC 分析文档看到对象链,并未完全坐实释放顺序
|
||||
|
||||
### `EnableRobot`
|
||||
|
||||
- C++ 公开签名:`bool EnableRobot(unsigned buffer_size = 2);`
|
||||
- Python 包装形态:`c.EnableRobot() -> bool`
|
||||
- 服务端归属:`ControllerServer._EnableRobot`
|
||||
- 协议 / 命令线索:命令名 `EnableRobot` 已坐实;字符串中可见 `EnableRobot success/failed`
|
||||
- 返回值与默认值:默认 `buffer_size=2`
|
||||
- 典型工作流位置:`Connect` 后使能机器人;多数运动 API 前置条件
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`UseRealRobot.py`、`ControllerServer_analysis.md`、`FANUC_realtime_comm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:`buffer_size` 在旧服务端具体如何映射到伺服缓冲区参数,当前未完全恢复
|
||||
|
||||
### `DisableRobot`
|
||||
|
||||
- C++ 公开签名:`bool DisableRobot();`
|
||||
- Python 包装形态:`c.DisableRobot() -> bool`
|
||||
- 服务端归属:`ControllerServer._DisableRobot`
|
||||
- 协议 / 命令线索:命令名 `DisableRobot` 已坐实;字符串中可见 `DisableRobot success/failed`
|
||||
- 返回值与默认值:直接返回布尔值
|
||||
- 典型工作流位置:停机或退出前关闭机器人使能
|
||||
- 证据来源:`ControllerClient.h`、`ControllerServer_analysis.md`、`FANUC_realtime_comm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:与 `StopMove` 的先后顺序约束未恢复
|
||||
|
||||
### `StopMove`
|
||||
|
||||
- C++ 公开签名:`bool StopMove();`
|
||||
- Python 包装形态:`c.StopMove() -> bool`
|
||||
- 服务端归属:`ControllerServer._StopMove`
|
||||
- 协议 / 命令线索:命令名 `StopMove` 已坐实;字符串中可见 `StopMove success/failed`
|
||||
- 返回值与默认值:直接返回布尔值
|
||||
- 典型工作流位置:当前运动中止;Python 示例中调用后会再次 `EnableRobot()`
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`ControllerServer_analysis.md`、`FANUC_realtime_comm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:是否会清空控制器执行队列、是否必须重新使能,当前只从示例看到倾向性而非硬约束
|
||||
|
||||
## 5. 参数与 IO
|
||||
|
||||
### `GetSpeedRatio`
|
||||
|
||||
- C++ 公开签名:`double GetSpeedRatio();`
|
||||
- Python 包装形态:`c.GetSpeedRatio() -> float`
|
||||
- 服务端归属:`ControllerServer._GetSpeedRatio`
|
||||
- 协议 / 命令线索:命令通道 `MsgID = 0x2206`;响应字段为 `ratio_int` 与 `result_code`;成功后客户端将 `ratio_int / 100.0`
|
||||
- 返回值与默认值:直接返回 `0~1` 之间的倍率
|
||||
- 典型工作流位置:连机并使能后读取当前速度倍率
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`CommonMsg_protocol_analysis.md`
|
||||
- 置信度:高
|
||||
- 待确认点:服务端 JSON 层到命令通道层的参数桥接结构未恢复
|
||||
|
||||
### `SetSpeedRatio`
|
||||
|
||||
- C++ 公开签名:`bool SetSpeedRatio(double ratio);`
|
||||
- Python 包装形态:`c.SetSpeedRatio(0.8) -> bool`
|
||||
- 服务端归属:`ControllerServer._SetSpeedRatio`
|
||||
- 协议 / 命令线索:命令通道 `MsgID = 0x2207`;请求字段为 `ratio_int_0_100`;输入 `double` 先乘 `100` 并夹到 `[0,100]`
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:连机并使能后修改控制器速度倍率
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`UseRealRobot.py`、SDK 手册、`ControllerServer_analysis.md`、`CommonMsg_protocol_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:ratio 越界时客户端是裁剪还是直接失败,当前更偏向裁剪,但缺少公开负例
|
||||
|
||||
### `GetTCP`
|
||||
|
||||
- C++ 公开签名:`bool GetTCP(Pose &tcp);`
|
||||
- Python 包装形态:`res, tcp = c.GetTCP()`
|
||||
- 服务端归属:`ControllerServer._GetTCP`
|
||||
- 协议 / 命令线索:控制器命令通道底层接口 `GetTCP` 已有 `MsgID = 0x2200` 证据,但 `ControllerClient` JSON 层请求结构未完全恢复
|
||||
- 返回值与默认值:C++ 为 `bool + out Pose`;Python 为 `(bool, Pose)`
|
||||
- 典型工作流位置:连机后读取当前控制器 TCP
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`ControllerServer_analysis.md`、`CommonMsg_protocol_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 层是否支持多个 TCP ID,目前只看到底层命令通道有 `tcp_id`
|
||||
|
||||
### `SetTCP`
|
||||
|
||||
- C++ 公开签名:`bool SetTCP(const Pose &tcp);`
|
||||
- Python 包装形态:`c.SetTCP(tcp) -> bool`
|
||||
- 服务端归属:`ControllerServer._SetTCP`
|
||||
- 协议 / 命令线索:控制器命令通道底层接口 `SetTCP` 已有 `MsgID = 0x2201` 证据;JSON 层精确字段未恢复
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:连机后修改控制器 TCP
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`ControllerServer_analysis.md`、`CommonMsg_protocol_analysis.md`、`FANUC_realtime_comm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 层是否也暴露 `tcp_id` 概念尚未恢复
|
||||
|
||||
### `GetIO`
|
||||
|
||||
- C++ 公开签名:`bool GetIO(unsigned port, bool &value, IOType type = kIOTypeDI);`
|
||||
- Python 包装形态:`res, value = c.GetIO(port=1, io_type=IOType.kIOTypeDI)`
|
||||
- 服务端归属:`ControllerServer._GetIO`
|
||||
- 协议 / 命令线索:命令通道 `MsgID = 0x2208`;请求字段顺序是 `io_type`、`io_index`;响应字段是 `result_code`、`io_value`
|
||||
- 返回值与默认值:默认 `type = kIOTypeDI`;C++ 为 `bool + out bool`;Python 为 `(bool, bool)`
|
||||
- 典型工作流位置:连机后读取 DI/DO/RI/RO 等 IO 值
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`CommonMsg_protocol_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:高层 JSON 是否把字段命名为 `port` / `value` / `type`,还是 `io_index` / `io_type`,当前未抓到完整包
|
||||
|
||||
### `SetIO`
|
||||
|
||||
- C++ 公开签名:`bool SetIO(unsigned port, bool value, IOType type = kIOTypeDO);`
|
||||
- Python 包装形态:`c.SetIO(port=1, value=True, io_type=IOType.kIOTypeDO) -> bool`
|
||||
- 服务端归属:`ControllerServer._SetIO`
|
||||
- 协议 / 命令线索:命令通道 `MsgID = 0x2209`;请求字段顺序是 `io_type`、`io_index`、`io_value`
|
||||
- 返回值与默认值:默认 `type = kIOTypeDO`
|
||||
- 典型工作流位置:连机后设置数字输出;飞拍链路之外的普通 IO 调试也会用到
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`CommonMsg_protocol_analysis.md`、`FANUC_realtime_comm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:布尔值在高层 JSON 中是否以 `true/false` 传输、在命令通道中以 `float` 传输,当前只坐实了命令通道层
|
||||
|
||||
## 6. 运动与求解
|
||||
|
||||
### `GetJointPosition`
|
||||
|
||||
- C++ 公开签名:`bool GetJointPosition(JointPositions &joint_position);`
|
||||
- Python 包装形态:`res, joints = c.GetJointPosition()`
|
||||
- 服务端归属:`ControllerServer._GetJointPositions`
|
||||
- 协议 / 命令线索:命令名 `GetJointPositions` 已坐实;客户端公开 API 名与服务端方法名存在单复数差异
|
||||
- 返回值与默认值:C++ 为 `bool + out JointPositions`;Python 为 `(bool, JointPositions)`
|
||||
- 典型工作流位置:读取当前关节角,常作为 `GetNearestIK` 的 seed 或 `MoveJoint` 的基准
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 层返回数组字段键名未恢复
|
||||
|
||||
### `GetPose`
|
||||
|
||||
- C++ 公开签名:`bool GetPose(Pose &pose);`
|
||||
- Python 包装形态:`res, pose = c.GetPose()`
|
||||
- 服务端归属:`ControllerServer._GetPose`
|
||||
- 协议 / 命令线索:命令名 `GetPose` 已坐实;字符串中可见 `GetPose success/failed`
|
||||
- 返回值与默认值:C++ 为 `bool + out Pose`;Python 为 `(bool, Pose)`
|
||||
- 典型工作流位置:读取当前 TCP 位姿,常与 `GetNearestIK` 配套使用
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:位姿坐标系定义虽然在 `Types.h` 中体现为 7 元数组,但 JSON 层字段结构未恢复
|
||||
|
||||
### `GetNearestIK`
|
||||
|
||||
- C++ 公开签名:`bool GetNearestIK(const Pose &pose, const JointPositions &seed, JointPositions &ik);`
|
||||
- Python 包装形态:`res, ik = c.GetNearestIK(pose, joint_seed=joints)`
|
||||
- 服务端归属:`ControllerServer._GetNearestIK`
|
||||
- 协议 / 命令线索:命令名 `GetNearestIK` 已坐实;字符串中可见 `GetNearestIK success/failed`
|
||||
- 返回值与默认值:C++ 为 `bool + out JointPositions`;Python 为 `(bool, JointPositions)`
|
||||
- 典型工作流位置:先 `GetPose` 得到当前位姿,再构造目标位姿,并使用当前关节或邻近关节作为 seed 求最近 IK
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 层中 seed 参数键名在 Python 里表现为 `joint_seed`,但 C++ 注释写的是 `seed`;高层字段命名仍待确认
|
||||
|
||||
### `MoveJoint`
|
||||
|
||||
- C++ 公开签名:`bool MoveJoint(const JointPositions &joint_position);`
|
||||
- Python 包装形态:`c.MoveJoint(home_joint) -> bool`
|
||||
- 服务端归属:`ControllerServer._MoveJoint`
|
||||
- 协议 / 命令线索:命令名 `MoveJoint` 已坐实;字符串中可见 `MoveJoint waypoint success/failed`
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:点到点回零或移动到飞拍轨迹起点
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`ControllerServer_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:移动速度/平滑参数是否固定在服务端内部,公开 API 未暴露
|
||||
|
||||
### `ExecuteTrajectory`
|
||||
|
||||
- C++ 公开签名:`bool ExecuteTrajectory(const std::vector<JointPositions> &waypoints, const std::string &method = "icsp", bool save_traj = false);`
|
||||
- Python 包装形态:`c.ExecuteTrajectory(waypoints=[...], method="icsp", save_traj=True) -> bool`
|
||||
- 服务端归属:`ControllerServer._ExecuteTrajectory`
|
||||
- 协议 / 命令线索:命令名 `ExecuteTrajectory` 已坐实;`method` 至少支持 `icsp` 与 `doubles`
|
||||
- 返回值与默认值:默认 `method="icsp"`、`save_traj=false`
|
||||
- 典型工作流位置:普通多点轨迹执行,不带飞拍 IO;输入是关节空间稀疏 waypoint,而不是笛卡尔点
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`Trajectory_generation_algorithm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 中 waypoint 列表的键名和序列化结构未恢复;`doubles` 的失败语义未在公开样例中体现
|
||||
|
||||
## 7. 飞拍轨迹
|
||||
|
||||
### `UploadFlyShotTraj`
|
||||
|
||||
- C++ 公开签名:`bool UploadFlyShotTraj(const std::string &name, const std::vector<JointPositions> &waypoints, const std::vector<bool> &shot_flags, const std::vector<int> &offset_values, const std::vector<std::vector<int>> &addrs);`
|
||||
- Python 包装形态:`c.UploadFlyShotTraj(name="test_traj", waypoints=..., shot_flags=..., offset_values=..., addrs=...) -> bool`
|
||||
- 服务端归属:`ControllerServer._UploadFlyShotTraj`
|
||||
- 协议 / 命令线索:命令名 `UploadFlyShotTraj` 已坐实;客户端字符串中可见 `StartUploadFlyShotTraj` 与 `EndUploadFlyShotTraj`,说明上传阶段很可能分为开始 / 传输 / 结束三个子步骤
|
||||
- 返回值与默认值:成功返回 `true`;无默认参数
|
||||
- 典型工作流位置:运行时动态构造飞拍轨迹时,先把轨迹定义登记到服务端
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`Trajectory_generation_algorithm_analysis.md`、`libControllerClient.so`、`ControllerServer` 字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 上传是否一次性发送完整 payload,还是像字符串暗示的那样分片上传,当前未完全恢复
|
||||
|
||||
### `DeleteFlyShotTraj`
|
||||
|
||||
- C++ 公开签名:`bool DeleteFlyShotTraj(const std::string &name);`
|
||||
- Python 包装形态:`c.DeleteFlyShotTraj(name="test_traj") -> bool`
|
||||
- 服务端归属:`ControllerServer._DeleteFlyShotTraj`
|
||||
- 协议 / 命令线索:命令名 `DeleteFlyShotTraj` 已坐实;字符串中可见 `DeleteFlyShotTraj {} success/failed`
|
||||
- 返回值与默认值:成功返回 `true`
|
||||
- 典型工作流位置:删除已上传的临时飞拍轨迹定义
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、SDK 手册、`ControllerServer_analysis.md`、`PyControllerClient` 字符串、`ControllerServer` 字符串
|
||||
- 置信度:高
|
||||
- 待确认点:删除配置内固有轨迹名与删除运行时上传轨迹时是否走同一条路径,当前未恢复
|
||||
|
||||
### `ListFlyShotTraj`
|
||||
|
||||
- C++ 公开签名:`std::vector<std::string> ListFlyShotTraj();`
|
||||
- Python 包装形态:`c.ListFlyShotTraj() -> list[str]`
|
||||
- 服务端归属:`ControllerServer._ListFlyShotTraj`
|
||||
- 协议 / 命令线索:命令名 `ListFlyShotTraj` 已坐实;客户端与服务端字符串都出现 `GetNextListFlyShotTraj`,说明底层列举很可能是迭代式获取,而不是一次性返回整个数组
|
||||
- 返回值与默认值:直接返回轨迹名称列表
|
||||
- 典型工作流位置:查看当前服务端已登记的飞拍轨迹
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py`、`ControllerServer_analysis.md`、`libControllerClient.so`、`ControllerServer` 字符串
|
||||
- 置信度:高
|
||||
- 待确认点:高层 JSON 是否真的直接返回数组,还是客户端内部循环拉取后再拼成数组,当前未完全恢复
|
||||
|
||||
### `ExecuteFlyShotTraj`
|
||||
|
||||
- C++ 公开签名:`bool ExecuteFlyShotTraj(const std::string &name, const bool move_to_start = false, const std::string &method = "icsp", bool save_traj = false, bool use_cache = false);`
|
||||
- Python 包装形态:`c.ExecuteFlyShotTraj(name="002", move_to_start=True, method="icsp", save_traj=True, use_cache=False) -> bool`
|
||||
- 服务端归属:`ControllerServer._ExecuteFlyShotTraj`
|
||||
- 协议 / 命令线索:命令名 `ExecuteFlyShotTraj` 已坐实;字符串中出现 `move_to_start`、`use_cache`;伪代码级逆向已恢复其主流程
|
||||
- 返回值与默认值:默认 `move_to_start=false`、`method="icsp"`、`save_traj=false`、`use_cache=false`
|
||||
- 典型工作流位置:对已存在的飞拍轨迹定义执行“生成 + 挂接 DO 时间轴 + 执行”
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.cpp`、`UseControllerClient.py`、`UseRealRobot.py`、SDK 手册、`ControllerServer_analysis.md`、`Trajectory_generation_algorithm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:JSON 包结构未恢复;`use_cache` 的缓存键是否只按 `name`,当前从伪代码判断是,但未见更底层证据
|
||||
|
||||
### `SaveTrajInfo`
|
||||
|
||||
- C++ 公开签名:`bool SaveTrajInfo(const std::string &name, const std::string &method = "icsp");`
|
||||
- Python 包装形态:未见运行样例,但包装库和服务端都有明确字符串;语义可由手册和分析文档确认
|
||||
- 服务端归属:`ControllerServer._SaveTrajInfo`
|
||||
- 协议 / 命令线索:命令名 `SaveTrajInfo` 已坐实;字符串中可见 `SaveTrajInfo {} success/failed`
|
||||
- 返回值与默认值:默认 `method="icsp"`;`self-adapt-icsp` 在执行时保存分析文件会回落成 `icsp` 导出语义
|
||||
- 典型工作流位置:按给定 `name + method` 生成并导出轨迹分析文件,例如 `JointTraj.txt`、`CartDetialTraj.txt`
|
||||
- 证据来源:`ControllerClient.h`、`ControllerServer_analysis.md`、`Trajectory_generation_algorithm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:Python 包装是否直接暴露该方法并返回 `bool`,虽然字符串存在,但公开示例未调用
|
||||
|
||||
### `IsFlyShotTrajValid`
|
||||
|
||||
- C++ 公开签名:`bool IsFlyShotTrajValid(double &time, const std::string &name, const std::string &method = "icsp", bool save_traj = false);`
|
||||
- Python 包装形态:`valid, time_sec = c.IsFlyShotTrajValid("EOL9_EAU_90", "icsp", save_traj=True)`
|
||||
- 服务端归属:`ControllerServer._IsFlyShotTrajValid`
|
||||
- 协议 / 命令线索:命令名 `IsFlyShotTrajValid` 已坐实;作用是“生成 + 合法性检查 + 返回轨迹总时长”
|
||||
- 返回值与默认值:默认 `method="icsp"`、`save_traj=false`;C++ 为 `bool + out double`;Python 为 `(bool, float)`
|
||||
- 典型工作流位置:在执行飞拍轨迹前预校验;也可与 `save_traj=True` 结合导出分析文件
|
||||
- 证据来源:`ControllerClient.h`、`UseControllerClient.py` 中的注释样例、`ControllerServer_analysis.md`、`Trajectory_generation_algorithm_analysis.md`、二进制字符串
|
||||
- 置信度:高
|
||||
- 待确认点:`method="self-adapt-icsp"` 是否被该接口完整支持,分析文档显示公开手册更强调 `icsp` / `doubles`,而示例注释里又出现 `self-adapt-icsp`,这里仍需后续抓包或真环境验证
|
||||
|
||||
## 8. 四条旧 SDK 工作流
|
||||
|
||||
### 8.1 初始化工作流
|
||||
|
||||
```text
|
||||
ControllerClient()
|
||||
-> ConnectServer("127.0.0.1", 50001)
|
||||
-> SetUpRobot("FANUC_LR_Mate_200iD") 或 SetUpRobotFromEnv(...)
|
||||
-> IsSetUp()
|
||||
-> GetName()
|
||||
-> GetDoF()
|
||||
-> SetShowTCP(...)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 这是最常见的仿真或真机前置流程。
|
||||
- `SetUpRobot` 是旧说明里明确要求首先执行的服务端初始化动作。
|
||||
|
||||
### 8.2 控制器状态工作流
|
||||
|
||||
```text
|
||||
SetActiveController(sim=True/False)
|
||||
-> Connect(robot_ip)
|
||||
-> EnableRobot(buffer_size=2)
|
||||
-> GetSpeedRatio() / SetSpeedRatio(...)
|
||||
-> GetTCP() / SetTCP(...)
|
||||
-> GetIO() / SetIO(...)
|
||||
-> StopMove()
|
||||
-> DisableRobot()
|
||||
-> Disconnect()
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 真机样例会使用 `sim=False`。
|
||||
- `StopMove()` 之后,Python 示例里会再次 `EnableRobot()`,说明停止运动后常伴随重新使能。
|
||||
|
||||
### 8.3 普通轨迹工作流
|
||||
|
||||
```text
|
||||
GetJointPosition()
|
||||
-> GetPose()
|
||||
-> GetNearestIK(pose, seed)
|
||||
-> MoveJoint(home_joint)
|
||||
-> ExecuteTrajectory(waypoints, method="icsp", save_traj=True)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 输入是关节空间稀疏 waypoint。
|
||||
- `ExecuteTrajectory` 至少支持 `icsp` 与 `doubles`。
|
||||
|
||||
### 8.4 飞拍轨迹工作流
|
||||
|
||||
#### 方案 A:轨迹名已在配置中存在
|
||||
|
||||
```text
|
||||
name
|
||||
-> IsFlyShotTrajValid(name, "icsp", save_traj=True)
|
||||
-> ExecuteFlyShotTraj(name, move_to_start=True, method="icsp", save_traj=True, use_cache=False)
|
||||
-> SaveTrajInfo(name, "icsp")
|
||||
```
|
||||
|
||||
#### 方案 B:客户端动态上传飞拍轨迹
|
||||
|
||||
```text
|
||||
UploadFlyShotTraj(name, waypoints, shot_flags, offset_values, addrs)
|
||||
-> ListFlyShotTraj()
|
||||
-> IsFlyShotTrajValid(name, "icsp", save_traj=True)
|
||||
-> ExecuteFlyShotTraj(name, move_to_start=True, method="self-adapt-icsp", save_traj=True, use_cache=True)
|
||||
-> DeleteFlyShotTraj(name)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `UploadFlyShotTraj` 只负责登记轨迹定义。
|
||||
- `IsFlyShotTrajValid` 负责“生成 + 合法性检查”。
|
||||
- `ExecuteFlyShotTraj` 负责“生成 + 挂接 `TrajectoryDO` + 执行”。
|
||||
- `SaveTrajInfo` 负责导出分析文件。
|
||||
|
||||
## 9. 已知高置信协议线索
|
||||
|
||||
当前能直接用于后续实现的高置信协议结论如下:
|
||||
|
||||
- 传输层为 `TCP + JSON` 风格协议,不是 HTTP/gRPC。
|
||||
- JSON 层至少存在 `method` 字段,服务端存在 `_ClientCB` 与 `_IsJsonValid`。
|
||||
- 命令通道字段已确认:
|
||||
- `GetSpeedRatio`:`MsgID = 0x2206`
|
||||
- `SetSpeedRatio`:`MsgID = 0x2207`
|
||||
- `GetIO`:`MsgID = 0x2208`
|
||||
- `SetIO`:`MsgID = 0x2209`
|
||||
- 飞拍轨迹相关额外字符串线索:
|
||||
- `StartUploadFlyShotTraj`
|
||||
- `EndUploadFlyShotTraj`
|
||||
- `GetNextListFlyShotTraj`
|
||||
- `move_to_start`
|
||||
- `use_cache`
|
||||
- `shot_flags`
|
||||
- `offset_values`
|
||||
- `addr` / `addrs`
|
||||
|
||||
## 10. 待确认问题
|
||||
|
||||
以下问题本轮故意保留,不冒充已确认结论:
|
||||
|
||||
1. `50001/TCP+JSON` 请求 JSON 的精确 envelope 结构、字段必填规则、响应包统一格式。
|
||||
2. `GetServerVersion` 在高层 JSON 中的完整请求 / 响应字段。
|
||||
3. `GetClientVersion` 的实际版本字符串来源,以及 Python 包装失败路径。
|
||||
4. `ListFlyShotTraj` 是高层一次性返回数组,还是客户端内部循环 `GetNextListFlyShotTraj` 后再拼装列表。
|
||||
5. `UploadFlyShotTraj` 是否采用开始 / 数据 / 结束的多阶段上传协议。
|
||||
6. `IsFlyShotTrajValid` 对 `self-adapt-icsp` 的真实支持边界。
|
||||
7. `SetTCP` / `GetTCP` 在高层 JSON 中是否暴露 `tcp_id` 概念。
|
||||
8. `SetActiveController` 切换控制器时是否会隐式触发 `_DisconnectAll`。
|
||||
|
||||
## 11. 后续实现使用方式
|
||||
|
||||
等继续扩展 `Flyshot.ControllerClientCompat` 时,建议按以下顺序使用本文档:
|
||||
|
||||
1. 先把 32 个 API 按本文档拆成命令表。
|
||||
2. 先实现高置信、状态简单的接口:
|
||||
- `GetServerVersion`
|
||||
- `SetUpRobot`
|
||||
- `IsSetUp`
|
||||
- `GetName`
|
||||
- `GetDoF`
|
||||
- `GetSpeedRatio`
|
||||
- `SetSpeedRatio`
|
||||
- `GetIO`
|
||||
- `SetIO`
|
||||
3. 再实现返回复杂结构的接口:
|
||||
- `GetTCP`
|
||||
- `GetJointPosition`
|
||||
- `GetPose`
|
||||
- `GetNearestIK`
|
||||
4. 最后实现飞拍轨迹相关接口,并把本文档中的“待确认问题”逐项收敛成兼容测试。
|
||||
@@ -0,0 +1,271 @@
|
||||
# Minimal Runtime Orchestration Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Build the first real execution slice after the HTTP-only refactor by routing `ExecuteTrajectory` and `ExecuteFlyShotTraj` through planning, triggering, and a new minimal FANUC runtime project instead of in-memory last-point assignment.
|
||||
|
||||
**Architecture:** Keep `Flyshot.Server.Host` as a pure HTTP adapter and keep uploaded program state in `Flyshot.ControllerClientCompat`, but move controller runtime state into a new `Flyshot.Runtime.Fanuc` project and add a focused planning/orchestration helper in `Flyshot.ControllerClientCompat`. Ordinary trajectory execution will use `ICspPlanner`; uploaded flyshot execution will use `SelfAdaptIcspPlanner` plus `ShotTimelineBuilder`, then hand the resulting `TrajectoryResult` to the runtime.
|
||||
|
||||
**Tech Stack:** C#, .NET 8, xUnit, existing `Flyshot.Core.Domain`, `Flyshot.Core.Planning`, `Flyshot.Core.Triggering`, ASP.NET Core DI.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add Runtime Contracts And Minimal FANUC Runtime
|
||||
|
||||
**Files:**
|
||||
- Create: `src/Flyshot.Runtime.Common/IControllerRuntime.cs`
|
||||
- Create: `src/Flyshot.Runtime.Fanuc/Flyshot.Runtime.Fanuc.csproj`
|
||||
- Create: `src/Flyshot.Runtime.Fanuc/FanucControllerRuntime.cs`
|
||||
- Modify: `FlyshotReplacement.sln`
|
||||
- Modify: `src/Flyshot.Server.Host/Flyshot.Server.Host.csproj`
|
||||
- Modify: `src/Flyshot.Server.Host/Program.cs`
|
||||
- Test: `tests/Flyshot.Core.Tests/RuntimeOrchestrationTests.cs`
|
||||
|
||||
- [x] **Step 1: Write the failing runtime test**
|
||||
|
||||
```csharp
|
||||
[Fact]
|
||||
public void FanucControllerRuntime_ExecuteTrajectory_UpdatesSnapshotAndFinalJointPositions()
|
||||
{
|
||||
var runtime = new FanucControllerRuntime();
|
||||
var robot = TestRobotFactory.CreateRobotProfile();
|
||||
runtime.ResetRobot(robot, "FANUC_LR_Mate_200iD");
|
||||
runtime.SetActiveController(sim: false);
|
||||
runtime.Connect("192.168.10.101");
|
||||
runtime.EnableRobot(bufferSize: 2);
|
||||
|
||||
var result = new TrajectoryResult(
|
||||
programName: "demo",
|
||||
method: PlanningMethod.Icsp,
|
||||
isValid: true,
|
||||
duration: TimeSpan.FromSeconds(1.2),
|
||||
shotEvents: Array.Empty<ShotEvent>(),
|
||||
triggerTimeline: Array.Empty<TrajectoryDoEvent>(),
|
||||
artifacts: Array.Empty<TrajectoryArtifact>(),
|
||||
failureReason: null,
|
||||
usedCache: false,
|
||||
originalWaypointCount: 4,
|
||||
plannedWaypointCount: 4);
|
||||
|
||||
runtime.ExecuteTrajectory(result, [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
|
||||
|
||||
var snapshot = runtime.GetSnapshot();
|
||||
Assert.Equal("Connected", snapshot.ConnectionState);
|
||||
Assert.False(snapshot.IsInMotion);
|
||||
Assert.Equal([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], snapshot.JointPositions);
|
||||
}
|
||||
```
|
||||
|
||||
- [x] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter FanucControllerRuntime_ExecuteTrajectory_UpdatesSnapshotAndFinalJointPositions -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: FAIL because `FanucControllerRuntime` and `IControllerRuntime` do not exist.
|
||||
|
||||
- [x] **Step 3: Write the minimal runtime contracts and implementation**
|
||||
|
||||
```csharp
|
||||
public interface IControllerRuntime
|
||||
{
|
||||
void ResetRobot(RobotProfile robot, string robotName);
|
||||
void SetActiveController(bool sim);
|
||||
void Connect(string robotIp);
|
||||
void Disconnect();
|
||||
void EnableRobot(int bufferSize);
|
||||
void DisableRobot();
|
||||
void StopMove();
|
||||
double GetSpeedRatio();
|
||||
void SetSpeedRatio(double ratio);
|
||||
IReadOnlyList<double> GetTcp();
|
||||
void SetTcp(double x, double y, double z);
|
||||
bool GetIo(int port, string ioType);
|
||||
void SetIo(int port, bool value, string ioType);
|
||||
IReadOnlyList<double> GetJointPositions();
|
||||
IReadOnlyList<double> GetPose();
|
||||
ControllerStateSnapshot GetSnapshot();
|
||||
void ExecuteTrajectory(TrajectoryResult result, IReadOnlyList<double> finalJointPositions);
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
public sealed class FanucControllerRuntime : IControllerRuntime
|
||||
{
|
||||
// Stage-1 runtime: owns controller state in one place so later sockets can replace internals without rewriting compat service.
|
||||
}
|
||||
```
|
||||
|
||||
- [x] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter FanucControllerRuntime_ExecuteTrajectory_UpdatesSnapshotAndFinalJointPositions -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: PASS.
|
||||
|
||||
### Task 2: Add Planning And Triggering Orchestration For Execution
|
||||
|
||||
**Files:**
|
||||
- Create: `src/Flyshot.ControllerClientCompat/PlannedExecutionBundle.cs`
|
||||
- Create: `src/Flyshot.ControllerClientCompat/ControllerClientTrajectoryOrchestrator.cs`
|
||||
- Modify: `src/Flyshot.ControllerClientCompat/Flyshot.ControllerClientCompat.csproj`
|
||||
- Modify: `tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj`
|
||||
- Test: `tests/Flyshot.Core.Tests/RuntimeOrchestrationTests.cs`
|
||||
|
||||
- [x] **Step 1: Write the failing orchestration tests**
|
||||
|
||||
```csharp
|
||||
[Fact]
|
||||
public void ControllerClientTrajectoryOrchestrator_PlanOrdinaryTrajectory_RejectsThreeTeachPoints()
|
||||
{
|
||||
var orchestrator = new ControllerClientTrajectoryOrchestrator();
|
||||
var robot = TestRobotFactory.CreateRobotProfile();
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
orchestrator.PlanOrdinaryTrajectory(robot,
|
||||
[
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[0.5, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[1.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ControllerClientTrajectoryOrchestrator_PlanUploadedFlyshot_BuildsShotTimeline()
|
||||
{
|
||||
var orchestrator = new ControllerClientTrajectoryOrchestrator();
|
||||
var robot = TestRobotFactory.CreateRobotProfile();
|
||||
var uploaded = TestRobotFactory.CreateUploadedTrajectoryWithSingleShot();
|
||||
|
||||
var bundle = orchestrator.PlanUploadedFlyshot(robot, uploaded);
|
||||
|
||||
Assert.True(bundle.Result.IsValid);
|
||||
Assert.Single(bundle.Result.ShotEvents);
|
||||
Assert.Single(bundle.Result.TriggerTimeline);
|
||||
}
|
||||
```
|
||||
|
||||
- [x] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter ControllerClientTrajectoryOrchestrator -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: FAIL because the orchestrator types do not exist.
|
||||
|
||||
- [x] **Step 3: Write the minimal orchestration layer**
|
||||
|
||||
```csharp
|
||||
public sealed class PlannedExecutionBundle
|
||||
{
|
||||
public PlannedExecutionBundle(PlannedTrajectory plannedTrajectory, ShotTimeline shotTimeline, TrajectoryResult result)
|
||||
{
|
||||
PlannedTrajectory = plannedTrajectory;
|
||||
ShotTimeline = shotTimeline;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public PlannedTrajectory PlannedTrajectory { get; }
|
||||
public ShotTimeline ShotTimeline { get; }
|
||||
public TrajectoryResult Result { get; }
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
public sealed class ControllerClientTrajectoryOrchestrator
|
||||
{
|
||||
public PlannedExecutionBundle PlanOrdinaryTrajectory(RobotProfile robot, IReadOnlyList<IReadOnlyList<double>> waypoints) { ... }
|
||||
public PlannedExecutionBundle PlanUploadedFlyshot(RobotProfile robot, ControllerClientCompatUploadedTrajectory uploaded) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter ControllerClientTrajectoryOrchestrator -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: PASS.
|
||||
|
||||
### Task 3: Rewire ControllerClientCompatService To Runtime + Orchestrator
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/Flyshot.ControllerClientCompat/ControllerClientCompatService.cs`
|
||||
- Modify: `src/Flyshot.ControllerClientCompat/ControllerClientCompatServiceCollectionExtensions.cs`
|
||||
- Modify: `src/Flyshot.ControllerClientCompat/IControllerClientCompatService.cs`
|
||||
- Modify: `tests/Flyshot.Server.IntegrationTests/LegacyHttpApiCompatibilityTests.cs`
|
||||
- Modify: `tests/Flyshot.Server.IntegrationTests/ControllerClientCompatRegistrationTests.cs`
|
||||
- Test: `tests/Flyshot.Core.Tests/RuntimeOrchestrationTests.cs`
|
||||
- Test: `tests/Flyshot.Server.IntegrationTests/LegacyHttpApiCompatibilityTests.cs`
|
||||
|
||||
- [x] **Step 1: Write the failing compat-service test**
|
||||
|
||||
```csharp
|
||||
[Fact]
|
||||
public void ControllerClientCompatService_ExecuteTrajectory_RejectsThreeTeachPointsAfterPlanningIsIntroduced()
|
||||
{
|
||||
var service = TestRobotFactory.CreateCompatService();
|
||||
service.SetUpRobot("FANUC_LR_Mate_200iD");
|
||||
service.SetActiveController(sim: false);
|
||||
service.Connect("192.168.10.101");
|
||||
service.EnableRobot(2);
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
service.ExecuteTrajectory(
|
||||
[
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[0.5, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[1.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
]));
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter ControllerClientCompatService_ExecuteTrajectory_RejectsThreeTeachPointsAfterPlanningIsIntroduced -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: FAIL because current service still treats ordinary execution as "move to last waypoint".
|
||||
|
||||
- [x] **Step 3: Rewire service to the runtime and orchestrator**
|
||||
|
||||
```csharp
|
||||
public sealed class ControllerClientCompatService : IControllerClientCompatService
|
||||
{
|
||||
private readonly IControllerRuntime _runtime;
|
||||
private readonly ControllerClientTrajectoryOrchestrator _trajectoryOrchestrator;
|
||||
|
||||
public void ExecuteTrajectory(IReadOnlyList<IReadOnlyList<double>> waypoints)
|
||||
{
|
||||
var robot = RequireActiveRobot();
|
||||
var bundle = _trajectoryOrchestrator.PlanOrdinaryTrajectory(robot, waypoints);
|
||||
_runtime.ExecuteTrajectory(bundle.Result, bundle.PlannedTrajectory.PlannedWaypoints[^1].Positions);
|
||||
}
|
||||
|
||||
public void ExecuteTrajectoryByName(string name)
|
||||
{
|
||||
var robot = RequireActiveRobot();
|
||||
var uploaded = RequireUploadedTrajectory(name);
|
||||
var bundle = _trajectoryOrchestrator.PlanUploadedFlyshot(robot, uploaded);
|
||||
_runtime.ExecuteTrajectory(bundle.Result, bundle.PlannedTrajectory.PlannedWaypoints[^1].Positions);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run focused tests to verify green**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter "ControllerClientCompatService|ControllerClientTrajectoryOrchestrator|FanucControllerRuntime" -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 5: Run integration verification**
|
||||
|
||||
Run: `dotnet test tests/Flyshot.Server.IntegrationTests/Flyshot.Server.IntegrationTests.csproj -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: PASS, with existing HTTP compatibility tests still green.
|
||||
|
||||
### Task 4: Verify Solution Build And Update Progress Docs
|
||||
|
||||
**Files:**
|
||||
- Modify: `README.md`
|
||||
- Modify: `AGENTS.md`
|
||||
- Modify: `docs/controller-client-api-compatibility-requirements.md`
|
||||
|
||||
- [x] **Step 1: Update docs to reflect the new stage**
|
||||
|
||||
```markdown
|
||||
- [x] 落地最小 FANUC 运行时骨架
|
||||
- [x] 将 ExecuteTrajectory / ExecuteFlyShotTraj 接入 Planning + Triggering + Runtime
|
||||
- [ ] 落地真实 10010 / 10012 / 60015 通讯
|
||||
- [ ] 落地 Web 状态页
|
||||
```
|
||||
|
||||
- [x] **Step 2: Run final build**
|
||||
|
||||
Run: `dotnet build FlyshotReplacement.sln --no-restore -v minimal -m:1 -nodeReuse:false`
|
||||
Expected: PASS with 0 errors.
|
||||
Reference in New Issue
Block a user