Independent project · October 2026 · Simulation
From ROS 2
to Go2.
Autonomous inspection, built one capability at a time.
A wheeled robot established the navigation and inspection workflow. A simulated quadruped then carried the application through the Unitree SDK—with learned vision, obstacle response and a memory of what it had seen.
Follow the development story ↓The challenge
Make a robot do useful work.
The goal was an inspection application that could travel between assets, read their indicators and return with recorded observations. Each extension had to produce evidence: movement, a camera result, a revised path or a persistent object location.
I built the mission software, ROS interfaces, SDK adapter, simulation server, perception model, depth tracker and verification tools around established robotics components. The project grew through separate preserved profiles, so each milestone could be inspected on its own.
ROS 2 foundation
Start with a platform
that lets the application grow.
The first custom chassis pitched during turns, disturbing the plane of the 2D LiDAR. I moved the application to the established TurtleBot 4 baseline in Gazebo Fortress, then tuned the VM simulation to keep the demonstration usable.
ROS 2 connects sensor streams, coordinate transforms and motion commands. LiDAR SLAM supplied the earlier map; saved-map AMCL localization and Nav2 supplied the inspection route.
Use laser scans and motion to build a map while estimating where the robot is.
Match current scans to a saved map to estimate the robot’s position.
Plan a route, follow it and respond to obstacles using current sensor data.
TurtleBot is the LiDAR SLAM reference. The footage below shows a later saved-map inspection mission, rather than mapping a new room.
Make navigation useful
Travel to an asset.
Look. Record a result.
I added a mission layer that sends navigation goals, waits for arrival, collects fresh onboard images and records an inspection result before continuing home. Cancellation and navigation failures have explicit handling.
OpenCV reads known ArUco asset markers and the colour of a perspective-corrected indicator region. This demonstrates controlled visual inspection: healthy pump and valve indicators, and a warning electrical panel.
Cross the robot interface
Turn a ROS command
into a responding Go2.
I first tested command mapping, limits, stop requests and error replies through the official C++ Unitree SDK2 against a local protocol test server. That established the communication contract; it did not yet demonstrate a moving robot.
The next backend connected those SDK calls to MuJoCo physics. A custom Sport API simulation server receives Move and StopMove calls; a credited pre-trained walking policy and motor control produce motion. Measured state returns through native DDS to ROS 2.
Commands become motion
- MissionInspection goals
- Nav2Planned velocity
- ROS relayArm / freshness gates
- Unitree SDK2Native DDS calls
- Custom serverSimulation Sport API
- MuJoCo + policyMotor torques / physics
Measured pose and velocity → SDK / DDS → ROS odometry and TF. Simulated LiDAR and camera streams feed navigation and perception.
A problem worth fixing
Remove the repeated turn at home.
Small gait drift repeatedly switched the navigation controller between approach and final-heading alignment. I added a C++ controller plugin with separate entry and exit radii, while retaining Nav2’s goal checker and collision checks. In the final comparison, home alignment went from 16 turn-direction reversals in 33.20 seconds to zero in 8.44 seconds.
Inspect the recorded arrival audit ↗See the earlier SDK communication test
Add learned perception
Recognize objects
without asset markers.
Marker-based panel reading is useful when the asset layout is known. To extend perception, I trained a compact PyTorch convolutional detector from scratch for traffic cones and fire extinguishers, using varied synthetic scenes.
The deployed ONNX model reads received ROS camera pixels and publishes standard detection messages. Six recognition targets are distributed around the room. They are visual fixtures; LiDAR handles collision avoidance separately.
Held-out synthetic test, IoU ≥ 0.50. False detections occurred in 15 of 148 empty images. These results measure this dataset, rather than physical-world recognition.
Respond to the unexpected
Find another route.
Or stop the mission.
A saved route is only a starting point. I introduced a collision- and LiDAR-visible crate after the robot began moving, without editing the saved floorplan. Nav2 updated its obstacle representation and replanned around the rack to the same active goal.
A separate full-width barrier left no route. An explicit no-recovery behaviour tree aborted navigation; the application disarmed movement and physics confirmed settling. Tests compared received plans, scan endpoints, costmaps, SDK calls and measured motion.

The first clear revised plan was independently observed 0.833 seconds after crate insertion. This is a nominal simulated timing, not a worst-case or hardware stopping guarantee. The detour’s electrical inspection required three viewpoint refinements.
Give detections a place
See an object.
Remember where it was.
A detection box says where an object is in an image. I added same-stamp RGB and metric depth, camera intrinsics and a stamped map transform to estimate visible surface points and their ranges.
A stationary-object tracker confirms repeated observations, associates new views with existing objects and remembers them when they leave view. Six confirmed objects receive stable public numbers 1–6; temporary candidates remain internal.

Fresh RGB-D evidence updates the object’s map location and surface range.
When the object is out of view, its marker fades and its observation age remains explicit.
A compatible later observation restores the same confirmed object number.

Verify the complete chain
Evidence behind
the demonstration.
The final depth mission completed pump, valve, electrical and home goals. Checks connect commands to SDK handlers, feedback to physics, and perception outputs to actual received camera and depth payloads.
1,720 movement publications matched 1,720 native SDK Move handlers. All six fixtures acquired distinct confirmed identities. Separate blocked-passage and occlusion tests exercise behaviours that the nominal route alone cannot prove.
Passing describes these controlled trials. Transport was not lossless, detections had misses and false positives, and the small set of runs does not establish broad reliability.
What this demonstrates
Application engineering
across the robot stack.
ROS 2 / Linux, LiDAR navigation, C++ and Python interfaces, SDK communication, mission logic, learned RGB perception, aligned depth, stationary-object memory and source-backed tests.
Simulation boundaries
Go2 uses a supplied geometry-derived floorplan and simulator-derived odometry. The SDK is official; the Sport API server is custom simulation code. The walking policy is reused from wty-yy/go2_rl_gym ↗, while the RGB detector was trained for this project.
Physical deployment, real sensor calibration, proprietary Sport locomotion, Go2 SLAM, moving-person tracking and hardware safety remain unverified. Depth is ideal synthetic RGB-D. Panel inspection uses known markers and indicators.
Videos show separate trials. Inspection footage is approximately 3× wall-time playback, with low capture frame rates. The final depth presentation was re-rendered from recorded measurements to improve labels; it is not a new live run.




