Program Listing for File mrpt_reactivenav2d_node.hpp

Return to documentation for file (include/mrpt_reactivenav2d/mrpt_reactivenav2d_node.hpp)

/* +------------------------------------------------------------------------+
   |                             mrpt_navigation                            |
   |                                                                        |
   | Copyright (c) 2014-2024, Individual contributors, see commit authors   |
   | See: https://github.com/mrpt-ros-pkg/mrpt_navigation                   |
   | All rights reserved. Released under BSD 3-Clause license. See LICENSE  |
   +------------------------------------------------------------------------+ */

#pragma once

#include <mrpt/config/CConfigFile.h>
#include <mrpt/config/CConfigFileMemory.h>
#include <mrpt/kinematics/CVehicleVelCmd_DiffDriven.h>
#include <mrpt/maps/CSimplePointsMap.h>
#include <mrpt/nav/reactive/CReactiveNavigationSystem.h>
#include <mrpt/nav/reactive/TWaypoint.h>
#include <mrpt/obs/CObservationOdometry.h>
#include <mrpt/ros2bridge/point_cloud2.h>
#include <mrpt/ros2bridge/pose.h>
#include <mrpt/ros2bridge/time.h>
#include <mrpt/system/CTimeLogger.h>
#include <mrpt/system/filesystem.h>
#include <mrpt/system/os.h>
#include <tf2/LinearMath/Matrix3x3.h>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_ros/buffer.h>
#include <tf2_ros/transform_listener.h>

#include <geometry_msgs/msg/polygon.hpp>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <mrpt_msgs/msg/waypoint.hpp>
#include <mrpt_msgs/msg/waypoint_sequence.hpp>
#include <mrpt_nav_interfaces/action/navigate_goal.hpp>
#include <mrpt_nav_interfaces/action/navigate_waypoints.hpp>
#include <mutex>
#include <nav_msgs/msg/odometry.hpp>
#include <rclcpp/rclcpp.hpp>
#include <rclcpp_action/rclcpp_action.hpp>
#include <sensor_msgs/msg/laser_scan.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include <std_msgs/msg/string.hpp>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
#include <visualization_msgs/msg/marker_array.hpp>

namespace mrpt_reactivenav2d
{
// The ROS node
class ReactiveNav2DNode : public rclcpp::Node
{
   public:
    /* Ctor*/
    explicit ReactiveNav2DNode(
        const rclcpp::NodeOptions& options = rclcpp::NodeOptions());
    /* Dtor*/
    ~ReactiveNav2DNode() {}

   private:
    // methods
    void read_parameters();
    void navigate_to(const mrpt::math::TPose2D& target);
    void on_do_navigation();
    void on_goal_received(
        const geometry_msgs::msg::PoseStamped::SharedPtr& trg_ptr);
    void on_local_obstacles(
        const sensor_msgs::msg::PointCloud2::SharedPtr& obs);
    void on_set_robot_shape(
        const geometry_msgs::msg::Polygon::SharedPtr& newShape);
    void on_odometry_received(const nav_msgs::msg::Odometry::SharedPtr& odom);
    void update_waypoint_sequence(const mrpt_msgs::msg::WaypointSequence& wp);
    void on_waypoint_seq_received(
        const mrpt_msgs::msg::WaypointSequence::SharedPtr& wps);

   private:
    rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr subOdometry_;
    rclcpp::Subscription<mrpt_msgs::msg::WaypointSequence>::SharedPtr subWpSeq_;
    rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr
        subNavGoal_;
    rclcpp::Subscription<sensor_msgs::msg::PointCloud2>::SharedPtr subLocalObs_;
    rclcpp::Subscription<geometry_msgs::msg::Polygon>::SharedPtr subRobotShape_;
    rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr pubCmdVel_;

    rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr
        pubSelectedPtg_;

    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr pubNavEvents_;

    std::shared_ptr<tf2_ros::Buffer> tfBuffer_;
    std::shared_ptr<tf2_ros::TransformListener> tfListener_;
    mrpt::system::CTimeLogger profiler_;
    bool initialized_ = false;

    std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;

    // Used for single goal commands. For waypoints, the node will use
    // the distances in the waypoints msg:
    double targetAllowedDistance_ = 0.40;
    double navPeriod_ = 0.10;

    std::string subTopicNavGoal_ = "reactive_nav_goal";
    std::string subTopicLocalObstacles_ = "local_map_pointcloud";
    std::string subTopicRobotShape_;
    std::string subTopicWpSeq_ = "reactive_nav_waypoints";
    std::string subTopicOdometry_ = "/odom";

    std::string pubTopicCmdVel_ = "/cmd_vel";
    std::string pubTopicSelectedPtg_ = "reactivenav_selected_ptg";
    std::string pubTopicEvents_ = "reactivenav_events";

    std::string frameidReference_ = "map";
    std::string frameidRobot_ = "base_link";

