Deploying wandering on Clearpath Jackal#

This software reference details how to deploy and run the wandering mobile robot application on a Clearpath Robotics Jackal robot upgraded with an Intel® Core™ Ultra Series 3 onboard compute board (e.g., Intel® Core™ Ultra X7 358H reference platform).

The pipeline combines RealSense depth camera sensing, RTAB-Map visual SLAM, multi-sensor point cloud fusion (adbscan_sensor_fusion), fast 3D clustering obstacle perception (adbscan_ros2), Nav2 navigation with custom costmap layers (nav2_adbscan_layer), and autonomous frontier exploration (wandering_app).

Architecture#

The Intel® Core™ Ultra Series 3 onboard compute board handles on-robot perception, SLAM, costmap marking, and autonomous navigation:

        flowchart TD
    subgraph Hardware["Onboard Hardware (Clearpath Jackal + Intel® Core™ Ultra Series 3)"]
        RS["RealSense Camera\n(RGB-D PointCloud2 & Depth)"]
        LiDAR3D["360° 3D LiDAR (e.g. Velodyne Puck)\n(PointCloud2)"]
        BaseServices["Clearpath Base Services / MCU\n(Encoders, IMU, Teleop Mux)"]
    end

    subgraph Perception["Onboard Perception & SLAM (Intel® Core™ Ultra Series 3)"]
        D2L["depthimage_to_laserscan\n(/scan)"]
        Fusion["adbscan_sensor_fusion\n(Time-sync & Voxel filter)"]
        ADBSCAN["ADBSCAN Node\n(3D Clustering)"]
        RTAB["RTAB-Map Visual SLAM\n(RGB-D Mapping & TF)"]
    end

    subgraph Navigation["Nav2 Navigation Stack"]
        Costmap["Nav2 Costmaps\n(ADBScanLayer + Standard Layers)"]
        NavServer["Nav2 Planner & Controller\n(FollowPath, Recovery)"]
    end

    subgraph Application["wandering_app Package"]
        WanderApp["wandering_app\n(Frontier Exploration)"]
    end

    RS --> D2L
    RS -.->|"Default point cloud"| Fusion
    LiDAR3D -.->|"Alternative 360° cloud"| Fusion
    D2L --> Fusion
    RS --> RTAB
    D2L --> RTAB
    Fusion -->|"/adbscan/points"| ADBSCAN
    ADBSCAN -->|"/obstacle_array"| Costmap
    RTAB -->|"/map & TF"| Navigation
    BaseServices -->|"odom, TF"| Navigation
    Costmap --> NavServer
    Costmap -->|"/global_costmap/costmap"| WanderApp
    WanderApp -->|"NavigateToPose action"| NavServer
    NavServer -->|"/cmd_vel"| BaseServices
    

Perception and Navigation Pipeline#

  1. Depth Sensing & 2D Scan Derivation: The onboard RealSense camera provides depth and color streams. The depthimage_to_laserscan node projects depth images into a 2D /scan topic used for SLAM and base obstacle clearing.

  2. Visual SLAM: dep_rtabmap_jackal runs RTAB-Map visual SLAM with RGB-D synchronization, producing real-time 3D and 2D occupancy mapping, loop closure, and the map $\rightarrow$ odom coordinate frame transform.

  3. Sensor Fusion: adbscan_sensor_fusion time-synchronizes the 2D scan and 3D point cloud (from either the RealSense camera or an optional 360° 3D LiDAR such as a Velodyne Puck), transforms them into the base_link frame, and applies voxel downsampling to generate /adbscan/points.

  4. 3D Obstacle Perception: adbscan_ros2 executes 3D density-based spatial clustering on /adbscan/points, detecting object-sized obstacles and publishing nav2_dynamic_msgs/ObstacleArray messages on /obstacle_array.

  5. Nav2 Costmap Integration: nav2_adbscan_layer::ADBScanLayer integrates into both local and global Nav2 costmaps, marking lethal circular obstacle regions based on /obstacle_array with configurable radius padding and detection lifetime.

  6. Autonomous Frontier Exploration: wandering_app (wandering_mapper node) continuously evaluates the global costmap for unexplored frontiers and issues NavigateToPose goals to Nav2.

Prerequisites#

