Files
ParkingRobot/docs/detour数据处理.txt
T

365 lines
8.2 KiB
Plaintext
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.
需要处理,而且对横向误差、航向误差和速度估计都会有明显影响。检测本身不难,困难的是区分:
```text
单帧错误定位
持续性的定位重定位/地图修正
车辆真实的快速运动
```
对你这种低速停车机器人,可以先采用一套偏安全、容易验证的处理。
## 定位跳变会造成什么影响
假设Detour在50ms内突然跳了10cm
\[
v=\frac{0.1}{0.05}=2m/s
\]
实际车辆可能只有 `0.3m/s`,但差分速度会产生 `2m/s` 的尖峰。
对控制器还有三个直接影响:
- 横向位置跳10cm,横向误差可能瞬间变化10cm。
- 航向跳5°,航向误差会瞬间变化5°。
- 全局轨迹投影可能跳到另一条临近或相交的轨迹线段。
Stanley在低速时尤其敏感:
\[
\delta =
e_\theta+
\arctan\left(\frac{k e_y}{v+\varepsilon}\right)
\]
低速时分母较小,横向误差突然变大,会产生很大的转向指令。因此不能完全不处理。
## 不建议直接低通掉定位跳变
不要简单地对Detour位置做强低通:
```text
错误位置跳变
→ 低通缓慢跟过去
```
这样虽然曲线看起来平滑,但控制器会在一段时间内使用滞后、虚构的位置,可能更加危险。
更好的做法是:
```text
检测跳变
→ 暂时不把该帧用于速度差分和控制
→ 观察后续定位
→ 判断是单帧异常还是持续重定位
```
## 第一层:运动学合理性检查
将当前Detour位姿和上一次接受的位姿比较。
位置变化:
\[
\Delta p=\sqrt{\Delta x^2+\Delta y^2}
\]
航向变化:
\[
\Delta\theta=
|\operatorname{ShortestAngleDifference}|
\]
允许的最大变化量可以按照车辆物理能力计算:
```csharp
var maximumAllowedDistance =
maximumLinearSpeedMetersPerSecond *
deltaTimeSeconds +
positionJumpMarginMeters;
var maximumAllowedHeadingChange =
maximumAngularSpeedRadiansPerSecond *
deltaTimeSeconds +
headingJumpMarginRadians;
```
然后判断:
```csharp
var positionJump =
displacementMeters >
maximumAllowedDistance;
var headingJump =
headingChangeRadians >
maximumAllowedHeadingChange;
```
你当前小车最高约 `1.2m/s`,假设Detour更新周期为50ms
```text
物理最大位移约为:
1.2 × 0.05 = 0.06m
```
初期可以额外留出约 `0.03~0.05m` 的定位余量。不过这些阈值最终应根据实际Detour数据确定,不建议永久写死。
## 第二层:不要立即接受异常帧
检测到一个异常帧时,不要立刻改变车辆状态:
```text
上一正常位置 A
异常位置 B
下一帧又回到 A 附近
```
这种情况说明B很可能是单帧异常,应直接丢弃。
如果后续连续若干帧都稳定在B附近:
```text
A → B → B附近 → B附近
```
这更可能是Detour发生了持续性的重定位。
可以使用:
```text
连续23个新定位帧相互一致
```
作为重新接受定位的条件。
## 第三层:重定位后必须重置速度估计
如果确认新的定位是持续有效的,不能用:
```text
新位置B - 旧位置A
```
计算速度,因为A到B是定位修正,不是车辆真实运动。
正确处理是:
```csharp
_velocityEstimator.Reset(
newPose,
currentTimestamp);
```
这会:
- 将新位姿作为新的差分起点。
- 清除之前的速度历史。
- 重置三个低通滤波器。
- 将速度暂时标记为无效或零。
- 等下一次正常Detour更新后重新开始估计。
## 第四层:控制器应该如何响应
对于实车轨迹跟踪,建议状态分为:
```text
Valid 正常定位,可以控制
Suspected 检测到疑似跳变
Reacquiring 正在确认新的定位
Stale 定位长时间没有更新
```
你的第一版不一定需要单独增加复杂枚举,但控制行为至少应该满足:
```text
正常:
继续轨迹跟踪
疑似单帧跳变:
不使用异常帧更新状态
短时间保持上一状态
连续异常或定位超时:
停车,不继续使用旧状态运动
确认重定位:
接受新位姿
重置速度估计
重新执行轨迹投影
确认稳定后恢复控制
```
停车机器人速度低、场地有限,定位连续异常时停车比盲目继续跟踪更合适。
## 还需要限制轨迹投影进度
即使Detour跳变检测做了,轨迹投影也最好增加进度保护。
当前投影器在整条轨迹上找最近点,如果轨迹自交,车辆可能从:
```text
当前第20段
```
突然投影到:
```text
第80段
```
后续可以增加一个 `TrajectoryProgressTracker`
```text
正常时只在上次线段索引附近搜索
例如 [previousIndex - 5, previousIndex + 20]
定位重定位后:
重新执行一次全局搜索
```
同时限制单周期允许的弧长进度变化:
\[
|\Delta s|
\leq
v_{\max}\Delta t+\text{margin}
\]
这样可以避免定位轻微波动导致轨迹进度突然跳段。
## 在五个文件中的分工
```text
DetourVehicleStateProvider
├─ 检查数值有效性
├─ 检查定位是否过期
├─ 检测重复帧
├─ 检测位置/航向跳变
├─ 暂存疑似新定位
└─ 确认重定位后触发Reset
VelocityEstimator2D
├─ 正常位姿差分
├─ 真实时间差计算
├─ 速度滤波
└─ 提供Reset()
FirstOrderLowPassFilter
└─ 提供Update()和Reset()
VehicleState
├─ 保存位姿和速度
└─ 表示速度估计是否有效
IVehicleStateProvider
└─ 向控制器返回有效状态或读取失败
```
因此定位跳变的主要逻辑放在 `DetourVehicleStateProvider`,而不是低通滤波器。
第一版建议先实现:
1. 非有限值检查。
2. 重复帧识别。
3. 基于最大速度和最大角速度的跳变检测。
4. 单帧异常拒绝。
5. 连续23帧确认重定位。
6. 重定位后重置速度估计。
7. 长时间定位无效时通知控制器停车。
这套方案足以保护当前Stanley和后续纵向控制,不需要现在就修改SLAM源码。
已经给 [DetourVehicleStateProvider.cs](/D:/Users/Desktop/入职培训/停车机器人/MyParking/MultiWheelC/StateEstimation/DetourVehicleStateProvider.cs:233) 增加了基于上一有效速度的预测残差检测。
现在采用两级判断:
```text
第一级:绝对物理运动边界
第二级:上一状态恒速预测残差
```
预测公式为:
\[
x_{pred}=x_{last}+v_x\Delta t
\]
\[
y_{pred}=y_{last}+v_y\Delta t
\]
\[
\theta_{pred}=
\theta_{last}+\omega\Delta t
\]
实测残差为:
\[
e_p=
\sqrt{
(x_{measured}-x_{pred})^2+
(y_{measured}-y_{pred})^2
}
\]
以及:
\[
e_\theta=
\operatorname{ShortestDifference}
(\theta_{measured},\theta_{pred})
\]
对应实现在:
- [IsPredictionResidualPlausible()](/D:/Users/Desktop/入职培训/停车机器人/MyParking/MultiWheelC/StateEstimation/DetourVehicleStateProvider.cs:536)
- [PredictPoseInWorld()](/D:/Users/Desktop/入职培训/停车机器人/MyParking/MultiWheelC/StateEstimation/DetourVehicleStateProvider.cs:573)
默认阈值为:
```csharp
位置预测残差:0.04m
航向预测残差:5°
```
没有采用最初考虑的30mm,是因为用现有数据离线统计后发现:
| 位置残差阈值 | 触发次数 | 占有效更新比例 |
|---:|---:|---:|
| 30mm | 55次 | 1.24% |
| 35mm | 28次 | 0.63% |
| 40mm | 13次 | 0.29% |
| 45mm | 7次 | 0.16% |
| 50mm | 4次 | 0.09% |
30mm容易把正常Detour波动也判成异常;40mm仍能识别现有数据中约49mm和66mm的明显跳变,同时误触发风险更低。
当前判定逻辑:
```csharp
if (!isWithinPhysicalBoundary ||
!isWithinPredictionResidual)
{
// 进入疑似重定位确认状态。
}
```
另外同步修正了跳变恢复逻辑:
- 发生预测残差跳变时,保存当时的预测位姿。
- 后续定位必须回到预测位姿附近,才能认为是单帧异常后的正常恢复。
- 不再使用较宽松的绝对物理范围立即放行。
- 持续远端定位仍需满足3次观测和0.25秒,才按重定位接管。
- 接管后重置速度估计,避免把坐标修正计算成车辆速度。
第一帧或重定位后的速度还没有建立时,不启用预测残差检测,只使用物理极限检查,避免没有速度基准时误判。
完整构建结果:
- CommonUsage0警告、0错误
- MedullaAdapter0警告、0错误
- MultiWheelC0警告、0错误