Project File / Chassis integration, first ground motion, and LiDAR-SLAM verified

NUC ROS2 Indoor Robot: From Sensor Links to a First Map

Real-hardware verification of unified launch, velocity commands, odometry, and an initial LiDAR map using an Intel NUC, Astra Pro, X2 LiDAR, and a mecanum chassis.

  • ROS2
  • NUC
  • Mobile robotics
  • SLAM
  • Mecanum chassis

The starting point was not a car that could listen to commands. It was the set of basic links that most easily break in an indoor mobile robot: whether sensors publish continuously, whether velocity reaches the chassis safely, whether encoder counts become useful odometry, and whether the LiDAR and chassis agree about which way is forward.

The hardware is an Intel NUC, an Orbbec Astra Pro RGB-D camera, an X2 2D LiDAR, and a four-wheel mecanum chassis. The software is Ubuntu 22.04 with ROS2 Humble. The result is not an autonomous navigation product; it is a prototype validated on real hardware, on the ground, and through an initial mapping run.

Two complementary front-distance signals

Astra Pro publishes color, depth, point clouds, and TF at roughly 30 Hz. A median of valid values in the center of the depth image becomes the independent front_obstacle_distance topic.

Depth is useful for closing an RGB-D loop but should not be the only safety source. In close desktop tests, the camera could return invalid values around 0.45 m, while the X2 continued measuring. The project combines a LiDAR sector distance and the depth result into obstacle_status: if either reliable path reports an obstruction, the blocked state is retained.

This is not sensor accumulation for its own sake. The failure modes become part of the decision: depth may fail in the near field, while LiDAR can serve as a short-range fallback. Similar readings also provide a cross-check for mounting and coordinate conventions.

From “LiDAR has data” to “LiDAR is in front”

The X2 publishes /scan reliably. Wall-distance tests were within roughly 1–4 mm, and full-vehicle startup confirmed stable coverage. The difficult issue was the coordinate convention: the physical forward sector appeared near 180° in the raw scan rather than the assumed 0°.

The static base_link → laser transform was therefore corrected with a 180° Z rotation, and the LiDAR and camera positions were placed in one TF tree. The latest configuration uses base_link as the chassis center, LiDAR at (0.095, 0, 0.10) m, and the camera at (0.11, 0, 0.15) m. robot_bringup starts the chassis, Astra Pro, static TF, X2, and obstacle status nodes, exposing /cmd_vel, /odom, /scan, /tf, /tf_static, and camera topics.

The LiDAR motor is off by default and starts only with start_lidar:=true. This keeps “can start” separate from “should always rotate,” which is a useful safety boundary.

Turning /cmd_vel into measurable motion

The original controller board was backed up and its minimum test program was verified through ST-Link. Because the NUC could not establish reliable communication through the original Type-C/CH340 path, the project switched to a driver board with four encoders, onboard speed control, and serial feedback instead of pretending the old protocol was solved.

The ROS2 chassis driver subscribes to /cmd_vel, distributes forward, lateral, and angular velocity to four wheels, publishes /odom, and broadcasts odom → base_link. At startup, current encoder counts become the zero reference. Command timeout sends zero velocity, and shutdown actively stops the wheels.

First ground verification

Low-speed timed commands were used first. Forward at 0.05 m/s for 10 seconds produced about 0.488 m of odometry versus 0.50 m measured. Left translation produced 0.408 m versus 0.38 m. Rotating left at 0.20 rad/s for 8 seconds produced about 90.8° versus 87°, with about 4.6 mm of translation drift.

These results show that the chassis, wheel order, encoder signs, and mecanum kinematics work together, while also showing that the odometry is an initial calibration. On the current tile floor, repeated 90° tests produced an angular correction factor of about 1.033; it remains a configurable value, not a universal constant.

SLAM without claiming navigation

With chassis motion and TF ready, the project connected 2D LiDAR-only slam_toolbox. The system produced /map, /map_metadata, and map → odom. The first stationary scan exported a 0.05 m map of 153 × 109 cells. After a low-speed square path, it expanded to 225 × 209; known free cells grew from about 1008 to 8243, and occupied cells from about 76 to 1152.

This is evidence that scans, odometry, and transforms participated together in mapping. It is not evidence that navigation is complete. LiDAR coverage is still mostly forward because of mounting and chassis occlusion. A read-only LAN map viewer was added for inspection and archiving, not as a control entry point.

Current boundary

The system can launch the chassis, camera, LiDAR, static TF, and obstacle-status path together. The X2 runs at roughly 16.6–17.1 Hz in full startup, and local sensor tests, the first ground motion, and initial mapping have replayable evidence.

Remaining work includes longer and combined odometry calibration, NUC power conversion and wiring, improved LiDAR mounting, repeatable stop/emergency-stop/low-voltage tests, Nav2 after odometry and maps stabilize, and only then connecting high-level language-model intent to navigation goals. A language interface must not control motors directly.