Before deploying the pipeline:

  1. Hardware Setup: Follow the Clearpath Robotics Jackal setup guide to install the Intel® Core™ Ultra Series 3 onboard compute board, mount and connect the RealSense camera (e.g. D435i), and configure the robot network and MCU firmware.

  2. Clearpath Base Services: Verify that the Clearpath systemd services (clearpath-platform.service, clearpath-sensors.service, clearpath-robot.service) are active and publishing topics under the robot’s namespace.

  3. Motor Control: Verify motor control and drive commands following the Validate Motor Control section.

  4. Target Environment: Ensure Ubuntu 24.04 LTS with ROS 2 Jazzy (or Ubuntu 22.04 LTS with ROS 2 Humble) is installed on the Intel® Core™ Ultra Series 3 board along with OpenVINO™ packages and Intel NPU drivers (if applicable for Intel® Core™ Ultra).

Install the Application#

Install the wandering metapackage for your installed ROS 2 distribution:

sudo apt update
sudo apt install ros-jazzy-wandering
sudo apt update
sudo apt install ros-humble-wandering

If building from source, build the application using the make build target:

ROS_DISTRO=jazzy make build
source install/setup.bash
ROS_DISTRO=humble make build
source install/setup.bash

Run the Deployment#

Configure the Robot Namespace#

Clearpath Jackal base services publish transforms and topics under a robot namespace (default: /j100_0812). Set the ROBOT_NAMESPACE environment variable to match your robot’s configured namespace in /etc/clearpath/robot.yaml:

export ROBOT_NAMESPACE=/j100_0812

Autonomous Exploration Mode (Default: RealSense Depth Sensing)#

Launch the complete autonomous pipeline using the RealSense depth camera:

export ROBOT_NAMESPACE=/j100_0812
ros2 launch wandering_bringup wandering_jackal.launch.py

What this starts:

  1. depthimage_to_laserscan: Derives 2D /scan from the RealSense depth image.

  2. dep_rtabmap_jackal: Starts RTAB-Map visual SLAM and RGB-D synchronization.

  3. dep_navigation_jackal: Starts the Jackal Nav2 stack configured with ADBScanLayer in both local and global costmaps.

  4. dep_adbscan_perception: Fuses the scan and RealSense point cloud, performs 3D ADBSCAN obstacle clustering, and publishes /obstacle_array.

  5. wandering_app: Frontier-exploration node (wandering_mapper) that evaluates unexplored frontiers on the costmap and sends NavigateToPose goals to Nav2.

  6. RViz visualization windows (when a display session or remote X11 forwarding is available).

After startup, the robot begins autonomously exploring its surroundings, mapping the environment while avoiding obstacles.

wandering-jackal-rviz2

To stop the pipeline, press Ctrl-c in the launch terminal.

Alternative Launch Path: 360-Degree 3D LiDAR (Velodyne Puck) Input#

When the Jackal robot is equipped with a 360-degree 3D LiDAR (such as a Velodyne Puck VLP-16, Ouster OS1, or equivalent 3D LiDAR), you can route the full 360-degree point cloud directly into the ADBSCAN perception pipeline as an alternative to the forward-facing RealSense depth camera point cloud.

How perception behaves in this path:

  • adbscan_sensor_fusion transforms the 360-degree LiDAR cloud into base_link, crops it to the robot’s near-field driveable envelope, filters out floor-level returns, and voxel-downsamples the points before streaming them on /adbscan/points.

  • The Velodyne preset intentionally does not append planar /scan points into this 3D point cloud; this avoids planar scan returns bridging distinct 3D objects into single oversized clusters. The 2D /scan topic remains independently active and continuously fed to RTAB-Map SLAM, standard Nav2 obstacle clearing layers, and collision monitoring.

  • adbscan_ros2 clusters the filtered 360-degree cloud in 3D mode, publishing detected object-sized 3D obstacles around the robot to /obstacle_array.

Step 1: Identify and verify the streaming 3D LiDAR topic and frame

Common Clearpath topic names for 3D LiDAR point clouds include /sensors/lidar3d_0/points or /velodyne_points. Check that your robot’s LiDAR driver service is actively streaming data by monitoring the publication rate:

ros2 topic hz /sensors/lidar3d_0/points
# or if using /velodyne_points:
ros2 topic hz /velodyne_points

Confirm that the header frame resolves to base_link through the robot’s namespaced TF tree:

ros2 topic echo --once /sensors/lidar3d_0/points header
ros2 run tf2_ros tf2_echo base_link <lidar_frame_id>

Step 2: Launch with the 3D LiDAR configuration preset

Pass the prepared Velodyne parameter presets and point cloud topic override:

export ROBOT_NAMESPACE=/j100_0812
export LIDAR3D_TOPIC=/sensors/lidar3d_0/points

