17#include <unordered_set>
20#include <boost/algorithm/string.hpp>
21#include <boost/algorithm/string/join.hpp>
28 : CarmaLifecycleNode(options),
29 lifecycle_mgr_(get_node_base_interface(), get_node_graph_interface(), get_node_logging_interface(), get_node_services_interface())
60 get_logger(),
"Received SystemAlert message of type: " <<
static_cast<int>(msg->type) <<
" with message: " << msg->description);
63 if (msg->type == carma_msgs::msg::SystemAlert::FATAL)
73 get_logger(),
"Failure in required node: " << msg->source_node);
75 carma_msgs::msg::SystemAlert alert;
76 alert.type = carma_msgs::msg::SystemAlert::FATAL;
78 alert.source_node = get_node_base_interface()->get_fully_qualified_name();
79 publish_system_alert(alert);
87 get_logger(),
"Failure in optional node: " << msg->source_node);
94 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem trying to configure");
116 RCLCPP_INFO_STREAM(get_logger(),
"Loaded config: " <<
base_config_);
120 system_alert_topic_, 100,
126 std::vector<std::string> managed_nodes = nodes_in_namespace;
132 managed_nodes.insert(managed_nodes.end(), additional_nodes.begin(), additional_nodes.end());
138 RCLCPP_INFO_STREAM(get_logger(),
"full_subsystem_required is True. Setting all namespace nodes as required");
142 RCLCPP_INFO_STREAM(get_logger(),
"New config: " <<
base_config_);
147 return CallbackReturn::SUCCESS;
156 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem able to configure");
157 return CallbackReturn::SUCCESS;
162 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem unable to configure");
163 return CallbackReturn::FAILURE;
169 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem trying to activate");
172 return CallbackReturn::SUCCESS;
180 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem able to activate");
181 return CallbackReturn::SUCCESS;
186 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem unable to activate");
187 return CallbackReturn::FAILURE;
193 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem trying to deactivate");
196 return CallbackReturn::SUCCESS;
204 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem able to deactivate");
205 return CallbackReturn::SUCCESS;
210 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem unable to deactivate");
211 return CallbackReturn::FAILURE;
217 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem trying to cleanup");
220 return CallbackReturn::SUCCESS;
228 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem able to cleanup");
229 return CallbackReturn::SUCCESS;
234 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem unable to cleanup");
235 return CallbackReturn::FAILURE;
241 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem trying to shutdown due to error");
248 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem able to shutdown");
249 return CallbackReturn::SUCCESS;
254 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem unable to shutdown");
255 return CallbackReturn::FAILURE;
261 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem trying to shutdown");
268 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem able to shutdown");
269 return CallbackReturn::SUCCESS;
274 RCLCPP_INFO_STREAM(get_logger(),
"Subsystem unable to shutdown");
275 return CallbackReturn::FAILURE;
283 static const std::string CHANGE_STATE_SRV =
"/change_state";
284 static const std::string GET_STATE_SRV =
"/get_state";
286 static const std::string CHANGE_STATE_TYPE =
"lifecycle_msgs/srv/ChangeState";
287 static const std::string GET_STATE_TYPE =
"lifecycle_msgs/srv/GetState";
289 static const std::string this_full_name = std::string(get_namespace()) +
"/" + std::string(get_name());
292 auto all_nodes = this->get_node_names();
294 std::vector<std::string> nodes_in_namspace;
295 nodes_in_namspace.reserve(all_nodes.size());
298 for (
const auto &node : all_nodes)
301 if (node == this_full_name)
304 if (node.find(node_namespace) == 0)
316 std::vector<std::string> result;
319 if (result.empty()) {
320 throw std::runtime_error(
"Fully specified node name does not contain '/' seems to suggest internal ROS error.");
323 std::string base_name = result.back();
325 std::string namespace_joined = boost::algorithm::join(result,
"/");
327 auto services_and_types = get_service_names_and_types_by_node(base_name, namespace_joined);
332 const std::string cs_srv = node + CHANGE_STATE_SRV;
333 const std::string gs_srv = node + GET_STATE_SRV;
335 if (services_and_types.find(cs_srv) != services_and_types.end()
336 && services_and_types.find(gs_srv) != services_and_types.end()
337 && std::find(services_and_types.at(cs_srv).begin(), services_and_types.at(cs_srv).end(), CHANGE_STATE_TYPE) != services_and_types.at(cs_srv).end()
338 && std::find(services_and_types.at(gs_srv).begin(), services_and_types.at(gs_srv).end(), GET_STATE_TYPE) != services_and_types.at(gs_srv).end())
341 nodes_in_namspace.emplace_back(node);
345 RCLCPP_WARN_STREAM(get_logger(),
"Failed to find lifecycle services for node: " << node <<
" this node will not be managed. NOTE: If this node is wrapped by a lifecycle component that is managed then this is not an issue.");
353 return nodes_in_namspace;
359 std::vector<std::string> non_intersecting_set;
360 non_intersecting_set.reserve(set_a.size());
362 std::unordered_set<std::string> set_b_lookup;
363 set_b_lookup.reserve(set_b.size());
365 set_b_lookup.insert(set_b.begin(), set_b.end());
367 for (
const auto &
string : set_a)
369 if (set_b_lookup.find(
string) == set_b_lookup.end())
371 non_intersecting_set.emplace_back(
string);
375 return non_intersecting_set;
std::chrono::milliseconds std_msec
BaseSubSystemControllerConfig base_config_
The configuration struct.
virtual carma_ros2_utils::CallbackReturn handle_on_shutdown(const rclcpp_lifecycle::State &prev_state)
bool trigger_managed_nodes_deactivate_from_base_class_
virtual carma_ros2_utils::CallbackReturn handle_on_error(const rclcpp_lifecycle::State &prev_state, const std::string &exception_string)
virtual carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &prev_state)
std::vector< std::string > get_nodes_in_namespace(const std::string &node_namespace) const
Returns the list of fully qualified node names for all ROS2 nodes in the provided namespace.
virtual carma_ros2_utils::CallbackReturn handle_on_deactivate(const rclcpp_lifecycle::State &prev_state)
rclcpp::Subscription< carma_msgs::msg::SystemAlert >::SharedPtr system_alert_sub_
The subscriber for the system alert topic.
bool trigger_managed_nodes_cleanup_from_base_class_
virtual carma_ros2_utils::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &prev_state)
virtual void on_system_alert(const carma_msgs::msg::SystemAlert::UniquePtr msg)
std::vector< std::string > get_non_intersecting_set(const std::vector< std::string > &set_a, const std::vector< std::string > &set_b) const
Returns all elements of the provided set_a which are NOT contained in the provided set_b.
bool trigger_managed_nodes_configure_from_base_class_
Collection of flags which, if true, will cause the base class to make lifecycle service calls to mana...
void set_config(BaseSubSystemControllerConfig config)
bool trigger_managed_nodes_activate_from_base_class_
ros2_lifecycle_manager::Ros2LifecycleManager lifecycle_mgr_
Lifecycle Manager which will track the managed nodes and call their lifecycle services on request.
BaseSubsystemController()=delete
virtual carma_ros2_utils::CallbackReturn handle_on_cleanup(const rclcpp_lifecycle::State &prev_state)
Stuct containing the algorithm configuration values for the BaseSubsystemController.
int service_timeout_ms
Timeout in ms for service availability.
std::vector< std::string > required_subsystem_nodes
List of nodes to consider required and who's failure shall result in system shutdown.
bool full_subsystem_required
If this flag is true then all nodes under subsystem_namespace are treated as required in addition to ...
std::string subsystem_namespace
Node Namespace. Any node under this namespace shall have its lifecycle managed by this controller.
int call_timeout_ms
Timeout in ms for service calls.
std::vector< std::string > unmanaged_required_nodes
List of nodes which will not be directly managed by this subsystem controller.