Skip to main content

Chapter 3: Visual SLAM for Humanoid Navigation

Introduction​

Imagine your humanoid robot entering an unknown warehouse. To navigate safely, it must answer two fundamental questions simultaneously:

  1. Where am I? (Localization)
  2. What does the environment look like? (Mapping)

Visual SLAM (Simultaneous Localization and Mapping) solves both problems by using camera data to build a map while tracking the robot's position within that map. This is a chicken-and-egg problem: you need a map to localize, and you need localization to build a map. SLAM algorithms elegantly solve this circular dependency.

In this chapter, you'll learn:

  • The fundamentals of Visual SLAM (feature extraction, matching, pose estimation)
  • How to deploy Isaac ROS Visual SLAM with NVIDIA CUDA acceleration
  • Integrating Visual SLAM with ROS 2 navigation
  • Advanced techniques (loop closure, drift correction, multi-camera fusion)

What is SLAM?​

SLAM is the process of constructing a map of an unknown environment while simultaneously tracking the robot's location within that map.

Types of SLAM​

TypeSensorsStrengthsWeaknesses
LiDAR SLAM2D/3D LiDARAccurate, works in darkExpensive, heavy, high power
Visual SLAMCameras (mono, stereo, RGB-D)Cheap, lightweight, rich semantic infoSensitive to lighting, textureless scenes
Inertial SLAMIMUHigh-rate odometryDrifts quickly without correction
Fusion SLAMCamera + IMU + LiDARBest accuracy and robustnessComplex sensor fusion

For humanoid robots, Visual SLAM is preferred because:

  • Cameras are lightweight and low-power
  • Visual data enables object recognition and scene understanding
  • Stereo or depth cameras provide 3D structure

Visual SLAM Pipeline​

A typical Visual SLAM system consists of:

1. Feature Extraction → Detect keypoints (corners, edges)
2. Feature Matching → Match features across frames
3. Motion Estimation → Estimate camera movement (odometry)
4. Mapping → Add new landmarks to the map
5. Loop Closure → Detect revisited locations and correct drift
6. Optimization → Refine poses and map (Bundle Adjustment)

Example Visual SLAM Frameworks​

FrameworkTypeFeaturesROS 2 Support
ORB-SLAM3Feature-basedMonocular, stereo, RGB-DVia third-party wrappers
RTAB-MapGraph-basedLoop closure, large mapsNative ROS 2
Isaac ROS Visual SLAMFeature-basedCUDA-accelerated, low latencyNative ROS 2
OpenVSLAMFeature-basedLightweightVia third-party wrappers

Isaac ROS Visual SLAM is optimized for real-time performance on NVIDIA GPUs, achieving sub-10ms latency on RTX hardware.


Isaac ROS Visual SLAM Architecture​

Isaac ROS Visual SLAM (cuVSLAM) uses:

  • ORB features: Fast corner detection (FAST) + binary descriptors
  • CUDA acceleration: Parallel feature extraction and matching
  • Keyframe-based mapping: Only select frames are added to the map
  • Graph optimization: Pose graph optimization for global consistency

Key Capabilities​

  • Stereo and RGB-D camera support
  • Visual odometry (pose estimation between frames)
  • Localization (pose relative to the map)
  • Loop closure detection (detect revisited areas to correct drift)
  • ROS 2 integration (publishes nav_msgs/Odometry and tf transforms)

Installing Isaac ROS Visual SLAM​

Prerequisites​

  • Isaac ROS Docker container (from Chapter 2)
  • Stereo camera (ZED, RealSense D435i, or Intel RealSense T265)
  • ROS 2 Humble

Step 1: Clone the Repository​

cd ~/workspaces/isaac_ros-dev/src
git clone https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_visual_slam.git

Step 2: Build the Package​

Inside the Docker container:

cd /workspaces/isaac_ros-dev
colcon build --packages-up-to isaac_ros_visual_slam
source install/setup.bash

Step 3: Download Sample Data (Optional)​

# Download rosbag with stereo camera data
wget https://nvidia-isaac-ros.github.io/data/r2b_galileo.bag

Running Isaac ROS Visual SLAM​

Example 1: Stereo Camera SLAM​

Launch File​

# File: isaac_vslam_stereo.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
Node(
package='isaac_ros_visual_slam',
executable='isaac_ros_visual_slam',
name='visual_slam',
parameters=[{
'enable_rectified_pose': True,
'denoise_input_images': False,
'rectified_images': True,
'enable_debug_mode': False,
'debug_dump_path': '/tmp/cuvslam',
'enable_slam_visualization': True,
'enable_landmarks_view': True,
'enable_observations_view': True,
'map_frame': 'map',
'odom_frame': 'odom',
'base_frame': 'base_link',
'input_base_frame': 'camera_link',
'camera_optical_frames': [
'camera_infra1_optical_frame',
'camera_infra2_optical_frame'
],
}],
remappings=[
('stereo_camera/left/image', '/camera/infra1/image_rect_raw'),
('stereo_camera/left/camera_info', '/camera/infra1/camera_info'),
('stereo_camera/right/image', '/camera/infra2/image_rect_raw'),
('stereo_camera/right/camera_info', '/camera/infra2/camera_info'),
]
)
])

