Skip to main content

Chapter 3.3: Isaac Manipulation and Navigation

Module: 3 - The AI-Robot Brain Week: 11 Estimated Reading Time: 30 minutes


Learning Objectives​

By the end of this chapter, you will be able to:

  1. Integrate Isaac Visual SLAM with Nav2 for autonomous navigation
  2. Use cuMotion for GPU-accelerated motion planning
  3. Configure costmaps and planners for mobile robots
  4. Implement autonomous waypoint navigation
  5. Debug navigation issues with RViz2 and logs

Prerequisites​

  • Completed Chapters 3.1 and 3.2
  • Understanding of navigation concepts (SLAM, costmaps, planners)
  • Familiarity with Nav2 (ROS 2 navigation stack)

Introduction​

GPU-accelerated navigation and manipulation enable real-time decision making for mobile robots. This chapter covers integrating Isaac's Visual SLAM and cuMotion with ROS 2's Nav2 stack, achieving <100ms planning latency for complex environments.

Why GPU Acceleration Matters:

  • Visual SLAM: 30-60 FPS localization (vs 5-10 FPS on CPU)
  • Motion Planning: 10-50ms trajectory generation (vs 200-500ms on CPU)
  • Sensor Fusion: Real-time processing of multiple depth cameras
  • Scalability: Run SLAM + planning + perception simultaneously

Key Terms​

Glossary Terms
  • Nav2: ROS 2 navigation framework for mobile robots
  • Costmap: 2D grid representing obstacle occupancy and traversability
  • cuMotion: NVIDIA's GPU-accelerated motion planning library
  • Visual SLAM: Simultaneous localization and mapping using cameras
  • AMCL: Adaptive Monte Carlo Localization (particle filter)
  • DWA: Dynamic Window Approach (local planner)

Core Concepts​

1. Isaac Visual SLAM​

Isaac Visual SLAM (vSLAM) provides GPU-accelerated stereo SLAM at 30+ FPS.

Architecture​

Stereo Camera → Image Rectification → Feature Extraction → Pose Estimation → Map Update
(ROS) (GPU, CUDA) (GPU, ORB) (GPU, BA) (GPU, OctoMap)

Key Features:

  1. Stereo SLAM: Uses ZED, RealSense D435, or Hawk cameras
  2. GPU Bundle Adjustment: Optimize poses at 30 Hz
  3. Loop Closure: Detect revisited areas for map consistency
  4. Odometry: Publishes to /odom topic for Nav2

Installation​

# Install Isaac ROS Visual SLAM
cd ~/isaac_ros_ws/src
git clone https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_visual_slam.git

# Build
cd ~/isaac_ros_ws
colcon build --packages-select isaac_ros_visual_slam
source install/setup.bash

Launch Configuration​

Launch File (vslam.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='visual_slam_node',
name='visual_slam',
parameters=[{
'enable_rectified_pose': True,
'denoise_input_images': True,
'rectified_images': True,
'enable_slam_visualization': True,
'enable_observations_view': True,
'enable_landmarks_view': True,
'map_frame': 'map',
'odom_frame': 'odom',
'base_frame': 'base_link',
'input_left_camera_frame': 'left_camera',
'input_right_camera_frame': 'right_camera',
}],
remappings=[
('/stereo_camera/left/image', '/zed/left/image_rect_color'),
('/stereo_camera/right/image', '/zed/right/image_rect_color'),
('/stereo_camera/left/camera_info', '/zed/left/camera_info'),
('/stereo_camera/right/camera_info', '/zed/right/camera_info'),
]
)
])

Run:

ros2 launch my_nav_pkg vslam.launch.py

Expected Output:

[visual_slam]: Initialized with GPU acceleration
[visual_slam]: Tracking: 850 features, pose confidence: 0.98
[visual_slam]: Map size: 12,543 landmarks
[visual_slam]: FPS: 32.1, latency: 31ms

Tuning Parameters​

For High-Speed Robots (2+ m/s):

parameters=[{
'num_cameras': 2,
'min_num_images': 4, # Require more images for stability
'horizontal_stereo_camera': True,
}]

For Low-Light Environments:

parameters=[{
'denoise_input_images': True,
'rectified_images': True,
'enable_image_denoising': True,
}]

2. Nav2 Integration​

Nav2 is the ROS 2 navigation stack. Isaac SLAM integrates via standard topics.

System Architecture​

Isaac vSLAM → /odom, /map → Nav2 Controller → /cmd_vel → Robot Base
↓
Costmap2D (obstacles) → Global Planner → Local Planner
↑
Sensor Data (lidar, depth)

