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.
localization_controller.cpp
Go to the documentation of this file.
1
2/*
3 * Copyright (C) 2021-2022 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
19
21{
22
23
26 {
27 config_.sensor_nodes = declare_parameter<std::vector<std::string>>("sensor_nodes", config_.sensor_nodes);
28 config_.sensor_fault_map = sensor_fault_map_from_json(declare_parameter<std::string>("sensor_fault_map", ""));
29
30 // Handle fact that parameter vectors cannot be empty
31 if (config_.sensor_nodes.size() == 1 && config_.sensor_nodes[0].empty()) {
32 config_.sensor_nodes.clear();
33 }
34
35 }
36
37 carma_ros2_utils::CallbackReturn LocalizationControllerNode::handle_on_configure(const rclcpp_lifecycle::State &prev_state) {
38 auto base_return = BaseSubsystemController::handle_on_configure(prev_state);
39
40 if (base_return != carma_ros2_utils::CallbackReturn::SUCCESS) {
41 RCLCPP_ERROR(get_logger(), "Localization Controller could not configure");
42 return base_return;
43 }
44
45 // Reset and reload config
47 get_parameter<std::vector<std::string>>("sensor_nodes", config_.sensor_nodes);
48
49 // Handle fact that parameter vectors cannot be empty
50 if (config_.sensor_nodes.size() == 1 && config_.sensor_nodes[0].empty()) {
51 config_.sensor_nodes.clear();
52 }
53
54 std::string json_string;
55 get_parameter<std::string>("sensor_fault_map", json_string);
56
57 RCLCPP_INFO_STREAM(get_logger(), "Loaded sensor_fault_map json string: " << json_string);
58
60
61 RCLCPP_INFO_STREAM(get_logger(), "Loaded localization config: " << config_);
62
63 for (auto node : config_.sensor_nodes) {
64 sensor_status_[node] = SensorBooleanStatus::OPERATIONAL; // Start tracking the sensor status's
65 }
66
67 return carma_ros2_utils::CallbackReturn::SUCCESS;
68 }
69
70 void LocalizationControllerNode::on_system_alert(carma_msgs::msg::SystemAlert::UniquePtr msg)
71 {
72 carma_msgs::msg::SystemAlert alert = *msg; // Keep local copy so parent method can be called with std::move
73 carma_msgs::msg::SystemAlert output_alert;
74 BaseSubsystemController::on_system_alert(std::move(msg)); // Call parent method
75
76 // Check if our list of coordinated sensors contains the node providing the alert
77 // No need to check required nodes as that has already been handled in the parent call
78 if (sensor_status_.find(alert.source_node) == sensor_status_.end()) {
79 RCLCPP_INFO_STREAM(get_logger(), "Alert not from a sensor node. Alerting node: " << alert.source_node);
80 return;
81 }
82
83 // Update our tracking of sensor statuses if this node failed
84 if (alert.type == carma_msgs::msg::SystemAlert::FATAL) {
86 }
87
88 // Combine all sensor statuses into a single set to index into the alert map
89 std::vector<SensorBooleanStatus> current_sensor_status;
90 for (const auto& node : config_.sensor_nodes) {
91 current_sensor_status.emplace_back(sensor_status_[node]);
92 }
93
94 // If the controller has not been configured to handle this fault configuration then do nothing
95 if (config_.sensor_fault_map.find(current_sensor_status) == config_.sensor_fault_map.end()) {
96 RCLCPP_INFO_STREAM(get_logger(), "Failure does not match with fault configuration. Assuming system remains operational ");
97 return;
98 }
99
100 // Extract the alert required by this type of sensor statuses
101 SensorAlertStatus alert_status = config_.sensor_fault_map[current_sensor_status];
102 output_alert.description = "Localization optional sensor failure from: " + alert.source_node;
103
104 switch(alert_status) {
106 output_alert.type = carma_msgs::msg::SystemAlert::FATAL;
107 output_alert.description = "Localization subsystem failed due to sensor failure from: " + alert.source_node;
108 break;
110 output_alert.type = carma_msgs::msg::SystemAlert::CAUTION;
111 break;
113 output_alert.type = carma_msgs::msg::SystemAlert::WARNING;
114 break;
115 default:
116 return; // OPERATIONAL case no-op as other subsystems do not need notification of operational status
117 }
118
119 // Publish the alert
120 output_alert.source_node = get_node_base_interface()->get_fully_qualified_name();
121 publish_system_alert(output_alert);
122 }
123
124 std::unordered_map<std::vector<SensorBooleanStatus>, SensorAlertStatus, VectorHash> LocalizationControllerNode::sensor_fault_map_from_json(std::string json_string) {
125
126 std::unordered_map<std::vector<SensorBooleanStatus>, SensorAlertStatus, VectorHash> map;
127
128 rapidjson::Document d;
129
130 if(d.Parse(json_string.c_str()).HasParseError())
131 {
132 RCLCPP_WARN(get_logger(), "Failed to parse sensor_fault map. Invalid json structure");
133 return map;
134 }
135
136 if (!d.HasMember("sensor_fault_map")) {
137 RCLCPP_WARN(get_logger(), "No sensor_fault_map found in localization config");
138 return map;
139 }
140
141 rapidjson::Value& map_value = d["sensor_fault_map"];
142
143 if (!map_value.IsArray()) {
144 RCLCPP_WARN(get_logger(), "sensor_fault_map cannot be read as array");
145 return map;
146 }
147
148 if (map_value.Size() == 0) {
149 RCLCPP_WARN(get_logger(), "sensor_fault_map has zero size");
150 return map;
151 }
152
153 for (rapidjson::SizeType i = 0; i < map_value.Size(); i++) {
154 if (!map_value[i].IsArray()) {
155 RCLCPP_WARN(get_logger(), "sensor_fault_map rows are not arrays");
156 continue;
157 }
158
159 if (map_value[i].Size() < 2) {
160 RCLCPP_WARN(get_logger(), "sensor_fault_map rows do not contain more than 1 element");
161 continue;
162 }
163
164 std::vector<SensorBooleanStatus> statuses;
165 statuses.reserve(map_value[i].Size()-1);
166 for (rapidjson::SizeType j = 0; j < map_value[i].Size() - 1; j++) {
167 if (!map_value[i][j].IsInt()) {
168 RCLCPP_WARN_STREAM(get_logger(), "sensor_fault_map row " << i << " element " << j << " is not an int");
169 continue;
170 }
171
172 statuses.emplace_back(static_cast<SensorBooleanStatus>(map_value[i][j].GetInt()));
173 }
174
175 rapidjson::Value& alert = map_value[i][map_value[i].Size() - 1];
176
177 if (!alert.IsInt()) {
178 RCLCPP_WARN_STREAM(get_logger(), "sensor_fault_map alert type is not an int in row " << i);
179 continue;
180 }
181
182 map[statuses] = static_cast<SensorAlertStatus>(alert.GetInt());
183 }
184
185 return map;
186 }
187
188} // namespace subsystem_controllers
189
190#include "rclcpp_components/register_node_macro.hpp"
191
192// Register the component with class_loader
193RCLCPP_COMPONENTS_REGISTER_NODE(subsystem_controllers::LocalizationControllerNode)
A base class for all subsystem_controllers which provides default lifecycle behavior for subsystems.
virtual carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &prev_state)
virtual void on_system_alert(const carma_msgs::msg::SystemAlert::UniquePtr msg)
std::unordered_map< std::vector< SensorBooleanStatus >, SensorAlertStatus, VectorHash > sensor_fault_map_from_json(std::string json_string)
Helper function to convert a json string into an unordered map of sensor status's to required alerts ...
std::unordered_map< std::string, SensorBooleanStatus > sensor_status_
void on_system_alert(const carma_msgs::msg::SystemAlert::UniquePtr msg)
carma_ros2_utils::CallbackReturn handle_on_configure(const rclcpp_lifecycle::State &prev_state)
Stuct containing the algorithm configuration values for the BaseSubsystemController.
std::unordered_map< std::vector< SensorBooleanStatus >, SensorAlertStatus, VectorHash > sensor_fault_map