Run SLAM​

# Terminal 1: Launch camera driver (Intel RealSense example)
ros2 launch realsense2_camera rs_launch.py \
enable_infra1:=true enable_infra2:=true enable_color:=false

# Terminal 2: Launch Visual SLAM
ros2 launch isaac_ros_visual_slam isaac_vslam_stereo.launch.py

# Terminal 3: Visualize in RViz
rviz2 -d $(ros2 pkg prefix isaac_ros_visual_slam)/share/isaac_ros_visual_slam/rviz/default.rviz

What You'll See in RViz​

  • Odometry path (green): Estimated robot trajectory
  • Landmarks (red points): 3D feature points in the map
  • Camera frustum: Current camera pose
  • Loop closures (blue lines): Connections when revisiting locations
✅Real-Time Performance

Isaac ROS Visual SLAM processes 640x480 stereo images at 60 FPS with lesser than 10ms latency on RTX 3070.


Example 2: RGB-D Camera SLAM​

For depth cameras (RealSense D435i, Kinect):

# File: isaac_vslam_rgbd.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
Node(
package='isaac_ros_visual_slam',
executable='isaac_ros_visual_slam',
name='visual_slam',
parameters=[{
'enable_rectified_pose': True,
'rectified_images': False,
'enable_imu_fusion': False,
}],
remappings=[
('visual_slam/image_0', '/camera/color/image_raw'),
('visual_slam/camera_info_0', '/camera/color/camera_info'),
('visual_slam/depth/image_0', '/camera/depth/image_rect_raw'),
('visual_slam/depth/camera_info_0', '/camera/depth/camera_info'),
]
)
])

Understanding Visual SLAM Outputs​

1. Odometry (nav_msgs/Odometry)​

Published on /visual_slam/tracking/odometry:

header:
frame_id: odom
child_frame_id: base_link
pose:
position: {x: 1.23, y: -0.45, z: 0.02}
orientation: {x: 0.0, y: 0.0, z: 0.1, w: 0.995}
twist:
linear: {x: 0.5, y: 0.0, z: 0.0}
angular: {x: 0.0, y: 0.0, z: 0.1}

2. TF Transforms​

Isaac ROS Visual SLAM publishes:

  • map → odom: Global correction (updated on loop closures)
  • odom → base_link: Continuous odometry
map
└─ odom
└─ base_link
└─ camera_link

3. Map Points (sensor_msgs/PointCloud2)​

Published on /visual_slam/tracking/landmarks:

# 3D coordinates of tracked features
points: [[x1, y1, z1], [x2, y2, z2], ...]

4. Tracking Status (isaac_ros_visual_slam_interfaces/VisualSlamStatus)​

Published on /visual_slam/status:

tracking_status: "TRACKING"  # or "LOST"
num_observations: 342
num_landmarks: 1523
loop_closure_count: 3

Loop Closure and Drift Correction​

What is Loop Closure?​

Loop closure detects when the robot revisits a previously mapped area. This is critical for correcting accumulated drift.

Without loop closure:

Start → ... → End (position error grows over time)

With loop closure:

Start → ... → revisit Start → Correct drift globally

How Isaac ROS Detects Loop Closures​

  1. Visual similarity: Compare current frame features with keyframes in the map
  2. Geometric verification: Verify spatial consistency (RANSAC)
  3. Pose graph optimization: Adjust all past poses to satisfy loop closure constraints

Enabling Loop Closure​

Loop closure is enabled by default in Isaac ROS Visual SLAM. Monitor it via:

ros2 topic echo /visual_slam/status | grep loop_closure_count

Localizing Against a Pre-Built Map​

Once you've built a map, you can save it and later localize against it (without re-building).

Step 1: Save the Map​

# While SLAM is running
ros2 service call /visual_slam/save_map \
isaac_ros_visual_slam_interfaces/srv/FilePath \
"{file_path: '/tmp/my_warehouse_map'}"

Step 2: Load the Map for Localization​

# Update launch file parameter
parameters=[{
'enable_localization_on_start': True,
'map_folder_path': '/tmp/my_warehouse_map',
}]

Step 3: Launch Localization Mode​

ros2 launch isaac_ros_visual_slam isaac_vslam_stereo.launch.py

Now the robot will localize itself against the saved map without creating a new one.

ℹ️Map Persistence

Saved maps include keyframes, landmarks, and the pose graph. They can be reused across sessions for consistent localization.


