ROS2 Jazzy on Jetson Orin: Warehouse Robotics Tutorial (2026)

ROS2 Jazzy on Jetson Orin: Warehouse Robotics Tutorial (2026)

ROS2 Jazzy on Jetson Orin: Warehouse Robotics Tutorial (2026)

Anyone who tried to stand up a warehouse AMR on a Jetson before 2025 remembers the taxes. You bought into a JetPack release that pinned you to Ubuntu 20.04, then fought a ROS2 Humble build chain that wanted 22.04, papered over the gap with Docker layers nobody on the team understood, watched CUDA-aware nodes crash on a kernel module mismatch the morning before a customer demo, and inevitably ended up with a perception stack and a navigation stack on different ROS distributions held together with a custom bridge. The maturity curve hurt — and it filtered out teams who should have been building robots, not chasing dependencies. The combination of JetPack 6.2 on the Jetson Orin platform with ROS2 Jazzy Jalisco as the long-term-support distribution finally closes that gap. This ROS2 Jazzy Jetson Orin tutorial walks through a complete reference build for a warehouse autonomous mobile robot — the stack, the install, Nav2 configuration, Isaac ROS perception, and the fleet and telemetry seam that lets one robot become a fleet without a rewrite.

Why ROS2 Jazzy on Jetson Orin Matters in 2026

Answer-first summary: ROS2 Jazzy Jalisco is the current LTS release, supported through May 2029, and the first ROS2 LTS that aligns cleanly with NVIDIA’s JetPack 6.x line on Ubuntu 22.04 and 24.04. The pairing matters because it eliminates the distro-skew and CUDA-version mismatch that broke earlier Jetson-plus-ROS deployments, while bringing Nav2 1.3, Isaac ROS 3.x, and a stable rclcpp ABI under the same release window. For warehouse robotics teams, that translates into a supported five-year horizon for a single robot platform — long enough to amortize fleet investments.

The five-year horizon is the structural point. Warehouse AMRs are capital equipment with seven- to ten-year working lives. Every prior ROS2 LTS — Foxy, Humble — sat at the wrong distro boundary for the Jetson family that was current at the time, forcing teams either to lag the Jetson generation or to run unsupported combinations in production. With Jazzy and JetPack 6.2, the OS, the CUDA stack (12.6 at the time of writing), the ROS distribution, the Nav2 release, and the Isaac ROS line are all on supported, overlapping timelines.

The hardware story matters as much as the software story. The Jetson Orin family — Nano 8GB, NX 16GB, AGX Orin 64GB — covers the realistic compute envelope for warehouse robots, from sub-AMR conveyor shuttles to forklift-class autonomous vehicles. The AGX Orin’s 275 TOPS of INT8 and 64 GB of unified memory is enough headroom to run multi-camera VSLAM, a 3D lidar pipeline, Nav2, a fleet client, and a Sparkplug B telemetry bridge simultaneously without thermal throttling at sustained warehouse duty cycles. The Orin NX 16GB hits a sweeter price point for single-lidar AMRs, and the Orin Nano 8GB has become the credible floor for camera-only AGVs and conveyor robots.

The ecosystem context also shifted. Isaac ROS 3.x now ships as a first-class set of ros-jazzy-isaac-ros-* packages rather than as a parallel build tree, the FoxgloveStudio replacement (Foxglove Studio 2.x) speaks to ROS2 Jazzy natively, and the major fleet managers — Open RMF 24.04, MiR Fleet, Otto Motors’ Autonomy Stack — all publish Jazzy-targeted clients in 2026. That is the difference between a tutorial that compiles and a stack that survives a production deployment.

Reference Stack and Components for a Warehouse AMR

A warehouse AMR is not a single program; it is a graph of nodes that has to agree on time, frames, and quality-of-service contracts. The reference stack we are building toward in this tutorial is the one we keep seeing converge across fielded systems in 2026 — perception fanned out from the sensors, SLAM and localization in the middle, Nav2 driving the behavior tree, a fleet client at the cloud seam, and a Sparkplug B bridge bringing telemetry into the plant’s unified namespace.

Figure 1: Warehouse AMR ROS2 node graph showing perception, SLAM, Nav2, fleet client, and Sparkplug bridge.

The graph above is intentionally not vendor-specific, but it maps cleanly onto a typical 2026 build: two RealSense D457 cameras and a Hesai XT-32 or Ouster OS0-32 lidar feeding into Isaac ROS perception nodes, an EKF localizer fusing wheel odometry with IMU and AMCL or VSLAM corrections, Nav2 1.3 with its behavior tree, an Open RMF or vendor fleet client over WebSockets, and an MQTT 5 bridge republishing diagnostics and mission state as Sparkplug B payloads.

Compute, Sensors, and the Bill of Materials

The compute platform is the choice that bounds everything else. For a single-lidar AMR with two RGB-D cameras and a 1 m/s top speed, the Jetson Orin NX 16GB on a Connect Tech Boson or Auvidea X230 carrier is the workhorse — enough to run Nav2, a single-lidar SLAM stack (slam_toolbox or KISS-ICP), one DNN-based perception node, and the bridge layer with a safety margin. For multi-lidar fleets, ESS-based stereo depth, or any deployment that wants to keep VSLAM in reserve, the Jetson AGX Orin 64GB is the right floor. The Orin Nano 8GB is viable for camera-only AGVs and lighter-duty conveyor robots, but it is a tight fit once Isaac ROS perception lands on top.

The sensor side splits into three roles. Safety perception is the certified scanner — typically a SICK nanoScan3 or Pilz PSENscan — wired into the safety PLC, not into ROS, because the safety function is judged against IEC 61496 and ISO 3691-4, not against your behavior tree. Navigation perception is the 2D or 3D lidar Nav2 uses for costmap updates and localization. Object and pallet perception is the camera stack feeding Isaac ROS DNN nodes for pallet detection, person classification, and barcode reading. Mixing the safety scanner into the Nav2 obstacle layer is a frequent design temptation and a frequent audit finding — keep the safety loop and the navigation loop on separate certified paths.

The motor and IO side is usually a CAN-bus interface to a motor controller (ODrive Pro, Roboteq HBL, or a Maxon EPOS4 on industrial robots) plus a small safety-rated IO module for E-stops, bumpers, and light curtains. ROS2’s ros2_control framework handles the velocity-command layer; the safety IO does not pass through ROS2 at all.

Software Stack From the BSP Up

Underneath the application graph sits a Linux for Tegra (L4T) base, currently L4T 36.4 for JetPack 6.2, on Ubuntu 22.04 LTS. The CUDA toolkit (12.6), cuDNN (9.3), TensorRT (10.3), and VPI (3.2) come from the JetPack archive. Above that, the ROS2 Jazzy distribution adds the core middleware (rclcpp, rclpy, the Cyclone DDS or Fast DDS implementations), the navigation stack (Nav2 1.3), and the Isaac ROS layer (3.x) for GPU-accelerated perception.

A few choices in this stack are worth thinking about up front. DDS implementation: Jazzy defaults to Cyclone DDS, which is the right call for most warehouse deployments — Fast DDS works but its default discovery is noisier on shared warehouse Wi-Fi. Set RMW_IMPLEMENTATION=rmw_cyclonedds_cpp in your robot’s systemd environment file and stop fighting QoS issues that come from discovery storms. Containerization: running the whole ROS stack inside a single Docker container on the Jetson is the path of least resistance for fleet management, but it costs you about 5–8 percent of effective compute due to NVIDIA Container Toolkit overhead and locks you out of some kernel features. Most production teams settle on a hybrid — Isaac ROS in a container, base ROS2 and Nav2 on the host — but the unified-container path is supported and works.

For the messaging seam to plant systems, the reference choice in 2026 is Sparkplug B 3.0 over MQTT 5 to a HiveMQ or EMQX broker that serves as the warehouse’s unified namespace. We cover that wire-level pattern in depth in the HiveMQ and Sparkplug B unified namespace architecture guide, and the broader protocol-layering question in the modular IoT protocol architecture design guide.

Setup: Flashing JetPack 6.2 and Installing ROS2 Jazzy

