diff --git a/include/iri_bt_basic_nodes.h b/include/iri_bt_basic_nodes.h index 10bd101e30d2d9d76755f4c47b85d2c9e6ef13c0..5701dc1212062638aac190ebc311ebb4feb81b49 100644 --- a/include/iri_bt_basic_nodes.h +++ b/include/iri_bt_basic_nodes.h @@ -37,12 +37,119 @@ class IriBTBasicNodes * */ BT::NodeStatus RUNNING(void); + + /** + * \brief Check that a bool variable is true or not. + * + * It has the following input ports: + * + * variable (bool): Bool variable to check. + * + * \return BT:NodeStatus::SUCCESS if variable is true. Otherwise returns + * BT:NodeStatus::FAILURE. If inputs are missing or incorrect it also + * returns BT:NodeStatus::FAILURE. + */ BT::NodeStatus is_variable_true(BT::TreeNode& self); + + /** + * \brief Check that a bool variable is false or not. + * + * It has the following input ports: + * + * variable (bool): Bool variable to check. + * + * \return BT:NodeStatus::SUCCESS if variable is false. Otherwise returns + * BT:NodeStatus::FAILURE. If inputs are missing or incorrect it also + * returns BT:NodeStatus::FAILURE. + */ BT::NodeStatus is_variable_false(BT::TreeNode& self); + + /** + * \brief Function to transform a pose to a target frame. + * + * It has the following input ports: + * + * pose_in (geometry_msgs::PoseStamped): Pose to be transformed. + * + * target_frame (std::string): Frame to transform the pose. + * + * It also has the following output ports: + * + * pose_out (geometry_msgs::PoseStamped): Transformed pose. + * + * \return BT:NodeStatus::SUCCESS if pose can be transformed. + * Otherwise returns BT:NodeStatus::FAILURE. If inputs are missing or incorrect it also + * returns BT:NodeStatus::FAILURE. + */ BT::NodeStatus transform_pose(BT::TreeNode& self); + + /** + * \brief Function to Compute the distance between two points. + * They must be in thew same frame. + * + * It has the following input ports: + * + * pose1 (geometry_msgs::PoseStamped): Pose 1. + * + * pose2 (geometry_msgs::PoseStamped): Pose 2. + * + * It also has the following output ports: + * + * distance (double): Distance. + * + * \return BT:NodeStatus::SUCCESS if distance can be computed. + * Otherwise returns BT:NodeStatus::FAILURE. If inputs are missing or incorrect it also + * returns BT:NodeStatus::FAILURE. + */ BT::NodeStatus compute_distance(BT::TreeNode& self); + + /** + * \brief Function to compare if a double is bigger than other. + * + * It has the following input ports: + * + * value1 (double): Value 1. + * + * value2 (double): Value 2. + * + * \return BT:NodeStatus::SUCCESS if value1 is bigger that value2. + * Otherwise returns BT:NodeStatus::FAILURE. If inputs are missing or incorrect it also + * returns BT:NodeStatus::FAILURE. + */ BT::NodeStatus compare_bigger(BT::TreeNode& self); - BT::NodeStatus compare_smaller(BT::TreeNode& self); -}; + + /** + * \brief Function to compare if a double is smaller than other. + * + * It has the following input ports: + * + * value1 (double): Value 1. + * + * value2 (double): Value 2. + * + * \return BT:NodeStatus::SUCCESS if value1 is smaller that value2. + * Otherwise returns BT:NodeStatus::FAILURE. If inputs are missing or incorrect it also + * returns BT:NodeStatus::FAILURE. + */ + BT::NodeStatus compare_smaller(BT::TreeNode& self); + + /** + * \brief Function to write in terminal. + * + * It has the following input ports: + * + * msg (std::string): Msg to print. + * + * type (std::string): It must be "info", "warn", "error" or "debug". + * + * \param _self node with the required ports: + * + * \return a BT:NodeStatus indicating whether the request has been + * successfull (BT::NodeStatus::SUCCESS) or not (BT::NodeStatus::FAILURE). + * If inputs are missing or incorrect it also returns BT::NodeStatus::FAILURE. + * + */ + BT::NodeStatus print_msg(BT::TreeNode& _self); + }; #endif diff --git a/src/iri_bt_basic_nodes.cpp b/src/iri_bt_basic_nodes.cpp index ecf9ca11569d301a8a6cb44046f295422a1eb692..6151e2b7670133de9ee86924ce5a0787913bd622 100644 --- a/src/iri_bt_basic_nodes.cpp +++ b/src/iri_bt_basic_nodes.cpp @@ -12,6 +12,7 @@ void IriBTBasicNodes::init(IriBehaviorTreeFactory &factory) BT::PortsList transform_pose_ports = {BT::InputPort<geometry_msgs::PoseStamped>("pose_in"),BT::InputPort<std::string>("target_frame"),BT::OutputPort<geometry_msgs::PoseStamped>("pose_out")}; BT::PortsList compute_distance_ports = {BT::InputPort<geometry_msgs::PoseStamped>("pose1"),BT::InputPort<geometry_msgs::PoseStamped>("pose2"),BT::OutputPort<double>("distance")}; BT::PortsList compare_ports = {BT::InputPort<double>("value1"),BT::InputPort<double>("value2")}; + BT::PortsList print_msg_ports = {BT::InputPort<std::string>("msg"), BT::InputPort<std::string>("type")}; //Registration of conditions factory.registerSimpleCondition("is_variable_true", std::bind(&IriBTBasicNodes::is_variable_true, this, std::placeholders::_1),check_variable_ports); @@ -22,6 +23,7 @@ void IriBTBasicNodes::init(IriBehaviorTreeFactory &factory) factory.registerSimpleAction("compute_distance", std::bind(&IriBTBasicNodes::compute_distance, this, std::placeholders::_1),compute_distance_ports); factory.registerSimpleAction("compare_bigger", std::bind(&IriBTBasicNodes::compare_bigger, this, std::placeholders::_1),compare_ports); factory.registerSimpleAction("compare_smaller", std::bind(&IriBTBasicNodes::compare_smaller, this, std::placeholders::_1),compare_ports); + factory.registerSimpleAction("print_msg", std::bind(&IriBTBasicNodes::print_msg, this, std::placeholders::_1), print_msg_ports); } BT::NodeStatus IriBTBasicNodes::is_variable_true(BT::TreeNode& self) @@ -64,15 +66,20 @@ BT::NodeStatus IriBTBasicNodes::transform_pose(BT::TreeNode& self) BT::Optional<geometry_msgs::PoseStamped> pose_in = self.getInput<geometry_msgs::PoseStamped>("pose_in"); BT::Optional<std::string> target_frame = self.getInput<std::string>("target_frame"); + geometry_msgs::PoseStamped new_pose; + //Set a default value + self.setOutput("pose_out", new_pose); + if((!pose_in) || (!target_frame)) { ROS_ERROR("IriBTBasicNodes::transform_pose-> Incorrect or missing input. It needs the following input ports: pose_in (geometry_msgs::PoseStamped) target_frame (std::string) pose_out (geometry_msgs::PoseStamped)"); return BT::NodeStatus::FAILURE; } - geometry_msgs::PoseStamped pose_in_value=pose_in.value(),new_pose; + geometry_msgs::PoseStamped pose_in_value=pose_in.value(); std::string target_frame_value=target_frame.value(); + if(target_frame_value!=pose_in_value.header.frame_id) { try{ @@ -102,6 +109,9 @@ BT::NodeStatus IriBTBasicNodes::compute_distance(BT::TreeNode& self) BT::Optional<geometry_msgs::PoseStamped> pose1 = self.getInput<geometry_msgs::PoseStamped>("pose1"); BT::Optional<geometry_msgs::PoseStamped> pose2 = self.getInput<geometry_msgs::PoseStamped>("pose2"); + double distance; + self.setOutput("distance",distance); + if((!pose1) || (!pose2)) { ROS_ERROR("IriBTBasicNodes::compute_distance-> Incorrect or missing input. It needs the following input ports: pose1 (geometry_msgs::PoseStamped) pose2 (geometry_msgs::PoseStamped) distance (double)"); @@ -110,7 +120,12 @@ BT::NodeStatus IriBTBasicNodes::compute_distance(BT::TreeNode& self) geometry_msgs::PoseStamped pose1_value=pose1.value(); geometry_msgs::PoseStamped pose2_value=pose2.value(); - double distance; + + if (pose1_value.header.frame_id != pose1_value.header.frame_id) + { + ROS_ERROR_STREAM("IriBTBasicNodes::compute_distance-> Points with different frame ids: pose1=" << pose1_value.header.frame_id << "; pose2=" << pose1_value.header.frame_id); + return BT::NodeStatus::FAILURE; + } distance=sqrt(pow(pose1_value.pose.position.x-pose2_value.pose.position.x,2.0)+pow(pose1_value.pose.position.y-pose2_value.pose.position.y,2.0)+pow(pose1_value.pose.position.z-pose2_value.pose.position.z,2.0)); @@ -165,3 +180,29 @@ BT::NodeStatus IriBTBasicNodes::RUNNING() return BT::NodeStatus::RUNNING; } +BT::NodeStatus IriBTBasicNodes::print_msg(BT::TreeNode& _self) +{ + BT::Optional<std::string> msg_p = _self.getInput<std::string>("msg"); + BT::Optional<std::string> type_p = _self.getInput<std::string>("type"); + std::string msg; + std::string type; + + if (!msg_p || !type_p) + { + ROS_ERROR_STREAM("common_helpers::print_msg-> Incorrect or missing input. It needs the following input ports:" + << " msg (sdt::string) and type (std::string)"); + return BT::NodeStatus::FAILURE; + } + msg = msg_p.value(); + type = type_p.value(); + + if (type == "warn") + ROS_WARN_STREAM(msg); + else if (type == "error") + ROS_ERROR_STREAM(msg); + else if (type == "debug") + ROS_DEBUG_STREAM(msg); + else + ROS_INFO_STREAM(msg); + return BT::NodeStatus::SUCCESS; +} \ No newline at end of file diff --git a/src/xml/bt_definitions.xml b/src/xml/bt_definitions.xml new file mode 100644 index 0000000000000000000000000000000000000000..35e3ec719e87f19a363fc0ee85e94fcf76ee97ba --- /dev/null +++ b/src/xml/bt_definitions.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<root main_tree_to_execute="BehaviorTree"> + <!-- ////////// --> + <BehaviorTree ID="BehaviorTree"> + <Action ID="RUNNING"/> + </BehaviorTree> + <!-- ////////// --> + <TreeNodesModel> + <!-- basic_nodes --> + <Action ID="RUNNING"/> + <Action ID="is_variable_true"> + <input_port name="variable"> (bool): Bool variable to check.</input_port> + </Action> + <Action ID="is_variable_false"> + <input_port name="variable"> (bool): Bool variable to check.</input_port> + </Action> + <Action ID="transform_pose"> + <input_port name="pose_in"> (geometry_msgs::PoseStamped): Pose to be transformed.</input_port> + <input_port name="target_frame"> (std::string): Frame to transform the pose.</input_port> + <output_port name="pose_out"> (geometry_msgs::PoseStamped): Transformed pose.</output_port> + </Action> + <Action ID="compute_distance"> + <input_port name="pose1"> (geometry_msgs::PoseStamped): Pose 1.</input_port> + <input_port name="pose2"> (geometry_msgs::PoseStamped): Pose 2.</input_port> + <output_port name="distance"> (double): Distance.</output_port> + </Action> + <Action ID="compare_bigger"> + <input_port name="value1"> (double): Value 1.</input_port> + <input_port name="value2"> (double): Value 2.</input_port> + </Action> + <Action ID="compare_smaller"> + <input_port name="value1"> (double): Value 1.</input_port> + <input_port name="value2"> (double): Value 2.</input_port> + </Action> + <Action ID="print_msg"> + <input_port name="msg"> (std::string): Msg to print.</input_port> + <input_port name="type"> (std::string): It must be info, warn, error or debug.</input_port> + </Action> + </TreeNodesModel> + <!-- ////////// --> +</root> \ No newline at end of file