Program Listing for File controller_handler.hpp

Return to documentation for file (/tmp/ws/src/aerostack2/as2_controller/include/as2_controller/controller_handler.hpp)

/*!*******************************************************************************************
 *  \file       controller_handler.hpp
 *  \brief      Controller handler class definition
 *  \authors    Miguel Fernández Cortizas
 *              Rafael Pérez Seguí
 *              Pedro Arias Pérez
 *              David Pérez Saura
 *
 *  \copyright  Copyright (c) 2022 Universidad Politécnica de Madrid
 *              All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ********************************************************************************/

#ifndef CONTROLLER_HANDLER_HPP
#define CONTROLLER_HANDLER_HPP

#include <algorithm>
#include <chrono>
#include <cstdint>
#include <fstream>
#include <rclcpp/clock.hpp>
#include <rclcpp/logging.hpp>
#include <rclcpp/rate.hpp>
#include <rclcpp/service.hpp>
#include <rclcpp/timer.hpp>
#include <vector>

#include <message_filters/subscriber.h>
#include <message_filters/sync_policies/approximate_time.h>
#include <message_filters/time_synchronizer.h>
#include <rcl/time.h>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <geometry_msgs/msg/twist_stamped.hpp>

#include "as2_core/names/services.hpp"
#include "as2_core/names/topics.hpp"
#include "as2_core/node.hpp"
#include "as2_core/synchronous_service_client.hpp"
#include "as2_core/utils/control_mode_utils.hpp"
#include "as2_core/utils/tf_utils.hpp"
#include "as2_msgs/msg/control_mode.hpp"
#include "as2_msgs/msg/platform_info.hpp"
#include "as2_msgs/msg/thrust.hpp"
#include "as2_msgs/msg/trajectory_point.hpp"
#include "as2_msgs/srv/list_control_modes.hpp"
#include "as2_msgs/srv/set_control_mode.hpp"
#include "controller_base.hpp"

#include "as2_core/utils/tf_utils.hpp"

#define MATCH_ALL 0b11111111
#define MATCH_MODE_AND_FRAME 0b11110011
#define MATCH_MODE 0b11110000
#define MATCH_MODE_AND_YAW 0b11111100

#define UNSET_MODE_MASK 0b00000000
#define HOVER_MODE_MASK 0b00010000

class ControllerHandler {
private:
  std::vector<uint8_t> controller_available_modes_in_;
  std::vector<uint8_t> controller_available_modes_out_;
  std::vector<uint8_t> platform_available_modes_in_;

  std::string enu_frame_id_ = "odom";
  std::string flu_frame_id_ = "base_link";

  std::string input_pose_frame_id_  = "odom";
  std::string input_twist_frame_id_ = "odom";

  std::string output_pose_frame_id_  = "odom";
  std::string output_twist_frame_id_ = "odom";

  as2::tf::TfHandler tf_handler_;

  rclcpp::Subscription<geometry_msgs::msg::TwistStamped>::SharedPtr twist_sub_;

  rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr ref_pose_sub_;
  rclcpp::Subscription<geometry_msgs::msg::TwistStamped>::SharedPtr ref_twist_sub_;
  rclcpp::Subscription<as2_msgs::msg::PlatformInfo>::SharedPtr platform_info_sub_;
  rclcpp::Subscription<as2_msgs::msg::TrajectoryPoint>::SharedPtr ref_traj_sub_;

  rclcpp::Publisher<as2_msgs::msg::Thrust>::SharedPtr thrust_pub_;
  rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr pose_pub_;
  rclcpp::Publisher<geometry_msgs::msg::TwistStamped>::SharedPtr twist_pub_;

  rclcpp::Service<as2_msgs::srv::SetControlMode>::SharedPtr set_control_mode_srv_;
  rclcpp::TimerBase::SharedPtr control_timer_;

  as2_msgs::msg::PlatformInfo platform_info_;