Fusing IMU Data (VIO: Visual-Inertial Odometry)​

For even better accuracy, fuse camera and IMU data. This is called VIO (Visual-Inertial Odometry).

Benefits of IMU Fusion​

  • Faster pose updates: IMU runs at 200-500 Hz (vs. camera at 30-60 Hz)
  • Better motion estimation: Especially during fast movements
  • Robustness: IMU helps when visual features are scarce

Example: Enabling IMU Fusion​

parameters=[{
'enable_imu_fusion': True,
}],
remappings=[
('visual_slam/imu', '/imu/data'),
]

Input: sensor_msgs/Imu from an IMU (e.g., RealSense built-in IMU)


Tuning Visual SLAM for Humanoid Robots​

1. Handle Dynamic Environments​

Humanoid robots often operate in dynamic spaces (people walking, objects moving). Enable outlier rejection:

parameters=[{
'enable_outlier_rejection': True,
'outlier_rejection_threshold': 2.0, # Stricter for dynamic scenes
}]

2. Adjust Feature Count​

More features = better tracking, but slower processing:

parameters=[{
'num_cameras': 2,
'max_features_per_camera': 400, # Default: 400 (reduce for speed)
}]

3. Optimize for Tall Aspect Ratio​

Humanoid cameras are often mounted high. Adjust the field of view assumptions if needed.


Integrating with Nav2​

To use Visual SLAM for navigation, publish odometry to Nav2:

# Nav2 expects odometry on /odom topic
remappings=[
('visual_slam/tracking/odometry', '/odom'),
]

Then Nav2's amcl or slam_toolbox can fuse this with laser scans.


Debugging Visual SLAM​

Issue 1: Tracking Lost​

Symptoms: Status shows LOST, odometry stops updating

Causes:

  • Insufficient features (textureless walls, uniform lighting)
  • Too fast motion (motion blur)
  • Camera not calibrated

Solutions:

  • Add visual features to the environment (posters, markers)
  • Reduce robot speed
  • Recalibrate camera with camera_calibration

Issue 2: Drift Over Time​

Symptoms: Robot position drifts away from ground truth

Causes:

  • No loop closures detected
  • Poor feature quality

Solutions:

  • Revisit start location to trigger loop closure
  • Improve lighting conditions
  • Enable IMU fusion

Issue 3: High Latency​

Symptoms: Odometry lags behind real motion

Causes:

  • Insufficient GPU resources
  • Too many features

Solutions:

  • Reduce max_features_per_camera
  • Lower image resolution
  • Ensure no other GPU processes are running

Visualizing SLAM in RViz​

Add these displays to RViz:

  1. Odometry (/visual_slam/tracking/odometry)

    • Display Type: Odometry
    • Show axes and path
  2. Landmarks (/visual_slam/tracking/landmarks)

    • Display Type: PointCloud2
    • Color by Z-axis
  3. Camera Pose (/visual_slam/tracking/vo_pose_covariance)

    • Display Type: PoseWithCovariance
  4. TF Tree

    • Display Type: TF
    • Show map, odom, base_link

Benchmarking Visual SLAM​

# Record a rosbag for repeatability
ros2 bag record -a -o slam_test.bag

# Play back and measure
ros2 bag play slam_test.bag

# Analyze trajectory accuracy (requires ground truth)
evo_ape bag slam_test.bag /visual_slam/tracking/odometry --pose_relation=trans_part

Advanced: Multi-Camera SLAM​

For 360° coverage, use multiple cameras:

parameters=[{
'num_cameras': 4,
'camera_optical_frames': [
'camera_front_optical',
'camera_left_optical',
'camera_right_optical',
'camera_back_optical',
],
}],
remappings=[
('visual_slam/image_0', '/camera_front/image'),
('visual_slam/image_1', '/camera_left/image'),
('visual_slam/image_2', '/camera_right/image'),
('visual_slam/image_3', '/camera_back/image'),
]

Summary​

In this chapter, you learned:

  • ✅ The fundamentals of Visual SLAM (localization + mapping)
  • ✅ Installing and running Isaac ROS Visual SLAM
  • ✅ Processing stereo and RGB-D camera data
  • ✅ Understanding SLAM outputs (odometry, landmarks, TF)
  • ✅ Enabling loop closure for drift correction
  • ✅ Localizing against pre-built maps
  • ✅ Fusing IMU data for Visual-Inertial Odometry
  • ✅ Debugging and tuning for humanoid robots

Next Steps: With localization and mapping in place, you're ready to plan paths and navigate autonomously. In Chapter 4: Nav2 Path Planning for Bipedal Movement, you'll learn how to configure Nav2 for humanoid navigation with footstep planning and balance constraints.


Additional Resources​

Next: Chapter 4: Nav2 Path Planning for Bipedal Movement →