ros2 launch wandering_bringup wandering_jackal.launch.py \
  fusion_params_file:=$(ros2 pkg prefix wandering_bringup)/share/wandering_bringup/params/pointcloud_fusion_jackal_velodyne.yaml \
  adbscan_params_file:=$(ros2 pkg prefix wandering_bringup)/share/wandering_bringup/params/adbscan_velodyne.yaml \
  pointcloud_topic:=$LIDAR3D_TOPIC

The stack starts up with full 360-degree obstacle clustering around the robot while maintaining visual SLAM mapping and autonomous frontier exploration.

Interactive Manual Override Mode & Nav2 Waypointing#

To retain autonomous SLAM mapping and ADBSCAN costmap protection while allowing an operator to pause exploration and send manual navigation goals or multi-stop waypoint routes via RViz:

export ROBOT_NAMESPACE=/j100_0812
ros2 launch wandering_bringup wandering_jackal_manual_nav.launch.py
  • Pausing Autonomous Exploration: In the RViz interface, click Manual mode in the Wandering Control panel to pause autonomous frontier exploration and cancel the active goal.

  • Single-Goal Navigation: Use Nav2’s Nav2 Goal (or 2D Goal Pose) tool in the RViz toolbar to click and drag a custom destination pose (position and orientation) on the map. Nav2 computes and follows a path while the ADBScanLayer continues updating obstacle regions around the robot.

  • Nav2 Waypoint Following: Switch Nav2 to Waypoint mode in the RViz Nav2 panel, click and place a sequence of goal poses across the mapped facility, and select Start Navigation to command the robot through all waypoints in order.

  • Resuming Autonomous Exploration: Click Autonomous mode in the Wandering Control panel to resume autonomous frontier wandering.

Note

The manual override launch file accepts the same fusion_params_file, adbscan_params_file, and pointcloud_topic arguments if you want to use the 360-degree LiDAR profile with interactive operator goals.

Standard 2D LiDAR Nav2 (without ADBSCAN)#

To run the standard 2D Nav2 pipeline without the ADBSCAN fusion and clustering nodes:

ros2 launch wandering_bringup wandering_jackal.launch.py enable_adbscan:=false

Perception Pipeline Tuning & Configuration Options#

The perception pipeline is composed of three interconnected stages: point cloud fusion and ground removal (adbscan_sensor_fusion), 3D density-based obstacle clustering (adbscan_ros2), and costmap marking (nav2_adbscan_layer). Tuning parameters across these stages allows optimizing obstacle detection sensitivity, cluster sizes, and false-positive rejection for different sensors and robot environments.

1. Point Cloud Fusion & Filtering (adbscan_sensor_fusion)#

Configured via pointcloud_fusion_jackal.yaml (RealSense) or pointcloud_fusion_jackal_velodyne.yaml (3D LiDAR). This node prepares and cleans point clouds before passing them to ADBSCAN:

Parameter

Default (RealSense / Velodyne)

Description & Tuning Impact

voxel_leaf_size

0.03 m / 0.05 m

Edge length of the 3D voxel grid filter. Larger values downsample more aggressively, reducing downstream clustering computation and clustering latency on dense sensors; smaller values preserve fine geometric details of small obstacles.

min_range / max_range

0.0 m / 0.40 m – 3.00 m

Radial distance cropping bounds relative to base_link. For 360° LiDAR, setting max_range: 3.0 focuses clustering within the robot’s immediate planning envelope and caps processing load.

min_z / max_z

Unbounded / -0.35 m – 1.50 m

Height window (metres) in base_link coordinates. Excludes returns from ceilings or overhead structures above the robot while keeping points from the floor plane upwards.

remove_ground

false / true

Enables RANSAC planar ground segmentation. Essential for 3D LiDAR sensors whose lowest rings intersect the ground.

ground_distance_threshold

0.08 m

Distance threshold in metres for points classified as ground plane inliers. Points closer than this to the estimated ground plane are stripped away.

ground_max_tilt_degrees

12.0 deg

Maximum tilt angle allowed for the estimated ground plane normal. Prevents steep walls from being erroneously classified as ground.

sync_max_interval

0.1 s

Maximum allowed timestamp skew when synchronizing 2D scan and 3D point cloud topics.

2. 3D Spatial Clustering (adbscan_ros2)#

Configured via adbscan_fused.yaml (RealSense) or adbscan_velodyne.yaml (Velodyne Puck). These parameters dictate how points are clustered into distinct obstacles:

Parameter

Default (Fused / Velodyne)

Description & Tuning Impact

x_filter_back

4.0 m / 2.5 m

Maximum distance behind the robot (in metres) to include points for obstacle clustering.

