
Autonomous Lawn Mower
Personal robotics project: a fully custom autonomous mowing stack for a differential-drive robot with Livox LiDAR, running onboard on Linux with ROS 2 Jazzy. The goal was reliable coverage of an irregular lawn perimeter including plants along the edge without leaning on Nav2’s generic navigation servers. I designed a layered pipeline: LiDAR localization, 2.5D global costmap fusion, boustrophedon coverage planning, and a C++ path follower with its own state machine (mowing stripes, orthogonal turns, transit connectors, and local obstacle handling). An Android app over Bluetooth drives mission start, pause/resume, zone selection, and live map view. Field runs are logged to CSV telemetry so every stall, ghost obstacle, and corner trim can be traced back to the code.
Role
Software Engineering, Embedded Systems, ROS 2, Mobile (Android)
Sector
Robotics & Autonomous Systems
Year
2025-2026
Standard ROS navigation failed on the real lawn. Stripes drifted, corners were messy, and the robot kept replanning around grass, plants, and fence clutter. Nav2 worked great to reach a goal, not to mow a full garden in 17 cm zig-zags.
I rebuilt the stack around coverage. A planner breaks the lawn into ordered segments: mow, turn, transit, perimeter, with 90° corners instead of wide arcs. A C++ follower executes them with straight-line tracking and pivot assist on turns.
Perception is tuned for mower height: tall grass is filtered out, real obstacles are fused into a live costmap. At plants along the edge, the path trims in close and cuts a sharp corner instead of detouring around every bush.
Real missions exposed problems the sim tests didn't: phantom obstacles from grass speckle, pointless detours that left the mower braking for half a minute, deadlocks during stripe alignment, and blade control that had to match what the robot was actually doing, not what it planned to do next.
Each issue was traced and fixed from field data, not guesswork. Spin direction latched on entry. Escape routes only triggered when the mower was truly stuck. Ground filtering was widened so grass stays grass. Blade stop logic tied to segment type, so cutting only pauses on real transit, not mid-stripe.
Motion runs end-to-end: navigation commands down to closed-loop wheel control with SimpleFOC, plus serial drivers for the blade and drive motors, so path following and physical motion stay in sync on uneven grass.
Stack: ROS 2 Jazzy · C++ path follower · Python coverage planner · Livox + NDT · SimpleFOC motor control · Kotlin/Compose Android app · Foxglove sim (real stack, dummy mower)
More projects
Get in touch
I'm always open to hearing from new people about their ideas, projects, or potential collaborations.