File size: 6,669 Bytes
a3549fd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | ---
license: mit
library_name: pytorch
pipeline_tag: robotics
tags:
- robotics
- social-navigation
- human-robot-interaction
- pedestrian-trajectory-prediction
- model-predictive-control
- convex-optimization
---
# crowd-nav — human-response models for the Foresight controller
Trained weights for **Foresight**, a convex receding-horizon controller that predicts how each
nearby pedestrian will respond to the robot's *candidate plan*, and then chooses that plan by
exact convex optimization. These are the response models the controller calls; the planner is
plain code (no learned policy, no RL).
| file | model | role |
|---|---|---|
| `linres_head.pt` | **Linear-response operator** (headline) | best closed-loop performance; makes planning an exact convex QP |
| `residual_predictor_k1.pt` | Residual predictor | most accurate on real data; the safest variant in closed loop |
| `residual_predictor.pt` | *legacy* | **deprecated** — trained with a robot-force prior of 0 but deployed at 1; superseded by `residual_predictor_k1.pt` |
## Which one should I use?
**`linres_head.pt`** unless you have a reason not to. It is a few centimetres less accurate as a
pure forecaster, but its prediction is *exactly affine* in the robot's planned displacement, so the
planner gets an exact constant Jacobian and the safety constraints stay linear — the whole plan
selection becomes a convex QP that solves in ~17 ms with a checkable feasibility certificate.
That trade wins where it counts: it leads our benchmark, and it is the only variant that crossed a
90-pedestrian oncoming corridor with zero contacts.
## Measured results
Isaac Sim, 16 scenarios × 10 paired seeds (160 episodes per method), identical hardware:
| model | goal reach | hard collisions / ep | plan latency (mean) |
|---|---|---|---|
| **Foresight-LinRes** (`linres_head.pt`) | **94.4 %** | 0.013 | **16.6 ms** |
| Foresight-Residual (`residual_predictor_k1.pt`) | 90.0 % | **0.006** | 19.7 ms |
| Foresight-SFM (physics only, ablation) | 93.8 % | 0.013 | 17.2 ms |
| Foresight-CV (straight-line, ablation) | 90.0 % | 0.019 | 16.4 ms |
| SICNav [T-RO '24] (nonconvex bilevel MPC) | 89.2 % | 0.042 | 1843 ms |
Stress test — a 4.5 m × 105 m corridor with 90 pedestrians *all walking against* the robot and a
continuous inflow so it never empties: LinRes reached the goal in 98.5 s with **zero contacts**;
against pedestrian models it was never tuned on (SRFM, social-force) it reached in 85.0 s and
91.7 s, also contact-free.
Prediction accuracy on the held-out real split (factual ADE, metres — lower is better):
| model | no robot | stationary robot | moving robot |
|---|---|---|---|
| Constant velocity | 0.240 | 0.253 | 0.354 |
| Social force | 0.343 | 0.358 | 0.416 |
| Residual (k1) | **0.192** | **0.217** | 0.285 |
| Linear response | 0.204 | 0.248 | 0.319 |
## Architecture
Both models are a **physics prior plus a learned correction** — small by design, because the real
moving-robot data is scarce.
```
prior (no parameters, per pedestrian per 0.25 s step)
f_goal = (1.3·(g−p)/‖g−p‖ − v)/0.5
f_ped = Σ 2.0·exp(−d/0.4)·d̂ (d < 2.0 m)
f_robot = k·exp(−d/0.5)·d̂ (d < 3.0 m)
v ← clip(v + f·Δt, 1.8); p ← p + v·Δt
residual_predictor_k1.pt ŷ = prior(k=1) + f_θ(x)
f_θ : MLP 22 → 128 → 128 → 16 (21,520 params)
linres_head.pt ŷ = prior(k=0) + f_θ(x) + G_φ(x)·ΔR
f_θ : MLP 22 → 128 → 128 → 16 (21,520 params)
G_φ : MLP 22 → 64 → 96 (7,712 params) ⇒ rank-3 16×16 operator
G = Σ_{r=1..3} a_r b_rᵀ, ΔR = (R − 1⊗r₀)/5.0
⇒ ∂ŷ/∂R = G/5.0 — exact, constant, no differentiation needed
```
Input `x` (22-d, pedestrian local frame): 1 s of past positions (4 @ 0.25 s), velocity, goal
direction, robot relative position, a robot-nearby flag, the two nearest neighbours, and a 3-way
condition one-hot. Output: 8 × 2 future displacements — 2.0 s at 0.25 s.
Training: supervised (Adam, lr 1e-3, batch 128, ~25 epochs), synthetic pre-train then fine-tune on
the real **PeRoI** robot–pedestrian recordings. No reinforcement learning anywhere in this stack.
Both run in well under 1 ms per call on CPU.
## Load
```bash
pip install huggingface_hub torch
hf download elmoghany/crowd-nav linres_head.pt residual_predictor_k1.pt --local-dir .
```
```python
import torch
ck = torch.load("linres_head.pt", map_location="cpu")
ck["config"]
# {'in_dim': 22, 'horizon_dim': 16, 'rank': 3, 'hidden': 64, 'dr_scale': 5.0,
# 'sfm_k_robot': 0.0, 'convention': 'y = sfm(k=0) + f_resid(x_ctx) + head(x_ctx, dR)'}
ck["f_resid"], ck["head"] # two state_dicts
```
The `config` block is authoritative: `sfm_k_robot` **must** match the robot-force strength used in
your prior at deployment. Mismatching them is a real bug we shipped once — the residual then
corrects an error that is not there. `residual_predictor.pt` is the artifact of that mistake and is
kept only for reproducibility.
Model classes (`ResidualPredictor`, `LinearResponseHead`) and the full controller live in the
**[github.com/elmoghany/crowd-nav](https://github.com/elmoghany/crowd-nav)** -- a one-file,
simulator-free controller with a `quickstart.py` that fetches these weights and verifies your
install in one command. The full research stack (convex-QP planner, Isaac benchmarks, paper) is at
[github.com/elmoghany/crowd-nav-legacy](https://github.com/elmoghany/crowd-nav-legacy).
## Honest limitations
- **Real-data forecasting is a tie.** On four real robot–pedestrian datasets (including JRDB),
every learned model here ties the analytic baselines on factual accuracy. Our measured
explanation: the counterfactual proxy those benchmarks rely on (constant-velocity extrapolation)
correlates only r ≈ 0.30 with exact simulated counterfactuals — the target is mostly noise. The
gains above are **closed-loop** gains, not forecasting gains.
- **Compliance bias.** The training recordings contain cooperative pedestrians. On deliberately
stubborn crowds the k1 residual is the weakest learned variant; compliance-randomized training
data is the known fix, not yet applied.
- **Cross-dataset transfer.** Moving `residual_predictor_k1.pt` to JRDB over-predicts robot-induced
deviation by ~6× (its k=1 prior is calibrated to our robot). It makes a controller conservative,
not unsafe — it still threaded real JRDB crowds contact-free — but retune `sfm_k_robot` for a
different platform.
|