mirte_lc_nav2
Coverage navigation node using Nav2 FollowPath action
README
Coverage Navigation package
Coverage navigation package for the LabClean application. Provides the action server that executes coverage plans, a set of pluggable path planners, and shared utilities for map processing and ROS path conversion.
Run
ros2 run mirte_lc_nav2 labclean_navigator
Nodes
labclean_action_server
Accepts NavigateCoverage goals, delegates path planning to the requested planner, and drives the robot through coverage segments using Nav2’s goThroughPoses. Supports pause, resume, and stop at runtime via a service interface.
Action servers
Action |
Type |
Description |
|---|---|---|
|
|
Execute a full coverage plan |
Services
Service |
Type |
Description |
|---|---|---|
|
|
Pause, resume, or stop ongoing coverage |
Subscribed topics
Topic |
Type |
Description |
|---|---|---|
|
|
Live costmap used for coverage planning |
Coverage execution flow
Receive NavigateCoverage goal
│
├── Look up robot position via TF (map → base_link)
├── Instantiate requested planner
├── planner.plan(costmap, start)
│ ├── update_map() — threshold, contour extraction, world↔pixel conversion
│ ├── generate_path() — planner-specific algorithm
│ └── sanitize_paths() — clamp waypoints to costmap bounds
│
├── Sort segments longest-first
│
└── For each segment:
├── goThroughPoses(segment)
├── Poll feedback loop
│ ├── cancel requested → canceled()
│ ├── stop requested → abort()
│ ├── pause requested → cancelTask()
│ │ ├── save_path() — reinsert remaining segment at queue front
│ │ └── spin until resume → goThroughPoses(remaining)
│ └── isTaskComplete() → advance to next segment
└── publish_feedback (completion %, current/total segments)
Pause / resume behaviour
On pause the server calls cancelTask() immediately, then calls save_path() to compute the remaining portion of the current segment before re-queuing it. On resume, goThroughPoses is re-issued on that saved segment. The remaining_poses field in the service response reflects the last feedback value from Nav2 at the time of the pause.
save_path() finds the resume index by computing the closest waypoint to the current robot pose (TF lookup). If that lookup fails it falls back to using remaining_poses to slice the tail of the segment.
Planners
All planners inherit from SystematicNavigator and implement generate_path(start). The PLANNERS registry maps name strings to classes.
from mirte_lc_nav2.navigators import PLANNERS
# PLANNERS = {
# "SkeletonPlanner": SkeletonPath,
# "SpanningTreePlanner": SpanningTreePath,
# "StraightLinePlanner": StraightLinePath,
# "CVTPlanner": CVTPath,
# }
SkeletonPlanner (default)
Computes the medial axis skeleton of the free space, converts it to a graph, and traverses between leaf nodes using shortest graph paths.

SpanningTreePlanner
Downsamples the costmap, builds a DFS spanning tree over free cells, and circumnavigates contours around the tree.

CVTPlanner
Samples coverage waypoints using Centroidal Voronoi Tessellation (Lloyd’s algorithm), then solves a nearest-neighbour TSP over the centroids.
Parameter |
Default |
Description |
|---|---|---|
|
|
Number of Voronoi cells |
|
|
Lloyd iterations |
StraightLinePath
Generates a single diagonal straight-line trajectory from the start pose. Useful for testing and calibration only.
SystematicNavigator — shared base class
All planners share this base. Key shared methods:
Method |
Description |
|---|---|
|
Entry point: calls |
|
Thresholds occupancy grid, extracts and groups polygon contours, stores |
|
Clamps all waypoints to valid costmap bounds; removes duplicate points introduced by clamping |
|
Builds a KDTree-connected |
|
Returns nodes with degree 1 |
|
Nearest node by Euclidean distance |
|
Map-frame coordinates → costmap pixel indices |
|
Costmap pixel indices → map-frame coordinates |
All planners also follow this pattern for retrieving a map

Published topics (when a node is provided)
Topic |
Type |
Description |
|---|---|---|
|
|
Extracted map boundary contours |
|
|
Decomposition cells (if applicable) |
|
|
Planned waypoint path |
Utilities
to_ros_path(points, frame_id, spacing)
Converts a list of (x, y) points into a nav_msgs/Path by removing duplicates (< 1 mm apart) and uniformly resampling to the requested spacing.
from mirte_lc_nav2.utils import to_ros_path
path = to_ros_path(segment, frame_id="map", spacing=0.1)
Argument |
Default |
Description |
|---|---|---|
|
— |
Sequence of |
|
|
TF frame for output poses |
|
|
Target distance between output poses |
log(node, msg_type, msg)
Thin wrapper around the ROS logger. Falls back to print() when node is None (e.g. running planners in Jupyter).
from mirte_lc_nav2.utils import log, LogType
log(node, LogType.INFO, "planning complete")
log(None, LogType.WARN, "running without ROS node")
|
ROS level |
|---|---|
|
|
|
|
|
|
|
|
Dependencies
rclpy,tf2_rosnav2_simple_commander(BasicNavigator,PyCostmap2D)mirte_lc_msgsnav_msgs,geometry_msgs,visualization_msgs,std_msgsnumpy,opencv-python(cv2)networkxscikit-image(skimage.morphology)scipy(KDTree,Voronoi)