Files
Tutorial/docs/MultiVehicleConfig.md
T

243 lines
16 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.
# 多车联动 配置与参数清单
本文件汇总 **MultiWheel 多车联动** 需要调整的全部配置项,分三层:
1. **每台车都不同**的身份/通信项(必须按车区分,配错直接导致组不成队或互相抢占)。
2. **编队几何**项(决定车间距、布局、互识别 ROI,全队应一致)。
3. **闭环/遥控/安全**调参项(手感与稳定性,可按需微调)。
涉及文件:
| 端 | 文件 | 作用 |
|----|------|------|
| Medulla | `build/Medulla*/startup.iocmd` | 插件加载、车号 `CarNum`、共享内存 tag、Playground 绑定、雷达初始化 |
| Medulla | 车体「Fields」面板 / `loader setp <字段> <值>` | `CartDefinition``[AsInitParam]` 字段(车号、手动最大速度等) |
| Clumsy | `build/Clumsy*/clumsy.json``msConf` | `PilotConfig` 全部联动参数(间距、检测、补偿、遥控系数等) |
| Clumsy | `build/Clumsy*/clumsyconsole.json` | `port``soTag``detourPort`(通信端口/共享内存/定位) |
> 提示:`msConf` 的 key 与 `MultiWheelC/PilotConfig.cs` 字段一一对应;Medulla 的 `[AsInitParam]` 字段见 `MultiWheelM/CartDefinition.cs`。
---
## 1. 每台车都不同(身份与通信)
以 Playground 双车(车1=主、车2=从)为例,**逐项对照**:
| 配置位置 | 字段 | 车1(主车) | 车2(从车) | 说明 |
|----------|------|-------------|-------------|------|
| Medulla `startup.iocmd` | `SetShareObjectTag` | `Multi1` | `Multi2` | 必须与对应 Clumsy 的 `soTag` 一致 |
| Medulla `startup.iocmd` | `loader setp CarNum` | `1` | `2` | 车号,决定编队 slot(±半间距)。**每台必须唯一** |
| Medulla `startup.iocmd` | `SetPlaygroundBinding` | `agv_multi_1` | `agv_multi_2` | 绑定的仿真小车名 |
| Medulla `startup.iocmd` | `lidar init ... <robot>` | `agv_multi_1` | `agv_multi_2` | 雷达挂到对应小车 |
| Clumsy `clumsyconsole.json` | `port` | `8008` | `8009` | 本车 HTTP/同步端口 |
| Clumsy `clumsyconsole.json` | `soTag` | `Multi1` | `Multi2` | 与 Medulla 的 ShareObjectTag 一致 |
| Clumsy `clumsyconsole.json` | `detourPort` | `4321` | `4421` | 与对应 Detour 实例一致 |
| Clumsy `clumsy.json` | `MultiVehicleMasterEndpoint` | `/` | `127.0.0.1:8008` | `/`=本车为主车;从车填**主车的 ip:port** |
| Clumsy `clumsy.json` | `PlaygroundRobotName` | `agv_multi_1` | `agv_multi_2` | WebAPI 操作/查询的小车名 |
| Clumsy `clumsy.json` | `TwoLegLidarName` | `rear_left_lidar_1,rear_right_lidar_1` | `rear_left_lidar_2,rear_right_lidar_2` | 互识别用的后向雷达名(与本车 startup 中的雷达名一致) |
| Detour | 运行目录 / `detourPort` | `Detour` (4321) | `Detour_AGV2` (4421) | 两套独立定位 |
**关键点**
- `MultiVehicleMasterEndpoint`:只有主车为 `/`;从车必须指向主车端口(这里主车 Clumsy `port=8008`,故从车填 `127.0.0.1:8008`)。
- `CarNum` 通过 Medulla 的 `[AsInitParam]` 配置(`setp` / Fields 面板 / `cartparams.json`),并以 `[AsLowerIO]` 上报给 Clumsy。**不要**改成 Clumsy 端写死。
- 全队 `MultiVehicleFleetNum` 必须等于实际车数(这里=2),否则永远 `ready=false`,不下发运动。
---
## 2. 编队几何(全队一致)
| 字段(`clumsy.json` | 含义 | Playground 参考值 | 默认值 |
|------|------|------|--------|
| `TestCarSyncDistance` | 车队两端**中心到中心**间距(mm) | `2400` | 2400 |
| `TestCarSyncTh` | 编队布局方向偏角(deg),0=沿 X 排布 | `0` | 0 |
| `DeltaDetectCenter` | 车中心到「互识别参考点」的偏移(mm) | `800` | 350 |
| `TwoLegGuessX` | 2腿检测初始猜测 X(车体系, mm) | `-1600` | 2000 |
| `MultiVehicleFleetNum` | 车队总数 | `2` | 2 |
**几何来源(Playground 默认场景 `default_scene.json`**
- `agv_multi_1` 初始位 `x=20200``agv_multi_2` 初始位 `x=17800` → 中心间距 = **2400 mm**,朝向相差 180°。
-`TestCarSyncDistance = 2400`
**必须遵守的换算关系**
```text
互识别检测距离 detectDistance = TestCarSyncDistance - DeltaDetectCenter
TwoLegGuessX = -(TestCarSyncDistance - DeltaDetectCenter)
= -(2400 - 800) = -1600
```
- `TwoLegGuessX` 取**负号**:邻车在本车后方(用后向雷达 `rear_*`),猜测点在车体 -X 方向。
-`TestCarSyncDistance` 时,**务必同步**更新 `TwoLegGuessX`,否则检测 ROI 偏离 → 检测失败 → 安全门拦停。
- `布局`(每车 slot)由 `TestCarSyncDistance`/`TestCarSyncTh` 唯一推导:车1=+半间距、车2=−半间距并翻转 180°。已删除独立的 `FormationSlots`,不要再引入重复参数。
---
## 3. 2 腿互识别(ROI / 聚类)
与「多舵轮-2腿检测」MovementTest 共用同一套参数;调好 MovementTest 再用于联动。
| 字段(`clumsy.json` | 含义 | Playground 参考值 | 默认值 |
|------|------|------|------|
| `TwoLegLidarName` | 后向雷达名(逗号分隔,按车区分,见 §1) | `rear_left_lidar_X,rear_right_lidar_X` | — |
| `TwoLegGuessX` | 初始猜测 X(见 §2 换算) | `-1600` | 2000 |
| `TwoLegWidth` | 两腿间距(mm) | `473` | 800 |
| `TwoLegWidthErr` | 两腿间距允许误差(mm) | `100` | 100 |
| `TwoLegFilterLength` | ROI 滤波框长(mm) | `500` | 1800 |
| `TwoLegFilterWidth` | ROI 滤波框宽(mm) | `1000` | 600 |
| `TwoLegBlobDist` / `TwoLegBlobSize` / `TwoLegBlobPtCount` | 聚类间距/尺寸/最小点数 | `100/200/5` | 100/200/5 |
| `TwoLegSgnDir` | 方向符号(±1) | `1` | 1 |
| `TwoLegCenterChangeX` | 中心 X 微调(mm) | `0` | 0 |
---
## 4. 手动遥控(Medulla 车队遥控)
遥控在 Medulla 侧产生指令(`MultiVehicleManual*``[AsLowerIO]` 上报 Clumsy)。车队联动遥控只上报归一化摇杆比例 `[-1,1]`;实际速度/舵角/角速度统一在 Clumsy 的 `FleetManual*` 参数中换算,避免 Medulla 和 Clumsy 两层缩放叠加。
| 端 | 字段 | 含义 | 推荐值 |
|----|------|------|--------|
| Medulla `[AsLowerIO]` | `MultiVehicleManualVx/Vy/Vth` | 车队遥控摇杆比例(仅 `[-1,1]`,不带物理单位) | 摇杆值 |
| Clumsy `clumsy.json` | `FleetManualMaxSpeed` | 满杆线速度(m/s) | `0.3` |
| Clumsy `clumsy.json` | `FleetManualMaxSteerAngleDeg` | 常规模式满杆转向舵角(deg) | `45` |
| Clumsy `clumsy.json` | `FleetManualMaxCrabAngleDeg` | 蟹行模式满杆蟹行舵角(deg) | `60` |
| Clumsy `clumsy.json` | `FleetManualMaxRotateOmegaDegPerSec` | 原地旋转模式满杆角速度(deg/s) | `45` |
| Clumsy `clumsy.json` | `SyncThAccPerSec` | 转向角爬升速率(deg/s) | `30` |
> 历史坑:旧链路会出现 `ManualCarSyncVxFac × MaxManualSpeed` 叠乘,导致满杆只有 `0.06 m/s` 这类异常低速;现在车队联动不再使用 Medulla 的 `MaxManualSpeed/MaxManualAngularSpeed`,这些字段只属于普通手动遥控。
操作:在 Medulla 打开车体工具 **「FleetRemote / 车队联动遥控」**workspace 摇杆,松手自动回零),开「车队联动」开关后拖摇杆即可。主车摇杆驱动全队;从车由主车广播自动跟随,**无需**各自开开关。**不要**同时打开普通「手动控制」面板(会抢占优先级)。
---
## 5. 闭环补偿与安全门
| 字段(`clumsy.json` | 含义 | 推荐值 |
|------|------|--------|
| `MultiVehicleUseDetect` | 启用互识别纠正 **+ 安全门**(任一车检测不到邻车→整队停车) | `true` |
| `MultiVehicleDetectBiasXFac/YFac/ThFac` | 互识别补偿系数 | `0.5/0.5/0.5` |
| `MultiVehicleDetectBiasXThreshold/YThreshold/ThThreshold` | 互识别补偿上限(mm/mm/deg) | `50/50/5` |
| `MultiVehiclePosBiasXFac/YFac/ThFac` | **车队内姿态纠正**(SLAM 逐车编队保持)补偿系数 | `0.5/0.5/0.5` |
| `MultiVehiclePosBiasXThreshold/YThreshold/ThThreshold` | 车队内姿态纠正上限(mm/mm/deg) | `50/50/5` |
| `SingleCarSyncPrecisionXy` / `SingleCarSyncPrecisionTh` | 对齐精度 / 补偿死区(mm/deg) | `10 / 0.2` |
| `MultiVehicleSyncUseDetour` | **仅**控制"定位是否参与**车队内姿态纠正**"(即上面的 `PosBias*` 补偿);**不影响**"整个车队姿态的计算" | `false` |
**`MultiVehicleSyncUseDetour` 语义(重要,勿混淆)**
该开关只切换 **"车队内姿态纠正"**(用 SLAM 逐车把每台车纠回其编队 slot,即 `PosBias*` 补偿),**不**切换 **"整个车队姿态的计算"**
| 用途 | 是否受该开关控制 | 说明 |
|------|------------------|------|
| 车队内姿态纠正(`PosBias*` 逐车 SLAM 补偿) | **是**(false=关闭,仅靠编队几何/互识别保持队形) | 唯一开关点 |
| 反推/广播车队中心、SLAM 间距、自动安全门、原地旋转判停航向 | **否,始终用 Detour** | 自动模式整队姿态恒依赖全局定位 |
- 即使 `MultiVehicleSyncUseDetour=false`**自动模式主车仍调用 `getCartLocation()`** 反推车队中心;若无有效全局定位则该调用阻塞 → 联动线程阻塞不下发速度(安全停车),定位恢复后自动继续。
- `false` 适用于:SLAM 两车相对精度不佳、希望只靠互识别/编队几何保持队形,但整车队的绝对位姿仍由 Detour 驱动(如自动循路径)。
**要点**
- `MultiVehicleUseDetect=true` 时若 2 腿检测没锁定,`fleetVx` 会被安全门置零(表现为摇杆"无效"——这是预期安全行为,不是 bug)。先确保检测稳定。
- 车队内姿态纠正(`PosBias*`)要求两车**共享同一 SLAM 世界系**;否则编队中心反推会错。Playground 两车同图,满足。
- 不需要绝对编队保持时,可把 `MultiVehiclePosBias*Fac` 设 0 或 `MultiVehicleSyncUseDetour=false`,仅靠互识别维持间距(整车队姿态仍由 Detour 计算)。
---
## 6. 自动蟹行动作(FleetCrabWalk / MovementTest「车队联动-自动蟹行」)
在 Clumsy 侧 MovementTest 面板触发,以**当前车队中心**为起点,构造一条与启动时车队朝向夹角 `FleetCrabAngleDeg`、长度 `FleetCrabLengthMm` 的**直线路径**。MovementTest 会保持启动时车身朝向追踪路径;因此如果“路径相对小车”的夹角为 `x` 度(路径在车体右侧为正),应配置 `FleetCrabAngleDeg = -x`。当前实现不再复用脚本手动链路,而是参考几何控制器思路,在 `MultiWheelC` 内计算并写入 `MultiVehicleAuto...` 字段:
- 动作每拍读取主车 Detour 反推车队中心,计算直线进度 `along`、横向偏差 `lateral`、剩余距离 `remain` 和车身目标朝向偏差 `headingErr`
- `lateral` 通过 `BiasFac/BiasThreshold` 转为前后 GCP 同向舵角修正;`headingErr` 通过 `DthLinearFac/DthLinearThreshold` 转为前后 GCP 反向舵角修正。
- 动作直接输出 `MultiVehicleAutoVx/FrontTh/RearTh/IdealX/IdealY/IdealTh`,由 `TickMultiVehicle` 的自动分支统一广播、下发 `SendMotion`,并继续受识别丢失、成员超时、舵角余量不足等整队缓停联锁保护。
- **前提**:在**主车**`MultiVehicleMasterEndpoint="/"`)上运行,且主车有 Detour 定位(用于反推车队中心起点与运行中闭环)。
| 字段(`clumsy.json``msConf` | 含义 | 默认值 |
|------|------|--------|
| `FleetCrabAngleDeg` | 蟹行路径方向相对**启动时车队朝向**的夹角(deg,逆时针为正)。MovementTest 同时把车身-路径夹角设为该值,因此 `FleetCrabAngleDeg=-x` 会让车身保持启动朝向,并以 `x` 度夹角追踪路径 | `45` |
| `FleetCrabLengthMm` | 蟹行路径**长度**(mm),沿夹角方向行驶该距离后停车结束 | `2000` |
| `FleetCrabSpeed` | 蟹行巡航速度(m/s),写入 `MultiVehicleAutoVx`;接近终点时会被自动蟹行专用减速参数下调 | `0.2` |
| `FleetCrabAccel` | 蟹行速度命令加速度限制(m/s^2),限制 `MultiVehicleAutoVx` 每拍变化量;`<=0` 表示不限制 | `0.2` |
| `FleetCrabSlowDistance` | 蟹行末端开始减速距离(mm) | `2000` |
| `FleetCrabFinishDistance` | 蟹行完成距离(mm),剩余距离低于该值时结束动作 | `20` |
| `FleetCrabFinishSpeed` | 蟹行末端最低速度(m/s) | `0.02` |
| `FleetCrabSlowingPow` | 蟹行末端减速曲线指数;越大越靠近终点才明显降速,越小越早降速 | `0.8` |
| `FleetCrabGcpThetaThreshold` | 自动蟹行输出 `frontTh/rearTh` 的绝对值上限(deg)。应小于实际舵角可行范围,并给 `AngleLimitMarginDeg` 留余量 | `95` |
自动蟹行还会使用下列通用控制参数:
| 字段 | 影响 | 默认来源 |
|------|------|----------|
| `BiasFac` / `BiasThreshold` | 横向偏差 `lateral` → 前后 GCP 同向修正。增大后收敛更快,但过大可能摆动 | `MultiWheelPilotConfig` |
| `DthLinearFac` / `DthLinearThreshold` | 车身目标朝向偏差 `headingErr` → 前后 GCP 反向修正,用于保持车身与路径夹角 | `MultiWheelPilotConfig` |
| `MultiVehicleAutoUseIdealCenter` | 是否把自动蟹行计算出的 `IdealX/Y/Th` 广播给从车做前馈 | `true` |
| `MultiVehicleAutoRequireFleetCenter` | 自动模式是否要求有效车队中心;定位/车队中心失效时整队停车 | `true` |
| `MultiVehicleAutoCmdTimeoutMs` | 自动命令新鲜度超时,0 表示按联动周期自动计算 | `0` |
| `MultiVehicleUseDetect` / `MultiVehicleDetectBias*` | 互识别纠正与安全门;检测丢失时整队停车 | 见 §5 |
| `MultiVehicleSyncUseDetour` / `MultiVehiclePosBias*` | 车队内姿态纠正(POS 补偿);不影响整车队中心计算 | 见 §5 |
已删除的旧自动蟹行参数:
| 已删除字段 | 原用途 | 当前替代 |
|------------|--------|----------|
| `FleetCrabCorrectionGain` | 旧脚本链路的横向误差纠偏增益 | `BiasFac` |
| `FleetCrabCorrectionAngleDeg` | 旧脚本链路的最大改向角 | `BiasThreshold` / `FleetCrabGcpThetaThreshold` |
| `FleetCrabCommandAccel` | 旧脚本链路的 `Vx/Vy` 斜率限制 | 新自动链路使用 `FleetCrabAccel` 限制 `MultiVehicleAutoVx` |
**行为要点 / 注意**
- 当前实现走 `MultiVehicleAuto*` 自动字段链路,不再开启 `MultiVehicleScriptEnabled`,也不受 `MultiVehicleCrabSteerLimitDeg` 影响(该字段只影响手动 `mode=1` 蟹行)。
- `FleetCrabDbg` 会记录 `along/lateral/remain/headingErr/baseTh/bias/dth/targetV/auto(vx,fTh,rTh)/ideal``MultiVehicleDbg` 可继续对照最终 `BASE/SEND`、POS/Detect 补偿、ready/stop 状态。
- `MultiVehicleUseDetect=true` 时仍受 2 腿检测安全门约束(检测丢失会被置零停车)。
- Playground 双车场景的 `actuator.maxSteeringAngle` 也必须与该上限一致;若仍为 `90`Clumsy 发出的 `-98°` 纠偏会在仿真执行层被夹回 `-90°`,表现为纯横移路径无法收敛。
---
## 7. 常见坑位(排查清单)
- **组不成队 / `ready=false`**`MultiVehicleFleetNum` 与实际车数不符;从车 `MultiVehicleMasterEndpoint` 没指向主车端口;`soTag` 不匹配。
- **摇杆无反应**`MultiVehicleUseDetect=true` 但检测没锁(安全门);或误把系数设成 <1 / 滑条乘零;或在从车而非主车上操作。
- **两车一起匀速跑飞**:编队中心反推必须用**真正的 SE(2) 逆**(`SolveTransform2D`),不能用逐分量取负 `-layout`(从车 `layoutTh=180` 会算错 → 补偿正反馈发散)。已修复于 `InferFleetCenterFromCar`
- **检测框位置不对**`TwoLegGuessX` 未随 `TestCarSyncDistance` 同步更新(见 §2 换算)。
- **车号不对/全为 1**`CarNum` 未通过 `[AsInitParam]``setp CarNum X`)按车配置。
---
## 8. 参考:Playground 双车验证值速查
```jsonc
// clumsy.json -> msConf (主车=agv_multi_1;从车把标注项改为车2值)
"TestCarSyncDistance": 2400,
"TestCarSyncTh": 0,
"DeltaDetectCenter": 800,
"TwoLegGuessX": -1600,
"MultiVehicleFleetNum": 2,
"MultiVehicleUseDetect": true,
"FleetManualMaxSpeed": 0.3,
"FleetManualMaxSteerAngleDeg": 45,
"FleetManualMaxCrabAngleDeg": 60,
"FleetManualMaxRotateOmegaDegPerSec": 45,
"SyncThAccPerSec": 30,
"MultiVehicleMasterEndpoint": "/", // 从车: "127.0.0.1:8008"
"PlaygroundRobotName": "agv_multi_1", // 从车: "agv_multi_2"
"TwoLegLidarName": "rear_left_lidar_1,rear_right_lidar_1", // 从车: *_2
// 自动蟹行动作(见 §6,仅主车触发)
"FleetCrabAngleDeg": 45,
"FleetCrabLengthMm": 2000,
"FleetCrabSpeed": 0.2,
"FleetCrabAccel": 0.2,
"FleetCrabSlowDistance": 2000,
"FleetCrabFinishDistance": 20,
"FleetCrabFinishSpeed": 0.02,
"FleetCrabSlowingPow": 0.8,
"FleetCrabGcpThetaThreshold": 95
```
```text
# Medulla startup.iocmd (主车)
loader SetShareObjectTag Multi1 # 从车: Multi2
loader setp CarNum 1 # 从车: 2
loader SetPlaygroundBinding agv_multi_1 tutorial-multi-wheel # 从车: agv_multi_2
```