Central engineering reference and operations manual for the MRDT Autonomy Software.
View the Project on GitHub MissouriMRDT/Autonomy_Software
Return to RoveSoDocs Guides for Today, Tomorrow, and Forever.
The Path Planning subsystem determines collision-free, kinematically viable trajectories from the rover’s current global position to target waypoints across complex terrain.
Path planning is orchestrated through two primary components: the GeoPlanner (for global terrain traversal) and SearchPattern (for localized target search).
[Target Destination] (from WaypointHandler)
|
v
[GeoPlanner::PlanPath()]
|
+---> [LiDARHandler Query] (DuckDB spatial lookup within corridor padding)
|
+---> [2.5D Costmap Generation] (Elevation, Slope, Roughness, Curvature)
|
+---> [Obstacle Dilation Pass] (nDilationPasses, dSafeTravScoreThreshold)
|
+---> [Kinematically Constrained Weighted A* Search]
|
v
[Path Post-Processing] (SplicePath, Waypoint Tolerance Pruning)
|
v
[Ordered Waypoint Path] (std::vector<geoops::Waypoint>)
GeoPlannerThe GeoPlanner (src/algorithms/planners/GeoPlanner.cpp) is a specialized geospatial path planner designed for rough natural environments:
Rather than assuming a flat 2D plane with binary open/closed cells, GeoPlanner constructs a continuous 2.5D costmap using preprocessed USGS LiDAR data from LiDARHandler (sourced from the team’s USGS_Data repository):
dMinTravScore are marked non-traversable.nDilationPasses, default 2), expanding obstacles by an inflation margin.dGridResolution = 0.5 meters, dTileSize = 50.0 meters).dCorridorPadding = 100.0 meters) along the direct line between start and goal.dPenaltyScalingFactor and dPenaltyPower to actively penalize rough ground even when traversable.dBetaBias): Tuning weight balancing shortest path distance against terrain smoothness.To maintain high runtime performance:
GeoPlanner caches evaluated grid tiles in memory.UnloadLiDARTiles() or ClearGeoCache().[!TIP] Route Pre-Planning & Inspection Mission routes, waypoint sequences, and A* navigation splines can be validated and previewed using the hosted Autonomy Task Visualizer. Underlying point cloud terrain tiles and slope hazards can be inspected in 3D using the LiDAR Tool, both part of the hosted MRDT Visualizer Suite.
SearchPattern.hpp)When the rover reaches the vicinity coordinate of an ArUco post or ground object but does not detect it, the state machine enters eSearchPattern. SearchPattern mathematically constructs structured search paths:
CalculateSpiralPatternWaypoints):
constants::SEARCH_ANGULAR_STEP_DEGREES (typically $15.0^\circ$), with radial arm separation controlled by constants::SEARCH_SPIRAL_SPACING (typically $2.0$ m). Outward generation continues until reaching the designated search radius $R$.SearchPatternState:
After filtering red-zone terrain and passing through GeoPlanSearchPattern(), the planned trajectory is split into two halves:
vFirstHalf): Stored in WaypointHandler as "GeoPlannerPath", assigned to PurePursuitController.vSecondHalf): Cached in WaypointHandler as "GeoPlannerPathReverse".
If the outward leg completes without acquiring the target, the state machine transitions m_eCurrentSearchPatternType to SearchPatternType::END, retrieves "GeoPlannerPathReverse", promotes it to "GeoPlannerPath", and navigates back to center.bReachedFinalTarget is guarded by target index verification:
\(\text{TargetIndex} > \text{size}(v_{\text{SearchPath}}) - 4\)
Only when the lookahead tracker has actively traversed through to the final segments of the path is eSearchFailed permitted to trigger.constants::SEARCH_ZIGZAG_SPACING.constants::SEARCH_SNAKE_SLITHERS.StuckState.cpp)If the rover encounters an unmapped obstruction or becomes stuck during transit:
DeclareObstacle):
When StuckState::Start() initiates, it computes an obstacle position projected constants::STUCK_OBSTACLE_DISTANCE (default 1.0 m) ahead along the rover’s current heading:
\(E_{\text{obs}} = E_{\text{rover}} + d_{\text{obs}} \cos(\theta), \quad N_{\text{obs}} = N_{\text{rover}} + d_{\text{obs}} \sin(\theta)\)
This obstacle is permanently recorded in WaypointHandler with radius constants::STUCK_OBSTACLE_RADIUS (default 2.0 m).eReverseCurrentHeading, eReverseLeft, eReverseRight). Once displacement from the stuck origin exceeds constants::STUCK_SAME_POINT_PROXIMITY (default 0.5 m), the state machine dispatches Event::eUnstuck, invoking ModifyPath().SplicePath):
"GeoPlannerPath" in place (and also splices "GeoPlannerPathReverse" if recovering during SearchPatternState), eliminating legacy intermediate path keys ("stuckPath", "unstuckPath", "RevSpiralPath").GetObstaclesCount() > 0 before querying obstacle records.GetObstaclesCount() - 1.it != std::prev(vPath.end()) prevents goal point excision.vPath.erase().GeoPlanner::PlanPath() generates a connecting detour between the last valid waypoint before the obstacle and the first valid waypoint beyond it.stStartCoordinate automatically falls back to stCurrentRoverPose.GetUTMCoordinate().vSplicePathCoordinates.size() - 2), preventing duplicate processing or iterator invalidation.geoops::UTMCoordinate).geoops::Waypoint).LiDARHandler*).std::vector<geoops::Waypoint> representing the sequential navigation points.dMaxSearchTimeSeconds (default 120.0 seconds). If terrain geometry creates an impenetrable barrier, the planner aborts rather than freezing the application.dGridResolution below 0.25 meters dramatically increases open-set node evaluations. A resolution of 0.5 meters provides optimal balance between path fidelity and real-time responsiveness.