  as2::SynchronousServiceClient<as2_msgs::srv::SetControlMode>::SharedPtr set_control_mode_client_;
  as2::SynchronousServiceClient<as2_msgs::srv::ListControlModes>::SharedPtr
      list_control_modes_client_;

  bool control_mode_established_  = false;
  bool motion_reference_adquired_ = false;
  bool state_adquired_            = false;

  as2_msgs::msg::ControlMode control_mode_in_;
  as2_msgs::msg::ControlMode control_mode_out_;

  uint8_t prefered_output_mode_ = 0b00000000;  // by default, no output mode is prefered

  std::shared_ptr<as2_controller_plugin_base::ControllerBase> controller_ptr_;

public:
  ControllerHandler(std::shared_ptr<as2_controller_plugin_base::ControllerBase> controller,
                    as2::Node* node);

  rcl_interfaces::msg::SetParametersResult parametersCallback(
      const std::vector<rclcpp::Parameter>& parameters);

  bool use_bypass_        = false;
  bool bypass_controller_ = false;

  void getMode(as2_msgs::msg::ControlMode& mode_in, as2_msgs::msg::ControlMode& mode_out) {
    mode_in  = control_mode_in_;
    mode_out = control_mode_out_;
    return;
  };

  void setInputControlModesAvailables(const std::vector<uint8_t>& available_modes) {
    controller_available_modes_in_ = available_modes;
    // sort modes in ascending order
    std::sort(controller_available_modes_in_.begin(), controller_available_modes_in_.end());
  };

  void setOutputControlModesAvailables(const std::vector<uint8_t>& available_modes) {
    controller_available_modes_out_ = available_modes;
    // sort modes in ascending order
    std::sort(controller_available_modes_out_.begin(), controller_available_modes_out_.end());
  };

  virtual ~ControllerHandler(){};

protected:
  as2::Node* node_ptr_;

private:
  rclcpp::Time last_time_;

  void state_callback(const geometry_msgs::msg::TwistStamped::SharedPtr msg);
  void ref_pose_callback(const geometry_msgs::msg::PoseStamped::SharedPtr msg);
  void ref_twist_callback(const geometry_msgs::msg::TwistStamped::SharedPtr msg);
  void ref_traj_callback(const as2_msgs::msg::TrajectoryPoint::SharedPtr msg);
  void platform_info_callback(const as2_msgs::msg::PlatformInfo::SharedPtr msg);

  geometry_msgs::msg::PoseStamped state_pose_;
  geometry_msgs::msg::TwistStamped state_twist_;
  geometry_msgs::msg::PoseStamped ref_pose_;
  geometry_msgs::msg::TwistStamped ref_twist_;
  as2_msgs::msg::TrajectoryPoint ref_traj_;
  geometry_msgs::msg::PoseStamped command_pose_;
  geometry_msgs::msg::TwistStamped command_twist_;
  as2_msgs::msg::Thrust command_thrust_;

  void control_timer_callback();
  void setControlModeSrvCall(const as2_msgs::srv::SetControlMode::Request::SharedPtr request,
                             as2_msgs::srv::SetControlMode::Response::SharedPtr response);
  bool listPlatformAvailableControlModes();

  std::string getFrameIdByReferenceFrame(uint8_t reference_frame);

  bool trySetPlatformHover();
  bool tryToBypassController(const uint8_t input_mode, uint8_t& output_mode);
  bool findSuitableControlModes(uint8_t& input_mode, uint8_t& output_mode);
  bool findSuitableOutputControlModeForPlatformInputMode(uint8_t& output_mode,
                                                         const uint8_t input_mode);
  bool checkSuitabilityInputMode(uint8_t& input_mode, const uint8_t output_mode);
  void sendCommand();
  bool setPlatformControlMode(const as2_msgs::msg::ControlMode& mode);

  void reset();

  void publishCommand();

};  //  ControllerBase

#endif