LCOV - code coverage report
Current view: top level - nodes - ControlsROS2Wrapper.h Hit Total Coverage
Test: doc-coverage.info Lines: 20 27 74.1 %
Date: 2026-06-17 17:03:54

          Line data    Source code
       1             : #ifndef CONTROLS_NODES_CONTROLSROS2WRAPPER_H
       2             : #define CONTROLS_NODES_CONTROLSROS2WRAPPER_H
       3             : 
       4             : #include <allocator/ThrustAllocator.h>
       5             : #include <utils/Types.h>
       6             : #include <utils/concurrentqueue.h>
       7             : #include <vehicle/Vehicle.h>
       8             : #include <yaml-cpp/yaml.h>
       9             : 
      10             : #include <atomic>
      11             : #include <bb_controls_msgs/action/locomotion.hpp>
      12             : #include <bb_controls_msgs/msg/controller_status.hpp>
      13             : #include <bb_controls_msgs/msg/thrusters.hpp>
      14             : #include <bb_controls_msgs/srv/controller.hpp>
      15             : #include <bb_controls_msgs/srv/encircle_traj.hpp>
      16             : #include <bb_controls_msgs/srv/spline_traj.hpp>
      17             : #include <bb_planner_msgs/srv/get_plan_through_poses.hpp>
      18             : #include <bb_sensor_msgs/msg/batteries_with_id.hpp>
      19             : #include <boost/uuid/uuid.hpp>
      20             : #include <boost/uuid/uuid_generators.hpp>
      21             : #include <boost/uuid/uuid_io.hpp>
      22             : #include <memory>
      23             : #include <mutex>
      24             : #include <rclcpp_action/rclcpp_action.hpp>
      25             : #include <rclcpp_action/server.hpp>
      26             : #include <std_msgs/msg/bool.hpp>
      27             : #include <string>
      28             : #include <string_view>
      29             : #include <thread>
      30             : #include <unordered_map>
      31             : 
      32             : /**
      33             :  * @brief ROS2 node that wraps the Vehicle control stack and exposes its interface to the rest of the system
      34             :  *
      35             :  * Manages all ROS publishers, subscribers, services, and actions.  Runs the
      36             :  * 20 Hz control loop (started on receipt of the first odometry message), drains
      37             :  * a lock-free debug queue at 20 Hz on a separate timer, and forwards parameter
      38             :  * updates to the Vehicle and SystemDynamicsBase objects at runtime.
      39             :  *
      40             :  * Services:
      41             :  *   - in/controller        — Enable (stationkeep) or disable the controller
      42             :  *   - in/xyzTraj           — Request a waypoint/spline trajectory
      43             :  *   - in/encircleTraj      — Request a circular arc trajectory
      44             :  *
      45             :  * Actions:
      46             :  *   - in/locomotion/poly — Execute a waypoint trajectory with tolerance-based success checking
      47             :  *
      48             :  * Subscriptions:
      49             :  *   - in/odom_ned   — Vehicle odometry (nav_msgs/Odometry)
      50             :  *   - in/batteries  — Battery voltages
      51             :  *   - in/teleop     — Direct force commands (disables the controller if running, then allocates directly)
      52             :  *
      53             :  * Publications:
      54             :  *   - out/force              — Controller body force (WrenchStamped)
      55             :  *   - out/force/allocated    — Achieved body force after allocation (WrenchStamped)
      56             :  *   - out/trajectory/status  — Trajectory and controller status
      57             :  *   - out/trajectory/viz     — Sampled trajectory poses for RViz
      58             :  *   - out/thrusters/input    — Per-thruster PWM commands
      59             :  *   - out/thrusters/forces   — Per-thruster forces in Newtons
      60             :  */
      61           1 : class ControlsROS2Wrapper : public rclcpp::Node {
      62             : public:
      63             :     /**
      64             :      * @brief Constructs the node, initialises all ROS interfaces, and loads parameters
      65             :      *
      66             :      * @param name              [in] ROS node name
      67             :      * @param robot             [in] Fully constructed Vehicle instance
      68             :      * @param body_frame_tf_name  [in] TF frame ID of the vehicle body frame
      69             :      * @param world_frame_tf_name [in] TF frame ID of the world frame
      70             :      */
      71           1 :     explicit ControlsROS2Wrapper(const std::string& name, std::unique_ptr<Vehicle> robot,
      72             :                                  std::string body_frame_tf_name = "base_link", std::string world_frame_tf_name = "map");
      73             : 
      74           0 :     ~ControlsROS2Wrapper() override;
      75             : 
      76             :     // Non-copyable and non-movable: mutex, atomic, unique_ptr, and thread members
      77           0 :     ControlsROS2Wrapper(const ControlsROS2Wrapper&)            = delete;
      78           0 :     ControlsROS2Wrapper& operator=(const ControlsROS2Wrapper&) = delete;
      79           0 :     ControlsROS2Wrapper(ControlsROS2Wrapper&&)                 = delete;
      80           0 :     ControlsROS2Wrapper& operator=(ControlsROS2Wrapper&&)      = delete;
      81             : 
      82           0 :     using Locomotion           = bb_controls_msgs::action::Locomotion;
      83           0 :     using GoalHandleLocomotion = rclcpp_action::ServerGoalHandle<Locomotion>;
      84             : 
      85             :     /**
      86             :      * @brief Internal representation of all ROS-declared controller and dynamics parameters
      87             :      *
      88             :      * Default values match the physical AUV4 vehicle.  Populated from the ROS
      89             :      * parameter server at startup and kept in sync via the set-parameter callback.
      90             :      * Pushed to the Vehicle subsystems by apply_config_to_vehicle().
      91             :      */
      92           1 :     struct Params {
      93             :         double ff_gain               = 0.0;
      94             :         double fb_gain               = 1.0;
      95             :         double buoyancy_gain         = 0.0;
      96             :         bool surface_gain_scheduling = false;
      97             :         double surface_threshold     = 0.1;
      98             :         double axis_gain_x           = 1.0;
      99             :         double axis_gain_y           = 1.0;
     100             :         double axis_gain_z           = 0.0;
     101             :         double axis_gain_roll        = 0.0;
     102             :         double axis_gain_pitch       = 0.0;
     103             :         double axis_gain_yaw         = 1.0;
     104             :         double kp_x                  = 1491.433;
     105             :         double ki_x                  = 35.628;
     106             :         double kd_x                  = 21.098;
     107             :         double kp_y                  = 600.345;
     108             :         double ki_y                  = 9.834;
     109             :         double kd_y                  = 330.864;
     110             :         double kp_z                  = 969.781;
     111             :         double ki_z                  = 474.207;
     112             :         double kd_z                  = 180.169;
     113             :         double kp_roll               = 79.701;
     114             :         double ki_roll               = 91.516;
     115             :         double kd_roll               = 10.975;
     116             :         double kp_pitch              = 117.765;
     117             :         double ki_pitch              = 135.223;
     118             :         double kd_pitch              = 16.209;
     119             :         double kp_yaw                = 150.113;
     120             :         double ki_yaw                = 10.038;
     121             :         double kd_yaw                = 54.212;
     122             :         double kp_x_surface          = 226.595;
     123             :         double ki_x_surface          = 4.124;
     124             :         double kd_x_surface          = 1643.310;
     125             :         double kp_y_surface          = 334.345;
     126             :         double ki_y_surface          = 9.834;
     127             :         double kd_y_surface          = 1589.864;
     128             :         double kp_z_surface          = 969.781;
     129             :         double ki_z_surface          = 474.207;
     130             :         double kd_z_surface          = 180.169;
     131             :         double kp_roll_surface       = 79.701;
     132             :         double ki_roll_surface       = 91.516;
     133             :         double kd_roll_surface       = 10.975;
     134             :         double kp_pitch_surface      = 117.765;
     135             :         double ki_pitch_surface      = 135.223;
     136             :         double kd_pitch_surface      = 16.209;
     137             :         double kp_yaw_surface        = 29.113;
     138             :         double ki_yaw_surface        = 1.038;
     139             :         double kd_yaw_surface        = 54.212;
     140             :         double slow_down_gain        = 0.0;
     141             :         double max_xy_vel            = 10.0;
     142             :         double max_xy_acc            = 5.0;
     143             :         double max_xy_jerk           = 0.8;
     144             :         double max_z_vel             = 0.0;
     145             :         double max_z_acc             = 0.0;
     146             :         double max_z_jerk            = 0.0;
     147             :         double max_yaw_vel           = 3.0;
     148             :         double max_yaw_acc           = 0.4;
     149             :         double max_yaw_jerk          = 0.3;
     150             : 
     151             :         // Adaptive buoyancy bias estimation (heave)
     152             :         bool buoyancy_adaptive_z            = false;
     153             :         double buoyancy_adaptive_rate       = 0.5;
     154             :         double buoyancy_adaptive_clamp_pct  = 0.15;
     155             :         double buoyancy_adaptive_pos_thresh = 0.15;
     156             :         double buoyancy_adaptive_vel_thresh = 0.05;
     157             : 
     158             :         // Adaptive buoyancy bias estimation (roll/pitch); thresholds in deg, deg/s
     159             :         bool buoyancy_adaptive_rp              = false;
     160             :         double buoyancy_adaptive_rate_rp       = 5.0;
     161             :         double buoyancy_adaptive_pos_thresh_rp = 0.2;
     162             :         double buoyancy_adaptive_vel_thresh_rp = 1.0;
     163             : 
     164             :         // System dynamics parameters
     165             :         double mass            = 36.10;
     166             :         double buoyancy_factor = 1.0;
     167             :         double i_xx            = 0.7699579;
     168             :         double i_yy            = 0.7699579;
     169             :         double i_zz            = 1.38624;
     170             :         double i_xy            = 0.0;
     171             :         double i_xz            = 0.0;
     172             :         double i_yz            = 0.0;
     173             :         double ma_x            = 12.19;
     174             :         double ma_y            = 17.44;
     175             :         double ma_z            = 26.47;
     176             :         double ma_roll         = 0.15;
     177             :         double ma_pitch        = 0.26;
     178             :         double ma_yaw          = 0.19;
     179             :         double dl_x            = 3.8;
     180             :         double dl_y            = 4.4;
     181             :         double dl_z            = 34.8;
     182             :         double dl_roll         = 0.131;
     183             :         double dl_pitch        = 0.201;
     184             :         double dl_yaw          = 0.077;
     185             :         double dnl_x           = 38.7;
     186             :         double dnl_y           = 54.6;
     187             :         double dnl_z           = 78.9;
     188             :         double dnl_roll        = 0.342;
     189             :         double dnl_pitch       = 0.465;
     190             :         double dnl_yaw         = 0.451;
     191             :         double rbb_x           = 0.0;
     192             :         double rbb_y           = 0.0;
     193             :         double rbb_z           = -0.05593619792;
     194             :         double rgb_x           = 0.0;
     195             :         double rgb_y           = 0.0;
     196             :         double rgb_z           = 0.0;
     197             :         double cg_offset_x     = 0.0;
     198             :         double cg_offset_y     = 0.0;
     199             :         double cg_offset_z     = 0.0;
     200             :     };
     201             : 
     202             :     // clang-format off
     203             :     /** @brief Maps ROS parameter names to their corresponding Params member pointers */
     204             :     static inline const std::unordered_map<std::string_view, double Params::*> DOUBLE_PARAM_MAP = {
     205             :         {"ff_gain", &Params::ff_gain},
     206             :         {"fb_gain", &Params::fb_gain},
     207             :         {"buoyancy_gain", &Params::buoyancy_gain},
     208             :         {"surface_threshold", &Params::surface_threshold},
     209             :         {"axis_gain_x", &Params::axis_gain_x},
     210             :         {"axis_gain_y", &Params::axis_gain_y},
     211             :         {"axis_gain_z", &Params::axis_gain_z},
     212             :         {"axis_gain_roll", &Params::axis_gain_roll},
     213             :         {"axis_gain_pitch", &Params::axis_gain_pitch},
     214             :         {"axis_gain_yaw", &Params::axis_gain_yaw},
     215             :         {"kp_x", &Params::kp_x},
     216             :         {"ki_x", &Params::ki_x},
     217             :         {"kd_x", &Params::kd_x},
     218             :         {"kp_y", &Params::kp_y},
     219             :         {"ki_y", &Params::ki_y},
     220             :         {"kd_y", &Params::kd_y},
     221             :         {"kp_z", &Params::kp_z},
     222             :         {"ki_z", &Params::ki_z},
     223             :         {"kd_z", &Params::kd_z},
     224             :         {"kp_roll", &Params::kp_roll},
     225             :         {"ki_roll", &Params::ki_roll},
     226             :         {"kd_roll", &Params::kd_roll},
     227             :         {"kp_pitch", &Params::kp_pitch},
     228             :         {"ki_pitch", &Params::ki_pitch},
     229             :         {"kd_pitch", &Params::kd_pitch},
     230             :         {"kp_yaw", &Params::kp_yaw},
     231             :         {"ki_yaw", &Params::ki_yaw},
     232             :         {"kd_yaw", &Params::kd_yaw},
     233             :         {"kp_x_surface", &Params::kp_x_surface},
     234             :         {"ki_x_surface", &Params::ki_x_surface},
     235             :         {"kd_x_surface", &Params::kd_x_surface},
     236             :         {"kp_y_surface", &Params::kp_y_surface},
     237             :         {"ki_y_surface", &Params::ki_y_surface},
     238             :         {"kd_y_surface", &Params::kd_y_surface},
     239             :         {"kp_z_surface", &Params::kp_z_surface},
     240             :         {"ki_z_surface", &Params::ki_z_surface},
     241             :         {"kd_z_surface", &Params::kd_z_surface},
     242             :         {"kp_roll_surface", &Params::kp_roll_surface},
     243             :         {"ki_roll_surface", &Params::ki_roll_surface},
     244             :         {"kd_roll_surface", &Params::kd_roll_surface},
     245             :         {"kp_pitch_surface", &Params::kp_pitch_surface},
     246             :         {"ki_pitch_surface", &Params::ki_pitch_surface},
     247             :         {"kd_pitch_surface", &Params::kd_pitch_surface},
     248             :         {"kp_yaw_surface", &Params::kp_yaw_surface},
     249             :         {"ki_yaw_surface", &Params::ki_yaw_surface},
     250             :         {"kd_yaw_surface", &Params::kd_yaw_surface},
     251             :         {"buoyancy_adaptive_rate", &Params::buoyancy_adaptive_rate},
     252             :         {"buoyancy_adaptive_clamp_pct", &Params::buoyancy_adaptive_clamp_pct},
     253             :         {"buoyancy_adaptive_pos_thresh", &Params::buoyancy_adaptive_pos_thresh},
     254             :         {"buoyancy_adaptive_vel_thresh", &Params::buoyancy_adaptive_vel_thresh},
     255             :         {"buoyancy_adaptive_rate_rp", &Params::buoyancy_adaptive_rate_rp},
     256             :         {"buoyancy_adaptive_pos_thresh_rp", &Params::buoyancy_adaptive_pos_thresh_rp},
     257             :         {"buoyancy_adaptive_vel_thresh_rp", &Params::buoyancy_adaptive_vel_thresh_rp},
     258             :         {"slow_down_gain", &Params::slow_down_gain},
     259             :         {"max_xy_vel", &Params::max_xy_vel},
     260             :         {"max_xy_acc", &Params::max_xy_acc},
     261             :         {"max_xy_jerk", &Params::max_xy_jerk},
     262             :         {"max_z_vel", &Params::max_z_vel},
     263             :         {"max_z_acc", &Params::max_z_acc},
     264             :         {"max_z_jerk", &Params::max_z_jerk},
     265             :         {"max_yaw_vel", &Params::max_yaw_vel},
     266             :         {"max_yaw_acc", &Params::max_yaw_acc},
     267             :         {"max_yaw_jerk", &Params::max_yaw_jerk},
     268             :         {"mass", &Params::mass},
     269             :         {"buoyancy_factor", &Params::buoyancy_factor},
     270             :         {"i_xx", &Params::i_xx},
     271             :         {"i_yy", &Params::i_yy},
     272             :         {"i_zz", &Params::i_zz},
     273             :         {"i_xy", &Params::i_xy},
     274             :         {"i_xz", &Params::i_xz},
     275             :         {"i_yz", &Params::i_yz},
     276             :         {"ma_x", &Params::ma_x},
     277             :         {"ma_y", &Params::ma_y},
     278             :         {"ma_z", &Params::ma_z},
     279             :         {"ma_roll", &Params::ma_roll},
     280             :         {"ma_pitch", &Params::ma_pitch},
     281             :         {"ma_yaw", &Params::ma_yaw},
     282             :         {"dl_x", &Params::dl_x},
     283             :         {"dl_y", &Params::dl_y},
     284             :         {"dl_z", &Params::dl_z},
     285             :         {"dl_roll", &Params::dl_roll},
     286             :         {"dl_pitch", &Params::dl_pitch},
     287             :         {"dl_yaw", &Params::dl_yaw},
     288             :         {"dnl_x", &Params::dnl_x},
     289             :         {"dnl_y", &Params::dnl_y},
     290             :         {"dnl_z", &Params::dnl_z},
     291             :         {"dnl_roll", &Params::dnl_roll},
     292             :         {"dnl_pitch", &Params::dnl_pitch},
     293             :         {"dnl_yaw", &Params::dnl_yaw},
     294             :         {"rbb_x", &Params::rbb_x},
     295             :         {"rbb_y", &Params::rbb_y},
     296             :         {"rbb_z", &Params::rbb_z},
     297             :         {"rgb_x", &Params::rgb_x},
     298             :         {"rgb_y", &Params::rgb_y},
     299             :         {"rgb_z", &Params::rgb_z},
     300             :         {"cg_offset_x", &Params::cg_offset_x},
     301             :         {"cg_offset_y", &Params::cg_offset_y},
     302             :         {"cg_offset_z", &Params::cg_offset_z},
     303             :     };
     304             : 
     305             :     static inline const std::unordered_map<std::string_view, bool Params::*> BOOL_PARAM_MAP = {
     306             :         {"surface_gain_scheduling", &Params::surface_gain_scheduling},
     307             :         {"buoyancy_adaptive_z", &Params::buoyancy_adaptive_z},
     308             :         {"buoyancy_adaptive_rp", &Params::buoyancy_adaptive_rp},
     309             :     };
     310             :     // clang-format on
     311             : 
     312             : protected:
     313             :     /** @brief Control loop frequency in Hz */
     314             :     static constexpr int CONTROL_LOOP_RATE = 20;
     315             : 
     316             :     /** @brief Minimum depth value clamp to avoid near-zero depth noise (m) */
     317             :     static constexpr double MIN_DEPTH_CLAMP = 0.00;
     318             : 
     319             :     /** @brief Position jump threshold for outlier rejection (m) */
     320             :     static constexpr double POSITION_JUMP_THRESHOLD = 0.5;
     321             : 
     322             :     /** @brief Flag for starting control loop **/
     323             :     std::once_flag control_loop_started_;
     324             : 
     325             :     /** @brief TF child_frame_id of the vehicle body frame */
     326             :     const std::string vehicle_frame_id_;
     327             : 
     328             :     /** @brief TF frame_id of the world frame */
     329             :     const std::string world_frame_id_;
     330             : 
     331             :     /** @brief Encapsulated vehicle control stack */
     332             :     std::unique_ptr<Vehicle> auv_;
     333             : 
     334             :     // ROS subscribers
     335             :     rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr world_sub_;
     336             :     rclcpp::Subscription<bb_sensor_msgs::msg::BatteriesWithId>::SharedPtr battery_sub_;
     337             :     rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr teleop_force_sub_;
     338             : 
     339             :     // ROS publishers
     340             :     rclcpp::Publisher<geometry_msgs::msg::WrenchStamped>::SharedPtr pub_controller_force_;
     341             :     rclcpp::Publisher<bb_controls_msgs::msg::ControllerStatus>::SharedPtr pub_status_;
     342             :     rclcpp::Publisher<geometry_msgs::msg::PoseArray>::SharedPtr pub_traj_viz_;
     343             :     rclcpp::Publisher<bb_controls_msgs::msg::Thrusters>::SharedPtr pub_thruster_commands_;
     344             :     rclcpp::Publisher<geometry_msgs::msg::WrenchStamped>::SharedPtr pub_allocator_force_;
     345             :     rclcpp::Publisher<bb_controls_msgs::msg::ThrusterForces>::SharedPtr pub_thruster_forces_;
     346             : 
     347             :     rclcpp::TimerBase::SharedPtr control_loop_timer_;
     348             :     rclcpp::TimerBase::SharedPtr debug_publish_timer_;
     349             : 
     350             :     /** @brief Lock-free queue through which the control loop passes debug messages to the publish timer */
     351             :     moodycamel::ConcurrentQueue<DebugMessage> debug_queue_;
     352             : 
     353             :     rclcpp::Service<bb_controls_msgs::srv::Controller>::SharedPtr controller_srv_;
     354             :     rclcpp::Service<bb_controls_msgs::srv::SplineTraj>::SharedPtr spline_traj_srv_;
     355             :     rclcpp::Service<bb_controls_msgs::srv::EncircleTraj>::SharedPtr encircle_traj_srv_;
     356             : 
     357             :     rclcpp_action::Server<Locomotion>::SharedPtr poly_action_server_;
     358             :     std::mutex action_goal_mutex_;
     359             :     std::shared_ptr<GoalHandleLocomotion> current_action_goal_;
     360             : 
     361             :     /** @brief Signals the action execution thread to exit its loop */
     362             :     std::atomic<bool> shutdown_requested_{false};
     363             : 
     364             :     /** @brief Thread running action execute method; joined before destruction */
     365             :     std::thread action_execute_thread_;
     366             : 
     367             :     OnSetParametersCallbackHandle::SharedPtr callback_handle_;
     368             : 
     369             :     /** @brief Local snapshot of ROS parameters, pushed to Vehicle subsystems on change */
     370             :     Params config_;
     371             : 
     372             :     /** @brief ROS timestamp of the previous control loop iteration */
     373             :     double prev_time_ = 0.0;
     374             : 
     375             :     rclcpp::CallbackGroup::SharedPtr odom_cb_group_, control_loop_cb_group_, services_cb_group_, actions_cb_group_,
     376             :         aux_cb_group_;
     377             : 
     378             :     /**
     379             :      * @brief Executes one iteration of the 20 Hz control loop
     380             :      *
     381             :      * Calls process_pending, get_force, allocate_force, and publishes thruster
     382             :      * commands.  Enqueues debug data for the background publish timer.
     383             :      */
     384           1 :     void control_loop();
     385             : 
     386             :     /**
     387             :      * @brief Publishes a ControllerStatus message from the given status snapshot
     388             :      *
     389             :      * @param status [in] Controller status snapshot to publish
     390             :      */
     391           1 :     void publish_controller_status(const Vehicle::ControllerStatus& status);
     392             : 
     393             :     /**
     394             :      * @brief Drains the debug queue and publishes all pending messages
     395             :      *
     396             :      * Also publishes the current controller status.  Called at 20 Hz by a
     397             :      * separate timer on the aux callback group.
     398             :      */
     399           1 :     void debug_publish_loop();
     400             : 
     401             :     /**
     402             :      * @brief Callback invoked by the ROS parameter system when any parameter changes
     403             :      *
     404             :      * @param parameters [in] List of parameters that were set
     405             :      *
     406             :      * @return Result indicating success or failure
     407             :      */
     408           1 :     rcl_interfaces::msg::SetParametersResult parameters_callback(const std::vector<rclcpp::Parameter>& parameters);
     409             : 
     410             :     /**
     411             :      * @brief Registers all entries in DOUBLE_PARAM_MAP / BOOL_PARAM_MAP with the ROS parameter server
     412             :      */
     413           1 :     void declare_controller_params();
     414             : 
     415             :     /**
     416             :      * @brief Reads all declared ROS parameters into config_
     417             :      *
     418             :      * Only valid when values have already been committed to the server (i.e. at
     419             :      * startup, after declare_controller_params).  Must NOT be called from inside
     420             :      * a set-parameter callback, where the new values are not yet committed.
     421             :      */
     422           1 :     void load_params_from_server();
     423             : 
     424             :     /**
     425             :      * @brief Applies config_ to the Vehicle's dynamics model, controller gains, and limits
     426             :      */
     427           1 :     void apply_config_to_vehicle();
     428             : 
     429             :     /**
     430             :      * @brief Odometry subscriber callback — updates vehicle state and starts the control loop
     431             :      *
     432             :      * @param m [in] Incoming odometry message
     433             :      */
     434           1 :     void sub_callback_world_position(const nav_msgs::msg::Odometry::ConstSharedPtr& m);
     435             : 
     436             :     /**
     437             :      * @brief Battery subscriber callback — forwards the minimum cell voltage to the Vehicle
     438             :      *
     439             :      * @param msg [in] Incoming battery message containing per-cell voltages
     440             :      */
     441           1 :     void sub_callback_battery_voltage(const bb_sensor_msgs::msg::BatteriesWithId::ConstSharedPtr& msg);
     442             : 
     443             :     /**
     444             :      * @brief Teleop subscriber callback — allocates the raw force directly if the controller is disabled
     445             :      *
     446             :      * If the controller is not disabled, issues a disable request and ignores the message.
     447             :      *
     448             :      * @param msg [in] Twist message interpreted as a 6DOF body force [Fx, Fy, Fz, Tx, Ty, Tz]
     449             :      */
     450           1 :     void sub_callback_teleop_force(const geometry_msgs::msg::Twist::ConstSharedPtr& msg);
     451             : 
     452             :     /**
     453             :      * @brief Service callback to enable (stationkeep) or disable the controller
     454             :      *
     455             :      * @param req [in]  Request with an enable flag
     456             :      * @param res [out] Response with a status flag (always true)
     457             :      */
     458           1 :     void srv_callback_controller(const std::shared_ptr<bb_controls_msgs::srv::Controller::Request> req,
     459             :                                  std::shared_ptr<bb_controls_msgs::srv::Controller::Response> res);
     460             : 
     461             :     /**
     462             :      * @brief Service callback to request a straight XYZ or multi-waypoint spline trajectory
     463             :      *
     464             :      * @param req [in]  SplineTraj request containing waypoints and relative-coordinate flags
     465             :      * @param res [out] Response populated with the assigned trajectory UUID, or empty on failure
     466             :      */
     467           1 :     void srv_callback_trajectory_xyz(const std::shared_ptr<bb_controls_msgs::srv::SplineTraj::Request> req,
     468             :                                      std::shared_ptr<bb_controls_msgs::srv::SplineTraj::Response> res);
     469             : 
     470             :     /**
     471             :      * @brief Service callback to request a circular arc (encircle) trajectory
     472             :      *
     473             :      * @param req [in]  EncircleTraj request containing radius, turn angle, and spiral parameters
     474             :      * @param res [out] Response populated with the assigned trajectory UUID, or empty on failure
     475             :      */
     476           1 :     void srv_callback_encircle_traj(const std::shared_ptr<bb_controls_msgs::srv::EncircleTraj::Request> req,
     477             :                                     std::shared_ptr<bb_controls_msgs::srv::EncircleTraj::Response> res);
     478             : 
     479             :     /**
     480             :      * @brief Action server goal handler — rejects goals when the controller is disabled
     481             :      *
     482             :      * @param uuid [in] Goal UUID assigned by the action client
     483             :      * @param goal [in] Locomotion goal
     484             :      *
     485             :      * @return ACCEPT_AND_EXECUTE if the controller is enabled; REJECT otherwise
     486             :      */
     487           1 :     rclcpp_action::GoalResponse poly_handle_goal(const rclcpp_action::GoalUUID& uuid,
     488             :                                                  std::shared_ptr<const Locomotion::Goal> goal);
     489             : 
     490             :     /**
     491             :      * @brief Action server cancel handler — always accepts cancel requests
     492             :      *
     493             :      * @param goal_handle [in] Handle to the goal being cancelled
     494             :      *
     495             :      * @return CancelResponse::ACCEPT
     496             :      */
     497           1 :     rclcpp_action::CancelResponse poly_handle_cancel(const std::shared_ptr<GoalHandleLocomotion> goal_handle);
     498             : 
     499             :     /**
     500             :      * @brief Action server accepted handler — preempts any active goal and starts a new execute thread
     501             :      *
     502             :      * @param goal_handle [in] Handle to the newly accepted goal
     503             :      */
     504           1 :     void poly_handle_accepted(const std::shared_ptr<GoalHandleLocomotion> goal_handle);
     505             : 
     506             :     /**
     507             :      * @brief Executes a Locomotion action: plans trajectory, waits for completion, checks tolerances
     508             :      *
     509             :      * Runs in action_execute_thread_.  Publishes periodic feedback and resolves the
     510             :      * action result to SUCCESS when pose errors fall within the goal tolerances,
     511             :      * or to ABORTED/FAILURE on preemption or planning errors.
     512             :      *
     513             :      * @param goal_handle [in] Handle used to publish feedback and set the final result
     514             :      */
     515           1 :     void poly_execute_action(const std::shared_ptr<GoalHandleLocomotion> goal_handle);
     516             : };
     517             : 
     518             : #endif  // CONTROLS_NODES_CONTROLSROS2WRAPPER_H

Generated by: LCOV version 1.14