File: nav2_params.yaml

bt_navigator:
ros__parameters:
use_sim_time: false
global_frame: map
robot_base_frame: base_link
odom_topic: /odom
bt_loop_duration: 10
default_server_timeout: 20

controller_server:
ros__parameters:
use_sim_time: false
controller_frequency: 20.0
min_x_velocity_threshold: 0.001
min_y_velocity_threshold: 0.5
min_theta_velocity_threshold: 0.001

# DWA (Dynamic Window Approach) parameters
FollowPath:
plugin: "dwb_core::DWBLocalPlanner"
max_vel_x: 0.5
min_vel_x: -0.5
max_vel_theta: 1.0
min_speed_xy: 0.0
acc_lim_x: 2.5
acc_lim_theta: 3.2

planner_server:
ros__parameters:
use_sim_time: false
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner"
tolerance: 0.5
use_astar: false
allow_unknown: true

global_costmap:
global_costmap:
ros__parameters:
update_frequency: 1.0
publish_frequency: 1.0
global_frame: map
robot_base_frame: base_link
use_sim_time: false
resolution: 0.05
width: 50
height: 50

plugins: ["static_layer", "obstacle_layer", "inflation_layer"]

obstacle_layer:
plugin: "nav2_costmap_2d::ObstacleLayer"
enabled: True
observation_sources: scan depth

scan:
topic: /scan
max_obstacle_height: 2.0
clearing: True
marking: True

depth:
topic: /depth/points
max_obstacle_height: 2.0
clearing: True
marking: True

inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
cost_scaling_factor: 3.0
inflation_radius: 0.55

local_costmap:
local_costmap:
ros__parameters:
update_frequency: 5.0
publish_frequency: 2.0
global_frame: odom
robot_base_frame: base_link
use_sim_time: false
rolling_window: true
width: 10
height: 10
resolution: 0.05

Launch Nav2 with Isaac SLAM​

Launch File (isaac_nav2.launch.py):

from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from ament_index_python.packages import get_package_share_directory
import os

def generate_launch_description():
nav2_bringup_dir = get_package_share_directory('nav2_bringup')

return LaunchDescription([
# Launch Isaac Visual SLAM
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('my_nav_pkg'), 'launch', 'vslam.launch.py')
)
),

# Launch Nav2
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(nav2_bringup_dir, 'launch', 'navigation_launch.py')
),
launch_arguments={
'params_file': os.path.join(get_package_share_directory('my_nav_pkg'), 'config', 'nav2_params.yaml'),
'use_sim_time': 'false'
}.items()
),

# RViz for visualization
Node(
package='rviz2',
executable='rviz2',
name='rviz2',
arguments=['-d', os.path.join(get_package_share_directory('my_nav_pkg'), 'rviz', 'nav2.rviz')]
)
])

3. cuMotion: GPU Motion Planning​

cuMotion accelerates trajectory optimization using GPU parallel computing.

Why cuMotion?​

Traditional Motion Planning (MoveIt2 on CPU):

  • Planning time: 200-500ms for complex scenes
  • Limited real-time replanning capability

cuMotion (GPU-accelerated):

  • Planning time: 10-50ms (10× faster)
  • Real-time obstacle avoidance
  • Parallel evaluation of 1000s of trajectories

Architecture​

Robot State → cuMotion Planner (GPU) → Optimized Trajectory → Controller
↑
Collision Check (GPU, parallel)

Installation​

# Install cuMotion (included in Isaac Manipulator package)
cd ~/isaac_ros_ws/src
git clone https://github.com/NVIDIA-ISAAC-ROS/isaac_manipulator.git

# Build
cd ~/isaac_ros_ws
colcon build --packages-select isaac_ros_cumotion
source install/setup.bash

Using cuMotion​

Example: Panda Arm Planning

from rclpy.node import Node
from geometry_msgs.msg import PoseStamped
from isaac_ros_cumotion_msgs.srv import GetMotionPlan

class CuMotionClient(Node):
def __init__(self):
super().__init__('cumotion_client')
self.client = self.create_client(GetMotionPlan, '/cumotion/get_motion_plan')

def plan_to_pose(self, target_pose):
request = GetMotionPlan.Request()
request.target_pose = target_pose
request.planning_time = 0.05 # 50ms timeout

future = self.client.call_async(request)
rclpy.spin_until_future_complete(self, future)

if future.result().success:
self.get_logger().info(f'Plan found in {future.result().planning_time:.3f}s')
return future.result().trajectory
else:
self.get_logger().error('Planning failed')
return None

Performance Comparison:

