Skip to content

PathPlannerNode

Overview

The PathPlannerNode class is a ROS2 node responsible for path planning in the Tekbot robot navigation stack.
It subscribes to the map, odometry, and goal topics, computes a path using the A* algorithm, and publishes the planned path for the robot to follow.


Class: PathPlannerNode

c++
class PathPlannerNode : public rclcpp::Node
{
    public:
    PathPlannerNode();
    ~PathPlannerNode() = default;

    private:
    void map_callback(const nav_msgs::msg::OccupancyGrid::SharedPtr map);
    void odom_callback(const nav_msgs::msg::Odometry::SharedPtr infos);
    void goal_callback(const geometry_msgs::msg::PoseStamped::SharedPtr infos);
    std::vector<Position> computePath();
    nav_msgs::msg::Path PositionToNav(std::vector<Position> path);
    void publishPath(nav_msgs::msg::Path path);

    nav_msgs::msg::OccupancyGrid _map;
    geometry_msgs::msg::Pose _current_position;
    geometry_msgs::msg::Pose _goal_position;

    rclcpp::Subscription<nav_msgs::msg::OccupancyGrid>::SharedPtr _map_subscriber;
    rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr _odom_subscriber;
    rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr _goal_subscriber;
    rclcpp::Publisher<nav_msgs::msg::Path>::SharedPtr _path_publisher;
};
  • Definition of the PathPlannerNode class, inheriting from rclcpp::Node

Attributes

  • _map:
    nav_msgs::msg::OccupancyGrid
    Stores the latest received occupancy grid map.

  • _current_position:
    geometry_msgs::msg::Pose
    Stores the robot's current pose (from odometry).

  • _goal_position:
    geometry_msgs::msg::Pose
    Stores the target pose to reach.

  • _map_subscriber:
    Subscription to /map topic.

  • _odom_subscriber:
    Subscription to /odom topic.

  • _goal_subscriber:
    Subscription to /goal_pose topic.

  • _path_publisher:
    Publisher for /planned_path topic.


Methods

Constructor and Subscriptions

c++
PathPlannerNode::PathPlannerNode() : Node("path_planner_node")
{
    //subscribe to the occupancy grid map published on /map
    _map_subscriber = this->create_subscription<nav_msgs::msg::OccupancyGrid>(
        "/map", 10, std::bind(&PathPlannerNode::map_callback, this, std::placeholders::_1));

    //subscribe to odometry for current robot pose, published on /odom
    _odom_subscriber = this->create_subscription<nav_msgs::msg::Odometry>(
        "/odom", 10, std::bind(&PathPlannerNode::odom_callback, this, std::placeholders::_1));

    //subscribe to goal pose, published on /goal_pose
    _goal_subscriber = this->create_subscription<geometry_msgs::msg::PoseStamped>(
        "/goal_pose", 10, std::bind(&PathPlannerNode::goal_callback, this, std::placeholders::_1));

    //publisher for the planned path, published on /planned_path
    _path_publisher = this->create_publisher<nav_msgs::msg::Path>("/planned_path", 10);
}
  • Purpose: Initializes subscriptions and publisher for map, odometry, goal, and path

Map Callback

c++
void PathPlannerNode::map_callback(const nav_msgs::msg::OccupancyGrid::SharedPtr map)
{
    //store the latest map for use in path planning
    _map = *map;
}
  • Purpose: Keeps the node's internal map up to date for path computation.

Odometry Callback

c++
void PathPlannerNode::odom_callback(const nav_msgs::msg::Odometry::SharedPtr infos)
{
    //update the current robot pose for use as the path start
    _current_position = infos->pose.pose;
}
  • Purpose: Tracks the robot's current position in the environment.

Goal Callback and Path Computation

c++
void PathPlannerNode::goal_callback(const geometry_msgs::msg::PoseStamped::SharedPtr infos)
{
    //update the goal position to reach
    _goal_position = infos->pose;
    //compute the path from current to goal position
    nav_msgs::msg::Path path = this->PositionToNav(this->computePath());
    //publish the computed path for the robot to follow
    this->publishPath(path);
}
  • Purpose: Triggers path computation and publishing when a new goal is set on /goal_pose topic.

Path Conversion

c++
nav_msgs::msg::Path PathPlannerNode::PositionToNav(std::vector<Position> path)
{
    nav_msgs::msg::Path path_msg;
    path_msg.header.frame_id = "map"; //set the frame to map
    path_msg.header.stamp = this->now(); //the timestamp

    for (const auto& pos : path) {
        geometry_msgs::msg::PoseStamped pose_stamped;
        pose_stamped.header.frame_id = "map";
        pose_stamped.header.stamp = this->now();

        //convert grid position (cell indices) to world coordinates
        pose_stamped.pose.position.x = _map.info.origin.position.x + pos.x * _map.info.resolution;
        pose_stamped.pose.position.y = _map.info.origin.position.y + pos.y * _map.info.resolution;
        pose_stamped.pose.position.z = 0.0;
        //set orientation to identity (no rotation)
        pose_stamped.pose.orientation.x = 0.0;
        pose_stamped.pose.orientation.y = 0.0;
        pose_stamped.pose.orientation.z = 0.0;
        pose_stamped.pose.orientation.w = 1.0;

        // Add this pose to the path
        path_msg.poses.push_back(pose_stamped);
    }

    return path_msg;
}
  • Purpose: Converts the computed path (as grid indices) into a ROS2 Path message for visualization and execution.

Path Computation (A* Algorithm)

c++
std::vector<Position> PathPlannerNode::computePath(void)
{
    int width = _map.info.width;
    int height = _map.info.height;
    //initialize the A* algorithm with the current map
    AStar astar_algo(_map);

    //convert current and goal positions from world coordinates to grid indices
    Position start = {static_cast<int>(_current_position.position.x), static_cast<int>(_current_position.position.y), 0};
    Position end = {static_cast<int>(_goal_position.position.x), static_cast<int>(_goal_position.position.y), 0};

    //create the A* grid and open list
    auto grid = astar_algo.create_astar_grid(height, width, end);
    std::vector<t_astar_node*> open_list;

    //initialize the A* search
    astar_algo.initialize_astar(grid, start, end, open_list);

    std::vector<Position> path;
    t_astar_node* current = nullptr;

    //A* loop: search for the optimal path
    while (!open_list.empty()) {
        //get the node with the lowest cost (f)
        current = astar_algo.pop_lowest_f(open_list);

        if (!current) break;

        current->visited = true;
        //if the goal is reached, reconstruct the path
        if (astar_algo.is_end_node(current, end)) {
            path = astar_algo.reconstruct_path(current);
            astar_algo.delete_astar_grid(grid);
            return path;
        }
        //process all valid neighbors of the current node
        astar_algo.process_neighbors(grid, current, end, open_list);
    }
    //clean up and return an empty path if no solution found
    astar_algo.delete_astar_grid(grid);
    return {};
}
  • Purpose: Implements the A* pathfinding algorithm to find a collision-free path from the robot's current position to the goal.

Path Publishing

c++
void PathPlannerNode::publishPath(nav_msgs::msg::Path path)
{
    path.header.frame_id = "map";
    _path_publisher->publish(path);
}
  • Purpose: Makes the computed path available to other nodes (motion_controller_node) by publishing on /lanned_path.

Main Function

c++
int main(int ac, char **av)
{
    rclcpp::init(ac, av);
    rclcpp::shutdown();
    return 0;
}
  • Purpose: Launches the PathPlannerNode and keeps it running until shutdown.

🤖 Tekbot Robotics Challenge 2K25 - Where innovation meets technical excellence