2026-07-15 11:19:02 +08:00
# SRU × Odin: Mapless Navigation with Spatially-Enhanced Recurrent Memory
2026-07-10 16:58:17 +08:00
2026-07-15 10:10:09 +08:00
<p align="center">
2026-07-15 17:57:43 +08:00
<img src="./Img/logo.png" alt="SRU × Odin1 Logo" width="20%">
2026-07-15 10:10:09 +08:00
</p>
2026-07-10 16:58:17 +08:00
<p align="center">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT">
<img src="https://img.shields.io/badge/Isaac%20Sim-4.5.0-76B900.svg" alt="Isaac Sim 4.5.0">
<img src="https://img.shields.io/badge/ROS-Noetic-22314E.svg" alt="ROS Noetic">
<img src="https://img.shields.io/badge/Sensor-Odin1-FF6F00.svg" alt="Sensor: Odin1">
2026-07-15 18:06:12 +08:00
<a href="https://www.bilibili.com/video/BV1LaNq6yEpX"><img src="https://img.shields.io/badge/Video-bilibili-pink" alt="bilibili"></a>
2026-07-10 16:58:17 +08:00
</p>
<p align="center">
2026-07-15 10:10:09 +08:00
<b>Deploy cutting-edge paper within half a day using Odin1.</b>
2026-07-10 16:58:17 +08:00
</p>
<p align="center">
2026-07-10 19:46:30 +08:00
<img src="./Img/SRU_ODIN1.gif" alt="SRU Navigation Demo" width="800"/>
2026-07-10 16:58:17 +08:00
</p>
---
## 1. Introduction
2026-07-15 17:56:01 +08:00
**SRU × Odin** brings the ETH RSL **SRU** (*Spatially-Enhanced Recurrent Memory for
2026-07-10 16:58:17 +08:00
Long-Range Mapless Navigation via End-to-End Reinforcement Learning*) policy to a real
quadruped using a single **Odin1** spatial-memory sensor. The original work relies on a
**ZED-X** stereo camera for depth mapping and a **DLIO** LIO stack for high-precision
odometry tracking; this project collapses both of those subsystems into one compact sensor.
> **Highlight — one sensor replaces two subsystems.** The **Odin1 spatial memory
> module completely replaces BOTH the depth-mapping functionality of the original ZED
> camera AND the high-precision odometry tracking from the DLIO LIO stack** used in the
> upstream paper. Odin1 publishes a depth stream (`sensor_msgs/Image`, meters,
> ~10 Hz) together with a high-frequency odometry topic, so a single device covers both
> exteroception and state estimation.
> **Highlight — Code Generation.** You do not have to hand-write the deployment stack. A
> structured LLM prompt (`Prompt/PORTING_GUIDE.md`) lets an AI agent **automatically
> generate ready-to-use navigation deployment code for physical robots** — from ONNX I/O
> specification through the ROS node down to the launch scripts.
**Paper:** *Spatially-Enhanced Recurrent Memory for Long-Range Mapless Navigation via
End-to-End Reinforcement Learning* — DOI: <https://doi.org/10.1177/02783649251401926> ·
Project page: <https://michaelfyang.github.io/sru-project-website/>
2026-07-15 16:07:10 +08:00
### Related Work
2026-07-15 17:56:01 +08:00
- **[ManifoldTech Real2Sim Tutorial ](https://github.com/ManifoldTechLtd/MT-Real2Sim-Tutorial )** — Transform the real world into a simulated environment using Q9000.
- **[Odin-Nav-Stack ](https://github.com/ManifoldTechLtd/Odin-Nav-Stack )** — A full-stack navigation framework based on Odin, integrating end-to-end navigation (NeuPAN), classical navigation, modular navigation, VLM, YOLO object detection, and VLN (Vision-and-Language Navigation) into a unified system.
2026-07-15 16:07:10 +08:00
2026-07-10 16:58:17 +08:00
---
## 2. Key Features
- **End-to-end mapless navigation** — depth image + goal vector → velocity command
(`/cmd_vel` ), with no occupancy grid, no SLAM map, and no global planner.
- **Spatially-enhanced recurrent memory** — a VAE depth encoder feeds an LSTM-SRU actor
(`rnn_hidden_size=512` , `num_layers=1` ) that remembers where obstacles were.
- **One sensor, two subsystems replaced** — the Odin1 spatial memory module supplies BOTH
the depth mapping that upstream took from the ZED-X camera AND the high-precision
odometry that upstream took from the DLIO LIO stack.
- **Sensor-agnostic depth pipeline** — any depth image works; Odin1 is the
reference sensor, ZED-X the upstream original.
- **Robot-agnostic output** — publishes a body-frame `geometry_msgs/Twist` ; any robot with
a `/cmd_vel` bridge can be driven.
- **ONNX Runtime inference** — no PyTorch at deployment time; single-file models, easy
CPU/GPU EP switching, ready-made aarch64 wheels for Jetson.
- **Reproducible Docker training** — Isaac Sim 4.5.0 + IsaacLab v2.1.1 image, one-click
training scripts, VRAM-aware environment scaling.
- **Prompt-driven deployment** — a physically tested ROS1 Noetic package plus a
prompt-driven workflow to regenerate it from scratch.
---
## 3. System Architecture
```
┌──────────────────────────── TRAINING (Isaac Sim 4.5 / Docker) ────────────────────────────┐
│ │
│ IsaacLab v2.1.1 + sru-navigation-sim task + rsl_rl (ActorCriticSRU: VAE + LSTM-SRU) │
│ parallel envs ──► PPO/MDPO ──► checkpoints (outputs/logs/.../model_*.pt) │
│ │
└───────────────────────────────────────────┬────────────────────────────────────────────┘
│ scripts/export_onnx.py
▼
┌──────────────────────────────── POLICY EXPORT ────────────────────────────────┐
│ model_best.pt ──► policy.onnx (obs[1,2576] + h/c[1,1,512] → act[1,3]) │
│ (deployment split: vae_encoder.onnx + nav_policy.onnx) │
└───────────────────────────────────────────┬──────────────────────────────────┘
│ copy into Deployment/models/
▼
┌──────────────────────── DEPLOYMENT (Go2 + Odin1 + ROS1 Noetic) ─────────────────────┐
│ │
│ Odin1 driver ──► /odin1/depth_img_competetion (depth) │
│ └─► /odin1/odometry_highfreq (odom) │
│ │ │
│ ▼ │
│ sru_nav_node: depth ─► VAE encoder ─► latent ─┐ │
│ odom + goal + prev_action ──────┼─► LSTM-SRU actor ─► /cmd_vel │
│ LSTM (h,c) held across frames ──┘ (Twist, body frame) │
│ │ │
│ ▼ │
│ cmd_vel bridge (unitree_legged_sdk) ──► sport-mode joint commands │
└────────────────────────────────────────────────────────────────────────────────────┘
```
---
## 4. Repository Structure
```
SRU_GO2_ODIN1/
├── Prompt/
│ └── PORTING_GUIDE.md # Source-of-truth prompt for LLM-based code generation
├── Deployment/ # Tested, working ROS1 deployment package (reference)
│ ├── src/sru_nav_go2/ # ONNX inference node + helpers (Odin1)
│ ├── config/sru_nav.yaml # The ONLY file users normally edit
│ ├── launch/sru_nav_go2.launch
│ ├── scripts/ # setup_conda_env.sh, launch_sru_nav.sh, verify_port.sh
│ ├── models/ # vae_encoder.onnx + nav_policy.onnx (user-supplied)
│ └── docs/ # DEPLOY_GO2_NX.md, PORTING_GUIDE(_EN).md
├── Train/ # Isaac Sim 4.5 Docker training environment
│ ├── Dockerfile # Base: nvcr.io/nvidia/isaac-sim:4.5.0
│ ├── docker-compose.yml # shm_size 16gb, NVIDIA runtime, cache volumes
│ ├── scripts/ # train_go2_scratch.sh, export_onnx.py
│ ├── mount/ # IsaacLab / rsl_rl / sru-navigation-sim (live-mounted)
│ └── outputs/logs/ # Checkpoints + TensorBoard logs
└── referee_readme/ # Style/structure reference READMEs
```
The three top-level directories map to the three phases of the project:
| Directory | Role |
| -------------- | ------------------------------------------------------------------- |
| `Prompt/` | The porting prompt — regenerate the deployment package from scratch |
| `Deployment/` | Physically validated deployment code, a practical debugging reference |
| `Train/` | Reproducible Docker environment to (re)train the policy |
---
## 5. Prompt-Based Code Generation & Deployment
`Prompt/PORTING_GUIDE.md` is a **three-in-one document** : a porting decision log, an
AI-agent replication prompt, and an automated acceptance script. Its purpose is to let an
LLM agent (Cascade, Claude Code, Cursor, etc.) **regenerate the entire `sru_nav_go2_ros1`
deployment package** starting only from the SRU paper and the five upstream repositories.
### 5.1 The Prompt
Modern LLMs cannot reliably one-shot ~1500 lines of ROS porting code, so
`Prompt/PORTING_GUIDE.md` cuts the task into a **6-step phased workflow** : reconnaissance,
IO specification, catkin skeleton, node logic, deploy scripts, and docs & verify. Each step
ends with grep-able validation points, so any diverging step is rolled back and retried
before moving on. The prompt is plain Markdown and works with any LLM coding agent.
### 5.2 `Deployment/` as a practical reference
The `Deployment/` package is **not generated on the fly** — it is the physically tested,
real-hardware-validated code. Think of it as a highly practical reference rather than a
strict rulebook: if you hit problems while replicating the code through the prompt workflow,
diff your generated package against `Deployment/` to debug and troubleshoot the divergence.
```bash
diff -r --exclude= __pycache__ --exclude= .git \
./generated_sru_nav_go2_ros1/ \
./Deployment/
```
> **Tip:** Structure should be broadly similar; comments and literal ordering may differ.
> When something misbehaves, focus your comparison on the critical parameters
> (`policy_scale`, control frequency, topic names, ONNX tensor shapes) — those are the ones
> that must match for correct behavior.
2026-07-15 16:07:10 +08:00
> The quality of code generated via the prompt workflow may vary depending on
> the capability of the LLM used. In some cases, the generated code may require further
> iteration and refinement with the LLM to achieve full functionality. Always validate
> against the `Deployment/` reference and run the acceptance checks before deploying to
> real hardware.
2026-07-10 16:58:17 +08:00
---
## 6. Training Guide
This is the core focus of the repository. Training is fully containerized around
**Isaac Sim 4.5.0 + IsaacLab v2.1.1** and the `sru-navigation-sim` task extension.
### 6.1 Adaptation Notes
**Sensor adaptation — ZED-X + DLIO → Odin1.**
The policy consumes a normalized single-channel depth image encoded by a VAE into a
`64× 5× 8` latent (2560 features). Upstream produced depth from a ZED-X stereo stream and
odometry from a DLIO LIO stack; here a single Odin1 sensor supplies both. The node ingests
Odin1's depth image, applies `nan_to_num` , clips to `[0.25, 10.0] m` , and
resizes to the training resolution `(40, 64)` before encoding — the network sees the same
tensor regardless of the physical sensor.
**Robot kinematics — B2W → Unitree Go2.**
The upstream B2W is a wheeled-legged platform; the target here is the Unitree Go2. Because the
policy only emits a body-frame velocity command, the kinematic difference is absorbed by
the actuator bridge and by a conservative action scale. The deployment `policy_scale`
defaults to `[0.6, 0.3, 0.6]` (vs. the training `[1.5, 1.0, 1.0]` ), leaving safety margin;
training randomized the action scale by `Uniform(0.6, 1.2)` , so the network is robust to
runtime rescaling.
### 6.2 Quick Start — Docker Training
#### Step 1 — Docker setup, NGC login, and build
```bash
# NVIDIA NGC login is required to pull the Isaac Sim base image.
docker login nvcr.io
# Username: $oauthtoken
# Password: <YOUR_NGC_API_KEY>
cd Train/
cp .env.example .env # optional: add WANDB_API_KEY
docker compose build # first build > 20 min (network dependent)
```
The build pulls `nvcr.io/nvidia/isaac-sim:4.5.0` , installs IsaacLab `v2.1.1` , replaces the
bundled `rsl_rl` with the SRU-enhanced fork (`ActorCriticSRU` + MDPO/PPO), and installs the
`sru-navigation-sim` task extension.
> **Warning — Shared memory is mandatory:** Isaac Sim's OmniGraph pipeline crashes (often as
> a silent segfault) if the container's shared memory is too small. Always run with at least
> **`--shm-size=4gb`** for `docker run`, or **`shm_size: '4gb'`** under the service in
> `docker-compose.yml`. This repository's `docker-compose.yml` and `train_go2_scratch.sh`
> already set `16gb` — do **not** lower this below `4gb`.
#### Step 2 — Launch the container and verify
```bash
docker compose up -d
docker compose exec sru-nav bash # working dir: /workspace/IsaacLab
# Inside the container: confirm the task extension + registered tasks
./isaaclab.sh -p -m pip show isaaclab_nav_task
./isaaclab.sh -p source/isaaclab_nav_task/scripts/train.py --help
```
You should see task IDs such as `Isaac-Nav-PPO-Go2-Dev-v0` and `Isaac-Nav-PPO-Go2-v0` .
#### Step 3 — One-click training with environment variables
From the host, `scripts/train_go2_scratch.sh` launches a cold-start training run inside a
disposable container (headless, 24 envs, 1000 iterations, `Isaac-Nav-PPO-Go2-Dev-v0` by
default). All knobs are overridable via environment variables:
```bash
# Default: 24 envs, 1000 iter, headless (safe on a 12 GB card)
./scripts/train_go2_scratch.sh
# Scale the parallel environment count to your GPU
NUM_ENVS = 64 MAX_ITER = 2000 ./scripts/train_go2_scratch.sh
# GUI debugging with a handful of envs
GUI = 1 NUM_ENVS = 4 MAX_ITER = 200 ./scripts/train_go2_scratch.sh
# Pin a specific GPU and run the full PPO task
GPU = 0 TASK = Isaac-Nav-PPO-Go2-v0 RUN_NAME = scratch_full ./scripts/train_go2_scratch.sh
```
> **VRAM Hardware Scaling Table** — pick `NUM_ENVS` to match your GPU:
| GPU | VRAM | Recommended `NUM_ENVS` |
| ------------------- | ----- | ---------------------- |
| RTX 4090 | 24 GB | 64– 128 |
| RTX 4070 / 5070 | 12 GB | 24 (default) |
| 8 GB Laptop GPU | 8 GB | 8– 12 |
> **Note:** On a 12 GB card, `GUI=1` combined with a large `NUM_ENVS` will OOM — keep GUI
> runs to ≤ 4 envs and use `--headless` (the default) for real training.
Outputs land in `outputs/logs/rsl_rl/<experiment>/<timestamp>_<RUN_NAME>/` on the host
(bind-mounted into the container).
#### Step 4 — Monitor and export
**Monitor** live metrics with TensorBoard:
```bash
# TensorBoard (inside container)
docker compose exec sru-nav \
./isaaclab.sh -p -m tensorboard.main --logdir logs --bind_all
# then open http://<host>:6006
```
**Export** the trained checkpoint to ONNX. The exporter reconstructs `ActorCriticSRU` from
the checkpoint weight shapes (no Isaac Sim needed) and writes `policy.onnx` :
```bash
python scripts/export_onnx.py \
--checkpoint outputs/logs/scratch_reward_fix_v1/model_best.pt \
--output-dir mount/
```
Useful flags (from `scripts/export_onnx.py` ):
| Flag | Default | Description |
| -------------- | -------------- | ---------------------------------------- |
| `--checkpoint` | *(required)* | Path to the `.pt` checkpoint |
| `--output-dir` | `<ckpt>/export` | Output directory |
| `--filename` | `policy.onnx` | Output filename |
| `--jit` | off | Also export a TorchScript `policy.pt` |
| `--verbose` | off | Print inferred config + architecture |
Copy the exported model(s) into `Deployment/models/` for on-robot inference.
---
## 7. ONNX I/O Contract
The training-side export (`export_onnx.py` ) produces a **single combined actor** ONNX that
already ingests the fused observation vector:
| Model | Tensor | Shape | Notes |
| ------------- | --------- | ----------------- | -------------------------------------- |
| `policy.onnx` | `obs` | `(1, 2576)` | 16 proprio + 2560 image latent (64× 5× 8)|
| (input) | `h_in` | `(1, 1, 512)` | LSTM hidden; zeros at episode start |
| (input) | `c_in` | `(1, 1, 512)` | LSTM cell; zeros at episode start |
| `policy.onnx` | `actions` | `(1, 3)` | `tanh` output in `(-1, 1)` |
| (output) | `h_out` | `(1, 1, 512)` | updated hidden state |
| (output) | `c_out` | `(1, 1, 512)` | updated cell state |
The **deployment** package splits inference into two ONNX files so the depth encoder and the
recurrent actor can be validated independently:
| Model | Inputs | Outputs |
| ------------------ | ---------------------------------------- | ---------------------------------- |
| `vae_encoder.onnx` | `input` `(B, 1, 40, 64)` | `mu` `(B, 64, 5, 8)` |
| `nav_policy.onnx` | `obs` `(B, 2576)` , `h` `(1, B, 512)` , `c` `(1, B, 512)` | `actions` `(B, 3)` , `h_new` , `c_new` |
> **Note:** The node discovers tensor names via `session.get_inputs()[i].name` **and**
> asserts them against this contract at startup — a shape mismatch raises immediately rather
> than silently producing garbage commands. Final velocity =
> `tanh_output × policy_scale`, with `policy_scale = [0.6, 0.3, 0.6]` → `[vx, vy, ωz]`.
---
## 8. Real-Hardware Deployment
### 8.1 Hardware & Software Requirements
| Component | Requirement |
| ---------------- | -------------------------------------------------------------------- |
| Robot | Unitree Go2 (or any `/cmd_vel` consumer quadruped) |
| Depth sensor | Odin1 (depth ~10 Hz + high-freq odometry); see launch file for physical mounting offsets |
| Compute | Jetson Orin NX (aarch64) or any Linux x86_64 |
| OS | Ubuntu 20.04 (native ROS Noetic) or `osrf/ros:noetic-desktop` docker |
| Middleware | ROS1 Noetic |
| Python env | conda `sru_go2` , Python **3.8** (bound to Noetic ABI — do not change)|
| Inference | `onnxruntime` (CPU) or `onnxruntime-gpu` (JetPack-matched wheel) |
| Operator input | Unitree remote control |
### 8.2 ROS1 Interface
| Topic | Type | Direction | Description |
| ------------------------------ | -------------------------- | --------- | ------------------------------------ |
| `/odin1/depth_img_competetion` | `sensor_msgs/Image` | in | dense float32 depth, meters, ~10 Hz |
| `/odin1/odometry_highfreq` | `nav_msgs/Odometry` | in | odom frame, ~400 Hz (IMU rate) |
| `/joy` | `sensor_msgs/Joy` | in | Unitree remote control input |
| `/goal_pose` | `geometry_msgs/PoseStamped` | in / out | goal; `frame_id` must equal odom frame|
| `/cmd_vel` | `geometry_msgs/Twist` | out | body-frame velocity command |
> **Note:** `/goal_pose.header.frame_id` **must** match the odom `frame_id` (default
> `odom`); otherwise the node rejects the goal to prevent body-frame coordinates being
> published as odom-frame goals.
### 8.3 Build & Environment Setup
Because conda and system ROS coexist, the launch wrapper handles several ABI hazards
automatically (notably the conda/system `libffi` mismatch that otherwise triggers
`libp11-kit.so.0: undefined symbol: ffi_type_pointer` ). You do not need to configure
anything by hand — `launch_sru_nav.sh` takes care of it.
One-time setup then build inside the conda env at the workspace root:
```bash
# 1) Create the conda env (installs onnxruntime, opencv, netifaces, defusedxml, ...)
bash scripts/setup_conda_env.sh
bash scripts/setup_conda_env.sh --check # ROS dist-packages may [FAIL] outside a container
# 2) Build in the ACTIVATED conda env, at the workspace root
conda activate sru_go2
cd $CATKIN_WS # folder containing src/
catkin_make -DPYTHON_EXECUTABLE= $( which python)
# 3) Self-check
cd $CATKIN_WS /src/sru_nav_go2_ros1
bash scripts/verify_port.sh # all PASS when ONNX present
```
### 8.4 Three-Terminal Launch
The first process to start brings up `roscore` .
**Terminal 1 — Odin1 driver**
```bash
conda activate neupan
roslaunch odin_ros_driver odin1_ros1.launch
# Ensure config/control_command.yaml has senddepth: 1 and sendodom: 1
```
**Terminal 2 — `/cmd_vel` actuator bridge**
```bash
conda activate sru_go2
cd $CATKIN_WS && source devel/setup.bash
rosrun unitree_control unitree_vel_controller __name:= vel_to_sdk
```
**Terminal 3 — SRU navigation node**
```bash
cd $CATKIN_WS /src/sru_nav_go2_ros1
bash scripts/launch_sru_nav.sh require_joystick:= false
```
Setting `require_joystick:=false` stops the Unitree remote control from constantly
broadcasting zero-velocity commands.
Send a goal (in the odom frame) and watch `/cmd_vel` :
```bash
rostopic pub -1 /goal_pose geometry_msgs/PoseStamped \
'{header: {frame_id: "odom"}, pose: {position: {x: 1.0, y: 0.0, z: 0.0}, orientation: {w: 1.0}}}'
rostopic echo /cmd_vel # expect a non-zero Twist stream
```
### 8.5 Configuration Notes
Edit `Deployment/config/sru_nav.yaml` — the only file you normally touch:
| Parameter | Default | Meaning |
| ------------------- | -------------------- | --------------------------------------------------- |
| `depth_topic` | `/odin1/depth_img_competetion` | depth image (meters) |
| `odom_topic` | `/odin1/odometry_highfreq` | world-frame odometry |
| `cmd_vel_topic` | `/cmd_vel` | output body-frame velocity |
| `control_frequency` | `5.0` | Hz — keep aligned with training |
| `policy_scale` | `[0.6, 0.3, 0.6]` | `[vx_max, vy_max, ωz_max]` ; raise gradually |
| `min_depth` /`max_depth` | `0.25` / `10.0` | depth clip range (meters) |
| `use_sim` | `false` | `true` = odom twist already in base frame |
| `require_joystick` | `true` | `false` stops the remote from broadcasting zero-velocity locks (TESTING ONLY) |
### 8.6 Camera Mounting
Camera mounting is set in the launch file, which publishes a static TF
`base_link → odin1_base_link` (adjust to the real measured mount). Offsets are xyz in
meters (forward, left, up) and rpy in radians; defaults are `odin1_x=0.258` , `odin1_y=0.0` ,
`odin1_z=0.154` , `odin1_roll=0.0` , `odin1_pitch=0.0` (0° downward), `odin1_yaw=0.0` :
```bash
roslaunch sru_nav_go2 sru_nav_go2.launch odin1_x:= 0.28 odin1_z:= 0.154 odin1_pitch:= 0.0
```
---
## 9. Troubleshooting / Common Pitfalls
| # | Problem | Solution |
| - | ------- | -------- |
| 1 | ** `/cmd_vel` is all zeros.** Node logs "ready" but the robot never moves. | The Unitree remote control is holding the robot stationary with zero-velocity commands. On jack stands / sim, launch with `require_joystick:=false` . |
| 2 | ** `ModuleNotFoundError: netifaces` / crash on first subscriber.** Node reaches "ready" then dies the moment a topic connects. | `netifaces` / `defusedxml` are missing in the conda env. `pip install netifaces defusedxml` (already built into `setup_conda_env.sh` ). |
| 3 | ** `libp11-kit.so.0: undefined symbol: ffi_type_pointer` .** | Conda's libffi clashes with system `cv_bridge` . Launch via `launch_sru_nav.sh` — the launch script handles this automatically. |
| 4 | **Node shebang points to `/usr/bin/python3`; ONNX import fails.** | `catkin_make` was run outside the conda env. `conda activate sru_go2 && cd $CATKIN_WS && catkin_make clean && catkin_make -DPYTHON_EXECUTABLE=$(which python)` . |
| 5 | ** `zsh` terminal: `setup.zsh: line 7: cd: -q: invalid option` , script dies silently.** | `ZSH_VERSION` leaks into the bash subprocess. `launch_sru_nav.sh` fixes this by exporting `CATKIN_SHELL=bash` and unsetting `ZSH_VERSION` /`ZSH_NAME` before sourcing. |
> **Note (bonus):** Isaac Sim training crashes with an OmniGraph shared-memory error →
> increase `shm_size` (≥ 4 GB, repo default 16 GB). Jetson pip TLS handshake failures →
> the RTC drained; run `sudo ntpdate -u ntp.aliyun.com && sudo hwclock --systohc`.
---
## 10. Citation
If you use this work, please cite the SRU paper:
```bibtex
@article { yang2025sru ,
author = {Yang, Fan and Frivik, Per and Hoeller, David and Wang, Chen and Cadena, Cesar and Hutter, Marco} ,
title = {Spatially-enhanced recurrent memory for long-range mapless navigation via end-to-end reinforcement learning} ,
journal = {The International Journal of Robotics Research} ,
year = {2025} ,
doi = {10.1177/02783649251401926} ,
url = {https://doi.org/10.1177/02783649251401926}
}
```
Paper: <https://doi.org/10.1177/02783649251401926> ·
Project page: <https://michaelfyang.github.io/sru-project-website/>
---
2026-07-15 10:10:09 +08:00
## 11. Acknowledgments
This project builds upon: <https://github.com/sallu-786/Go2_Isaac_ros2>
---
## 12. License
2026-07-10 16:58:17 +08:00
- **Algorithm & training code** — copyright of the original SRU author team (ETH RSL);
follows their upstream LICENSE. Files containing upstream-derived code retain their
original headers.
- **This deployment port** (`Deployment/` ) — released under an **MIT-style** license.
- **Upstream sources:** `sru-navigation-learning` , `sru-navigation-sim` ,
`sru-robot-deployment` , `sru-pytorch-spatial-learning` , `sru-depth-pretraining`
(see <https://michaelfyang.github.io/sru-project-website/>).
- **Simulation stack:** NVIDIA Isaac Sim 4.5.0 + IsaacLab v2.1.1.
- **Odin1 driver:** <https://github.com/manifoldsdk/odin_ros_driver>.
Issues and PRs — especially one-click support for additional robots or cameras — are welcome.