# 轨迹规划时长差异调查记录

## 背景

当前新 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_send = k * 0.008
t_traj = t_send * 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`，再用返回值替换当前反推参数；在此之前，显式内部参数是当前可控且可审计的兼容策略。