y_filter_left / y_filter_right

3.0 m, -3.0 m / 1.75 m, -1.75 m

Lateral region-of-interest bounds (metres) to the left and right of the robot’s longitudinal centerline.

subsample_ratio

1.0 / 2.0

Subsampling ratio applied to incoming points before clustering. A ratio of 2.0 clusters every second point, halving density to speed up clustering on dense clouds.

scale_factor

0.20

Scaling coefficient for density-adaptive clustering radius calculation. Lower values enforce tighter clusters; higher values allow sparser, wider clusters to merge.

min_3d_epsilon

0.15 m

Minimum neighborhood radius ($\epsilon$) in metres for a point to be linked to an adjacent point in 3D clustering. Increase if sparse sensor returns fragment single objects into separate clusters; decrease if nearby objects bridge across empty space.

base, coeff_1, coeff_2

Adaptive polynomial

Quadratic distance-adaptive coefficients ($r = \text{base} + \text{coeff}_1 \cdot d + \text{coeff}_2 \cdot d^2$) that scale clustering radius as a function of object distance $d$. Accounts for angular divergence in LiDAR beams or camera depth dispersion at greater ranges.

z_filter / Z_based_ground_removal

-0.15 m / 1.0

Secondary floor height gate to discard points beneath floor level in base_link frame.

3. Costmap Marking & Obstacle Bounds (nav2_adbscan_layer)#

Configured under local_costmap and global_costmap in jackal_nav_adbscan.param.yaml. Controls how ADBSCAN clusters are stamped into Nav2 costmaps:

Parameter

Default

Description & Tuning Impact

min_mark_radius

0.04 m

Minimum circular lethal marking radius in metres stamped into the costmap, guaranteeing that even thin objects (e.g. table legs or cables) receive non-zero lethal clearance.

footprint_padding

0.05 m

Extra buffer distance (metres) added around the perimeter of the detected obstacle cluster.

max_obstacle_extent

2.5 m

Maximum allowed bounding box dimension (metres) for a valid obstacle. Clusters exceeding this size (such as large continuous walls or unsegmented floor patches) are rejected from dynamic layer marking to avoid overwriting static map features.

max_detection_distance

3.0 m (local) / 4.0 m (global)

Maximum distance from the robot at which obstacle detections will be committed to the costmap. Prevents distant, noisy detections from degrading local path planning.

time_to_live

0.5 s (local) / 1.0 s (global)

Duration (seconds) that an obstacle remains marked in the costmap after being detected. Once this time elapses without a new detection update, the obstacle is cleared. Keeps the costmap responsive to dynamic environments.

Advanced Configuration#

Persistent RTAB-Map Database#

To preserve or extend an existing RTAB-Map SLAM database across multiple sessions, specify a database file path:

ros2 launch wandering_bringup wandering_jackal.launch.py \
  rtabmap_database_path:=/data/maps/site_jackal.db

Velocity Command Stamping (Twist vs TwistStamped)#

Depending on your robot’s Clearpath base driver version and ROS 2 distribution:

  • Set enable_stamped_cmd_vel: true in the Nav2 parameter file (jackal_nav_adbscan.param.yaml) when the platform driver or teleop multiplexer accepts geometry_msgs/msg/TwistStamped.

  • Set enable_stamped_cmd_vel: false for unstamped geometry_msgs/msg/Twist drivers.

  • If adapting mismatched driver types, the twist_stamper ROS 2 package can convert between Twist and TwistStamped topics.

To inspect the velocity topic expected by your robot:

ros2 topic info /${ROBOT_NAMESPACE#/}/cmd_vel -v

Camera Topic Overrides#

If your RealSense camera is configured with custom topic names, override them at launch:

ros2 launch wandering_bringup wandering_jackal.launch.py \
  camera_namespace:=/sensors/camera_0 \
  depth_image_topic:=/sensors/camera_0/camera/depth/image_rect_raw \
  rgb_image_topic:=/sensors/camera_0/camera/color/image_raw

Troubleshooting#

1. Robot Does Not Move Despite Active Exploration Goals#

  • Symptom: wandering_app picks frontiers and sends NavigateToPose goals to Nav2, but the robot remains stationary.

  • Root Cause: Stamped vs. unstamped velocity command mismatch between Nav2 and the Clearpath base multiplexer (twist_mux), or an incorrect topic namespace.

  • Verification: Check what message type the robot’s base controller is subscribing to:

    ros2 topic info /cmd_vel -v
    # or under the robot namespace:
    ros2 topic info /${ROBOT_NAMESPACE#/}/cmd_vel -v
    
  • Remedy:

    • If the base driver expects unstamped geometry_msgs/msg/Twist, set enable_stamped_cmd_vel: false under controller_server in jackal_nav_adbscan.param.yaml.

    • If the base driver expects geometry_msgs/msg/TwistStamped, set enable_stamped_cmd_vel: true.

    • Alternatively, use the twist_stamper ROS 2 node to bridge unstamped and stamped velocity topics.

2. Missing RealSense Point Cloud (/sensors/camera_0/points Not Publishing)#

  • Symptom: adbscan_pointcloud_fusion waits indefinitely without publishing /adbscan/points, even though camera image topics are active.

  • Root Cause: The RealSense camera ROS 2 driver was launched without point cloud generation enabled, or the USB connection fell back to USB 2.0.

  • Verification:

    ros2 topic hz /sensors/camera_0/points
    lsusb -t | grep -i uvcvideo
    
  • Remedy:

    • In /etc/clearpath/robot.yaml under the camera device parameters, ensure pointcloud.enable: true is configured.

    • Verify that the camera is plugged into a USB 3.0 / 3.1 port providing SuperSpeed (5000M) throughput. USB 2.0 connections lack sufficient bandwidth for simultaneous RGB, depth, and point cloud streams.

3. Sensor Fusion Synchronization Dropouts (adbscan_sensor_fusion)#

  • Symptom: Warning logs indicating dropped messages or timestamp skew in adbscan_pointcloud_fusion.

  • Root Cause: The approximate-time message synchronizer cannot pair RealSense depth point clouds and derived /scan frames within the skew tolerance window (sync_max_interval).

  • Remedy: In pointcloud_fusion_jackal.yaml, increase the synchronizer queue and tolerance window:

    sync_queue_size: 30
    sync_max_interval: 0.20
    

4. Floor Returns Clustered as Ghost Obstacles#

  • Symptom: The robot stops or oscillates in place because lethal costmap obstacles are falsely marked on the clear floor directly in front of the robot.

  • Root Cause: Camera pitch angle deflection, vehicle chassis pitch under acceleration, or floor points falling above the ground filter cutoff.

  • Verification: Echo /obstacle_array or inspect RViz /adbscan/obstacle_markers to verify if obstacles have $z \approx 0$:

    ros2 topic echo /obstacle_array --once
    
  • Remedy:

    • Adjust the height cutoff z_filter: -0.10 in adbscan_fused.yaml (or min_z in the fusion parameter file).

    • For 3D LiDAR deployments, verify that remove_ground: true is active and tune ground_distance_threshold (e.g. 0.08 m to 0.10 m) and ground_max_tilt_degrees.

5. Namespaced TF Lookup Failures#

  • Symptom: Nodes log errors like ExtrapolationException or Could not transform from camera_0_link to base_link.

  • Root Cause: Clearpath Jackal publishes TF transforms under /<robot_namespace>/tf and /<robot_namespace>/tf_static. If ROBOT_NAMESPACE is unset or mismatched, nodes listen on the root /tf topic instead.

  • Verification:

    echo $ROBOT_NAMESPACE
    ros2 topic list | grep tf
    ros2 run tf2_tools view_frames
    
  • Remedy: Export ROBOT_NAMESPACE to match the exact prefix defined in /etc/clearpath/robot.yaml (e.g. export ROBOT_NAMESPACE=/j100_0812) before executing any launch commands.

6. High Perception Latency or Stuttering on 360-Degree LiDAR#

  • Symptom: Laggy costmap updates, delayed obstacle avoidance, or high CPU utilization during 3D clustering.

  • Root Cause: Raw 3D point cloud is overly dense or the spatial region of interest is excessively large for real-time clustering.

  • Remedy:

    • Increase voxel_leaf_size in pointcloud_fusion_jackal_velodyne.yaml from 0.05 to 0.07 or 0.08.

    • Increase subsample_ratio in adbscan_velodyne.yaml from 1.0 to 2.0 or 3.0.

    • Reduce max_range in the fusion parameters (e.g., to 2.5 m) to restrict clustering to the immediate driveable envelope.

General Troubleshooting#

  • No topics visible: Verify that the ROS_DOMAIN_ID environment variable matches the domain_id configured in /etc/clearpath/robot.yaml.

  • Missing sensor topics: Check the status of the Clearpath systemd services:

    sudo systemctl status clearpath-platform.service clearpath-sensors.service clearpath-robot.service
    
  • For general system issues, refer to the troubleshooting guide.

Next Steps#

Now that you’ve deployed the wandering workflow on physical hardware: