add wishlist add wishlist show wishlist add compare add compare show compare preloader icon-theme-126 icon-theme-161 icon-theme-138 icon-theme-027 electro-thumb electro-return-icon electro-brands-icon electro-payment
  • +1 (857) 226-1305
  • +86 18825289328

ROSOrin Pro Explained: The Full ROS 2 AI-Agent Pipeline — OpenClaw, SLAM, YOLO, Nav2, and MoveIt2

Tell the robot "Bring me the red block on the table," and it drives to the table, finds the block, picks it up with the 6-DOF arm, and sets it down where you asked. That loop is not a single algorithm. Voice I/O, slam_toolbox laser SLAM, Nav2, OpenCV color detection, and arm kinematics each run as their own ROS 2 services. This article walks the official ROSOrin Pro (Jetson Orin NX) source tree and docs, one module at a time.

1. System function overview

Hiwonder ROSOrin Pro is a ROS 2 robot car built around NVIDIA Jetson Orin NX. The kit includes a depth camera, LiDAR, an AI voice box, and a 6-DOF robotic arm. A spoken command drives the full loop: understand -> navigate to the target -> recognize the block -> grasp -> place.

The main computer is a configuration option. Kits can ship with Jetson Orin Nano, Orin NX, or Orin AGX. This teardown uses the Jetson Orin NX 8 GB variant.

Figure 1 - End-to-end workflow
Stage Trigger What runs
Wake word wakeup_flag = True WonderEcho Pro microphone array
Command understanding ASR text is non-empty Text POST over HTTP to the OpenClaw agent
Start navigation Command contains a place name / pose Nav2 loads the map; AMCL localizes
Block detection Robot arrives at the nav goal Call /set_color to set the target color
Grasp Depth reading is valid Pixel coordinates -> arm base frame -> IK
Place Grasp succeeds Navigate to the drop-off pose and open the gripper

Section takeaway. Workflow: voice command -> WonderEcho Pro ASR -> OpenClaw agent -> Nav2 -> OpenCV color detect -> arm grasp -> place. Each step is bounded by a ROS 2 service call. Failures fall back automatically.

2. Hardware architecture

ROSOrin Pro uses a dual-controller design: Jetson Orin NX + STM32. Orin NX runs the high-level stack (SLAM, YOLO, navigation, language). STM32 runs the real-time loop (motors, bus servos, raw sensors). Perception devices attach over USB to the Jetson. Actuators are driven by the STM32.

Figure 2 - Dual-controller hardware

Jetson Orin NX takes the depth camera, LiDAR, and microphone array over USB, and talks to the STM32 through USB-UART (/dev/nrc, 1 Mbps). The STM32 drives chassis motors with PWM, arm servos on the dedicated servo bus, the OLED and IMU over I2C/SPI, and battery voltage on the onboard ADC. Wi-Fi comes from the Jetson radio. Splitting host + MCU keeps YOLO inference and SLAM optimization from blocking the real-time loop (motor PWM, servo bus updates).

Section takeaway. Hardware is Jetson Orin NX (host) + STM32 (real-time MCU). Sensors enter over USB. Chassis motors are STM32 PWM. Arm servos use a serial bus protocol. Host-MCU link is USB-UART at 1 Mbps.

3. Software framework

3.1 Layered architecture

Software is five layers: Interaction, Decision, Perception, Control, and Hardware Abstraction. Data flows sensors -> Perception -> Decision -> Control -> HAL -> actuators. A layer talks only to its neighbors. No skip-level calls.

Figure 3 - Five-layer software stack

3.2 How modules talk

Mechanism When to use Examples
ROS 2 Topic (pub/sub) Continuous streams and setpoints /depth_cam/rgb0/image_raw, /cmd_vel, /controller/...
ROS 2 Service (req/resp) One-shot calls and mode switches Trigger, /kinematics/set_pose_target, /set_color
ROS 2 Action (feedback) Long jobs navigate_to_pose, navigate_through_poses
HTTP REST OpenClaw LLM gateway POST http://127.0.0.1:18789/v1/chat/completions
Serial bus Low-level servo packets bus_servo_control -> HX-12H servos

Section takeaway. Five layers, data only moves toward the actuators. Topics carry streams, services do one-shot work, actions cover long tasks. OpenClaw uses HTTP REST. Servos stay on the serial bus.

4. Core modules

4.1 Voice I/O and the OpenClaw agent

There are two stages. The front end is the WonderEcho Pro voice box (capture + ASR). The back end is the OpenClaw agent: language understanding and task decisions.

Figure 4 - Voice pipeline and OpenClaw agent

Voice front end (WonderEcho Pro): Implemented by the wonder_echo_pro_node in the xf_mic_asr_offline package. It talks to the microphone over serial and publishes /vocal_detect/wakeup (Bool) and /vocal_detect/asr_result (String).

Agent brain (OpenClaw): Implemented by the claw_voice node in the openclaw_controller package. It subscribes to WonderEcho Pro's ASR result, then sends an HTTP POST to the OpenClaw gateway at 127.0.0.1:18789 for language understanding. The API matches the OpenAI Chat Completions format.

# Source: claw_voice.py
payload = {
    "model": "openclaw/default",
    "messages": [{"role": "user", "content": text}],
    "user": SESSION_KEY
}
resp = requests.post(
    f"{GATEWAY_URL}/v1/chat/completions",
    headers=headers,
    json=payload
)
reply = result["choices"][0]["message"]["content"]

OpenClaw is more than speech understanding. Package openclaw_controller registers eight nodes: speech understanding, speech synthesis, target tracking, track-and-grasp, arm group control, chassis motion, navigation manager, and AprilTag localization. Together they are the robot "brain": they split a sentence into navigate / detect / grasp subtasks and dispatch them.

Cloud brain vs local brain. By default the gateway forwards to a remote API. If onboard compute is high enough (the article uses "100 TOPS+" as a rule of thumb), point the model field in ~/.openclaw/openclaw.json at a local checkpoint. Local inference cuts latency and works offline, but RAM is tight: SLAM + YOLO + an LLM on 8 GB is a squeeze.

Setting Meaning Path / value
API token Gateway auth token ~/.openclaw/openclaw.json -> gateway.auth.token
Gateway URL OpenClaw agent endpoint http://127.0.0.1:18789
ASR mode Online vs offline recognition mode=1 (on-device online ASR in this write-up)
Wake enable Wake-word switch Service /vocal_detect/enable_wakeup

Key points. WonderEcho Pro does ASR. OpenClaw understands the sentence and schedules modules. Default path is cloud; a local model is optional. The gateway speaks OpenAI-style JSON, so switching models is a config change.

4.2 SLAM mapping

ROSOrin Pro maps with slam_toolbox's sync_slam_toolbox_node (synchronous SLAM). The front end is scan matching. The back end is pose-graph optimization with Ceres Solver. Each laser scan is aligned to the map while the robot pose and the occupancy grid are updated together.

Figure 5 - SLAM mapping flow

Core parameters in slam/config/slam.yaml:

Parameter Value Meaning
solver_plugin solver_plugins::CeresSolver Nonlinear back-end
mode mapping mapping or localization
resolution 0.05 5 cm per grid cell
max_laser_range 12.0 Ignore returns beyond 12 m
do_loop_closing true Enable loop closure

Official mapping backends. Launch argument slam_method selects the stack. Pick the one that fits the room:

Method Traits Best for
slam_toolbox (default) Ceres sync SLAM, loop closure, live map-to-localize switch Indoor rooms that need loop closure
Cartographer Google pose-graph SLAM, submaps, usually cleaner large maps Large spaces, longer runs
Gmapping Classic particle filter, light CPU, ~30 particles Small rooms, weak compute

Switch at launch:

ros2 launch slam slam.launch.py slam_method:=cartographer

Configs live at:

  • slam/config/slam.yaml (slam_toolbox)
  • slam/config/cartographer_2d.lua (Cartographer)
  • slam/config/gmapping.yaml (Gmapping)

Mapping procedure:

# 1. Bring up chassis and sensors
ros2 launch bringup bringup.launch.py

# 2. Start SLAM
ros2 launch slam slam.launch.py

# 3. Drive slowly with a joystick or keyboard while the map fills in

# 4. Save the map
ros2 run nav2_map_server map_saver_cli -f ~/my_map

Map quality depends on three things: speed (keep under 0.3 m/s), scene texture (empty corridors need extra passes), and a completed loop (close the path at least once).

Key points. Official options: slam_toolbox (default), Cartographer (large, high-quality maps), Gmapping (small scenes, low CPU). Switch with slam_method.

4.3 Nav2 navigation

ROSOrin Pro uses Nav2 as a two-layer stack: global plan + local control.

Figure 6 - Nav2 architecture
Component Algorithm Job
Global planner (planner_server) Smac Planner Hybrid-A* Plan on the static map
Local controller (controller_server) TEB (Timed Elastic Band) Track the path, dodge live obstacles, respect kinematics
Costmap Global 5 cm + local 5 cm Fuse LiDAR (and other sensors) into occupancy costs
Localization (AMCL) Adaptive Monte Carlo, 500-2000 particles Match live scans to the saved map
Behavior tree (bt_navigator) BT + recoveries On failure: Spin, Backup, Wait, then retry

Nav2 is not only "go to one pose." Built-in patterns:

Mode How What it does
Single-goal nav navigate_to_pose action One (x, y, yaw) goal
Multi-waypoint navigate_through_poses action Visit poses in order
Nav + haul navigation_transport node graph Drive, grasp, drive, place
Custom BT Edit the BT XML in nav2_params.yaml Change failure recoveries
Multi-robot Separate robot_1_ekf.yaml / robot_2_ekf.yaml Several bases sharing a map

Local controller knobs in nav2_params.yaml:

controller_server:
  ros__parameters:
    controller_frequency: 20.0   # 20 Hz control loop
    FollowPath:
      plugin: "teb_local_planner::TEBController"
      max_vel_x: 0.5             # max linear speed 0.5 m/s
      max_vel_theta: 1.0         # max yaw rate 1.0 rad/s
      xy_goal_tolerance: 0.1     # 10 cm XY tolerance
      yaw_goal_tolerance: 0.1    # ~5.7 deg yaw tolerance

Key points. Nav2 covers single goals, waypoint tours, transport missions, custom behavior trees, and multi-robot setups. Global plan is Hybrid-A*. Local track is TEB at 20 Hz.

4.4 YOLO detection and OpenCV color tracking

Two vision stacks, two jobs:

Figure 7 - Two vision stacks
  • YOLO - traffic-sign detection for the autonomous-driving demos (straight, right turn, stop, traffic light, crosswalk). Ultralytics stack. Default engine YOLOv26n; optional YOLOv11s. Exported to TensorRT .engine files and run on the Jetson.
  • OpenCV color detection - block finding for the arm. LAB threshold + contours, implemented by class ColorTracker in node claw_track_and_grab.

YOLO node (yolo_node) - core loop

# Source: yolo_node.py - detection loop
results = self.yolo_detect(image, conf=self.conf, task=self.task)
for result in results:
    for i in range(len(items)):
        confidence = items.conf[i].item()
        class_name = self.classes[class_id]
        object_info = ObjectInfo()
        object_info.class_name = class_name   # class label
        object_info.score = float(confidence) # 0-1 confidence
        object_info.box = box_coords          # [x1, y1, x2, y2]
        objects_info.append(object_info)
object_msg = ObjectsInfo()
object_msg.objects = objects_info
self.object_pub.publish(object_msg)          # ~/object_detect

YOLO interfaces:

Interface Kind Name Meaning
RGB subscribe Topic (Image) /depth_cam/rgb0/image_raw Depth-camera RGB
Detections Topic (ObjectsInfo) ~/object_detect List of class / score / box
Overlay Topic (Image) ~/object_image Frame with drawn boxes
Start Service (Trigger) /yolo/start Enable the detector
Stop Service (Trigger) /yolo/stop Disable the detector

ObjectsInfo fields (interfaces/msg/ObjectInfo.msg):

Field Type Meaning
class_name string Class label
score float32 Confidence 0-1
box int32[4] Pixel box [x1, y1, x2, y2]
width int32 Source image width
height int32 Source image height
angle int32 Rotation; 0 in this detect mode

OpenCV color tracker used by the gripper:

Figure 8 - Block-detect data path
# Source: claw_track_and_grab.py - ColorTracker
img_lab = cv2.cvtColor(img_blur, cv2.COLOR_BGR2LAB)  # BGR -> LAB
mask = cv2.inRange(img_lab, tuple(color['min']), tuple(color['max']))
contours = cv2.findContours(
    dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE
)[-2]
# Keep the largest contour -> min enclosing circle -> block center
(center_x, center_y), radius = cv2.minEnclosingCircle(best_c[0])

Model choice: YOLO + OpenCV. YOLO is a TensorRT engine on Orin NX. With spare TOPS you can swap in Faster R-CNN or SSD by changing the engine:= parameter only.

Launch examples:

# Start YOLO (default YOLOv26n traffic weights)
ros2 run example yolo_node --ros-args -p engine:=best_traffic_26

# Switch to YOLOv11s
ros2 run example yolo_node --ros-args -p engine:=best_traffic_11

Key points. YOLO watches traffic signs. OpenCV ColorTracker finds colored blocks in LAB space. Detections go out as ObjectsInfo. Engines are swappable.

4.5 MoveIt2 and arm control

ROSOrin Pro ships a 6-DOF arm on a bus-servo link. The current official path is direct bus-servo control, in three layers.

Figure 9 - Arm control layers

Kinematic model: modified Denavit-Hartenberg. Five revolute joints plus a gripper = six DOF. Inverse kinematics takes target [x, y, z] and pitch, then solves the five arm joints. Gripper open/close is independent. If the requested pitch has no solution, the solver searches pitch_range (default ±180°) at resolution (default 1°).

When to add MoveIt2. Direct servo packets are enough for fixed pick-and-place. For live obstacle avoidance, trajectory smoothing, or coordinated multi-axis motion, put MoveIt2 in front of the same servo layer:

MoveIt2 feature What you get
Motion planning OMPL RRT / PRM style planners, collision-free joint trajectories
Collision checking URDF + FCL against the arm and the world
Trajectory execution FollowJointTrajectory action into servo_controller
Visualization RViz2 MotionPlanning plugin: drag a goal, preview the path

Integration steps:

# 1. Install MoveIt2 (ROS 2 Humble)
sudo apt install ros-humble-moveit

# 2. Load the arm URDF in MoveIt Setup Assistant -> generate moveit_config

# 3. Map FollowJointTrajectory to servo_controller

# 4. Launch
ros2 launch moveit_config move_group.launch.py

MoveIt2 Python API sketch:

from moveit.planning import MoveItPy
from moveit.core.robot_state import RobotState

# Init
robot = MoveItPy(node_name="arm_planner")
arm = robot.get_planning_component("arm")

# Goal + plan
arm.set_start_state_to_current_state()
arm.set_goal_state(configuration_name="ready")
plan_result = arm.plan()
if plan_result:
    robot.execute(plan_result.trajectory, controllers=[])

MoveItPy is the Humble-era Python binding. configuration_name="ready" is a named state from the SRDF produced by Setup Assistant. After plan() succeeds, execute() sends FollowJointTrajectory to the controller mapped onto the Hiwonder bus servos. Keep the existing kinematics service for simple scripted picks; use MoveIt when the path must weave around the camera mast or the chassis.

Key points. Today's kit talks to servos directly - fine for scripted grasps. Add MoveIt2 when you need OMPL planning, FCL collision checks, and RViz drag-to-plan. Install the moveit package, generate a config from the URDF, and map the trajectory action.

5. Summary

Figure 10 - One agent, five modules

ROSOrin Pro covers the main teaching blocks of a mobile manipulator:

  • WonderEcho Pro is the ASR front end. OpenClaw is the brain that parses language and schedules modules. Default brain is cloud; a local model is optional if memory allows.
  • SLAM backends: slam_toolbox (default), Cartographer (large, high quality), Gmapping (small, cheap). Switch with slam_method.
  • Nav2 is more than point-to-point: waypoints, transport missions, custom behavior trees, multi-robot.
  • YOLO detects traffic signs. OpenCV color tracking finds blocks. Engines can be swapped (Faster R-CNN, SSD, etc.).
  • MoveIt2 upgrades the arm from bus-servo setpoints to planned, collision-checked trajectories.

The design idea is layered decoupling: five software layers, each talking only next door; Jetson + STM32 on the metal; Topic / Service / Action covering stream vs one-shot vs long job.

Appendix A - Topic / service cheat sheet

Name Kind Role
/vocal_detect/wakeup Topic Bool Wake word
/vocal_detect/asr_result Topic String ASR text
/vocal_detect/enable_wakeup Service Enable wake word
127.0.0.1:18789 /v1/chat/completions HTTP OpenClaw gateway
/depth_cam/rgb0/image_raw Topic Image RGB for YOLO / color
~/object_detect Topic ObjectsInfo YOLO boxes
/yolo/start /yolo/stop Service Trigger YOLO on/off
/set_color Service Target block color
/kinematics/set_pose_target Service Arm IK goal
/servo_controller Topic Servo setpoints
navigate_to_pose Action Single Nav2 goal
navigate_through_poses Action Waypoint list

Appendix B - Launch commands

ros2 launch bringup bringup.launch.py
ros2 launch slam slam.launch.py
ros2 launch slam slam.launch.py slam_method:=cartographer
ros2 run nav2_map_server map_saver_cli -f ~/my_map
ros2 run example yolo_node --ros-args -p engine:=best_traffic_26
ros2 run example yolo_node --ros-args -p engine:=best_traffic_11
sudo apt install ros-humble-moveit
ros2 launch moveit_config move_group.launch.py
Comments (0)

    Leave a comment

    Comments have to be approved before showing up

    Light
    Dark