F1TENTH



f1tenth

Mapping

Implement a collision-free map converter that takes the built occupancy grid map from slam_toolbox as input. It generates an occupancy grid cost map to avoid possible obstacle collision in the mission planning process. It also labels the map grid outside the drivable area for the user interface so that waypoints are added correctly in the interface.

Figure: Correct dataflow shown in rqt_graph
Figure: Map after Map Editing Tool
Map inflation results: robot_radius:0.2m, inflation_radius: 0.5m

Path Planning Algorithm

Map Inflator

Motivation:

Instead of relying on Nav2 as done previously in the map_converter module, we aimed to implement a custom map inflation method. This approach removes the need to launch multiple redundant Nav2 nodes and allows tighter integration with our custom planning pipeline.

Methodology:

This work introduces a map_inflator ROS 2 node that inflates obstacles in an OccupancyGrid to improve navigation safety. The node expands occupied cells to create a buffer zone that accounts for the robot’s physical footprint, ensuring the global planner maintains safe clearance from obstacles and walls.

Key Features

Obstacle Inflation: Transforms a standard occupancy grid into a “cost map” where obstacles are thickened based on a configurable radius in meters.

Configurable Safety Buffer: Uses the inflation_radius_m parameter to automatically calculate the required number of grid cells based on the map’s resolution.

Customizable Thresholds: Allows users to define what constitutes an “occupied” cell and toggle whether unknown territory (v < 0) should be treated as a lethal obstacle.

TopicTypeDescription
/mapnav_msgs/msg/OccupancyGridInput: The raw static map from a map server or SLAM node.
/cost_mapnav_msgs/msg/OccupancyGridOutput: Current robot state from Localization (Particle Filter).
Figure: Map in Rviz2 before Inflation
Figure: Map in Rviz2 after Inflation

Path Planning:

Motivation:

Methodology:

Key Features:

TopicTypeDescription
/mapnav_msgs/msg/OccupancyGridInput: The raw static map from a map server or SLAM node.
/cost_mapnav_msgs/msg/OccupancyGridOutput: Current robot state from Localization (Particle Filter).

Smoothing

Motivation:

Methodology:

Key Features:

TopicTypeDescription
/mapnav_msgs/msg/OccupancyGridInput: The raw static map from a map server or SLAM node.
/cost_mapnav_msgs/msg/OccupancyGridOutput: Current robot state from Localization (Particle Filter).
  • Replaced the initial brute-force search (O(n!)) which was computationally
  • prohibitive for n > 10.
  • o Implemented a bitmasking approach to optimize the storage of the DP table,
  • reducing time complexity to O(n^2 2^n).
  • o Result: Capable of finding the mathematically optimal tour for small-to-medium
  • waypoint sets.

Held-Karp Algorithm (Dynamic Programming)

Nearest Neighbor (Greedy Heuristic):

  • o Implemented as a fallback for high-density waypoint scenarios (n > 20).
  • o Utilizes Dijkstra’s algorithm for cost estimation between nodes.
  • o Result: Provides rapid solutions with minimal memory overhead, ensuring
  • system responsiveness when optimality is secondary to speed.

Implemented one-to-all Dijkstra from the start to compute true grid-based travel costs to every target waypoint. And ensures costs reflect feasible paths around static obstacles, rather than relying on Euclidean distance.
● Built a TSP solver for waypoint ordering, which use Nearest neighbor as the first stage as an initial greedy tour, then apply 2-opt (swap edges) refinement to reduce crossings and lower total cost iteratively
● After determining the waypoint visiting order, used Hybrid A* to generate the
kinematically feasible path connecting the ordered waypoints.
● Packaged the Python implementation into a ROS2 package: path_planning

Figure: Hybrid A* output path for traversing 30 waypoints in a grid map of 200×200
Figure: TSP without smoothing (left), Dijkstra (middle), Dijkstra + NN (right)

Local Planning (Pure Pursuit)

Implemented a pure-pursuit local planning module that takes the planned path and current vehicle state as input, computes a steering command, and publishes it to the vehicle control module. This enables the robot to follow smooth trajectories generated by the planning unit.

Pure Pursuit Algorithm:

κ=2sin(α/L)\kappa = 2 \sin(\alpha / L)

Bicycle Model Integration:

δ=arctan(L/κ)\delta = \arctan(L / \kappa)
TopicTypeDescription
/planning/pathnav_msgs/PathInput: Sequence of waypoints from the Planning unit.
/pf/pose/odomnav_msgs/OdometryInput: Current robot state from Localization (Particle Filter).
/driveackermann_msgs/AckermannDriveStampedOutput: Target steering angle and velocity for the vehicle.
Figure: Visualization of Standalone Pure Pursuit Test
Video: Pure Pursuit Test in ROS2 Envrionment Visualized in Rviz2

UI/UX

Implemented a web-based user interface to visualize the map and robot pose, manage waypoints (add/drag/delete), publish missions, and render subscribed paths on the map.

After the robot is launched, start the frontend application and open it in a browser. The application subscribes to the map and robot position from ROS2 topics and renders them in the interface. Users can click directly on the map to create new waypoints or drag existing waypoints to modify their positions. In delete mode, users can click an existing waypoint to remove it (a button will be provided to switch between waypoint editing modes). Once all mission waypoints are set, users can click a button to publish them back to ROS2 as a PoseArray topic. The planner node then generates a path topic as expected, which the application subscribes to and renders in the interface.