Files
FlyShotHost/docs/planning-duration-mismatch-investigation.md
yunxiao.zhu af65ca03a0 feat(compat): 补齐飞拍执行等待与 FANUC 状态驱动链路
- 为 ExecuteFlyShotTraj 补齐 wait 语义,并让 move_to_start
  先完成临时 PTP 运动后再启动正式飞拍轨迹
- 将 J519 命令发送改为由机器人 UDP status sequence 驱动,
  避免在未收到状态包时主动发周期命令
- 将 10010 状态通道关节字段统一按 JointRadians 命名,
  同步更新运行时读取逻辑与协议测试
- 新增 FANUC 10010 状态帧、流运动手册和 Python client
  逆向文档,并更新 README 与兼容需求说明
- 补充兼容层编排测试与 HTTP 集成测试,覆盖 wait 和
  move_to_start 串行化行为
2026-05-03 19:29:31 +08:00

592 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 轨迹规划时长差异调查记录
## 背景
当前新 C# 规划链路在不额外缩放规划约束时,部分真实现场轨迹会比旧 RVBUST/FlyingShot 导出的 `JointTraj.txt` 更短。
最典型现象:
- 真实 `Rvbust/uttc-20260428/Data/JointTraj.txt``UTTC_MS11` 总时长约 `7.403046s`
- 新 C# 当前默认规划输出:`src/Flyshot.Server.Host/bin/Debug/net8.0/Config/Data/UTTC_MS11/JointTraj.txt` 总时长约 `5.495112s`
- 实体机复核确认:修改运行时 `speed_ratio` 不影响 `IsFlyshotTrajectoryValid` / `SaveTrajectoryInfo` 生成的 `JointTraj.txt` 规划时长。
因此,本问题不应继续归因到运行时 `speed_ratio`,而应归到规划阶段的有效关节约束来源。
## 已确认事实
1. `speed_ratio` 是运行执行倍率。
UTTC 抓包和实体机测试都显示,`speed_ratio=0.7` 会拉伸 J519 实际下发时间和包数,但不会改变已生成的 `JointTraj.txt` 规划时间轴。
2. `JointTraj.txt` 是规划结果点位。
`saveTrajectory` / `SaveTrajInfo` / `IsFlyshotTrajectoryValid(saveTrajectory=true)` 生成的 `JointTraj.txt` 表示规划后的 sparse waypoint 时间轴,不是上传的原始飞拍路径,也不是 J519 逐周期下发点。
3. UTTC_MS11 的差异是整条时间轴等比例缩放。
`UTTC_MS11`,真实时间和当前 C# 默认规划时间之间的比例在所有 waypoint 上都一致:
```text
C#默认规划时间 / 真实规划时间 = 5.495112 / 7.403046 = 0.742277
```
这说明路点顺序、相对分段时间和 ICSP 主要逻辑基本一致,差异更像是规划时传入的有效 `vel/acc/jerk` joint limits 存在整体倍率差异。
4. 现场配置中没有找到显式倍率字段。
已检查现场现有配置,未发现类似 `planning_speed_scale` 或等价字段保存了 `0.742277`、`0.7`、`0.9` 等规划倍率值。
## 样本对比
| 样本 | 真实 `JointTraj.txt` 时长 | 当前/已有新规划时长 | 等效倍率 `新规划/真实` | 说明 |
| --- | ---: | ---: | ---: | --- |
| `UTTC_MS11` | `7.403046s` | `5.495112s` | `0.742277` | 所有 waypoint 时间均为同一比例 |
| `UTTC_MS11_TEST01` | `7.805885s` | `5.814370s` | `0.744870` | `20260428 多点` 新增 1 个路径点后仍几乎是整条时间轴等比例缩放 |
| `EOL10_EAU_0` | `14.849788s` | `10.489800s` | `0.706394` | 同样表现为新规划偏快 |
| `EOL9_EAU_0` / `EOL9_EAU_90` | `6.400851s` | `5.651140s` | `0.882873` | `EOL9 EAU 0` 与 `EOL9 EAU 90` 的真实 `JointTraj.txt` 文件一致 |
| `EOL9_EAU_90` | `6.400851s` | `6.471610s` | `1.011055` | 使用 `speedRatio=0.9 + self-adapt-icsp` 的旧离线结果已接近真实 |
这些样本说明差异不是 `UTTC_MS11` 的个案,也不是一个可以全局写死的常数。不同真实样本对应的等效规划倍率不同。
## `20260428 多点` 新样本对比
2026-04-30 追加现场新样本:
```text
../Rvbust/20260428 多点/RobotConfig.json
../Rvbust/20260428 多点/JointTraj.txt
../Rvbust/20260428 多点/JointDetialTraj.txt
```
该样本中的飞拍程序名为:
```text
UTTC_MS11_TEST01
```
配置摘要:
```text
waypoints=21
shot_flags=21
acc_limit=1
jerk_limit=1
```
实机导出的 `JointTraj.txt`
```text
rows=21
duration=7.805885s
```
用当前 C# `ICspPlanner`、同一个 `LR_Mate_200iD_7L.robot`、同一份 `RobotConfig.json` 规划:
```text
rows=21
duration=5.814370s
C# / 实机 = 0.744870
```
逐点/逐段统计:
```text
point_ratio_std = 2.18e-7
segment_ratio_std = 9.0e-7
max_joint_diff = 5.0e-7 rad
```
这说明:
1. 新样本的路点关节值与 C# 输入基本完全一致,不是解析错点或单位错位。
2. 新增 1 个路径点后C# 与旧系统仍然保持几乎严格的整条时间轴等比例差异。
3. `UTTC_MS11_TEST01` 的倍率 `0.744870` 与原 `UTTC_MS11` 的 `0.742277` 非常接近,进一步支持“同一类 UTTC 现场导出使用了一组更保守的 effective JointLimits”这一判断。
和原 `UTTC_MS11` 对比:
```text
原 UTTC_MS11 实机 rows=20 duration=7.403046s
新 UTTC_MS11_TEST01 实机 rows=21 duration=7.805885s
新增路径点后实机时长增加 0.402839s
```
当前观察不到新增点导致规划形状或局部段比例失真;它更像是在同一套旧系统规划约束下正常增加了一段路径时间。
## `20260430.pcap` 初始化抓包复核
2026-04-30 继续复核现场提供的完整初始化抓包:
```text
../Rvbust/20260428 多点/20260430.pcap
```
抓包总览:
```text
packet_count=4821
tcp_payload_bytes=35302
udp_payload_bytes=451946
```
主要有效负载会话为:
```text
UDP 192.168.10.11:60015 -> 192.168.10.10:56118 260700B
UDP 192.168.10.11:60015 -> 192.168.10.10:48455 127116B
UDP 192.168.10.10:48455 -> 192.168.10.11:60015 62088B
TCP 192.168.10.11:10010 -> 192.168.10.10:42106 35102B
TCP 192.168.10.11:10012 -> 192.168.10.10:33528 106B
TCP 192.168.10.10:33528 -> 192.168.10.11:10012 94B
```
全包搜索以下明文关键字没有命中:
```text
Joint / joint / Limit / limit / vel / acc / jerk / Speed / speed /
Robot / JSON / Traj / ratio / Ratio / GetJoint / SetJoint
```
`TCP 10012` 命令通道按 `doz + length + message_id + body + zod` 解码后,只看到以下初始化/程序命令:
| 方向 | 消息号 | 含义 | 请求体/结果 |
| --- | ---: | --- | --- |
| C->R | `0x0001` | 未知握手 | 空请求 |
| R->C | `0x0001` | 未知握手响应 | `result=0` |
| C->R | `0x2000` | 未知版本/状态查询 | 空请求 |
| R->C | `0x2000` | 未知版本/状态响应 | 包含 `0.6.0` 字符串 |
| C->R | `0x2100` | `ResetRobot` | 空请求 |
| R->C | `0x2100` | `ResetRobot` 响应 | `result=0` |
| C->R | `0x2003` | `GetProgramStatus("RVBUSTSM")` | 程序名 `RVBUSTSM` |
| R->C | `0x2003` | 程序状态响应 | `result=0, status=1` |
| C->R | `0x2102` | `StartProgram("RVBUSTSM")` | 程序名 `RVBUSTSM` |
| R->C | `0x2102` | 启动响应 | `result=0` |
没有看到:
- `0x2207 SetSpeedRatio`
- `0x2206 GetSpeedRatio`
- `0x2200/0x2201 GetTcp/SetTcp`
- `0x2208/0x2209 GetIo/SetIo`
- 任何疑似 `JointLimits / velocity / acceleration / jerk` 的参数帧
`TCP 10010` 状态通道只有机器人侧到上位机的状态帧:
```text
390 个 90B 状态帧
1 个 2B 连接前导
```
这些帧与已逆向的 `pose[6] + joint[6] + external_axes[3] + raw_tail_words[4]` 状态布局一致,不携带规划约束。
`UDP 60015` J519 通道只出现既有三类长度:
```text
C->R 8B 初始化包 1 个
C->R 64B 目标关节命令包 970 个
R->C 132B 反馈包 2938 个
```
没有出现其他长度的 UDP 参数帧。64B 命令包是 J519 逐周期目标关节/IO 命令132B 是机器人反馈;这条链路承载的是执行期 streaming motion而不是旧 RVBUST 规划器的 joint limit 配置。
阶段结论:
```text
20260430.pcap 只覆盖机器人侧 10010 / 10012 / 60015 通信。
它没有 50001/TCP+JSON也没有 ControllerServer/Python 客户端到旧服务端的配置调用。
因此,这份抓包看不到旧规划阶段的 effective JointLimits。
```
这并不否定“旧系统规划瞬间存在更保守的 effective JointLimits”这一方向它只说明这份初始化抓包不是抓取该信息的位置。若要抓到这类限制需要抓旧服务端内部 `_GetJointLimits/_SetJointLimits`,或者抓上层 Python/GUI 与 ControllerServer 之间的配置/规划调用,而不是只抓机器人控制柜侧的执行链路。
## `all-50001.pcap` 本机 50001 抓包复核
2026-04-30 追加复核本机所有网卡抓包:
```text
../Rvbust/20260428 多点/all-50001.pcap
SHA256=C3543F314AE446CABA8E2097EFAFB36F39DD73FFE166F051A1F9387CFD15990F
```
该文件由 `tcpdump -i any` 生成pcap linktype 为 `113`,即 Linux cooked capture。按 SLL 头解析后,确认抓到了本机到本机的 `50001` TCP JSON 通信:
```text
192.168.1.100:35814 -> 192.168.1.100:50001 217B payload
192.168.1.100:50001 -> 192.168.1.100:35814 91B payload
```
客户端到服务端的完整 JSON 命令序列为:
```json
{"reply_from_client":true}
{"cmd":"SetUpRobot","robot_name":"FANUC_LR_Mate_200iD_7L"}
{"cmd":"IsSetUp"}
{"cmd":"SetActiveController","sim":false}
{"cmd":"Connect","ip":"192.168.10.11"}
{"buffer_size":8,"cmd":"EnableRobot"}
```
服务端返回为:
```json
{"test_from_server": true}
{"res": true}
{"res": true}
{"res": true}
{"res": true}
{"res": true}
```
这说明本次抓包确实覆盖到了旧 `50001` 控制链路,但当前只包含机器人初始化、连接和使能流程。里面没有看到:
- `ExecuteFlyShotTraj`
- `SaveTrajInfo`
- `IsFlyShotTrajValid`
- `GetJointLimits / SetJointLimits`
- `SetVelocityLimit / SetAccelerationLimit / SetJerkLimit`
- 任何包含 `acc_limit / jerk_limit / JointLimits / velocity / acceleration / jerk` 的配置 JSON
阶段结论:
```text
all-50001.pcap 已经证明抓包接口选对了;
但这次只抓到了初始化链路,没有抓到规划/保存轨迹那一刻的 50001 请求。
```
该待确认点已由下一节 `all-50001-plan.pcap` 覆盖:后续抓包确实抓到了 `ExecuteFlyShotTraj(save_traj=true,use_cache=false)`,仍未出现规划限制字段。
## `all-50001-plan.pcap` 规划执行抓包复核
2026-04-30 追加复核规划/执行动作期间的本机 50001 抓包:
```text
../Rvbust/20260428 多点/all-50001-plan.pcap
SHA256=311DC45B4789ED11EBEAB7A396E2EE7A16EC8534E20F10127FB43BBAD823C21D
```
该抓包同样是 `tcpdump -i any` 生成的 Linux cooked capture已按 SLL 头解析。有效 TCP JSON 流为:
```text
192.168.1.100:35814 -> 192.168.1.100:50001 2612B payload
192.168.1.100:50001 -> 192.168.1.100:35814 516B payload
```
客户端到服务端的关键命令序列为:
```json
{"cmd":"ListFlyShotTraj"}
{"cmd":"GetNextListFlyShotTraj","count":0}
{"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}
{"cmd":"StartUploadFlyShotTraj","name":"UTTC_MS11"}
{"cmd":"UploadFlyShotTraj", "...":"4 批共 20 个 waypoint每批包含 waypoints / shot_flags / offset_values / addrs"}
{"cmd":"EndUploadFlyShotTraj","name":"UTTC_MS11"}
{"cmd":"ListFlyShotTraj"}
{"cmd":"GetNextListFlyShotTraj","count":0}
```
两次执行请求均为:
```json
{
"cmd": "ExecuteFlyShotTraj",
"method": "icsp",
"move_to_start": true,
"name": "UTTC_MS11_TEST01",
"save_traj": true,
"use_cache": false,
"wait": true
}
```
它们前面的速度倍率分别为:
```text
第一次SetSpeedRatio ratio=0.5
第二次SetSpeedRatio ratio=1.0
```
服务端对所有命令均返回:
```json
{"res": true}
```
这份抓包确认了两点:
1. 公开 50001 JSON 链路确实会把 `SetSpeedRatio` 和 `ExecuteFlyShotTraj(save_traj=true,use_cache=false)` 发给旧服务端。
2. 即便覆盖到了实际执行/保存轨迹动作,请求中仍没有出现 `GetJointLimits / SetJointLimits`、`SetVelocityLimit / SetAccelerationLimit / SetJerkLimit`,也没有 `acc_limit / jerk_limit / velocity / acceleration / jerk / JointLimits` 等规划限制字段。
因此,当前能从 50001 抓包确认的是:
```text
规划方法、是否保存轨迹、是否使用缓存、是否等待执行,都会显式发到旧服务端;
速度倍率通过 SetSpeedRatio 单独发到旧服务端;
但 effective JointLimits 没有通过这次公开 50001 JSON 请求显式传入。
```
这进一步收敛了差异来源:如果旧系统规划时确实使用了更保守的 joint limits它更可能来自旧服务端在 `SetUpRobot("FANUC_LR_Mate_200iD_7L")` 后加载/初始化的内部状态,或来自 GUI/服务端内部私有路径,而不是这次 50001 公开 JSON 在 `ExecuteFlyShotTraj` 请求中传入的字段。
## Joint3/Joint2 couple A/B 测试
2026-04-30 追加测试:为了验证 `.robot` 中 `Joint3` 对 `Joint2` 的 couple 是否是规划时长差异主因,使用 Python ICSP demo 做了多组只读 A/B。
测试模型来自:
```text
flyshot-replacement/Config/Models/LR_Mate_200iD_7L.robot
```
其中 `Joint3` 的 couple 信息为:
```text
q3_kin = q3_raw + q2_kin * 1.0 + 0.0
```
测试变体:
- `raw`:原始 6 轴路点直接规划。
- `replace_q3=q3+q2`:规划输入中把第 3 轴替换为耦合后的运动学角。
- `replace_q3=q3-q2`:反向符号试探,排除符号理解错误。
- `raw+constraint(q3+q2)`:保留原始 6 轴,同时追加虚拟约束轴 `q3+q2`,用 Joint3 的 `vel/acc/jerk` 限值检查。
- `raw+constraint(q3-q2)`:反向符号的虚拟约束轴试探。
结果:
| 样本 | 真实时长 | 最接近变体 | 变体时长 | 变体/真实 | 与真实差值 | 结论 |
| --- | ---: | --- | ---: | ---: | ---: | --- |
| `UTTC_MS11` | `7.403046s` | `raw` | `5.495112s` | `0.742277` | `1.907934s` | couple 变体全部更短,且破坏原本严格等比例关系 |
| `EOL10_EAU_0` | `14.849788s` | `replace_q3=q3+q2` | `10.600711s` | `0.713863` | `4.249077s` | couple 只改善约 `0.11s`,距离真实仍差 `4.25s` |
| `EOL9_EAU_90` | `6.400851s` | `raw+constraint(q3+q2)` | `5.748560s` | `0.898093` | `0.652291s` | couple 约束有小幅影响,但仍不足以解释真实时长 |
关键观察:
1. `UTTC_MS11` 的 `raw` 规划时间和真实时间保持严格等比例,`point_ratio_std=0`、`segment_ratio_std≈0`;加入 couple 后反而出现分段比例波动。
2. `EOL10_EAU_0` 与 `EOL9_EAU_90` 的 couple 变体只带来小幅时长变化,不能解释 10% 到 30% 级别的差异。
3. 因此,当前证据不支持“只要把 Joint3/Joint2 couple 带入 ICSP就能对齐旧 RVBUST 规划时长”。
阶段结论:
`Joint3` couple 确实是 C# 与 Python demo 当前都没有进入规划约束的缺口,但它不像本轮时长 mismatch 的主因。它更可能影响 FK/运动学边界或少数局部段约束;当前主要时长差异仍更像有效 joint limits、旧系统运行期规划倍率、或 RPS 内部 ICSP 参数来源不同。
## 同模型复核与更可能的差异层
2026-04-30 继续复核:
1. 当前仓库固化的模型与旧 `FlyingShot/FlyingShot/Models/LR_Mate_200iD_7L.robot` 字节哈希一致。
2. `ControllerClientCompatRobotCatalog` 当前会把 `FANUC_LR_Mate_200iD` 和 `FANUC_LR_Mate_200iD_7L` 都映射到 `LR_Mate_200iD_7L.robot`。
3. `LR_Mate_200iD.robot` 短臂模型的前三轴 `vel/acc/jerk` 比 `7L` 更高。用短臂模型试算会让轨迹更短,不会解释“旧系统真实导出更慢”。
模型 A/B
| 样本 | 真实时长 | `LR_Mate_200iD_7L.robot` | `LR_Mate_200iD.robot` | 结论 |
| --- | ---: | ---: | ---: | --- |
| `UTTC_MS11` | `7.403046s` | `5.495112s` | `5.345600s` | 短臂模型方向更错 |
| `EOL10_EAU_0` | `14.849788s` | `10.489800s` | `10.342456s` | 短臂模型方向更错 |
因此,如果现场确认机器人模型确实一致,差异层就不应继续放在 `.robot` 静态文件本身,而应放在旧服务端规划时的运行态:
- 服务端内部存在 `_GetJointLimits / _SetJointLimits`,说明规划消费的是一份可能被运行期覆写的 `current JointLimits`。
- `ControllerClient.h` 的 `ExecuteFlyShotTraj(..., use_cache=false)` 明确说明旧服务端可以把计算好的轨迹保存在内存中并复用。
- `SaveTrajInfo(name, method)` 没有 `use_cache` 参数,不能仅凭公开头文件判断它一定每次从当前配置重新规划。
当前更合理的解释是:
```text
同一个 .robot
-> SetUpRobot 初始化基础 JointLimits
-> 旧服务端运行期间可能被 _SetJointLimits / 速度倍率联动 / 缓存轨迹 覆盖
-> SaveTrajInfo 或 IsFlyShotTrajValid(save_traj=true) 导出的是真正规划时那份状态
-> 当前 C# 每次用静态 .robot + RobotConfig 重新规划,所以时长更短
```
尤其需要注意:`EOL10_EAU_0` 的 `新规划/真实` 比例为 `0.706394`,接近 `0.7``EOL9_EAU_90` 的比例为 `0.882873`,接近 `0.9`。这不像模型误差,更像历史导出时混入了某个运行态速度/限制倍率。`UTTC_MS11` 的 `0.742277` 不等于抓包确认的执行层 `0.7`,所以不能简单把所有样本都归因到 `SetSpeedRatio`,但“运行态规划约束不是静态模型值”仍是目前最强方向。
## 旧服务端与 GUI 二进制复核
2026-04-30 继续从旧系统二进制字符串中复核,重点看公开 Python/HTTP 层没有暴露出来的运行态对象。
### 服务端确实持有 runtime JointLimits
`../FlyingShot/FlyingShot/Python/ControllerServer/ControllerServer.cpython-37m-x86_64-linux-gnu.so` 中能稳定看到以下方法和关键字:
```text
ControllerServer.ControllerServer._GetJointLimits
ControllerServer.ControllerServer._SetJointLimits
ControllerServer.ControllerServer._IsWaypointInJointLimits
ControllerServer.ControllerServer._IsTrajInJointLimits
ControllerServer.ControllerServer._IsTrajInJerkLimits
ControllerServer.ControllerServer._ExecuteFlyShotTraj
ControllerServer.ControllerServer._SaveTrajInfo
ControllerServer.ControllerServer._IsFlyShotTrajValid
SetVelocityLimit
SetAccelerationLimit
SetJerkLimit
GetMaxVelocity
GetMaxAcceleration
GetMaxJerk
m_acc_limit
m_jerk_limit
save_traj_only
use_cache
```
这比公开 `ControllerClient.h` 暴露的信息更多。它说明旧服务端内部不是只把 `.robot` 静态值直接传给 `TrajectoryRnICSP`,而是存在一份可以查询、设置、校验、再用于规划的运行期 `JointLimits`。
### GUI 也直接接触规划约束与保存逻辑
旧 GUI 二进制里也能看到同一条链:
- `../FlyingShot/FlyingShot/Python/GUI/Robot/RobotManager.cpython-37m-x86_64-linux-gnu.so`
- `GetJointLimits`
- `TrajectoryRnICSP`
- `IsTrajInJointLimits`
- `IsTrajInJerkLimits`
- `acc_limit`
- `jerk_limit`
- `../FlyingShot/FlyingShot/Python/GUI/Robot/RobotConfig.cpython-37m-x86_64-linux-gnu.so`
- `SaveTraj`
- `m_acc_limit`
- `m_jerk_limit`
- `../FlyingShot/FlyingShot/Python/GUI/Panels/FlyshotDockPanel.cpython-37m-x86_64-linux-gnu.so`
- `__SaveTraj`
- `IsTrajInJointLimits`
- `IsTrajInJerkLimits`
- `m_acc_limit`
- `m_jerk_limit`
这说明旧 GUI 的“保存轨迹/检查轨迹”路径很可能不是简单调用公开 `ControllerClient.SaveTrajInfo` 后结束,而是直接拿当前 `JointLimits + acc_limit + jerk_limit` 做规划、合法性检查或保存。
### UAES 接口没有显式对齐 JointLimits
`../flyshot-uaes-interface/main.py` 中 `/execute_flyshot/` 的执行路径是:
```text
c.ExecuteFlyShotTraj(name=name, move_to_start=True, method="icsp", save_traj=True)
```
`/set_speedRatio/` 是单独接口:
```text
c.SetSpeedRatio(speed)
```
同时,`../flyshot-uaes-interface/lib/PyControllerClient.cpython-37m-x86_64-linux-gnu.so` 和 `../flyshot-uaes-interface/lib/libControllerClient.so` 中只看到公开客户端侧的:
```text
GetSpeedRatio
SetSpeedRatio
ExecuteFlyShotTraj
SaveTrajInfo
IsFlyShotTrajValid
JointLimits
```
没有看到客户端侧 `GetJointLimits / SetJointLimits` 符号。也就是说UAES Python 服务本身大概率没有主动把旧服务端的 runtime JointLimits 设置成某个值;如果现场旧导出时的 limits 被改过,更可能来自:
- 旧 GUI 初始化/保存路径;
- 旧服务端内部默认初始化;
- 服务端隐藏 TCP JSON 方法;
- 历史上某次执行/保存后留下的缓存结果。
### 样本文件与配置文件可能不是同一次运行态
新增一个需要警惕的现象:
- `../Rvbust/EOL9 EAU 0/eol9_eau_0.json` 中 `acc_limit=1`、`jerk_limit=1`。
- `../Rvbust/EOL9 EAU 90/eol9_eau_90.json` 中 `acc_limit=0.8`、`jerk_limit=0.8`。
- 但两个目录下保存的真实 `JointTraj.txt` 内容和时长一致。
哈希复核:
```text
EOL9 EAU 0 JointTraj.txt SHA256=DFD8E1130742CFB4ED72F70D0E8CA4E3A16F421E0D0D9D921B9F5177717536EC
EOL9 EAU 90 JointTraj.txt SHA256=DFD8E1130742CFB4ED72F70D0E8CA4E3A16F421E0D0D9D921B9F5177717536EC
eol9_eau_0.json SHA256=354D0D3F71499951976504802C4B2860132D1E4FF753738715A500529CD0BB68
eol9_eau_90.json SHA256=7F854AA227D842CAE734AFA378FEEFA742D797F99FBE536E1B98DF981CD32B27
```
这说明不能默认认为“某个 JSON 文件当前内容”就一定是旁边 `Data/JointTraj.txt` 的生成状态。旧系统的保存文件可能来自缓存、拷贝、历史运行态,或 GUI/服务端中未落盘到该 JSON 的当前 `JointLimits`。
本轮新增证据把方向进一步收敛为:
```text
同一个 .robot 文件本身不是问题核心;
真正影响时长的是旧系统规划瞬间的 effective JointLimits
但这份状态没有出现在现有配置、机器人侧抓包或 50001 公开 JSON 中。
```
如果未来能直接进入旧服务端进程,仍可在 `SaveTrajInfo` / `IsFlyShotTrajValid(save_traj=true)` 前后抓取 `_GetJointLimits` 返回值,并把它与 `.robot` 原始 `vel/acc/jerk` 和当前 JSON 的 `acc_limit/jerk_limit` 做数值对比。但这不再阻塞 replacement 的现场对齐:当前设计默认用显式内部规划加速度参数补齐这份不可见状态。
## 当前判断
当前最可信的解释是:
1. 旧 RVBUST/FlyingShot 生成真实 `JointTraj.txt` 时,规划阶段使用的有效 joint limits 并不总是 `.robot` 文件中的原始 `velocity / acceleration / jerk`。
2. 这些有效 joint limits 可能来自服务运行期状态,例如旧服务端内部的 `_SetJointLimits`、上层 GUI/脚本初始化流程、机器人环境配置,或其他未落入当前 JSON 文件的运行时参数。
3. 现有现场 JSON 中只明确保存了:
- `acc_limit`
- `jerk_limit`
- `adapt_icsp_try_num`
- IO 相关配置
4. 已重新抓取机器人侧 `10010/10012/60015` 和本机 `50001/TCP+JSON`,仍没有看到 `JointLimits / velocity / acceleration / jerk / acc_limit / jerk_limit` 通过公开链路在规划时下发。
5. 目前没有证据表明现场配置文件或公开 TCP JSON 显式保存了一个“规划速度倍率”或“规划加速度限制”。
因此,`0.742277` 不应被理解为固定业务常量。它只是 `UTTC_MS11` 在当前 C# 默认约束和真实导出结果之间反推出来的等效规划倍率。
## 兼容设计决策
由于重新抓包后仍抓不到旧系统的 effective limits新系统后续不再继续假设公开链路会传入这份数据而是采用 replacement-only 的显式规划约束参数补齐不可见状态。
参数分层如下:
1. `acc_limit / jerk_limit`
- 来源:旧 `RobotConfig.json` 中已经存在的字段。
- 语义:继续作为旧配置的基础倍率,参与 `.robot` 模型加载。
- 限制:现场样本中 `acc_limit=1`、`jerk_limit=1` 时,不能解释旧导出轨迹更慢的问题。
2. `planning_acceleration_scale`
- 来源:新系统内部兼容参数,不声称来自旧 RVBUST 配置或抓包。
- 语义:只用于规划阶段,额外缩放 `JointLimit.AccelerationLimit`,用于复现旧服务端不可见的保守加速度约束。
- 默认值:`1.0`,表示不额外限制。
- 现场校准:若按纯加速度限制解释 `UTTC_MS11_TEST01`,可先用 `(5.814370 / 7.805885)^2 ≈ 0.5548` 作为候选起点,再用真实 `JointTraj.txt` 对拍确认。
3. `planning_speed_scale`
- 来源:当前 C# 已支持的显式兼容字段。
- 语义把整条规划时间轴按速度倍率解释联动缩放速度、加速度、jerk。
- 定位:保留为临时整体验证开关;当后续落地 `planning_acceleration_scale` 后,现场默认优先使用加速度限制参数,而不是把 `planning_speed_scale` 当成旧系统事实。
当前 C# 已支持的 `planning_speed_scale` 形式为:
```json
{
"robot": {
"planning_speed_scale": 0.742277
}
}
```
该字段只用于规划阶段:
- `vel *= planning_speed_scale`
- `acc *= planning_speed_scale^2`
- `jerk *= planning_speed_scale^3`
它不等同于运行时 `/set_speedRatio/`,也不改变 J519 的 8ms 发送周期。运行阶段仍按:
```text
t_traj = k * 0.008 * speed_ratio
```
从已生成轨迹中重采样。
由于现场真实配置和本轮抓包中都没有找到这类倍率,所有 `planning_*` 字段都必须标注为 replacement-only 兼容校准参数,不能声称它们来自旧配置文件或公开 TCP JSON。
## 后续设计方向
1. 默认不再把运行时 `speed_ratio` 混入 `IsFlyshotTrajectoryValid` / `SaveTrajectoryInfo` 的规划时间计算。
2. 后续实现优先新增 `planning_acceleration_scale`,只限制规划加速度,并将其写入 `RobotConfig.json` 的 `robot` 节点或当前现场默认配置。
3. 若只需快速对齐整条时间轴,可临时使用现有 `planning_speed_scale`;但文档、日志和配置说明必须标注它是新系统校准值。
4. 如果未来能直接调用旧服务端 `_GetJointLimits`,再用返回值替换当前反推参数;在此之前,显式内部参数是当前可控且可审计的兼容策略。