The setup sequence below assumes a freshly received Jetson Orin developer kit or a carrier board with an Orin module, an Ubuntu 22.04 host machine for flashing (NVIDIA SDK Manager does not yet officially support 24.04 hosts as of JetPack 6.2), and a network connection that can reach developer.nvidia.com and packages.ros.org.

Figure 2: Jetson Orin software stack from L4T BSP through ROS2 Jazzy.

The flashing step is the one that takes the longest and is the most tempting to skip. Do not skip it. JetPack 6.2 ships an L4T 36.4 kernel with the security and CUDA driver updates that make the rest of the stack supportable; older JetPack 5.x images do not have a clean upgrade path to Jazzy, and trying to run Jazzy on a JetPack 5 base will compile but will hit kernel-module and CUDA-version mismatches in surprising places.

# === Host machine (Ubuntu 22.04) — flash the Jetson Orin with JetPack 6.2 ===
# Install SDK Manager from developer.nvidia.com, then launch it.
# In SDK Manager:
#   1. Select Jetson Orin target (Nano / NX / AGX as applicable).
#   2. Select JetPack 6.2 (rev 1) — confirm L4T 36.4.
#   3. Tick CUDA 12.6, cuDNN 9.3, TensorRT 10.3, VPI 3.2, and the
#      developer tools group. Skip DeepStream unless you need it.
#   4. Put the Jetson into Force Recovery mode (jumper for AGX dev kit;
#      hold the REC button while powering on for module-on-carrier).
#   5. Flash. The Jetson reboots into Ubuntu 22.04 first-time setup.

# === On the Jetson itself, after first boot ===
sudo apt update && sudo apt -y full-upgrade
sudo apt install -y curl gnupg lsb-release locales software-properties-common
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

# Add the ROS2 apt repository
sudo add-apt-repository universe
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
  -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \
  http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" \
  | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
sudo apt update

# Install ROS2 Jazzy (base + Nav2 + SLAM Toolbox + dev tools)
sudo apt install -y \
  ros-jazzy-ros-base \
  ros-jazzy-navigation2 ros-jazzy-nav2-bringup \
  ros-jazzy-slam-toolbox \
  ros-jazzy-robot-localization \
  ros-jazzy-rmw-cyclonedds-cpp \
  ros-dev-tools

# Choose Cyclone DDS, source ROS in shell init
echo "export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp" | sudo tee -a /etc/environment
echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc
source ~/.bashrc

# Quick smoke test
ros2 doctor --report | head -40
ros2 topic list

A few notes on the commands above.

The ros-jazzy-ros-base metapackage is the right pick for a robot — it gives you rclcpp, rclpy, the launch tooling, and the diagnostics packages without dragging in the full desktop environment, which you do not want on a Jetson because it pulls Gazebo and Rviz dependencies that consume disk and add no value to a production robot. Run Rviz from a separate workstation that subscribes to the robot over the network.

The rmw_cyclonedds_cpp line is load-bearing. The default RMW on Jazzy is now Cyclone DDS, but it does not hurt to be explicit, particularly when you start adding containers to the mix and want predictable behavior across container boundaries. Set CYCLONEDDS_URI to a local config file if you need to tune the network interface, max-message-size, or peer-discovery range — warehouse Wi-Fi often needs a tighter discovery scope than the defaults.

The robot-localization package gives you ekf_node for fusing wheel odometry, IMU, and a localization source (AMCL or a VSLAM correction). On Jetson Orin NX and AGX, the EKF is essentially free in CPU terms; do not be tempted to skip it and trust raw odometry, especially on warehouses with epoxy floors where wheel slip is non-trivial.

If the install lands cleanly, ros2 doctor should report no critical issues, and ros2 topic list should at minimum show /parameter_events and /rosout. From here, you can pull in your robot’s hardware drivers — most commercial AMR vendors publish ros-jazzy-* driver packages for their motor controllers and sensors in 2026, and Foxglove Studio 2.x running on a workstation gives you the live introspection that used to require Rviz on the robot.