    bool pure_pursuit_mode_ = false;
    std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_pure_pursuit_mode_;

    std::string pluginFile_ = {};
    std::string cfgFileReactive_ = "reactive2d_config.ini";

    bool saveNavLog_ = false;

    rclcpp::TimerBase::SharedPtr timerRunNav_;

    mrpt::obs::CObservationOdometry odometry_;
    std::mutex odometryMtx_;

    mrpt::maps::CSimplePointsMap lastObstacles_;
    std::mutex lastObstaclesMtx_;

    bool waitForTransform(
        mrpt::poses::CPose3D& des, const std::string& target_frame,
        const std::string& source_frame, const int timeoutMilliseconds = 50);

    void publish_last_log_record_to_ros(const mrpt::nav::CLogFileRecord& lr);

    visualization_msgs::msg::MarkerArray log_to_margers(
        const mrpt::nav::CLogFileRecord& lr);

    void publish_event_message(const std::string& text);

    struct MyReactiveInterface : public mrpt::nav::CRobot2NavInterface
    {
        ReactiveNav2DNode& parent_;

        MyReactiveInterface(ReactiveNav2DNode& parent) : parent_(parent) {}

        bool getCurrentPoseAndSpeeds(
            mrpt::math::TPose2D& curPose, mrpt::math::TTwist2D& curVel,
            mrpt::system::TTimeStamp& timestamp,
            mrpt::math::TPose2D& curOdometry, std::string& frame_id) override;

        bool changeSpeeds(
            const mrpt::kinematics::CVehicleVelCmd& vel_cmd) override;

        bool stop(bool isEmergency) override;

        bool startWatchdog(float T_ms) override { return true; }

        bool stopWatchdog() override { return true; }

        bool senseObstacles(
            mrpt::maps::CSimplePointsMap& obstacles,
            mrpt::system::TTimeStamp& timestamp) override;

        mrpt::kinematics::CVehicleVelCmd::Ptr getEmergencyStopCmd() override
        {
            return getStopCmd();
        }

        mrpt::kinematics::CVehicleVelCmd::Ptr getStopCmd() override
        {
            auto ret = mrpt::kinematics::CVehicleVelCmd_DiffDriven::Create();
            ret->setToStop();
            return ret;
        }

        void sendNavigationStartEvent() override;

        void sendNavigationEndEvent() override;

        void sendWaypointReachedEvent(
            int waypoint_index, bool reached_nSkipped) override;

        void sendNewWaypointTargetEvent(int waypoint_index) override;

        void sendNavigationEndDueToErrorEvent() override;

        void sendWaySeemsBlockedEvent() override;

        void sendApparentCollisionEvent() override;

        void sendCannotGetCloserToBlockedTargetEvent() override;
    };

    MyReactiveInterface reactiveInterface_{*this};
    mrpt::nav::CReactiveNavigationSystem rnavEngine_{reactiveInterface_};
    std::mutex rnavEngineMtx_;

    // ACTION INTERFACE: NavigateGoal
    // --------------------------------------
    using NavigateGoal = mrpt_nav_interfaces::action::NavigateGoal;
    using HandleNavigateGoal = rclcpp_action::ServerGoalHandle<NavigateGoal>;

    rclcpp_action::Server<NavigateGoal>::SharedPtr action_server_goal_;

    rclcpp_action::GoalResponse handle_goal(
        const rclcpp_action::GoalUUID& uuid,
        std::shared_ptr<const NavigateGoal::Goal> goal);

    rclcpp_action::CancelResponse handle_cancel(
        const std::shared_ptr<HandleNavigateGoal> goal_handle);

    void handle_accepted(const std::shared_ptr<HandleNavigateGoal> goal_handle);
    void execute_action_goal(
        const std::shared_ptr<HandleNavigateGoal> goal_handle);

    std::optional<bool> currentNavEndedSuccessfully_;
    std::mutex currentNavEndedSuccessfullyMtx_;

    // ACTION INTERFACE: NavigateWaypoints
    // --------------------------------------
    using NavigateWaypoints = mrpt_nav_interfaces::action::NavigateWaypoints;
    using HandleNavigateWaypoints =
        rclcpp_action::ServerGoalHandle<NavigateWaypoints>;

    rclcpp_action::Server<NavigateWaypoints>::SharedPtr
        action_server_waypoints_;

    rclcpp_action::GoalResponse handle_goal_wp(
        const rclcpp_action::GoalUUID& uuid,
        std::shared_ptr<const NavigateWaypoints::Goal> goal);

    rclcpp_action::CancelResponse handle_cancel_wp(
        const std::shared_ptr<HandleNavigateWaypoints> goal_handle);

    void handle_accepted_wp(
        const std::shared_ptr<HandleNavigateWaypoints> goal_handle);
    void execute_action_wp(
        const std::shared_ptr<HandleNavigateWaypoints> goal_handle);
};

}  // namespace mrpt_reactivenav2d