Program Listing for File basic_motion_references.cpp

Return to documentation for file (/tmp/ws/src/aerostack2/as2_motion_reference_handlers/src/basic_motion_references.cpp)

// Copyright 2023 Universidad Politécnica de Madrid
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * 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.
//
//    * Neither the name of the Universidad Politécnica de Madrid 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.


/*!*******************************************************************************************
 *  \file       basic_motion_references.cpp
 *  \brief      Virtual class for basic motion references implementations
 *  \authors    Miguel Fernández Cortizas
 *              Pedro Arias Pérez
 *              David Pérez Saura
 *              Rafael Pérez Seguí
 ********************************************************************************/

#include "as2_motion_reference_handlers/basic_motion_references.hpp"
#include "as2_core/names/services.hpp"
#include "as2_core/names/topics.hpp"
#include "as2_core/synchronous_service_client.hpp"
#include "as2_core/utils/control_mode_utils.hpp"
#include "as2_msgs/srv/set_control_mode.hpp"

namespace as2
{
namespace motionReferenceHandlers
{
BasicMotionReferenceHandler::BasicMotionReferenceHandler(
  as2::Node * as2_ptr,
  const std::string & ns)
: node_ptr_(as2_ptr), namespace_(ns)
{
  if (number_of_instances_ == 0) {
    namespace_ = ns == "" ? ns : "/" + ns + "/";

    // Publisher
    command_traj_pub_ = node_ptr_->create_publisher<as2_msgs::msg::TrajectoryPoint>(
      namespace_ + as2_names::topics::motion_reference::trajectory,
      as2_names::topics::motion_reference::qos);

    command_pose_pub_ = node_ptr_->create_publisher<geometry_msgs::msg::PoseStamped>(
      namespace_ + as2_names::topics::motion_reference::pose,
      as2_names::topics::motion_reference::qos);

    command_twist_pub_ = node_ptr_->create_publisher<geometry_msgs::msg::TwistStamped>(
      namespace_ + as2_names::topics::motion_reference::twist,
      as2_names::topics::motion_reference::qos);

    // Subscriber
    controller_info_sub_ = node_ptr_->create_subscription<as2_msgs::msg::ControllerInfo>(
      namespace_ + as2_names::topics::controller::info, rclcpp::QoS(1),
      [](const as2_msgs::msg::ControllerInfo::SharedPtr msg) {
        current_mode_ = msg->input_control_mode;
      });

    // Set initial control mode
    desired_control_mode_.yaw_mode = as2_msgs::msg::ControlMode::NONE;
    desired_control_mode_.control_mode = as2_msgs::msg::ControlMode::UNSET;
    desired_control_mode_.reference_frame = as2_msgs::msg::ControlMode::UNDEFINED_FRAME;
  }

  number_of_instances_++;
  RCLCPP_DEBUG(
    node_ptr_->get_logger(),
    "There are %d instances of BasicMotionReferenceHandler created",
    number_of_instances_);
}

BasicMotionReferenceHandler::~BasicMotionReferenceHandler()
{
  number_of_instances_--;
  if (number_of_instances_ == 0 && node_ptr_ != nullptr) {
    RCLCPP_DEBUG(node_ptr_->get_logger(), "Deleting node_ptr_");
    controller_info_sub_.reset();
    command_traj_pub_.reset();
    command_pose_pub_.reset();
    command_twist_pub_.reset();
  }
}

bool BasicMotionReferenceHandler::checkMode()
{
  // TODO(rps): Check comparation
  // if (this->current_mode_ != desired_control_mode_)
  if ((this->current_mode_.control_mode == desired_control_mode_.control_mode) &&
    (this->current_mode_.control_mode == as2_msgs::msg::ControlMode::HOVER))
  {
    return true;
  }

  if (this->current_mode_.yaw_mode != desired_control_mode_.yaw_mode ||
    this->current_mode_.control_mode != desired_control_mode_.control_mode)
  {
    if (!setMode(desired_control_mode_)) {
      return false;
    }
  }
  return true;
}

bool BasicMotionReferenceHandler::sendPoseCommand()
{
  if (!checkMode()) {
    return false;
  }
  command_pose_pub_->publish(command_pose_msg_);
  return true;
}

bool BasicMotionReferenceHandler::sendTwistCommand()
{
  if (!checkMode()) {
    return false;
  }
  command_twist_pub_->publish(command_twist_msg_);
  return true;
}

bool BasicMotionReferenceHandler::sendTrajectoryCommand()
{
  if (!checkMode()) {
    return false;
  }
  command_traj_pub_->publish(command_trajectory_msg_);
  return true;
}

bool BasicMotionReferenceHandler::setMode(const as2_msgs::msg::ControlMode & mode)
{
  RCLCPP_INFO(
    node_ptr_->get_logger(), "Setting control mode to [%s]",
    as2::control_mode::controlModeToString(mode).c_str());

  // Set request
  auto request = as2_msgs::srv::SetControlMode::Request();
  auto response = as2_msgs::srv::SetControlMode::Response();
  request.control_mode = mode;

  auto set_mode_cli = as2::SynchronousServiceClient<as2_msgs::srv::SetControlMode>(
    namespace_ + as2_names::services::controller::set_control_mode, node_ptr_);

  bool out = set_mode_cli.sendRequest(request, response);

  if (out && response.success) {
    this->current_mode_ = mode;
    // Sleep for controller info callback to update
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    return true;
  }
  RCLCPP_ERROR(
    node_ptr_->get_logger(),
    " Controller Control Mode was not able to be settled sucessfully");
  return false;
}

int BasicMotionReferenceHandler::number_of_instances_ = 0;

rclcpp::Subscription<as2_msgs::msg::ControllerInfo>::SharedPtr
BasicMotionReferenceHandler::controller_info_sub_ = nullptr;

as2_msgs::msg::ControlMode BasicMotionReferenceHandler::current_mode_ =
  as2_msgs::msg::ControlMode();

rclcpp::Publisher<as2_msgs::msg::TrajectoryPoint>::SharedPtr
BasicMotionReferenceHandler::command_traj_pub_ = nullptr;
rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr
BasicMotionReferenceHandler::command_pose_pub_ = nullptr;
rclcpp::Publisher<geometry_msgs::msg::TwistStamped>::SharedPtr
BasicMotionReferenceHandler::command_twist_pub_ = nullptr;

}    // namespace motionReferenceHandlers
}  // namespace as2