For Isaac ROS, hold off on adding it until your Nav2 stack is running cleanly on the base ROS2 install. Bringing Isaac ROS up in parallel with first-light Nav2 is one of the most common ways to confuse yourself about which layer is misbehaving.

Configuring Nav2 for a Warehouse AMR

Nav2 1.3 is the navigation stack you will spend the most time configuring. The defaults shipped with nav2_bringup are tuned for a TurtleBot-class differential-drive robot in a clean indoor environment — every warehouse deployment needs the params reworked for the robot’s footprint, the controller’s velocity limits, the costmap resolution that matches the lidar, and the behavior tree the mission actually wants.

Figure 3: Nav2 behavior tree for a warehouse pick-and-place mission.

Three configuration files dominate the work: the planner server, the controller server, and the behavior-tree navigator. The snippet below shows the load-bearing sections of a Nav2 configuration that has held up across a half-dozen real warehouse deployments — names are illustrative, but the structure is what to copy.

# nav2_params.yaml — warehouse AMR, differential drive, 0.6 m square footprint
bt_navigator:
  ros__parameters:
    use_sim_time: false
    global_frame: map
    robot_base_frame: base_link
    odom_topic: /odometry/filtered
    bt_loop_duration: 10
    default_server_timeout: 20
    # Behaviour trees are now selected per goal via the "behavior_tree" goal field.
    # Keep your mission BT (pick-place, dock, charge) in its own .xml file.
    default_nav_to_pose_bt_xml: $(find-pkg-share warehouse_amr_bt)/bt/nav_to_pose.xml
    default_nav_through_poses_bt_xml: $(find-pkg-share warehouse_amr_bt)/bt/nav_through.xml
    plugin_lib_names:
      - nav2_compute_path_to_pose_action_bt_node
      - nav2_follow_path_action_bt_node
      - nav2_back_up_action_bt_node
      - nav2_spin_action_bt_node
      - nav2_recovery_node_bt_node
      - nav2_pipeline_sequence_bt_node
      - nav2_round_robin_node_bt_node
      - nav2_clear_costmap_service_bt_node

planner_server:
  ros__parameters:
    expected_planner_frequency: 1.0
    planner_plugins: ["GridBased"]
    GridBased:
      plugin: "nav2_smac_planner::SmacPlannerHybrid"
      tolerance: 0.25
      downsample_costmap: false
      allow_unknown: false
      max_iterations: 1000000
      max_planning_time: 3.5
      motion_model_for_search: "DUBIN"   # diff-drive can still benefit from Dubin paths
      angle_quantization_bins: 72
      analytic_expansion_ratio: 3.5
      analytic_expansion_max_length: 3.0
      minimum_turning_radius: 0.30
      reverse_penalty: 2.1
      change_penalty: 0.15
      non_straight_penalty: 1.2
      cost_penalty: 2.0
      retrospective_penalty: 0.015
      lookup_table_size: 20.0
      smooth_path: true

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
    progress_checker_plugins: ["progress_checker"]
    goal_checker_plugins: ["goal_checker"]
    controller_plugins: ["FollowPath"]
    progress_checker:
      plugin: "nav2_controller::SimpleProgressChecker"
      required_movement_radius: 0.3
      movement_time_allowance: 10.0
    goal_checker:
      plugin: "nav2_controller::SimpleGoalChecker"
      xy_goal_tolerance: 0.05
      yaw_goal_tolerance: 0.05
      stateful: true
    FollowPath:
      plugin: "nav2_mppi_controller::MPPIController"
      time_steps: 56
      model_dt: 0.05
      batch_size: 2000
      vx_std: 0.20
      wz_std: 0.40
      vx_max: 1.0
      vx_min: -0.30
      wz_max: 1.5
      iteration_count: 1
      prune_distance: 1.7
      transform_tolerance: 0.1
      temperature: 0.3
      visualize: false
      TrajectoryVisualizer:
        trajectory_step: 5
        time_step: 3
      critics: ["ConstraintCritic", "ObstaclesCritic", "GoalCritic",
                "GoalAngleCritic", "PathAlignCritic", "PathFollowCritic",
                "PathAngleCritic", "PreferForwardCritic"]

