Apollo 11.0
自动驾驶开放平台
action_command_processor.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2023 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
22
23#include <cxxabi.h>
24
25#include "modules/common_msgs/planning_msgs/planning.pb.h"
26#include "modules/external_command/command_processor/command_processor_base/proto/command_processor_config.pb.h"
27
32
33namespace apollo {
34namespace external_command {
35
36bool ActionCommandProcessor::Init(const std::shared_ptr<cyber::Node>& node) {
37 if (!CommandProcessorBase::Init(node)) {
38 return false;
39 }
40 message_reader_ = MessageReader::Instance();
41 const auto& config = GetProcessorConfig();
42 // Get special config for ActionCommandProcessor.
43 int status = 0;
44 std::string class_name =
45 abi::__cxa_demangle(typeid(*this).name(), nullptr, nullptr, &status);
46 std::string special_config_path =
49 class_name, "conf/special_config.pb.txt");
50 if (!cyber::common::LoadConfig<ActionCommandConfig>(special_config_path,
51 &special_config_)) {
52 AERROR << "Cannot get special config of ActionCommandProcessor";
53 return false;
54 }
55 // Create service for input command.
56 command_service_ = node->CreateService<ActionCommand, CommandStatus>(
57 config.input_command_name(),
58 [this](const std::shared_ptr<ActionCommand>& command,
59 std::shared_ptr<CommandStatus>& status) {
60 this->OnCommand(command, status);
61 });
62 // Create writers for output command.
63 CHECK_GT(config.output_command_name().size(), 1);
64 auto message_writer = MessageWriter::Instance();
65 planning_action_writer_ =
66 message_writer->RegisterMessage<apollo::planning::PadMessage>(
67 config.output_command_name().Get(0));
68 control_action_writer_ =
69 message_writer->RegisterMessage<apollo::control::PadMessage>(
70 config.output_command_name().Get(1));
71 // Create reader for input command status.
72 CHECK_GT(config.input_command_status_name().size(), 2);
73
74 chassis_status_name_ = config.input_command_status_name().Get(0);
75 planning_status_name_ = config.input_command_status_name().Get(1);
76 planning_command_status_name_ = config.input_command_status_name().Get(2);
78 chassis_status_name_);
80 planning_status_name_);
81 message_reader_->RegisterMessage<CommandStatus>(
82 planning_command_status_name_);
83 return true;
84}
85
87 CommandStatus* status) const {
88 CHECK_NOTNULL(status);
89 if (nullptr == last_command_) {
90 return false;
91 }
92 if (last_command_->command_id() != command_id) {
93 return false;
94 }
95 std::string module_name = "UNKNOWN";
96 if (last_command_->has_header()) {
97 module_name = last_command_->header().module_name();
98 }
99 common::util::FillHeader(module_name, status);
100 status->set_command_id(command_id);
101 switch (last_command_->command()) {
102 // Get status of "FOLLOW", "CHANGE_LEFT", "CHANGE_RIGHT".
106 // todo: Check the real planning status and set command status.
108 status->set_message("Cannot execute the command!");
109 } break;
110 // Get status of "PULL_OVER".
112 // When planning is in PullOverScenario and the scenario is finished,
113 // command status is finished.
114 CheckScenarioFinished(special_config_.pull_over_scenario_name(), status);
115 } break;
116 // Get status of "STOP".
118 CheckScenarioFinished(special_config_.stop_scenario_name(), status);
119 } break;
120 // Get status of "START".
122 auto* latest_chassis_status =
123 message_reader_->GetMessage<apollo::canbus::Chassis>(
124 chassis_status_name_);
125 if (nullptr == latest_chassis_status) {
127 status->set_message("Cannot get chassis status!");
128 return true;
129 }
130 // If the vehicle is moving, the command is considered as finished.
131 if (latest_chassis_status->speed_mps() >
132 special_config_.minimun_non_zero_speed()) {
133 status->set_status(
135 }
137 } break;
138 // Get status of "CLEAR_PLANNING".
141 } break;
142 // Get status of "SWITCH_TO_MANUAL".
144 CheckModeSwitchFinished(canbus::Chassis::COMPLETE_MANUAL, status);
145 } break;
146 // Get status of "SWITCH_TO_AUTO".
148 CheckModeSwitchFinished(canbus::Chassis::COMPLETE_AUTO_DRIVE, status);
149 } break;
150 // Get status of "VIN_REQ".
151 default: {
152 // todo: Get the real result of control.
154 } break;
155 }
156 return true;
157}
158
159void ActionCommandProcessor::OnCommand(
160 const std::shared_ptr<ActionCommand>& command,
161 std::shared_ptr<CommandStatus>& status) {
162 std::string module_name = "UNKNOWN";
163 if (command->has_header()) {
164 module_name = command->header().module_name();
165 double timestamp = apollo::cyber::Clock::NowInSeconds();
166 AINFO << std::setprecision(12) << "timestamp: " << timestamp << " "
167 << "request for " << command->header().timestamp_sec();
168 if (timestamp - command->header().timestamp_sec() > 2.0) {
169 AINFO << "request for " << command->header().module_name()
170 << " has been timeouted";
171 return;
172 }
173 }
174 status->set_status(CommandStatusType::RUNNING);
175 status->set_command_id(command->command_id());
176 switch (command->command()) {
177 // Send "FOLLOW" message to planning.
179 planning::PadMessage planning_message;
180 common::util::FillHeader(module_name, &planning_message);
181 planning_message.set_action(planning::PadMessage::FOLLOW);
182 planning_action_writer_->Write(planning_message);
183 } break;
184 // Send "CHANGE_LEFT" message to planning.
186 planning::PadMessage planning_message;
187 common::util::FillHeader(module_name, &planning_message);
188 planning_message.set_action(planning::PadMessage::CHANGE_LEFT);
189 planning_action_writer_->Write(planning_message);
190 } break;
191 // Send "CHANGE_RIGHT" message to planning.
193 planning::PadMessage planning_message;
194 common::util::FillHeader(module_name, &planning_message);
195 planning_message.set_action(planning::PadMessage::CHANGE_RIGHT);
196 planning_action_writer_->Write(planning_message);
197 } break;
198 // Send "PULL_OVER" message to planning.
200 planning::PadMessage planning_message;
201 common::util::FillHeader(module_name, &planning_message);
202 planning_message.set_action(planning::PadMessage::PULL_OVER);
203 planning_action_writer_->Write(planning_message);
204 } break;
205 // Send "STOP" message to planning.
207 planning::PadMessage planning_message;
208 common::util::FillHeader(module_name, &planning_message);
209 planning_message.set_action(planning::PadMessage::STOP);
210 planning_action_writer_->Write(planning_message);
211 } break;
212 // Send "CLEAR_PLANNING" message to planning.
214 planning::PadMessage planning_message;
215 common::util::FillHeader(module_name, &planning_message);
216 planning_message.set_action(planning::PadMessage::CLEAR_PLANNING);
217 planning_action_writer_->Write(planning_message);
218 status->set_status(CommandStatusType::FINISHED);
219 } break;
220 // Send "START" message to planning.
222 planning::PadMessage planning_message;
223 common::util::FillHeader(module_name, &planning_message);
224 planning_message.set_action(planning::PadMessage::RESUME_CRUISE);
225 planning_action_writer_->Write(planning_message);
226 } break;
227 // Send "SWITCH_TO_MANUAL" message to control.
229 // Use async function to wait for the chassis to be in manual mode.
230 cyber::Async(&ActionCommandProcessor::SwitchToManualMode, this,
231 module_name);
232 } break;
233 // Send "SWITCH_TO_AUTO" message to control.
235 // Chassis need be switched to manual mode before switch to auto mode.
236 // Use async function to wait for the chassis to be in auto mode.
237 cyber::Async(&ActionCommandProcessor::SwitchToAutoMode, this,
238 module_name);
239 } break;
240 // Send "ENTER_MISSION" message to planning.
242 planning::PadMessage planning_message;
243 common::util::FillHeader(module_name, &planning_message);
244 planning_message.set_action(planning::PadMessage::ENTER_MISSION);
245 planning_action_writer_->Write(planning_message);
246 } break;
247 // Send "EXIT_MISSION" message to planning.
249 planning::PadMessage planning_message;
250 common::util::FillHeader(module_name, &planning_message);
251 planning_message.set_action(planning::PadMessage::EXIT_MISSION);
252 planning_action_writer_->Write(planning_message);
253 } break;
254 // Send "VIN_REQ" message to control.
255 default: {
256 control::PadMessage control_message;
257 common::util::FillHeader(module_name, &control_message);
258 control_message.set_action(control::DrivingAction::VIN_REQ);
259 control_action_writer_->Write(control_message);
260 } break;
261 }
262}
263
264void ActionCommandProcessor::SwitchToAutoMode(const std::string& module_name) {
265 last_mode_switch_status_.set_status(
267 // Get the chassis' driving mode first.
268 auto* latest_chassis_status =
269 message_reader_->GetMessage<apollo::canbus::Chassis>(
270 chassis_status_name_);
271 if (nullptr == latest_chassis_status) {
272 UpdateModeSwitchStatus("Failed to get chassis data!", true);
273 return;
274 }
275 // Do nothing if chassis is already in auto mode.
277 latest_chassis_status->driving_mode()) {
278 UpdateModeSwitchStatus("Chassis is already in auto mode.", false);
279 return;
280 }
281 // Make sure chassis is in manual mode.
282 if (!SwitchMode(canbus::Chassis::COMPLETE_MANUAL,
283 control::DrivingAction::RESET, module_name)) {
284 UpdateModeSwitchStatus("Chassis cannot be switched to manual mode first!",
285 true);
286 return;
287 }
288 // Switch to auto mode.
290 control::DrivingAction::START, module_name);
291}
292
293void ActionCommandProcessor::SwitchToManualMode(
294 const std::string& module_name) {
295 last_mode_switch_status_.set_status(
298 module_name);
299}
300
301bool ActionCommandProcessor::SwitchMode(
302 const canbus::Chassis::DrivingMode& driving_mode,
303 const control::DrivingAction& driving_action,
304 const std::string& module_name) {
305 const std::string& mode_name =
306 canbus::Chassis::DrivingMode_Name(driving_mode);
307 // Get the chassis' driving mode first.
308 auto* latest_chassis_status =
309 message_reader_->GetMessage<apollo::canbus::Chassis>(
310 chassis_status_name_);
311 if (nullptr == latest_chassis_status) {
312 UpdateModeSwitchStatus("Failed to get chassis data!", true);
313 return false;
314 }
315 // Do nothing if chassis is already in manual mode.
316 if (driving_mode == latest_chassis_status->driving_mode()) {
317 UpdateModeSwitchStatus("Chassis is already in " + mode_name, false);
318 return true;
319 }
320 control::PadMessage control_message;
321 common::util::FillHeader(module_name, &control_message);
322 static constexpr int kMaxTries = 3;
323 static constexpr auto kTryInterval = std::chrono::milliseconds(500);
324 control_message.set_action(driving_action);
325 bool is_switch_success = false;
326 for (int i = 0; i < kMaxTries; ++i) {
327 // Send driving action periodically until entering target driving mode.
328 control_action_writer_->Write(control_message);
329 std::this_thread::sleep_for(kTryInterval);
330
331 latest_chassis_status =
332 message_reader_->GetMessage<apollo::canbus::Chassis>(
333 chassis_status_name_);
334 if (nullptr == latest_chassis_status) {
335 UpdateModeSwitchStatus("Failed to get chassis data!", true);
336 return false;
337 }
338 if (latest_chassis_status->driving_mode() == driving_mode) {
339 is_switch_success = true;
340 break;
341 }
342 }
343 if (!is_switch_success) {
344 UpdateModeSwitchStatus("Chassis cannot be switched to " + mode_name, true);
345 return false;
346 }
347 return true;
348}
349
350void ActionCommandProcessor::CheckScenarioFinished(
351 const std::string& scenario_name, CommandStatus* status) const {
352 // When planning is in the given scenario and the scenario is finished,
353 // command status is finished.
355 status->set_message("Cannot get planning scenario status!");
356 auto* latest_planning_status =
358 planning_status_name_);
359 if (nullptr == latest_planning_status) {
361 status->set_message("Cannot get planning status!");
362 return;
363 }
364 if (!latest_planning_status->has_debug() ||
365 latest_planning_status->debug().has_planning_data()) {
366 return;
367 }
368 const auto& debug = latest_planning_status->debug().planning_data();
369 if (!debug.has_scenario()) {
370 return;
371 }
372 const auto& scenario = debug.scenario();
373 if (!scenario.has_scenario_plugin_type()) {
374 return;
375 }
376 auto* latest_planning_command_status =
377 message_reader_->GetMessage<CommandStatus>(planning_command_status_name_);
378 if (nullptr == latest_planning_command_status) {
380 status->set_message("Cannot get planning command status!");
381 return;
382 }
383 status->set_message("");
384 const auto& scenario_type = scenario.scenario_plugin_type();
385 if (scenario_type == scenario_name &&
386 latest_planning_command_status->status() ==
389 return;
390 }
392}
393
394void ActionCommandProcessor::CheckModeSwitchFinished(
395 const apollo::canbus::Chassis::DrivingMode& drive_mode,
396 CommandStatus* status) const {
397 auto* latest_chassis_status =
398 message_reader_->GetMessage<apollo::canbus::Chassis>(
399 chassis_status_name_);
400 if (nullptr == latest_chassis_status) {
402 status->set_message("Cannot get chassis status!");
403 return;
404 }
405 if (latest_chassis_status->has_driving_mode() &&
406 latest_chassis_status->driving_mode() == drive_mode) {
408 return;
409 }
410 status->CopyFrom(last_mode_switch_status_);
411}
412
413void ActionCommandProcessor::UpdateModeSwitchStatus(const std::string& message,
414 bool is_error) {
415 if (is_error) {
416 last_mode_switch_status_.set_status(
418 } else {
419 last_mode_switch_status_.set_status(
421 }
422 last_mode_switch_status_.set_message(message);
423 AERROR << message;
424}
425
426} // namespace external_command
427} // namespace apollo
static double NowInSeconds()
gets the current time in second.
Definition clock.cc:56
std::string GetPluginConfPath(const std::string &class_name, const std::string &conf_name)
get plugin configuration file location
static PluginManager * Instance()
get singleton instance of PluginManager
bool Init(const std::shared_ptr< cyber::Node > &node) override
bool GetCommandStatus(int64_t command_id, CommandStatus *status) const override
Get the command status.
virtual bool Init(const std::shared_ptr< cyber::Node > &node)
const CommandProcessorConfig & GetProcessorConfig() const
void RegisterMessage(const std::string &channel_name)
Register the message reader with the given channel name.
const T * GetMessage(const std::string &channel_name) const
Get the message with the channel name.
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
Some string util functions.
class register implement
Definition arena_queue.h:37
optional string module_name
Definition header.proto:12
optional apollo::common::Header header
optional apollo::planning_internal::Debug debug