AutoAPMS
Resilient Robot Mission Management
Loading...
Searching...
No Matches
ros_node_context.cpp
1// Copyright 2024 Robin Müller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "auto_apms_behavior_tree_core/node/ros_node_context.hpp"
16
17#include <iterator>
18#include <regex>
19
20#include "auto_apms_behavior_tree_core/exceptions.hpp"
21#include "auto_apms_util/logging.hpp"
22
24{
26 rclcpp::Node::SharedPtr ros_node, rclcpp::CallbackGroup::SharedPtr tree_node_waitables_callback_group,
27 rclcpp::executors::SingleThreadedExecutor::SharedPtr tree_node_waitables_executor,
28 const NodeRegistrationOptions & options)
29: ros_node_name_(ros_node ? ros_node->get_name() : ""),
30 fully_qualified_ros_node_name_(ros_node ? ros_node->get_fully_qualified_name() : ""),
31 base_logger_(ros_node ? ros_node->get_logger() : rclcpp::get_logger("")),
32 nh_(ros_node),
33 cb_group_(tree_node_waitables_callback_group),
34 executor_(tree_node_waitables_executor),
35 registration_options_(options)
36{
37}
38
39std::string RosNodeContext::getROSNodeName() const { return ros_node_name_; }
40
41std::string RosNodeContext::getFullyQualifiedRosNodeName() const { return fully_qualified_ros_node_name_; }
42
43rclcpp::Logger RosNodeContext::getBaseLogger() const { return base_logger_; }
44
45rclcpp::Logger RosNodeContext::getChildLogger(const std::string & name)
46{
47 const rclcpp::Logger child_logger = base_logger_.get_child(name);
48 try {
49 auto_apms_util::setLoggingSeverity(child_logger, registration_options_.logger_level);
50 } catch (const auto_apms_util::exceptions::SetLoggingSeverityError & e) {
51 RCLCPP_ERROR(
52 base_logger_, "Failed to set the logging severity for the child logger using the node's registration options: %s",
53 e.what());
54 }
55 return child_logger;
56}
57
59{
60 if (const rclcpp::Node::SharedPtr node = nh_.lock()) {
61 return node->now();
62 }
63 return rclcpp::Clock(RCL_ROS_TIME).now();
64}
65
66std::string RosNodeContext::getFullyQualifiedTreeNodeName(const BT::TreeNode * node, bool with_class_name) const
67{
68 // NOTE: registrationName() is empty during construction as this member is first set after the factory constructed the
69 // object
70 const std::string instance_name = node->name();
71 const std::string registration_name = node->registrationName();
72 if (!registration_name.empty() && instance_name != registration_name) {
73 if (with_class_name) {
74 return instance_name + " (" + registration_name + " : " + registration_options_.class_name + ")";
75 }
76 return instance_name + " (" + registration_name + ")";
77 }
78 return with_class_name ? (instance_name + " (" + registration_options_.class_name + ")") : instance_name;
79}
80
81BT::Expected<std::string> RosNodeContext::getCommunicationPortName(const BT::TreeNode * node) const
82{
83 std::string res = registration_options_.port;
84 BT::PortsRemapping input_ports = node->config().input_ports;
85
86 // Parameter registration_options_.port may contain substrings, that that are to be replaced with values retrieved
87 // from a specific node input port. Must be something like (input:my_port) where 'my_port' is the key/name of the
88 // BT::InputPort to use. Anything before or after the expression is kept and used as a prefix respectively suffix.
89 const std::regex pattern(R"(\‍(input:([^)\s]+)\))");
90 const std::sregex_iterator replace_begin(res.begin(), res.end(), pattern);
91 const std::sregex_iterator replace_end = std::sregex_iterator();
92
93 // We iterate over each substitution expression. If there are none, this for loop has no effect, and we simply return
94 // the parameters value.
95 for (std::sregex_iterator it = replace_begin; it != replace_end; ++it) {
96 const std::smatch match = *it;
97 const std::string input_port_key = match[1].str();
98
99 // Search for the specified input port key in the list of input ports passed at construction time
100 if (input_ports.find(input_port_key) != input_ports.end()) {
101 // The input port has been found using input_port_key
102
103 // Make sure its value is either a blackboard pointer or a static string (Must not be empty)
104 if (input_ports.at(input_port_key).empty()) {
105 return nonstd::make_unexpected(
107 " - Cannot get the name of the node's ROS 2 communication port: Input port '" + input_port_key +
108 "' required by substring '" + match.str() + "' must not be empty.");
109 }
110
111 // We try to get the value from the node input port. If the value is a string pointing at a blackboard entry, this
112 // does not work during construction time. In that case we return the unexpected value to indicate we must try
113 // again.
114 const BT::Expected<std::string> expected = node->getInput<std::string>(input_port_key);
115 if (expected) {
116 // Replace the respective substring with the value returned from getInput()
117 res.replace(match.position(), match.length(), expected.value());
118 } else {
119 // Return expected (contains error) if value couldn't be retrieved from input ports
120 return expected;
121 }
122 } else {
123 return nonstd::make_unexpected(
125 " - Cannot get the name of the node's ROS 2 communication port: Node input port '" + input_port_key +
126 "' required by substring '" + match.str() + "' doesn't exist.");
127 }
128 }
129 return res;
130}
131
132} // namespace auto_apms_behavior_tree::core
std::string getROSNodeName() const
Get the name of the ROS 2 node passed to the constructor.
rclcpp::Logger getChildLogger(const std::string &name)
Get a child logger created using the associated ROS 2 node.
rclcpp::Time getCurrentTime() const
Get the current time using the associated ROS 2 node.
RosNodeContext(rclcpp::Node::SharedPtr ros_node, rclcpp::CallbackGroup::SharedPtr tree_node_waitables_callback_group, rclcpp::executors::SingleThreadedExecutor::SharedPtr tree_node_waitables_executor, const NodeRegistrationOptions &options)
Constructor.
std::string getFullyQualifiedTreeNodeName(const BT::TreeNode *node, bool with_class_name=true) const
Create a string representing the detailed name of a behavior tree node.
std::string getFullyQualifiedRosNodeName() const
Get the fully qualified name of the ROS 2 node passed to the constructor.
rclcpp::Logger getBaseLogger() const
Get the logger of the associated ROS 2 node.
void setLoggingSeverity(const rclcpp::Logger &logger, const std::string &severity)
Set the logging severity of a ROS 2 logger.
Definition logging.cpp:38
Core API for AutoAPMS's behavior tree implementation.
Definition builder.hpp:30
Parameters for loading and registering a behavior tree node class from a shared library using e....
std::string port
Default port name of the corresponding ROS 2 communication interface.