Three choices in there deserve commentary.

SmacPlannerHybrid over NavFn. The classic NavfnPlanner is fine for a TurtleBot but underwhelms on a warehouse robot that needs to plan through narrow aisles with kinematic constraints. SmacPlannerHybrid with a DUBIN motion model and a tuned minimum-turning-radius produces paths the controller can actually execute without the corner-cutting and zig-zagging that plague NavFn-plus-DWB. The plan cost is non-trivial — 1–3 seconds for a 50 m goal on AGX Orin — but acceptable for the goal cadence of a warehouse mission.

MPPI over DWB. Nav2’s MPPI controller, mature in 1.3, is the right default for warehouse AMRs in 2026. Its trajectory-rollout cost is GPU-friendly if you build it with CUDA support, and its critic stack gives you the levers (PathAlign, PathFollow, PreferForward) that warehouse paths need. DWB is still in the repository and still works, but tuning DWB to behave well in warehouse aisles is more art than science. MPPI converges faster in practice.

Behavior trees per mission, not per stack. Set default_nav_to_pose_bt_xml and default_nav_through_poses_bt_xml to BT files that live in your application’s package, not in nav2_bt_navigator. A warehouse pick-and-place mission has its own recovery and docking branches that do not belong in the navigation library. The BT in Figure 3 above shows the structure — top-level mission states for navigate-to-pickup, dock, lift, navigate-to-dropoff, lower, and clear-area, with Nav2’s primitives as leaves.

The costmap configuration is its own discussion. The short version: keep the global costmap resolution at 0.05 m, the local costmap at 0.025 m with a 3 m rolling window, the inflation layer’s cost_scaling_factor at 3.0 and inflation_radius at 0.8 m for a 0.6 m footprint, and put your 3D lidar through a voxel_layer rather than an obstacle_layer if you are using one — the voxel layer’s height filtering keeps overhead shelving out of the costmap. We cover the multi-protocol fieldbus side of how warehouse robots interact with cell-level systems in the OPC UA FX field-level communications analysis for teams whose AMRs handshake with conveyors and stationary cells.

Adding Isaac ROS for Perception

Once Nav2 is running on lidar and odometry, Isaac ROS is what turns the AMR from a navigator into a perceiver — pallet detection, person classification, barcode reading, depth-from-stereo on RealSense modules, and VSLAM as a localization fallback when AMCL drops out in featureless aisles.

Figure 4: Isaac ROS perception pipeline (camera/lidar → ESS/VSLAM/DNN → costmap).

Isaac ROS 3.x is structured as a set of GPU-accelerated ROS2 nodes, each wrapped around a CUDA, TensorRT, or VPI kernel. The packages you reach for first on a warehouse AMR are isaac_ros_visual_slam for VSLAM, isaac_ros_ess for GPU stereo depth, isaac_ros_apriltag for fiducial localization at known dock points, isaac_ros_dnn_image_encoder plus isaac_ros_tensor_rt for DNN inference, and isaac_ros_nitros underneath them as the zero-copy GPU-memory message-passing layer that keeps the pipeline from drowning in memcpy overhead.

The install pattern is container-first. NVIDIA ships pre-built Isaac ROS 3.x containers for JetPack 6.2 — pulling nvcr.io/nvidia/isaac-ros-dev:3.x-jetpack6.2 is faster and more reliable than building from source, and the container is set up with the right CUDA, TensorRT, and VPI versions out of the box. Mount your workspace and your sensor device nodes into the container, and run your Isaac ROS nodes there while your base ROS2 and Nav2 run on the host. They share a Cyclone DDS network because Cyclone DDS will discover across the container boundary as long as the container is on host networking.

The two design decisions worth deliberating on are VSLAM versus AMCL and ESS versus the camera’s onboard depth.

VSLAM versus AMCL. AMCL is the right primary localizer for a warehouse with a stable, surveyed map and decent lidar coverage. It is computationally cheap, well-understood, and predictable. Where it struggles is in long featureless aisles, especially with high-bay racking where the lidar sees the same wall on both sides for tens of meters. Isaac ROS VSLAM is the supplement: run it alongside AMCL, feed both into robot_localization‘s EKF as separate pose sources with appropriate covariances, and let the EKF handle disagreement. Do not try to run VSLAM as the only localizer in a warehouse — feature drop-outs in low-light areas like cold-storage zones make pure VSLAM brittle.

