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.
lightbar_manager_worker.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 LEIDOS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
18#include <algorithm>
19
20namespace lightbar_manager
21{
23
25 {
26 lbsm_.next(event);
27 }
28
30 {
31 return lbsm_.getCurrentState();
32 }
33
34 std::vector<carma_msgs::msg::LightBarIndicator> LightBarManagerWorker::getMsg(std::vector<LightBarIndicator> indicators)
35 {
36 std::vector<carma_msgs::msg::LightBarIndicator> return_msg;
37 for (auto indicator : indicators)
38 {
40 msg.indicator = indicator;
41 return_msg.push_back(msg);
42 }
43 return return_msg;
44 }
45
46 std::vector<carma_msgs::msg::LightBarCDAType> LightBarManagerWorker::getMsg(std::vector<LightBarCDAType> cda_types)
47 {
48 std::vector<carma_msgs::msg::LightBarCDAType> return_msg;
49 for (auto cda_type : cda_types)
50 {
52 msg.type = cda_type;
53 return_msg.push_back(msg);
54 }
55 return return_msg;
56 }
57 carma_msgs::msg::LightBarIndicatorControllers LightBarManagerWorker::getMsg(std::map<LightBarIndicator, std::string> ind_ctrl_map)
58 {
59 carma_msgs::msg::LightBarIndicatorControllers curr;
60 curr.green_solid_owner = ind_ctrl_map[GREEN_SOLID];
61 curr.green_flash_owner = ind_ctrl_map[GREEN_FLASH];
62 curr.yellow_sides_owner= ind_ctrl_map[YELLOW_SIDES];
63 curr.yellow_dim_owner = ind_ctrl_map[YELLOW_DIM];
64 curr.yellow_flash_owner = ind_ctrl_map[YELLOW_FLASH];
65 curr.yellow_arrow_left_owner = ind_ctrl_map[YELLOW_ARROW_LEFT];
66 curr.yellow_arrow_right_owner = ind_ctrl_map[YELLOW_ARROW_RIGHT];
67 curr.yellow_arrow_out_owner = ind_ctrl_map[YELLOW_ARROW_OUT];
68
69 return curr;
70 }
71
72 void LightBarManagerWorker::handleStateChange(const carma_planning_msgs::msg::GuidanceState& msg)
73 {
75 return;
76 }
77
78 std::vector<lightbar_manager::LightBarIndicator> LightBarManagerWorker::handleTurnSignal(const automotive_platform_msgs::msg::TurnSignalCommand& msg)
79 {
80 std::vector<lightbar_manager::LightBarIndicator> turn_signal;
81 if (msg.turn_signal == current_turn_signal_)
82 {
83 return {};
84 }
85 if (msg.turn_signal == automotive_platform_msgs::msg::TurnSignalCommand::LEFT) //NONE -> LEFT
86 {
88 }
89 else if (msg.turn_signal == automotive_platform_msgs::msg::TurnSignalCommand::RIGHT) //NONE -> RIGHT
90 {
92 }
93 else if (msg.turn_signal == automotive_platform_msgs::msg::TurnSignalCommand::NONE)
94 {
95 // check previous signal
96 if (current_turn_signal_ == automotive_platform_msgs::msg::TurnSignalCommand::RIGHT) // RIGHT -> NONE
98 else if (current_turn_signal_ == automotive_platform_msgs::msg::TurnSignalCommand::LEFT) // LEFT -> NONE
100 }
101
102 current_turn_signal_ = msg.turn_signal;
103
104 return turn_signal;
105 }
106 std::map<LightBarIndicator, std::string> LightBarManagerWorker::getIndicatorControllers()
107 {
108 return ind_ctrl_map_;
109 }
110
111
112 std::map<LightBarCDAType, LightBarIndicator> LightBarManagerWorker::setIndicatorCDAMap(const std::vector<std::string>& lightbar_cda_table, const std::vector<std::string>& lightbar_ind_table)
113 {
114 // In case if the parameter is not loaded corretly and there is an error, return this
115 std::map<std::string, std::string> raw_map;
116 for (size_t i = 0; i < lightbar_cda_table.size(); i ++)
117 {
118 raw_map[lightbar_cda_table[i]] = lightbar_ind_table[i];
119 }
120
121 std::map<LightBarCDAType, LightBarIndicator> default_map;
122
123 default_map[TYPE_A] = YELLOW_DIM;
124 default_map[TYPE_B] = YELLOW_DIM;
125 default_map[TYPE_C] = YELLOW_FLASH;
126 default_map[TYPE_D] = YELLOW_SIDES;
127
128 if (raw_map.size() < 4)
129 {
130 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),"In function: " << __FUNCTION__ << ": LightBarManager's CDAType to Indicator table is not configured correctly. Using default mapping...");
131 cda_ind_map_ = default_map;
132 return cda_ind_map_;
133 }
134
135 // Convert from string:string mapping to correct enums
136 for (std::pair<std::string, std::string> element : raw_map)
137 {
138 LightBarCDAType cda_type;
139 LightBarIndicator indicator;
140 try
141 {
142 cda_type = cda_type_dict_.at(element.first);
143 }
144 catch(const std::exception& e)
145 {
146 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),"In function: " << __FUNCTION__ <<
147 ": LightBarManager Received unknown CDA Msg Type. Using default mapping for cda-indicators...");
148 cda_ind_map_ = default_map;
149 return cda_ind_map_;
150 }
151 try
152 {
153 indicator = ind_dict.at(element.second);
154 }
155 catch(const std::exception& e)
156 {
157 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),"In function: " << __FUNCTION__ <<
158 ": LightBarManager Received unknown indicator type. Using default mapping for cda-indicators...");
159 cda_ind_map_ = default_map;
160 return cda_ind_map_;
161 }
162 cda_ind_map_.emplace(cda_type, indicator);
163 }
164 return cda_ind_map_;
165 }
166
167 bool LightBarManagerWorker::hasHigherPriority (std::string requester, std::string controller)
168 {
169 auto start = control_priorities.begin();
170 auto end = control_priorities.end();
171
172 auto requesterPriority = std::find(start, end, requester);
173 auto controllerPriority = std::find(start, end, controller);
174
175 // Components not in the priority list are assumed to have the lowest priority
176 if (requesterPriority == end)
177 {
178 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),requester << " is referenced in lightbar_manager, but is not in the priority list");
179 return false;
180 }
181 else if (controllerPriority == end)
182 {
183 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),controller << " is referenced in lightbar_manager and is controlling an indicator, but is not in the priority list");
184 return true;
185 }
186 return (requesterPriority - end) <= (controllerPriority - end);
187 }
188
189 std::vector<LightBarIndicator> LightBarManagerWorker::requestControl(std::vector<LightBarIndicator> ind_list, std::string requester_name)
190 {
191 std::vector<LightBarIndicator> denied_list;
192 std::string indicator_owner;
193 // Attempt to acquire control of every indicators
194 for (LightBarIndicator indicator: ind_list)
195 {
196 // Attempt control
197 try
198 {
199 indicator_owner = ind_ctrl_map_.at(indicator);
200 }
201 catch(const std::exception& e)
202 {
203 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),"In function: " << __FUNCTION__ << ", the component, " << requester_name
204 << ", requested a control of invalid indicator. Skipping with WARNING:" << e.what() << "\n");
205 continue;
206 }
207
208 if (indicator_owner == "")
209 {
210 // Add new controller If no other component has claimed this indicator
211 handleControlChange(indicator, requester_name, CONTROL_GAINED);
212 }
213 else if (indicator_owner != requester_name)
214 {
215 // If this indicator is already controlled
216 // If the requesting component has higher priority it may take control of this indicator
217 if (hasHigherPriority(requester_name, indicator_owner))
218 {
219 // Handle previous controller
220 handleControlChange(indicator, indicator_owner, CONTROL_LOST);
221 // Add new controller
222 handleControlChange(indicator, requester_name, CONTROL_GAINED);
223 }
224 else
225 {
226 denied_list.push_back(indicator); // Notify caller of failure to take control of component
227 }
228 }
229 }
230 return denied_list;
231 }
232
233 void LightBarManagerWorker::releaseControl(std::vector<LightBarIndicator> ind_list, std::string owner_name)
234 {
235 std::string current_owner;
236
237 // Attempt to release control of all indicators
238 for (LightBarIndicator indicator: ind_list)
239 {
240 // Attempt release control
241 try
242 {
243 current_owner = ind_ctrl_map_.at(indicator);
244 }
245 catch(const std::exception& e)
246 {
247 RCLCPP_WARN_STREAM(rclcpp::get_logger("lightbar_manager"),"In function: " << __FUNCTION__ << ", the component, " << owner_name
248 << ", requested a release of an invalid indicator. Skipping with WARNING:" << e.what() << "\n");
249 continue;
250 }
251
252 // Lose control only if the requester is currently controlling it
253 if (current_owner == owner_name)
254 {
255 handleControlChange(indicator,owner_name, CONTROL_LOST);
256 }
257 }
258
259 return;
260 }
261
263 {
264 // Pick new owner name depending on losing or gaining control
265 std::string new_owner;
266 if (event == CONTROL_GAINED)
267 new_owner = controller;
268 else
269 new_owner = "";
270
271 // Handle mutually in-exclusive indicators
272 // These are indicators that are controlled indirectly due to change in one indicator
273 // Priority of every one of those indicators, must be compared to that of requester to change it.
274 // e.g. if A>B and YELLOW_RIGHT= "" & YELLOW_LEFT = A (means YELLOW_FLASH = A & YELLOW_OUT = A)
275 // Then if YELLOW_RIGHT = "" -> YELLOW_RIGHT = "B", B should not be able to control YELLOW_FLASH nor YELLOW_OUT
276 switch (indicator)
277 {
282 ind_ctrl_map_[YELLOW_FLASH] = ind_ctrl_map_[YELLOW_ARROW_OUT]; //they always have same owner
283 ind_ctrl_map_[indicator] = new_owner;
284 break;
285 case YELLOW_ARROW_OUT:
286 case YELLOW_FLASH:
293 ind_ctrl_map_[YELLOW_FLASH] = ind_ctrl_map_[YELLOW_ARROW_OUT]; //they always have same owner
294 break;
295 case GREEN_FLASH:
296 case GREEN_SOLID:
299 ind_ctrl_map_[GREEN_SOLID] = ind_ctrl_map_[GREEN_FLASH]; //they always have same owner
300 break;
301 default:
302 ind_ctrl_map_[indicator] = new_owner;
303 break;
304 }
305 return;
306 }
307
308 std::vector<IndicatorStatus> LightBarManagerWorker::setIndicator(LightBarIndicator ind, IndicatorStatus ind_status, std::string requester_name)
309 {
310 std::string current_controller = ind_ctrl_map_[ind];
311
312 // Use a local copy in case manager fails to set the light
313 std::vector<IndicatorStatus> light_status_copy = light_status;
314
315 // Handle mutually non-exclusive cases
316 // If desired indicator is already at the status do not change any indicators
317 if (ind_status != light_status_copy[ind])
318 {
319 switch(ind)
320 {
323 light_status_copy[YELLOW_ARROW_OUT] = OFF;
324 light_status_copy[YELLOW_FLASH] = OFF;
325 break;
326 case YELLOW_ARROW_OUT:
327 case YELLOW_FLASH:
328 light_status_copy[YELLOW_ARROW_OUT] = OFF;
329 light_status_copy[YELLOW_FLASH] = OFF;
330 light_status_copy[YELLOW_ARROW_LEFT] = OFF;
331 light_status_copy[YELLOW_ARROW_RIGHT] = OFF;
332 break;
333 case GREEN_FLASH:
334 case GREEN_SOLID:
335 light_status_copy[GREEN_FLASH] = OFF;
336 light_status_copy[GREEN_SOLID] = OFF;
337 break;
338 default:
339 break;
340 }
341 }
342
343 // Set the desired indicator now that there is no conflict.
344 light_status_copy[ind] = ind_status;
345 return light_status_copy;
346
347 }
348
349 carma_driver_msgs::msg::LightBarStatus LightBarManagerWorker::getLightBarStatusMsg(std::vector<IndicatorStatus> indicators)
350 {
351 // it is assumed that mutually exclusive cases are handled properly.
352 carma_driver_msgs::msg::LightBarStatus msg;
358
361 // for YELLOW_ARROW_OUT set left and right
362 if (indicators[YELLOW_ARROW_OUT] == ON)
363 {
366 }
367 return msg;
368 }
369
371 {
372 for (int i = 0; i <= INDICATOR_COUNT; i++ )
373 {
374 LightBarIndicator indicator = static_cast<LightBarIndicator>(i);
375 // initialize the owner as empty string
376 ind_ctrl_map_[indicator] = "";
377 }
378 }
379
380 void LightBarManagerWorker::setIndicatorControllers(std::map<LightBarIndicator, std::string> ind_ctrl_map)
381 {
382 ind_ctrl_map_ = ind_ctrl_map;
383 }
384
386 {
387 return cda_ind_map_[cda_type];
388 }
389
391 {
392 for (std::pair<LightBarCDAType,LightBarIndicator> element : cda_ind_map_)
393 {
394 if (element.second == indicator)
395 return element.first;
396 }
397 // if the indicator does not have any mapped CDA Msg Type, throw and handle outside
398 throw INDICATOR_NOT_MAPPED(std::string("Specified indicator does not have a mapped CDA Msg Type. Skipping..."));
399 }
400
401}
LightBarState getCurrentState()
Get current state machine status.
void next(const LightBarEvent &event)
Transition to the next state of the LightBarStateMachine.
void handleStateChange(const carma_planning_msgs::msg::GuidanceState &msg)
This function triggers the transitioning to the next state in LightBarStateMachine based on the guida...
void handleControlChange(LightBarIndicator indicator, std::string controller, IndicatorControlEvent event)
Helper function that handles control lost/gained event of a component. This function registers/remove...
std::map< LightBarCDAType, LightBarIndicator > cda_ind_map_
LightBarCDAType getCDATypeFromIndicator(LightBarIndicator indicator)
Helper functions that translates a CDA msg type to its corresponding indicator The mapping between ...
carma_driver_msgs::msg::LightBarStatus getLightBarStatusMsg(std::vector< IndicatorStatus > indicators)
Helper function that translates IndicatorStatus vector into LightBarStatus.msg, a lightbar driver com...
std::vector< IndicatorStatus > setIndicator(LightBarIndicator ind, IndicatorStatus ind_status, std::string requester_name)
Try to turn the given indicator ON or OFF (locally) upon the given component's request.
std::map< std::string, LightBarIndicator > ind_dict
std::map< LightBarCDAType, LightBarIndicator > setIndicatorCDAMap(const std::vector< std::string > &lightbar_cda_table, const std::vector< std::string > &lightbar_ind_table)
Helper function that initializes CDAType to Indicator Mapping (updates internal copy)
void setIndicatorControllers()
Helper function that initializes supporting Indicators and their owner mapping as empty strings.
std::vector< lightbar_manager::LightBarIndicator > handleTurnSignal(const automotive_platform_msgs::msg::TurnSignalCommand &msg)
This function checks if the turn signal should be changed on the lightbar.
std::vector< carma_msgs::msg::LightBarIndicator > getMsg(std::vector< LightBarIndicator > indicators)
Helper function that translates LightBarIndicator vector into LightBarIndicator.msg vector.
LightBarIndicator getIndicatorFromCDAType(LightBarCDAType cda_type)
Helper functions that translates an indicator to its corresponding CDA msg type The mapping between...
void next(const LightBarEvent &event)
Transition to the next state of the LightBarStateMachine Not used at the moment as state machine full...
void releaseControl(std::vector< LightBarIndicator > ind_list, std::string owner_name)
Releases the specified owner plugin or component's control of the given indicator list....
std::map< LightBarIndicator, std::string > ind_ctrl_map_
LightBarState getCurrentState()
Get current state of the LightBarStateMachine.
LightBarManagerWorker()
Default constructor for LightBarManager.
std::map< LightBarIndicator, std::string > getIndicatorControllers()
Helper function that gets all current owners of the indicator.
void handleStateChange(const carma_planning_msgs::msg::GuidanceState &msg)
This function relays the state change msg to the state maching. It triggers the transitioning to the ...
std::map< std::string, LightBarCDAType > cda_type_dict_
std::vector< LightBarIndicator > requestControl(std::vector< LightBarIndicator > ind_list, std::string requester_name)
Requests the control of the given list of indicators to the requester. This function handles successf...
bool hasHigherPriority(std::string requester, std::string controller)
Helper function that checks if the first input component has higher priority than the second.
#define INDICATOR_COUNT