PlannerPlanning TimeSuccess RateHardware
OMPL (CPU)450ms85%Intel i7
cuMotion (GPU)35ms92%RTX 3060

4. Autonomous Navigation Pipeline​

End-to-End System​

Complete Navigation Node:

import rclpy
from rclpy.node import Node
from geometry_msgs.msg import PoseStamped
from nav2_msgs.action import NavigateToPose
from rclpy.action import ActionClient

class AutonomousNavigator(Node):
def __init__(self):
super().__init__('autonomous_navigator')

# Nav2 action client
self.nav_client = ActionClient(self, NavigateToPose, 'navigate_to_pose')

# Wait for Nav2 to be ready
self.nav_client.wait_for_server()
self.get_logger().info('Nav2 action server ready')

def navigate_to_waypoint(self, x, y, theta):
"""Navigate to a waypoint (x, y, theta)"""
goal_msg = NavigateToPose.Goal()
goal_msg.pose.header.frame_id = 'map'
goal_msg.pose.header.stamp = self.get_clock().now().to_msg()

goal_msg.pose.pose.position.x = x
goal_msg.pose.pose.position.y = y
goal_msg.pose.pose.position.z = 0.0

# Convert theta to quaternion
goal_msg.pose.pose.orientation.z = np.sin(theta / 2.0)
goal_msg.pose.pose.orientation.w = np.cos(theta / 2.0)

self.get_logger().info(f'Navigating to ({x:.2f}, {y:.2f}, {theta:.2f})')

send_goal_future = self.nav_client.send_goal_async(goal_msg)
rclpy.spin_until_future_complete(self, send_goal_future)

goal_handle = send_goal_future.result()
if not goal_handle.accepted:
self.get_logger().error('Goal rejected')
return False

# Wait for result
result_future = goal_handle.get_result_async()
rclpy.spin_until_future_complete(self, result_future)

result = result_future.result().result
if result:
self.get_logger().info('Goal reached!')
return True
else:
self.get_logger().error('Navigation failed')
return False

def multi_waypoint_mission(self, waypoints):
"""Navigate through multiple waypoints"""
for i, (x, y, theta) in enumerate(waypoints):
self.get_logger().info(f'Waypoint {i+1}/{len(waypoints)}')
success = self.navigate_to_waypoint(x, y, theta)

if not success:
self.get_logger().error(f'Mission aborted at waypoint {i+1}')
return False

self.get_logger().info('Mission complete!')
return True

def main():
rclpy.init()
navigator = AutonomousNavigator()

# Define warehouse patrol route
waypoints = [
(2.0, 0.0, 0.0), # Waypoint 1
(2.0, 2.0, 1.57), # Waypoint 2 (90° turn)
(0.0, 2.0, 3.14), # Waypoint 3 (180° turn)
(0.0, 0.0, -1.57), # Waypoint 4 (return)
]

navigator.multi_waypoint_mission(waypoints)

rclpy.shutdown()

if __name__ == '__main__':
main()

Run:

ros2 run my_nav_pkg autonomous_navigator

Practical Example: Warehouse Robot Navigation​

Scenario: TurtleBot3 autonomously navigates a warehouse to scan shelves.

Step 1: Launch Isaac SLAM + Nav2​

# Terminal 1: Launch Isaac Visual SLAM and Nav2
ros2 launch my_nav_pkg isaac_nav2.launch.py

# Expected output:
# [visual_slam]: Tracking at 32 FPS
# [nav2]: Controller server active
# [nav2]: Planner server active

Step 2: Create Initial Map​

# Terminal 2: Teleoperate robot to build map
ros2 run teleop_twist_keyboard teleop_twist_keyboard

# Drive around warehouse for 2-3 minutes

Step 3: Save Map​

# Terminal 3: Save map
ros2 run nav2_map_server map_saver_cli -f ~/maps/warehouse_map

Step 4: Run Autonomous Mission​

# warehouse_patrol.py
import rclpy
from autonomous_navigator import AutonomousNavigator

def main():
rclpy.init()
navigator = AutonomousNavigator()

# Define shelf inspection waypoints
shelf_waypoints = [
(1.0, 0.5, 0.0), # Shelf A
(3.5, 0.5, 0.0), # Shelf B
(6.0, 0.5, 0.0), # Shelf C
(6.0, 3.0, 1.57), # Turn corner
(3.5, 3.0, 3.14), # Shelf D
(1.0, 3.0, 3.14), # Shelf E
(0.5, 1.5, -1.57), # Return to base
]

navigator.multi_waypoint_mission(shelf_waypoints)
rclpy.shutdown()

