Program Listing for File takeoff_behavior.cpp
↰ Return to documentation for file (/tmp/ws/src/aerostack2/as2_behaviors/as2_behaviors_motion/takeoff_behavior/src/takeoff_behavior.cpp
)
// 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.
#include "takeoff_behavior/takeoff_behavior.hpp"
TakeoffBehavior::TakeoffBehavior(const rclcpp::NodeOptions & options)
: as2_behavior::BehaviorServer<as2_msgs::action::Takeoff>(
as2_names::actions::behaviors::takeoff,
options)
{
try {
this->declare_parameter<std::string>("plugin_name");
} catch (const rclcpp::ParameterTypeException & e) {
RCLCPP_FATAL(
this->get_logger(),
"Launch argument <plugin_name> not defined or "
"malformed: %s",
e.what());
this->~TakeoffBehavior();
}
try {
this->declare_parameter<double>("takeoff_height");
} catch (const rclcpp::ParameterTypeException & e) {
RCLCPP_FATAL(
this->get_logger(),
"Launch argument <takeoff_height> not defined or "
"malformed: %s",
e.what());
this->~TakeoffBehavior();
}
try {
this->declare_parameter<double>("takeoff_speed");
} catch (const rclcpp::ParameterTypeException & e) {
RCLCPP_FATAL(
this->get_logger(),
"Launch argument <takeoff_speed> not defined or "
"malformed: %s",
e.what());
this->~TakeoffBehavior();
}
try {
this->declare_parameter<double>("takeoff_threshold");
} catch (const rclcpp::ParameterTypeException & e) {
RCLCPP_FATAL(
this->get_logger(),
"Launch argument <takeoff_threshold> not defined or "
"malformed: %s",
e.what());
this->~TakeoffBehavior();
}
try {
this->declare_parameter<double>("tf_timeout_threshold");
} catch (const rclcpp::ParameterTypeException & e) {
RCLCPP_FATAL(
this->get_logger(),
"Launch argument <tf_timeout_threshold> not defined or malformed: %s", e.what());
this->~TakeoffBehavior();
}
loader_ = std::make_shared<pluginlib::ClassLoader<takeoff_base::TakeoffBase>>(
"as2_behaviors_motion", "takeoff_base::TakeoffBase");
tf_handler_ = std::make_shared<as2::tf::TfHandler>(this);
try {
std::string plugin_name = this->get_parameter("plugin_name").as_string();
plugin_name += "::Plugin";
takeoff_plugin_ = loader_->createSharedInstance(plugin_name);
takeoff_base::takeoff_plugin_params params;
params.takeoff_height = this->get_parameter("takeoff_height").as_double();
params.takeoff_speed = this->get_parameter("takeoff_speed").as_double();
params.takeoff_threshold = this->get_parameter("takeoff_threshold").as_double();
params.tf_timeout_threshold = this->get_parameter("tf_timeout_threshold").as_double();
tf_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::duration<double>(params.tf_timeout_threshold));
takeoff_plugin_->initialize(this, tf_handler_, params);
RCLCPP_INFO(this->get_logger(), "TAKEOFF BEHAVIOR PLUGIN LOADED: %s", plugin_name.c_str());
} catch (pluginlib::PluginlibException & ex) {
RCLCPP_ERROR(
this->get_logger(), "The plugin failed to load for some reason. Error: %s\n",
ex.what());
this->~TakeoffBehavior();
}
base_link_frame_id_ = as2::tf::generateTfName(this, "base_link");
platform_cli_ =
std::make_shared<as2::SynchronousServiceClient<as2_msgs::srv::SetPlatformStateMachineEvent>>(
as2_names::services::platform::set_platform_state_machine_event, this);
twist_sub_ = this->create_subscription<geometry_msgs::msg::TwistStamped>(
as2_names::topics::self_localization::twist, as2_names::topics::self_localization::qos,
std::bind(&TakeoffBehavior::state_callback, this, std::placeholders::_1));
RCLCPP_DEBUG(this->get_logger(), "Takeoff Behavior ready!");
}
TakeoffBehavior::~TakeoffBehavior() {}
void TakeoffBehavior::state_callback(const geometry_msgs::msg::TwistStamped::SharedPtr _twist_msg)
{
try {
auto [pose_msg, twist_msg] =
tf_handler_->getState(*_twist_msg, "earth", "earth", base_link_frame_id_, tf_timeout);
takeoff_plugin_->state_callback(pose_msg, twist_msg);
} catch (tf2::TransformException & ex) {
RCLCPP_WARN(this->get_logger(), "Could not get transform: %s", ex.what());
}
return;
}
bool TakeoffBehavior::sendEventFSME(const int8_t _event)
{
as2_msgs::srv::SetPlatformStateMachineEvent::Request set_platform_fsm_req;
as2_msgs::srv::SetPlatformStateMachineEvent::Response set_platform_fsm_resp;
set_platform_fsm_req.event.event = _event;
auto out = platform_cli_->sendRequest(set_platform_fsm_req, set_platform_fsm_resp, 3);
if (out && set_platform_fsm_resp.success) {return true;}
return false;
}
bool TakeoffBehavior::process_goal(
std::shared_ptr<const as2_msgs::action::Takeoff::Goal> goal,
as2_msgs::action::Takeoff::Goal & new_goal)
{
if (goal->takeoff_height < 0.0f) {
RCLCPP_ERROR(this->get_logger(), "TakeoffBehavior: Invalid takeoff height");
return false;
}
if (goal->takeoff_speed < 0.0f) {
RCLCPP_WARN(
this->get_logger(), "TakeoffBehavior: Invalid takeoff speed, using default: %f",
this->get_parameter("takeoff_speed").as_double());
return false;
}
new_goal.takeoff_speed = (goal->takeoff_speed != 0.0f) ?
goal->takeoff_speed :
this->get_parameter("takeoff_speed").as_double();
if (!sendEventFSME(PSME::TAKE_OFF)) {
RCLCPP_ERROR(this->get_logger(), "TakeoffBehavior: Could not set FSM to takeoff");
return false;
}
return true;
}
bool TakeoffBehavior::on_activate(std::shared_ptr<const as2_msgs::action::Takeoff::Goal> goal)
{
as2_msgs::action::Takeoff::Goal new_goal = *goal;
if (!process_goal(goal, new_goal)) {
return false;
}
return takeoff_plugin_->on_activate(
std::make_shared<const as2_msgs::action::Takeoff::Goal>(new_goal));
}
bool TakeoffBehavior::on_modify(std::shared_ptr<const as2_msgs::action::Takeoff::Goal> goal)
{
as2_msgs::action::Takeoff::Goal new_goal = *goal;
if (!process_goal(goal, new_goal)) {
return false;
}
return takeoff_plugin_->on_modify(
std::make_shared<const as2_msgs::action::Takeoff::Goal>(new_goal));
}
bool TakeoffBehavior::on_deactivate(const std::shared_ptr<std::string> & message)
{
return takeoff_plugin_->on_deactivate(message);
}
bool TakeoffBehavior::on_pause(const std::shared_ptr<std::string> & message)
{
return takeoff_plugin_->on_pause(message);
}
bool TakeoffBehavior::on_resume(const std::shared_ptr<std::string> & message)
{
return takeoff_plugin_->on_resume(message);
}
as2_behavior::ExecutionStatus TakeoffBehavior::on_run(
const std::shared_ptr<const as2_msgs::action::Takeoff::Goal> & goal,
std::shared_ptr<as2_msgs::action::Takeoff::Feedback> & feedback_msg,
std::shared_ptr<as2_msgs::action::Takeoff::Result> & result_msg)
{
return takeoff_plugin_->on_run(goal, feedback_msg, result_msg);
}
void TakeoffBehavior::on_execution_end(const as2_behavior::ExecutionStatus & state)
{
if (state == as2_behavior::ExecutionStatus::SUCCESS) {
if (!sendEventFSME(PSME::TOOK_OFF)) {
RCLCPP_ERROR(this->get_logger(), "TakeoffBehavior: Could not set FSM to Took OFF");
}
} else {
if (!sendEventFSME(PSME::EMERGENCY)) {
RCLCPP_ERROR(this->get_logger(), "TakeoffBehavior: Could not set FSM to EMERGENCY");
}
}
return takeoff_plugin_->on_execution_end(state);
}
#include "rclcpp_components/register_node_macro.hpp"
// Register the component with class_loader.
// This acts as a sort of entry point, allowing the component to be discoverable when its library
// is being loaded into a running process.
RCLCPP_COMPONENTS_REGISTER_NODE(TakeoffBehavior)