Program Listing for File follow_path_base.hpp
↰ Return to documentation for file (/tmp/ws/src/aerostack2/as2_behaviors/as2_behaviors_motion/follow_path_behavior/include/follow_path_behavior/follow_path_base.hpp
)
// Copyright 2024 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.
#ifndef FOLLOW_PATH_BEHAVIOR__FOLLOW_PATH_BASE_HPP_
#define FOLLOW_PATH_BEHAVIOR__FOLLOW_PATH_BASE_HPP_
#include <Eigen/Dense>
#include <memory>
#include <string>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <geometry_msgs/msg/twist_stamped.hpp>
#include <rclcpp_action/rclcpp_action.hpp>
#include "as2_behavior/behavior_server.hpp"
#include "as2_core/utils/frame_utils.hpp"
#include "as2_core/utils/tf_utils.hpp"
#include "as2_motion_reference_handlers/hover_motion.hpp"
#include "as2_msgs/action/follow_path.hpp"
#include "as2_msgs/msg/platform_info.hpp"
#include "as2_msgs/msg/platform_status.hpp"
namespace follow_path_base
{
struct follow_path_plugin_params
{
double follow_path_speed = 0.0;
double follow_path_threshold = 0.0;
double tf_timeout_threshold = 0.0;
};
class FollowPathBase
{
public:
using GoalHandleFollowPath = rclcpp_action::ServerGoalHandle<as2_msgs::action::FollowPath>;
FollowPathBase() {}
virtual ~FollowPathBase() {}
void initialize(
as2::Node * node_ptr,
std::shared_ptr<as2::tf::TfHandler> tf_handler,
follow_path_plugin_params & params)
{
node_ptr_ = node_ptr;
tf_handler = tf_handler;
params_ = params;
hover_motion_handler_ = std::make_shared<as2::motionReferenceHandlers::HoverMotion>(node_ptr_);
reset();
ownInit();
}
virtual void state_callback(
geometry_msgs::msg::PoseStamped & pose_msg,
geometry_msgs::msg::TwistStamped & twist_msg)
{
actual_pose_ = pose_msg;
feedback_.actual_speed = Eigen::Vector3d(
twist_msg.twist.linear.x, twist_msg.twist.linear.y,
twist_msg.twist.linear.z)
.norm();
if (goal_accepted_) {
feedback_.actual_distance_to_next_waypoint =
(getTargetPosition() - Eigen::Vector3d(
actual_pose_.pose.position.x,
actual_pose_.pose.position.y,
actual_pose_.pose.position.z))
.norm();
}
localization_flag_ = true;
return;
}
void platform_info_callback(const as2_msgs::msg::PlatformInfo::SharedPtr msg)
{
platform_state_ = msg->status.state;
return;
}
bool on_activate(std::shared_ptr<const as2_msgs::action::FollowPath::Goal> goal)
{
as2_msgs::action::FollowPath::Goal goal_candidate = *goal;
if (!processGoal(goal_candidate)) {return false;}
if (own_activate(goal_candidate)) {
goal_ = goal_candidate;
return true;
}
return false;
}
bool on_modify(std::shared_ptr<const as2_msgs::action::FollowPath::Goal> goal)
{
as2_msgs::action::FollowPath::Goal goal_candidate = *goal;
if (!processGoal(goal_candidate)) {return false;}
if (own_modify(goal_candidate)) {
goal_ = goal_candidate;
return true;
}
return false;
}
inline bool on_deactivate(const std::shared_ptr<std::string> & message)
{
return own_deactivate(message);
}
inline bool on_pause(const std::shared_ptr<std::string> & message) {return own_pause(message);}
inline bool on_resume(const std::shared_ptr<std::string> & message) {return own_resume(message);}
void on_execution_end(const as2_behavior::ExecutionStatus & state)
{
reset();
own_execution_end(state);
return;
}
virtual as2_behavior::ExecutionStatus on_run(
const std::shared_ptr<const as2_msgs::action::FollowPath::Goal> goal,
std::shared_ptr<as2_msgs::action::FollowPath::Feedback> & feedback_msg,
std::shared_ptr<as2_msgs::action::FollowPath::Result> & result_msg)
{
goal_accepted_ = true;
as2_behavior::ExecutionStatus status = own_run();
feedback_msg = std::make_shared<as2_msgs::action::FollowPath::Feedback>(feedback_);
result_msg = std::make_shared<as2_msgs::action::FollowPath::Result>(result_);
return status;
}
private:
bool processGoal(as2_msgs::action::FollowPath::Goal & _goal)
{
if (platform_state_ != as2_msgs::msg::PlatformStatus::FLYING) {
RCLCPP_ERROR(node_ptr_->get_logger(), "Behavior reject, platform is not flying");
return false;
}
if (!localization_flag_) {
RCLCPP_ERROR(node_ptr_->get_logger(), "Behavior reject, there is no localization");
return false;
}
for (auto & waypoint : _goal.path) {
if (waypoint.id == "") {
RCLCPP_ERROR(node_ptr_->get_logger(), "Behavior reject, waypoint id is empty");
}
}
return true;
}
void reset()
{
localization_flag_ = false;
goal_accepted_ = false;
feedback_.actual_distance_to_next_waypoint = 2.0 * params_.follow_path_threshold;
feedback_.next_waypoint_id = "unknown";
feedback_.actual_speed = 0.0;
feedback_.remaining_waypoints = 0;
return;
}
private:
std::shared_ptr<as2::motionReferenceHandlers::HoverMotion> hover_motion_handler_ = nullptr;
bool goal_accepted_ = false;
/* Interface with plugin */
protected:
virtual void ownInit() {}
virtual bool own_activate(as2_msgs::action::FollowPath::Goal & goal) = 0;
virtual bool own_modify(as2_msgs::action::FollowPath::Goal & goal)
{
RCLCPP_INFO(node_ptr_->get_logger(), "Follow path can not be modified, not implemented");
return false;
}
virtual bool own_deactivate(const std::shared_ptr<std::string> & message) = 0;
virtual bool own_pause(const std::shared_ptr<std::string> & message)
{
RCLCPP_INFO(
node_ptr_->get_logger(),
"Follow path can not be paused, not implemented, try to cancel it");
return false;
}
virtual bool own_resume(const std::shared_ptr<std::string> & message)
{
RCLCPP_INFO(node_ptr_->get_logger(), "Follow path can not be resumed, not implemented");
return false;
}
virtual void own_execution_end(const as2_behavior::ExecutionStatus & state) = 0;
virtual as2_behavior::ExecutionStatus own_run() = 0;
virtual Eigen::Vector3d getTargetPosition() = 0;
inline void sendHover()
{
hover_motion_handler_->sendHover();
return;
}
inline float getActualYaw()
{
return as2::frame::getYawFromQuaternion(actual_pose_.pose.orientation);
}
protected:
as2::Node * node_ptr_;
std::shared_ptr<as2::tf::TfHandler> tf_handler = nullptr;
as2_msgs::action::FollowPath::Goal goal_;
as2_msgs::action::FollowPath::Feedback feedback_;
as2_msgs::action::FollowPath::Result result_;
int platform_state_;
follow_path_plugin_params params_;
geometry_msgs::msg::PoseStamped actual_pose_;
bool localization_flag_ = false;
}; // FollowPathBase class
} // namespace follow_path_base
#endif // FOLLOW_PATH_BEHAVIOR__FOLLOW_PATH_BASE_HPP_