if __name__ == '__main__':
main()

Run:

ros2 run my_nav_pkg warehouse_patrol

Expected Performance:

  • Map coverage: 95%+ of warehouse
  • Average speed: 0.4 m/s
  • Obstacle avoidance: <50cm clearance
  • Mission completion: 8-10 minutes for 7 waypoints

Debugging Navigation Issues​

Issue 1: Robot Not Moving​

Symptoms: Nav2 accepts goal but robot doesn't move

Diagnosis:

# Check cmd_vel topic
ros2 topic hz /cmd_vel
# Expected: 20 Hz

# Check controller status
ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose "{pose: {header: {frame_id: 'map'}, pose: {position: {x: 1.0, y: 0.0}}}}" --feedback

Solution:

# Increase velocity limits in nav2_params.yaml
controller_server:
ros__parameters:
FollowPath:
max_vel_x: 0.5 # Increase from 0.26
min_vel_x: -0.5

Issue 2: Poor Localization​

Symptoms: Robot pose drifts, map doesn't align

Diagnosis:

# Check vSLAM tracking
ros2 topic echo /visual_slam/tracking_status

# Check feature count
ros2 topic echo /visual_slam/status

Solution:

  1. Add more visual features to environment (posters, markers)
  2. Increase feature detection threshold:
parameters=[{
'num_cameras': 2,
'enable_slam_visualization': True,
'min_num_images': 4, # Increase for better tracking
}]

Issue 3: Oscillation Near Goal​

Symptoms: Robot oscillates back and forth near waypoint

Solution:

# Tune DWA parameters
controller_server:
ros__parameters:
FollowPath:
xy_goal_tolerance: 0.1 # Increase tolerance
yaw_goal_tolerance: 0.2
trans_stopped_velocity: 0.05

Performance Optimization​

1. Reduce Latency​

Enable Zero-Copy Transport:

Node(
package='isaac_ros_visual_slam',
executable='visual_slam_node',
parameters=[{
'use_intra_process_comms': True, # Zero-copy
}]
)

2. Increase Planning Frequency​

controller_server:
ros__parameters:
controller_frequency: 30.0 # Increase from 20.0

3. Optimize Costmap​

local_costmap:
local_costmap:
ros__parameters:
update_frequency: 10.0 # Increase from 5.0
resolution: 0.03 # Finer resolution

Summary​

This chapter covered Isaac ROS Navigation and Manipulation:

  1. Isaac Visual SLAM: 30+ FPS stereo SLAM with GPU acceleration
  2. Nav2 Integration: Seamless connection to ROS 2 navigation stack
  3. cuMotion: 10× faster motion planning with GPU
  4. Autonomous Navigation: Waypoint missions with obstacle avoidance

Key Takeaways:

  • GPU acceleration enables real-time SLAM + planning simultaneously
  • Isaac vSLAM integrates with Nav2 via standard /odom and /map topics
  • cuMotion reduces planning time from 500ms to 35ms
  • Proper parameter tuning critical for reliable navigation

Next Chapter: Isaac Gym for reinforcement learning and sim-to-real transfer.


End-of-Chapter Exercises​

Exercise 1: Autonomous Waypoint Navigation (Difficulty: Medium)​

Tasks:

  1. Launch Isaac Visual SLAM with stereo camera
  2. Build a map of your environment
  3. Configure Nav2 with custom parameters
  4. Create a 5-waypoint patrol route
  5. Measure navigation success rate (>90%)

Success Criteria: Complete 10 consecutive patrol missions without manual intervention

Exercise 2: Dynamic Obstacle Avoidance (Difficulty: Hard)​

Tasks:

  1. Add depth camera to robot
  2. Configure obstacle layer in costmap
  3. Test navigation with moving obstacles (people, boxes)
  4. Tune inflation radius for safe clearance
  5. Measure replanning frequency

Success Criteria: Robot successfully avoids 5 dynamic obstacles per mission


Further Reading​

  1. Isaac ROS Visual SLAM: https://nvidia-isaac-ros.github.io/repositories_and_packages/isaac_ros_visual_slam/
  2. Nav2 Documentation: https://navigation.ros.org/
  3. cuMotion: https://nvidia-isaac-ros.github.io/repositories_and_packages/isaac_manipulator/
  4. Nav2 Tuning Guide: https://navigation.ros.org/tuning/index.html

Next Chapter​

Continue to Chapter 3.4: Isaac Gym and RL (Optional) or Module 4: Vision-Language-Action

Module 3 Complete! You can now build GPU-accelerated AI perception systems.