ESS versus onboard depth. RealSense modules ship with onboard stereo depth that works fine for short-range obstacle detection. Isaac ROS ESS (Efficient Stereo Stereo) is a GPU-accelerated stereo depth network that produces denser, longer-range depth maps and runs comfortably on AGX Orin at 30 FPS for VGA-class resolution. The question is whether your application needs ESS quality (pallet pocket detection, person classification at distance) or whether onboard depth suffices (basic obstacle hazard maps). On Orin NX 16GB, ESS is feasible but tight; on Orin Nano, you are picking one or two perception nodes total, and ESS will not be one of them.

The DNN side — Isaac ROS DNN Image Encoder feeding TensorRT — is where the real perception work happens. The 2026 pattern is to deploy one or two specialized models rather than one big multi-task model: a pallet detector (typically a YOLOv8-class model trained on a warehouse-specific dataset), optionally a person-detector head for safety-adjacent monitoring (kept clearly separate from the certified safety scanner), and a barcode/QR-code reader at the pickup station. Each model lives in a TensorRT engine file built once at deployment time for the specific Jetson variant, then runs in fp16 mode for the latency budget.

The output of the perception pipeline does not feed Nav2 directly. It feeds a costmap layer plugin that fuses perception detections with the lidar-driven costmap, and it publishes structured detection messages to the mission BT so the pick-and-place logic can act on them. Keeping perception’s output bounded to the costmap and to a clean detection topic is what stops a perception bug from cascading into a navigation failure.

Telemetry, OTA, and Fleet Integration

A single AMR is a project. A fleet is a product. The seam between the on-robot ROS2 stack and the plant’s broader IT and OT systems is what makes the difference, and in 2026 the reference pattern is converging fast.

Figure 5: Fleet integration architecture from on-robot ROS to Sparkplug bridge to fleet manager.

The fleet seam has three concerns: mission orchestration (who tells the robot where to go), telemetry and diagnostics (how the rest of the plant sees what the robot is doing), and OTA updates (how new software gets onto the robot safely). The 2026 reference stack handles them with three distinct components on the robot side.

Mission orchestration typically goes through Open RMF or a vendor fleet manager over a WebSocket connection, with the robot running a small fleet-client node that translates RMF task requests into Nav2 goals and reports task state back. Open RMF 24.04 is solid for multi-vendor fleets; vendor-specific managers (MiR Fleet, Otto Autonomy Stack, Geek+ MFC) are the right choice when the whole fleet is single-vendor and you want the deeper integration.

Telemetry is where Sparkplug B earns its keep. A small bridge node on the robot subscribes to a curated set of ROS2 topics — battery state, mission state, errors, position, key diagnostics — and republishes them as Sparkplug B 3.0 NBIRTH and NDATA messages to the plant’s MQTT 5 broker. This is the same broker that serves the unified namespace for stationary equipment, so the robot’s data appears in WMS, fleet dashboards, and historian feeds without per-system integrations.

# mqtt_sparkplug_bridge.yaml — minimal config for a Sparkplug B 3.0 bridge node
sparkplug_bridge:
  ros__parameters:
    broker_host: mqtt.warehouse.local
    broker_port: 8883
    broker_tls: true
    broker_ca_file: /etc/ssl/certs/warehouse-ca.crt
    client_cert: /etc/robot/certs/amr-007.crt
    client_key:  /etc/robot/certs/amr-007.key
    group_id: warehouse_north
    edge_node_id: amr-007
    primary_host_id: fleet-manager-01
    publish_topics:
      - { ros_topic: /battery_state,    sparkplug_metric: Robot/Battery/Percent,    type: float,  units: "%" }
      - { ros_topic: /amr/mission_state, sparkplug_metric: Robot/Mission/State,     type: string }
      - { ros_topic: /odometry/filtered, sparkplug_metric: Robot/Pose,              type: template }
      - { ros_topic: /diagnostics,       sparkplug_metric: Robot/Diagnostics/Level, type: int32 }
    qos: 1
    keepalive_seconds: 30
    rebirth_on_reconnect: true

