Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
guidance_controller.cpp
Go to the documentation of this file.
1
2/*
3 * Copyright (C) 2021 LEIDOS.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy of
7 * the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17
18#include <chrono>
20
21using std_msec = std::chrono::milliseconds;
22
24{
25 GuidanceControllerNode::GuidanceControllerNode(const rclcpp::NodeOptions &options)
27 {
28 // Don't automatically trigger state transitions from base class on configure
29 // In this class the managed nodes list first needs to be modified then the transition will be triggered manually
31 config_.required_plugins = declare_parameter<std::vector<std::string>>("required_plugins", config_.required_plugins);
32 config_.auto_activated_plugins = declare_parameter<std::vector<std::string>>("auto_activated_plugins", config_.auto_activated_plugins);
33 }
34
35 cr2::CallbackReturn GuidanceControllerNode::handle_on_configure(const rclcpp_lifecycle::State &prev_state) {
36 auto base_return = BaseSubsystemController::handle_on_configure(prev_state);
37
38 if (base_return != cr2::CallbackReturn::SUCCESS) {
39 RCLCPP_ERROR(get_logger(), "Guidance Controller could not configure");
40 return base_return;
41 }
42
44
45 auto base_managed_nodes = lifecycle_mgr_.get_managed_nodes();
46
47 std::string plugin_namespace = base_config_.subsystem_namespace + "/plugins/";
48
49
50 std::vector<std::string> guidance_plugin_nodes;
51 // Extract the nodes under the plugin namespaces (ie. /guidance/plugins/)
52 std::copy_if(base_managed_nodes.begin(), base_managed_nodes.end(),
53 std::back_inserter(guidance_plugin_nodes),
54 [plugin_namespace](const std::string& s) { return s.rfind(plugin_namespace, 0) == 0; });
55
56 std::vector<std::string> non_plugin_guidance_nodes = get_non_intersecting_set(base_managed_nodes, guidance_plugin_nodes);
57
58 lifecycle_mgr_.set_managed_nodes(non_plugin_guidance_nodes);
59
60 // Load required plugins and default enabled plugins
61 get_parameter<std::vector<std::string>>("required_plugins", config_.required_plugins);
62 get_parameter<std::vector<std::string>>("auto_activated_plugins", config_.auto_activated_plugins);
63
64 RCLCPP_INFO_STREAM(get_logger(), "Config: " << config_);
65
66 // The core need is that plugins need to be managed separately from guidance nodes
67 auto plugin_lifecycle_manager = std::make_shared<ros2_lifecycle_manager::Ros2LifecycleManager>(
68 get_node_base_interface(), get_node_graph_interface(), get_node_logging_interface(), get_node_services_interface());
69
70 plugin_manager_ = std::make_shared<PluginManager>(
73 plugin_lifecycle_manager,
74 [this](){ return get_current_state().id(); },
75 [this](auto node, auto ns){ return get_service_names_and_types_by_node(node, ns); },
77 );
78
79 plugin_discovery_sub_ = create_subscription<carma_planning_msgs::msg::Plugin>(
80 "plugin_discovery", 50,
81 std::bind(&PluginManager::update_plugin_status, plugin_manager_, std::placeholders::_1));
82
83 get_registered_plugins_server_ = create_service<carma_planning_msgs::srv::PluginList>(
84 "plugins/get_registered_plugins",
85 std::bind(&PluginManager::get_registered_plugins, plugin_manager_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
86
87 get_active_plugins_server_ = create_service<carma_planning_msgs::srv::PluginList>(
88 "plugins/get_active_plugins",
89 std::bind(&PluginManager::get_active_plugins, plugin_manager_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
90
91 activate_plugin_server_ = create_service<carma_planning_msgs::srv::PluginActivation>(
92 "plugins/activate_plugin", // TODO check topic name
93 std::bind(&PluginManager::activate_plugin, plugin_manager_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
94
95 get_strategic_plugins_by_capability_server_ = create_service<carma_planning_msgs::srv::GetPluginApi>(
96 "plugins/get_strategic_plugins_by_capability",
97 std::bind(&PluginManager::get_strategic_plugins_by_capability, plugin_manager_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
98
99 get_tactical_plugins_by_capability_server_ = create_service<carma_planning_msgs::srv::GetPluginApi>(
100 "plugins/get_tactical_plugins_by_capability",
101 std::bind(&PluginManager::get_tactical_plugins_by_capability, plugin_manager_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
102
103 get_control_plugins_by_capability_server_ = create_service<carma_planning_msgs::srv::GetPluginApi>(
104 "plugins/get_control_plugins_by_capability",
105 std::bind(&PluginManager::get_control_plugins_by_capability, plugin_manager_, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
106
107
108
109 // With all of our non-plugin managed nodes now being tracked we can execute their configure operations
111
112 // Configure our plugins
113 try {
114 plugin_manager_->configure(); // Only checking required nodes. Other node failure tracked by activity status
115 } catch(const std::runtime_error& e) {
116 RCLCPP_ERROR_STREAM(get_logger(), "Error configuring plugin manager " << e.what());
117 success = false;
118 }
119
120
121
122 if (success)
123 {
124
125 RCLCPP_INFO_STREAM(get_logger(), "Subsystem able to configure");
126 return CallbackReturn::SUCCESS;
127 }
128 else
129 {
130
131 RCLCPP_INFO_STREAM(get_logger(), "Subsystem unable to configure");
132 return CallbackReturn::FAILURE;
133 }
134
135 }
136
137 cr2::CallbackReturn GuidanceControllerNode::handle_on_activate(const rclcpp_lifecycle::State &prev_state)
138 {
139 auto base_return = BaseSubsystemController::handle_on_activate(prev_state); // This will activate all nodes in the namespace TODO what about the plugins?
140
141 if (base_return != cr2::CallbackReturn::SUCCESS) {
142 RCLCPP_ERROR(get_logger(), "Guidance Controller could not activate");
143 return base_return;
144 }
145
146 bool success = true;
147 try {
148 plugin_manager_->activate(); // Only checking required nodes. Other node failure tracked by activity status
149 } catch(const std::runtime_error& e) {
150 RCLCPP_ERROR_STREAM(get_logger(), "Error activating plugin manager " << e.what());
151 success = false;
152 }
153
154 if (success)
155 {
156
157 RCLCPP_INFO_STREAM(get_logger(), "Subsystem able to activate");
158 return CallbackReturn::SUCCESS;
159 }
160 else
161 {
162
163 RCLCPP_INFO_STREAM(get_logger(), "Subsystem unable to activate");
164 return CallbackReturn::FAILURE;
165 }
166
167 }
168
169 cr2::CallbackReturn GuidanceControllerNode::handle_on_deactivate(const rclcpp_lifecycle::State &prev_state)
170 {
171 auto base_return = BaseSubsystemController::handle_on_deactivate(prev_state);
172
173 if (base_return != cr2::CallbackReturn::SUCCESS) {
174 RCLCPP_ERROR(get_logger(), "Guidance Controller could not deactivate");
175 return base_return;
176 }
177
178 bool success = true;
179 try {
180 plugin_manager_->deactivate(); // Only checking required nodes. Other node failure tracked by activity status
181 } catch(const std::runtime_error& e) {
182 RCLCPP_ERROR_STREAM(get_logger(), "Error deactivating plugin manager " << e.what());
183 success = false;
184 }
185
186 if (success)
187 {
188
189 RCLCPP_INFO_STREAM(get_logger(), "Subsystem able to deactivate");
190 return CallbackReturn::SUCCESS;
191 }
192 else
193 {
194
195 RCLCPP_INFO_STREAM(get_logger(), "Subsystem unable to deactivate");
196 return CallbackReturn::FAILURE;
197 }
198 }
199
200 cr2::CallbackReturn GuidanceControllerNode::handle_on_cleanup(const rclcpp_lifecycle::State &prev_state)
201 {
202 auto base_return = BaseSubsystemController::handle_on_cleanup(prev_state);
203
204 if (base_return != cr2::CallbackReturn::SUCCESS) {
205 RCLCPP_ERROR(get_logger(), "Guidance Controller could not cleanup");
206 return base_return;
207 }
208
209 bool success = true;
210 try {
211 plugin_manager_->cleanup(); // Only checking required nodes. Other node failure tracked by activity status
212 } catch(const std::runtime_error& e) {
213 RCLCPP_ERROR_STREAM(get_logger(), "Error cleaning up plugin manager " << e.what());
214 success = false;
215 }
216
217 if (success)
218 {
219
220 RCLCPP_INFO_STREAM(get_logger(), "Subsystem able to cleanup");
221 return CallbackReturn::SUCCESS;
222 }
223 else
224 {
225
226 RCLCPP_INFO_STREAM(get_logger(), "Subsystem unable to cleanup");
227 return CallbackReturn::FAILURE;
228 }
229 }
230
231 cr2::CallbackReturn GuidanceControllerNode::handle_on_shutdown(const rclcpp_lifecycle::State &prev_state)
232 {
233 auto base_return = BaseSubsystemController::handle_on_shutdown(prev_state);
234
235 if (base_return != cr2::CallbackReturn::SUCCESS) {
236 RCLCPP_ERROR(get_logger(), "Guidance Controller could not shutdown");
237 return base_return;
238 }
239
240 bool success = plugin_manager_->shutdown();
241
242 if (success)
243 {
244
245 RCLCPP_INFO_STREAM(get_logger(), "Subsystem able to shutdown cleanly");
246 return CallbackReturn::SUCCESS;
247 }
248 else
249 {
250
251 RCLCPP_INFO_STREAM(get_logger(), "Subsystem unable to shutdown cleanly");
252 return CallbackReturn::FAILURE;
253 }
254 }
255
256
257} // namespace subsystem_controllers
258
259#include "rclcpp_components/register_node_macro.hpp"
260
261// Register the component with class_loader
262RCLCPP_COMPONENTS_REGISTER_NODE(subsystem_controllers::GuidanceControllerNode)
std::chrono::milliseconds std_msec
A base class for all subsystem_controllers which provides default lifecycle behavior for subsystems.
BaseSubSystemControllerConfig base_config_
The configuration struct.
virtual carma_ros2_utils::CallbackReturn handle_on_shutdown(const rclcpp_lifecycle::State &prev_state)
virtual carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &prev_state)
virtual carma_ros2_utils::CallbackReturn handle_on_deactivate(const rclcpp_lifecycle::State &prev_state)
virtual carma_ros2_utils::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &prev_state)
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...
ros2_lifecycle_manager::Ros2LifecycleManager lifecycle_mgr_
Lifecycle Manager which will track the managed nodes and call their lifecycle services on request.
virtual carma_ros2_utils::CallbackReturn handle_on_cleanup(const rclcpp_lifecycle::State &prev_state)
cr2::SubPtr< carma_planning_msgs::msg::Plugin > plugin_discovery_sub_
ROS handles.
cr2::ServicePtr< carma_planning_msgs::srv::GetPluginApi > get_control_plugins_by_capability_server_
cr2::CallbackReturn handle_on_activate(const rclcpp_lifecycle::State &)
cr2::ServicePtr< carma_planning_msgs::srv::GetPluginApi > get_strategic_plugins_by_capability_server_
cr2::CallbackReturn handle_on_deactivate(const rclcpp_lifecycle::State &)
cr2::ServicePtr< carma_planning_msgs::srv::GetPluginApi > get_tactical_plugins_by_capability_server_
cr2::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &)
cr2::ServicePtr< carma_planning_msgs::srv::PluginList > get_active_plugins_server_
cr2::ServicePtr< carma_planning_msgs::srv::PluginActivation > activate_plugin_server_
cr2::CallbackReturn handle_on_cleanup(const rclcpp_lifecycle::State &)
cr2::ServicePtr< carma_planning_msgs::srv::PluginList > get_registered_plugins_server_
GuidanceControllerConfig config_
Config for user provided parameters.
cr2::CallbackReturn handle_on_shutdown(const rclcpp_lifecycle::State &)
std::shared_ptr< PluginManager > plugin_manager_
Plugin manager to handle all the plugin specific discovery and reporting.
void get_control_plugins_by_capability(SrvHeader, carma_planning_msgs::srv::GetPluginApi::Request::SharedPtr req, carma_planning_msgs::srv::GetPluginApi::Response::SharedPtr res)
Get control plugins by capability.
void get_registered_plugins(SrvHeader, carma_planning_msgs::srv::PluginList::Request::SharedPtr req, carma_planning_msgs::srv::PluginList::Response::SharedPtr res)
Returns the list of known plugins.
void update_plugin_status(carma_planning_msgs::msg::Plugin::UniquePtr msg)
Update the status of a certain plugin.
void get_active_plugins(SrvHeader, carma_planning_msgs::srv::PluginList::Request::SharedPtr req, carma_planning_msgs::srv::PluginList::Response::SharedPtr res)
Get the list of currently active plugins.
void get_strategic_plugins_by_capability(SrvHeader, carma_planning_msgs::srv::GetPluginApi::Request::SharedPtr req, carma_planning_msgs::srv::GetPluginApi::Response::SharedPtr res)
Get strategic plugins by capability.
void get_tactical_plugins_by_capability(SrvHeader, carma_planning_msgs::srv::GetPluginApi::Request::SharedPtr req, carma_planning_msgs::srv::GetPluginApi::Response::SharedPtr res)
Get tactical plugins by capability.
void activate_plugin(SrvHeader, carma_planning_msgs::srv::PluginActivation::Request::SharedPtr req, carma_planning_msgs::srv::PluginActivation::Response::SharedPtr res)
Activate the specified plugin.
std::chrono::milliseconds std_msec
std::string subsystem_namespace
Node Namespace. Any node under this namespace shall have its lifecycle managed by this controller.
Stuct containing the algorithm configuration values for the GuidanceController.
std::vector< std::string > auto_activated_plugins
List of guidance plugins which are not required but the user wishes to have automatically activated.
std::vector< std::string > required_plugins
List of guidance plugins (node name) to consider required and who's failure shall result in automatio...