# Odin-Nav-Stack
**Repository Path**: xapples/Odin-Nav-Stack
## Basic Information
- **Project Name**: Odin-Nav-Stack
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-05-11
- **Last Updated**: 2026-05-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
Odin Navigation Stack
**Odin1** is a high-performance spatial sensing module that delivers **high-precision 3D mapping**, **robust relocalization**, and rich sensory streams including **RGB images**, **depth**, **IMU**, **odometry**, and **dense point clouds**. Built on this foundation, we have developed various robotic intelligence stacks for ground platforms like the **Unitree Go2**, enabling:
- **Autonomous navigation with high-efficiency dynamic obstacle avoidance**
- **Semantic object detection + natural-language navigation**
- **Vision-Language Model (VLM) scene understanding and description**
## Key Features
- **High-Accuracy SLAM & Persistent Relocalization** (inside Odin1, not open-sourced)
Real-time mapping with long-term relocalization using compact binary maps.
- **Dynamic Obstacle-Aware Navigation** (fully open-sourced)
Reactive local planners combined with global path planning for safe, smooth motion in complicated environments.
- **Semantic Navigation** (fully open-sourced)
Detect, localize, and navigate to objects using spoken or typed commands (e.g., _“Go to the left of the chair”_).
- **Vision-Language Integration** (fully open-sourced)
Generate contextual scene descriptions in natural language using multimodal AI.
- **Modular, ROS1-Based Architecture**
Easy to extend, customize, and integrate into your own robotic applications.
# Quick Start
The code has been tested on:
- OS: Ubuntu 20.04
- ROS: ROS1 Noetic
- Robot Platform: Unitree Go2
- Hardware: NVIDIA Jetson (Orin Nano) or x86 with GPU
## 1. Clone the Repository
``` shell
git clone --depth 1 --recursive https://github.com/ManifoldTechLtd/Odin-Nav-Stack.git
```
The Odin1 driver may need to update:
``` shell
cd Odin-Nav-Stack/ros_ws/src/odin_ros_driver
git fetch origin
git checkout main
git pull origin main
```
### Odin1 ROS driver modification
We need to modify certain features of the odin1 ROS driver to adapt it for navigation, which may cause conflicts with your other programs.
Please edit the `ros_ws/src/odin_ros_driver/include/host_sdk_sample.h`. Please note the location to modify. You should modify the ROS1 section, not the ROS2 section.
1. Modifiy the `ns_to_ros_time` function:
``` cpp
inline ros::Time ns_to_ros_time(uint64_t timestamp_ns) {
ros::Time t;
#ifdef ROS2
t.sec = static_cast(timestamp_ns / 1000000000);
t.nanosec = static_cast(timestamp_ns % 1000000000);
#else
// t.sec = static_cast(timestamp_ns / 1000000000);
// t.nsec = static_cast(timestamp_ns % 1000000000);
return ros::Time::now();
#endif
return t;
}
```
2. Comment out the low-frequency TF transform in function `publishOdometry`:
``` cpp
switch(odom_type) {
case OdometryType::STANDARD:
{
// geometry_msgs::TransformStamped transformStamped;
// transformStamped.header.stamp = msg.header.stamp;
// transformStamped.header.frame_id = "odom";
// transformStamped.child_frame_id = "odin1_base_link";
// transformStamped.transform.translation.x = msg.pose.pose.position.x;
// transformStamped.transform.translation.y = msg.pose.pose.position.y;
// transformStamped.transform.translation.z = msg.pose.pose.position.z;
// transformStamped.transform.rotation.x = msg.pose.pose.orientation.x;
// transformStamped.transform.rotation.y = msg.pose.pose.orientation.y;
// transformStamped.transform.rotation.z = msg.pose.pose.orientation.z;
// transformStamped.transform.rotation.w = msg.pose.pose.orientation.w;
// tf_broadcaster->sendTransform(transformStamped);
odom_publisher_.publish(msg);
...
```
3. Add high-frequency TF transform publication in function `publishOdometry`:
``` cpp
case OdometryType::HIGHFREQ:{
geometry_msgs::TransformStamped transformStamped;
transformStamped.header.stamp = msg.header.stamp;
transformStamped.header.frame_id = "odom";
transformStamped.child_frame_id = "odin1_base_link";
transformStamped.transform.translation.x = msg.pose.pose.position.x;
transformStamped.transform.translation.y = msg.pose.pose.position.y;
transformStamped.transform.translation.z = msg.pose.pose.position.z;
transformStamped.transform.rotation.x = msg.pose.pose.orientation.x;
transformStamped.transform.rotation.y = msg.pose.pose.orientation.y;
transformStamped.transform.rotation.z = msg.pose.pose.orientation.z;
transformStamped.transform.rotation.w = msg.pose.pose.orientation.w;
tf_broadcaster->sendTransform(transformStamped);
odom_highfreq_publisher_.publish(msg);
break;
}
```
## 2. Install System Dependencies
``` shell
export ROS_DISTRO=noetic
sudo apt update
sudo apt install -y \
ros-${ROS_DISTRO}-tf2-ros \
ros-${ROS_DISTRO}-tf2-geometry-msgs \
ros-${ROS_DISTRO}-cv-bridge \
ros-${ROS_DISTRO}-tf2-eigen \
ros-${ROS_DISTRO}-pcl-ros \
ros-${ROS_DISTRO}-move-base \
ros-${ROS_DISTRO}-dwa-local-planner
```
## 3. Install Unitree Go2 SDK
Follow the official guide:
[Unitree Go2 SDK](https://support.unitree.com/home/zh/developer/Obtain%20SDK?spm=a2ty_o01.29997173.0.0.737bc921PvkEw8)
## 4. Set Up Conda & Mamba
Follow the installation in [miniconda](https://www.anaconda.com/docs/getting-started/miniconda/install#basic-install-instructions).
``` shell
conda install -n base -c conda-forge mamba
# Re-login to your shell after installation
```
## 5. Create the NeuPAN Environment
``` shell
export ROS_DISTRO=noetic
mamba create -n neupan -y
mamba activate neupan
conda config --env --add channels conda-forge
conda config --env --remove channels defaults
conda config --env --add channels robostack-${ROS_DISTRO}
mamba install -n neupan ros-${ROS_DISTRO}-desktop colcon-common-extensions catkin_tools rosdep ros-dev-tools -y
mamba run -n neupan pip install torch==2.8.0 --index-url https://download.pytorch.org/whl/cpu
pip install -e NeuPAN
```
**For different Jetson users**: Replace the PyTorch install with a compatible .whl from [NVIDIA's Jeston PyTorch Page](https://forums.developer.nvidia.com/t/pytorch-for-jetson/72048).
## 6. Build the ROS Workspace
There are two methods for compiling workspaces: one involves using ROS within a conda environment, and the other involves ROS installed system-wide. If you need to compile using the system-installed ROS, ensure all conda environments are deactivated by running `mamba deactivate`.
### System-installed ROS build
``` shell
cd ros_ws
source /opt/ros/${ROS_DISTRO}/setup.bash
catkin_make -DCMAKE_BUILD_TYPE=Release
```
### Conda ROS build
Some packages need to be installed before compile
``` shell
mamba activate neupan
mamba install -c conda-forge -c robostack-noetic ros-noetic-pcl-ros ros-noetic-compressed-image-transport ros-noetic-compressed-depth-image-transport ros-noetic-image-transport
```
Compile:
``` shell
mamba activate neupan
cd ros_ws
catkin_make -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DPCL_VISUALIZATION=OFF -DQT_HOST_PATH=$CONDA_PREFIX
```
## 7. Set USB Rules for Odin1
``` shell
sudo vim /etc/udev/rules.d/99-odin-usb.rules
```
Add the following content to `/etc/udev/rules.d/99-odin-usb.rules`:
``` shell
SUBSYSTEM=="usb", ATTR{idVendor}=="2207", ATTR{idProduct}=="0019", MODE="0666", GROUP="plugdev"
```
Reload rules and reinsert devices
``` shell
sudo udevadm control --reload
sudo udevadm trigger
```
# Usage
- Mapping & Relocalization
- Navigation
- YOLO object detection
- VLM scene explanation
## Mapping and Relocalization with Odin1
Building maps and performing relocalization with Odin1
### 1. Configure Mapping Mode
Edit `ros_ws/src/odin_ros_driver/config/control_command.yaml`, set `custom_map_mode: 1` to enable mapping.
### 2. Launch Mapping
Terminal 1 – Start Odin driver:
``` shell
source ros_ws/devel/setup.bash
roslaunch odin_ros_driver odin1_ros1.launch
```
Terminal 2 – Run mapping script:
``` shell
bash scripts/map_recording.sh awesome_map
```
The pcd map will be saved to `ros_ws/src/pcd2pgm/maps/` and the grid map will be saved to `ros_ws/src/map_planner/maps/`
After the map is constructed, you can view and modify the grid map using GIMP:
``` shell
sudo apt update && sudo apt install gimp
```
### 3. Relocalization & Navigation
Enable relocalization by editing `control_command.yaml`:
``` shell
custom_map_mode: 2
relocalization_map_abs_path: "/abs/path/to/your/map"
```
Launch:
``` shell
roslaunch odin_ros_driver odin1_ros1.launch
```
Verify TF tree: visualize TF tree in rqt: map → odom → odin1_base_link
Relocalization may require manually initiating motion.
## Navigation Modes
### Standard ROS Navigation (Not recommended, TODO)
Use Nav1 and move-base. Please [install](https://wiki.ros.org/navigation) before running.
``` shell
roslaunch navigation_planner navigation_planner.launch
```
### Custom Planner (Not recommended, TODO)
Tune `global_planner.yaml` and `local_planner.yaml` in `ros_ws/src/model_planner`, then:
``` shell
roslaunch model_planner model_planner.launch
```
You can modify the code and replace it with your own custom algorithm.
### End-to-End Neural Planner (Recommended)
This is our recommended high-performance local planner; please refer to the paper: [NeuPAN](https://ieeexplore.ieee.org/document/10938329/).
#### Model Training
If you are not using Unitree Go2, please train the dune model. Modify the training configuration file `NeuPAN/example/dune_train/dune_train_*.py` based on the chassis type, then run:
``` shell
cd NeuPAN/example/dune_train
python dune_train_*.py
```
Replace `*` with your chassis type. For more training detail, please refer to [here](https://github.com/hanruihua/NeuPAN?tab=readme-ov-file#dune-model-training-for-your-own-robot-with-a-specific-convex-geometry).
#### Launch
``` shell
# Terminal 1
roslaunch map_planner whole.launch
# Terminal 2
mamba activate neupan
python NeuPAN/neupan/ros/neupan_ros.py
```
Use RViz to publish 2D Nav Goals. Verify relocalization by visualize TF tree in rqt before publishing goal.
## Object detection
Enables navigation to specific objects. Requires depth maps and undistorted images from Odin1.
### 1. Install YOLOv5 in Virtual Environment:
First, install YOLOv5:
``` shell
python3 -m venv ros_ws/venvs/ros_yolo_py38
source ros_ws/venvs/ros_yolo_py38/bin/activate
pip install --upgrade pip "numpy<2.0.0"
cd ros_ws/src && git clone https://github.com/ultralytics/yolov5.git
pip install -r yolov5/requirements.txt
```
Please note that we encountered a conflict between the automatic installation of torch and torchvision on a certain Jetson Orin Nano. If you encounter this issue, please refer to the troubleshooting section.
Then, install other dependencies:
``` shell
pip install opencv-python pillow pyyaml requests tqdm scipy matplotlib seaborn pandas empy==3.3.4 catkin_pkg ros_pkg vosk sounddevice
```
Verify PyTorch and CUDA:
``` shell
python -c "import torch, torchvision; print('PyTorch:', torch.__version__); print('torchvision:', torchvision.__version__); print('CUDA available:', torch.cuda.is_available())"
```
Download resources:
``` shell
mkdir -p ros_ws/src/yolo_ros/scripts/voicemodel
cd ros_ws/src/yolo_ros/scripts/voicemodel
wget https://alphacephei.com/vosk/models/vosk-model-small-cn-0.22.zip
unzip vosk-model-small-cn-0.22.zip
wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt -O ../models/yolov5s.pt
chmod +x ../yolo_detector.py
```
### 2. Calibrate Camera
Copy `Tcl_0` and `cam_0` from `odin_ros_driver/config/calib.yaml` into `yolo_detector.py`.
### 3. Launch
Terminal 1:
``` shell
roslaunch odin_ros_driver odin1_ros1.launch
```
Terminal 2:
``` shell
./run_yolo_detector.sh
```
In Terminal 2, you can enter the following commands to control it:
- list: Query recognized objects.
- object name: Display the 3D position in RViz.
- Move to the [Nth] [object] [direction]: Publish a navigation goal. (Supprot Chinese input)
- mode: Toggle between text and voice input.
## Vision-Language Model (VLM)
Install LLaMA.cpp:
``` shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install llama.cpp
```
Download models (e.g., SmolVLM):
``` shell
wget https://huggingface.co/ggml-org/SmolVLM-500M-Instruct-GGUF/resolve/main/SmolVLM-500M-Instruct-Q8_0.gguf
wget https://huggingface.co/ggml-org/SmolVLM-500M-Instruct-GGUF/resolve/main/mmproj-SmolVLM-500M-Instruct-Q8_0.gguf
```
### Launch
Terminal 1:
``` shell
llama-server -m SmolVLM-500M-Instruct-Q8_0.gguf --mmproj mmproj-SmolVLM-500M-Instruct-Q8_0.gguf
```
Terminal 2:
``` shell
roslaunch odin_ros_driver odin1_ros1.launch
```
Terminal 3:
``` shell
roslaunch odin_vlm_terminal odin_vlm_terminal.launch
```
## VLN
### Launch
Terminal 1:
``` shell
roslaunch map_planner whole.launch
```
Terminal 2:
``` shell
roslaunch odin_ros_driver odin1_ros1.launch
```
Terminal 3:
``` shell
mamba activate neupan
python NeuPAN/neupan/ros/neupan_ros.py
```
Terminal 4:
``` shell
mamba activate neupan
python scripts/str_cmd_control.py
```
Terminal 5:
``` shell
mamba activate neupan
python scripts/VLN.py
```
# FAQ
## How to check the status of relocalization
Open RViz, set `Global Options`-> `Fixed Frame` to map. In the bottom-left corner, select `Add` -> `By display type` -> `rviz` -> double-click `TF`. The appearance of the odom-map's coordinate axes and connections indicates successful relocalization.
## Start or goal is occupied after publishing the goal
If the start or end point is occupied, you can check the inflation map `/inflated_map` in RViz. The start and end points must lie outside the inflation area. Additionally, you can modify the inflation radius in `ros_ws/src/map_planner/launch/whole.launch:inflation_radius`.
## Unable to stop near the target point
This is a NeuPAN issue; there may be errors in reaching the target point. You can try increasing the `goal_tolerance` parameter in `ros_ws/src/map_planner/launch/whole.launch`.
If you have any other questions, you can post them on GitHub Issues.
# Troubleshooting
## torch conflict with torchvision
Error:`torch.cuda.is_available() returns False`
Cause: torchvision overwrote the CUDA-enabled PyTorch installation.
Fix:
``` shell
pip uninstall torch torchvision torchaudio
# Reinstall torch from .whl
pip install torch-*.whl
pip install --no-cache-dir "git+https://github.com/pytorch/vision.git@v0.16.0"
```
If the problem persists, you can try the following methods:
Navigate to `cd ros_ws/src/yolov5/utils`, open the `general.py` file, and locate the following code:
``` python
# Batched NMS
c = x[:, 5:6] * (0 if agnostic else max_wh) # classes
boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores
i = torchvision.ops.nms(boxes, scores, iou_thres) # NMS
```
Modify the YOLO code:
``` python
# Batched NMS (using pure PyTorch to avoid torchvision.ops compatibility issues)
c = x[:, 5:6] * (0 if agnostic else max_wh) # classes
boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores
# Pure PyTorch NMS implementation
sorted_idx = torch.argsort(scores, descending=True)
keep = []
while len(sorted_idx) > 0:
current_idx = sorted_idx[0]
keep.append(current_idx)
if len(sorted_idx) == 1:
break
current_box = boxes[current_idx:current_idx+1]
rest_boxes = boxes[sorted_idx[1:]]
# Calculate IoU
inter_x1 = torch.max(current_box[:, 0], rest_boxes[:, 0])
inter_y1 = torch.max(current_box[:, 1], rest_boxes[:, 1])
inter_x2 = torch.min(current_box[:, 2], rest_boxes[:, 2])
inter_y2 = torch.min(current_box[:, 3], rest_boxes[:, 3])
inter_w = torch.clamp(inter_x2 - inter_x1, min=0)
inter_h = torch.clamp(inter_y2 - inter_y1, min=0)
inter_area = inter_w * inter_h
current_area = (current_box[:, 2] - current_box[:, 0]) * (current_box[:, 3] - current_box[:, 1])
rest_area = (rest_boxes[:, 2] - rest_boxes[:, 0]) * (rest_boxes[:, 3] - rest_boxes[:, 1])
union_area = current_area + rest_area - inter_area
iou = inter_area / union_area
sorted_idx = sorted_idx[1:][iou < iou_thres]
i = torch.tensor(keep, dtype=torch.long, device=boxes.device)
```
## libgomp problem
Error: `libgomp` not found or similar problem
Cause: Missing installation or corrupted library files.
Fix:
``` shell
for f in ~/venvs/ros_yolo_py38/lib/python3.8/site-packages/torch.libs/libgomp*.so*; do
[ -f "$f" ] && mv "$f" "$f.bak"
done
```
# Acknowledgements
Thanks to the excellent work by [ROS Navigation](https://github.com/ros-planning/navigation), [NeuPAN](https://github.com/hanruihua/NeuPAN), [Ultralytics YOLO](https://github.com/ultralytics/ultralytics) and [Qwen](https://github.com/QwenLM/Qwen3-VL).
Special thanks to [hanruihua](https://github.com/hanruihua), [KevinLADLee](https://github.com/KevinLADLee) and [bearswang](https://github.com/bearswang) for their technical support.