The bridge config above is illustrative — the exact metric names should follow your plant’s UNS naming convention, and the certificate paths assume an mTLS broker setup. The rebirth_on_reconnect flag is non-optional in production: Sparkplug B clients must republish NBIRTH after every reconnection, and any bridge that omits this will cause stale-state ghosts in the broker. The pattern of nesting Sparkplug B robot topics under a warehouse-wide UNS, and the broker-side considerations around HiveMQ for this kind of traffic, are covered in our unified namespace architecture guide.

OTA is the third leg. For Jetson-based AMRs, the 2026 pattern is to combine NVIDIA’s Mender or Foundries.io LMP image-based updates for the L4T base with bluechi-managed systemd services for ROS2 application layer updates, and to gate every update through a fleet-manager-driven staged rollout (one robot, then a canary group, then the fleet). Image-based base updates are essential because rolling forward a CUDA driver or kernel module piecemeal on a fleet is how you build a museum of incompatible robots. Application-layer updates can be debs or Docker images depending on which side of the host-versus-container debate your stack landed on. Either way, the OTA system should verify a signed manifest before applying, and the robot should refuse to start a mission if the running image hash does not match the fleet manager’s expected hash for that robot.

Trade-offs, Gotchas, and What Goes Wrong

The pattern above works, but every layer has a trapdoor. The ones that have bitten real teams in 2026 cluster into a few families.

Distro mismatch creep. It is tempting to keep one node on Humble because the vendor driver has not been ported. Resist it. Bridging Humble and Jazzy via the ROS1-bridge cousin works in demos and rots in production — DDS QoS contracts subtly differ across distros, and the bridge becomes the load-bearing layer nobody understands. Either find or build a Jazzy driver, or stay on Humble until the whole stack can move.

Container networking surprises. Running Isaac ROS in a container while base ROS2 lives on the host works only if both share the same DDS network and the container is on --network=host. Bridge networking will appear to work and silently drop discovery beacons on lossy Wi-Fi. Pin the container to host networking and set ROS_DOMAIN_ID and RMW_IMPLEMENTATION identically on both sides.

Wi-Fi assumptions. Warehouse Wi-Fi is hostile. Discovery storms from a permissive DDS configuration will degrade everything on the SSID, including other robots. Restrict DDS discovery to the robot’s own interface and a known fleet-manager peer list — Cyclone DDS’s peer config is the right place to do this — and put fleet-manager traffic on a dedicated VLAN or 5GHz network separate from operator handhelds.

Twin-and-real drift. Teams that test in Isaac Sim and then field on the real robot frequently see Nav2 behavior diverge because the sim’s lidar noise model and the real Hesai or Ouster’s noise characteristics differ. Calibrate your sim against the real sensor early, not late.

Safety-and-ROS confusion. The single most common audit finding is a perception node feeding the costmap getting confused for “the safety system.” The certified safety scanner and PLC are the safety system. ROS2 is not. Document that boundary and enforce it.

Practical Recommendations

For teams kicking off a new warehouse AMR build in 2026, a short checklist that has held up:

  • Standardize on ROS2 Jazzy + JetPack 6.2 for any robot that needs a five-year-plus production horizon. Skip Humble for greenfield builds; the LTS clock favors Jazzy now.
  • Right-size the Jetson. Orin NX 16GB for single-lidar AMRs with one or two perception nodes; AGX Orin 64GB for multi-lidar, VSLAM-plus-AMCL, or any robot that will host fleet-edge analytics; Orin Nano only for camera-only AGVs.
  • Decouple safety from ROS entirely. Certified safety scanner into a safety PLC, ROS2 reads the safety state as advisory.
  • Containerize Isaac ROS, keep base ROS on the host. Hybrid layout, host networking, shared Cyclone DDS.
  • Build the Sparkplug bridge early. Plant-side observability is what turns a robot project into a fleet program.
  • Image-based OTA, signed manifests, staged rollouts. Anything less is a museum-in-waiting.
  • Test against real lidar early. Sim is necessary, not sufficient. Replay actual warehouse bag files against your Nav2 config before you trust it.

The teams that get warehouse robots into production are the ones that resist the urge to chase the bleeding edge in every layer simultaneously. Jazzy plus JetPack 6.2 is the boring, stable, supported choice in 2026 — and that is exactly why it is the right one.

FAQ

Should I use ROS2 Jazzy or Humble in 2026?
Use ROS2 Jazzy for any new warehouse robotics project starting in 2026. Jazzy is the current LTS with support through May 2029, while Humble’s support window closes in May 2027 — too soon to start a new AMR platform on. Jazzy also aligns cleanly with JetPack 6.2’s Ubuntu 22.04 base and ships with Nav2 1.3, Isaac ROS 3.x, and the latest Cyclone DDS. The only reason to start a new project on Humble in 2026 is a hard dependency on a vendor driver that has not been ported to Jazzy yet, and even then, plan the migration.

Which Jetson Orin variant is right for a warehouse AMR?
For most warehouse AMRs — single 2D or 3D lidar, two cameras, Nav2, one or two perception nodes — the Jetson Orin NX 16GB hits the sweet spot of compute headroom and cost. The AGX Orin 64GB is the right pick if you plan to run VSLAM alongside AMCL, multiple DNN perception nodes, ESS stereo depth, and a fleet-edge analytics layer on the same robot, or if you want headroom for future capability without re-spinning the carrier board. The Orin Nano 8GB works for camera-only AGVs and conveyor robots but constrains your perception choices significantly.

Can Isaac ROS run on Jetson Orin Nano?
Yes, but with constraints. Isaac ROS 3.x supports the Orin Nano 8GB and the entry-level perception nodes (AprilTag, basic DNN inference with a small TensorRT engine, monocular VSLAM) run well. ESS stereo depth is feasible but tight on memory; running ESS plus a DNN detector plus VSLAM simultaneously is not realistic on Nano. The practical Nano deployment runs one or two perception nodes alongside Nav2 and base ROS2, with the rest of the perception budget reserved for application-specific logic.

Is Nav2 production-ready for warehouse robots?
Yes. Nav2 has been deployed in production warehouse fleets since the 2022 timeframe, and Nav2 1.3 on Jazzy is the most mature release yet. The MPPI controller and SmacPlannerHybrid planner are the production defaults; the behavior-tree navigator gives you the mission-level flexibility warehouse picking and docking workflows need. Production readiness in this context means “the navigation primitives are solid”; the application BT, costmap tuning, recovery behaviors, and fleet integration are still where each deployment earns its keep. Plan to spend real engineering time on the configuration, not on Nav2 itself.

How do I integrate ROS2 with a Sparkplug B unified namespace?
Run a small bridge node on the robot that subscribes to a curated set of ROS2 topics — battery, mission state, pose, diagnostics — and republishes them as Sparkplug B 3.0 metrics to your plant’s MQTT 5 broker (HiveMQ or EMQX). The bridge issues NBIRTH on startup and on every reconnection, sends NDATA for changed metrics, and uses NDEATH via MQTT will-messages so the broker sees clean state on robot disconnect. Use mTLS to the broker, place robot topics under a UNS path like warehouse_north/amr-007/..., and let the rest of the plant — WMS, fleet manager, historian — subscribe to the broker rather than to ROS directly.

Further Reading / References

Internal:

External:

  • ROS2 Jazzy Jalisco documentation — https://docs.ros.org/en/jazzy/
  • Nav2 documentation — https://docs.nav2.org/
  • Isaac ROS 3.x documentation — https://nvidia-isaac-ros.github.io/
  • NVIDIA JetPack 6.2 release notes — developer.nvidia.com/embedded/jetpack
  • Sparkplug 3.0 specification — Eclipse Foundation, sparkplug.eclipse.org
  • Open RMF — open-rmf.org
  • REP 2000 (ROS2 Releases and Target Platforms) — ros.org/reps/rep-2000.html

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *