文章目录
- ExternalCommandProcessComponent(服务端)
- 输入
- 输出
- external_command_demo(客户端)
- 插件ActionCommandProcessor
ExternalCommandProcessComponent(服务端)
输入
用户业务模块发送的命令为apollo::external_command::ExternalCommandProcessComponent的输入,用户输入命令通过 apollo::cyber::Client客户端 调用。
在每个命令对应的CommandProcessor中创建处理命令的apollo::cyber::Service,service的Response一般都是当前命令处理的状态。
通过cat /apollo/modules/external_command/process_component/conf/config.pb.txt
可以看到conf配置文件中包含7个服务端处理器。
output_command_status_name: "/apollo/external_command/command_status"
processor: "apollo::external_command::LaneFollowCommandProcessor"
processor: "apollo::external_command::ValetParkingCommandProcessor"
processor: "apollo::external_command::ActionCommandProcessor"
processor: "apollo::external_command::ChassisCommandProcessor"
processor: "apollo::external_command::FreeSpaceCommandProcessor"
processor: "apollo::external_command::PathFollowCommandProcessor"
processor: "apollo::external_command::SpeedCommandProcessor"
service 名 | Request类型 | Response类型 | 描述 |
---|---|---|---|
/apollo/external_command/action | apollo::external_command::ActionCommand | apollo::external_command::CommandStatus | 流程干预命令,如暂停,启动,切换手动模式等 |
/apollo/external_command/chassis | apollo::external_command::ChassisCommand | apollo::external_command::CommandStatus | 自定义底盘命令(园区) |
/apollo/external_command/free_space | apollo::external_command::FreeSpaceCommand | apollo::external_command::CommandStatus | 指定位姿停车命令(园区) |
/apollo/external_command/lane_follow | apollo::external_command::LaneFollowCommand | apollo::external_command::CommandStatus | 沿道路点对点行驶命令 |
/apollo/external_command/path_follow | apollo::external_command::PathFollowCommand | apollo::external_command::CommandStatus | 指定线路行驶命令(园区) |
/apollo/external_command/speed | apollo::external_command::SpeedCommand | apollo::external_command::CommandStatus | 更改速度命令(园区) |
/apollo/external_command/valet_parking | apollo::external_command::ValetParkingCommand | apollo::external_command::CommandStatus | 指定停车位泊车命令 |
输出
输入外部命令经过预处理,被转换成内部命令发送给planning,control或者canbus模块。被转换成的内部命令以cyber topic的形式发送,有如下几种:
Channel 名 | 类型 |
描述
|
---|---|---|
/apollo/planning/command | apollo::planning::PlanningCommand | 具有导航动作的外部命令转换成的内部命令,发送给planning模块 |
/apollo/routing_response | apollo::routing::RoutingResponse | 在高精地图上沿车道线点对点行驶的外部命令,预处理时生成的routing线路,用于HMI显示时使用 |
/apollo/planning/pad | apollo::planning::PadMessage | 外部命令ActionCommand转换成的内部命令,发送给planning模块 |
/apollo/control/pad | apollo::control::PadMessage | 外部命令ActionCommand转换成的内部命令,发送给control模块 |
/apollo/canbus/chassis_control | apollo::external_command::ChassisCommand | 外部命令ChassisCommand转换成的内部命令,发送给canbus模块 |
通过代码可以此处ExternalCommandProcessComponent
根据conf初始化创建了7个service,配合external_command_demo
客户端来使用.
namespace apollo {
namespace external_command {
bool ExternalCommandProcessComponent::Init() {
// Load the external command processors according to the config.
ProcessComponentConfig config;
if (!GetProtoConfig(&config)) {
AERROR << "Unable to load ExternalCommandProcessComponent conf file: "
<< ConfigFilePath();
return false;
}
const auto& plugin_manager = cyber::plugin_manager::PluginManager::Instance();
for (const auto& processor_class_name : config.processor()) {
command_processors_.emplace_back(
plugin_manager->CreateInstance<CommandProcessorBase>(
processor_class_name));
command_processors_.back()->Init(node_);
}
command_status_service_ =
node_->CreateService<CommandStatusRequest, CommandStatus>(
config.output_command_status_name(),
[this](const std::shared_ptr<CommandStatusRequest>& request,
std::shared_ptr<CommandStatus>& response) {
bool is_get_status = false;
// Get the command status from command processors.
for (const auto& processor : command_processors_) {
if (processor->GetCommandStatus(request->command_id(),
response.get())) {
is_get_status = true;
break;
}
}
if (!is_get_status) {
response->set_status(CommandStatusType::UNKNOWN);
response->set_message("Cannot get the status of command.");
}
});
AINFO << "ExternalCommandProcessComponent init finished.";
return true;
}
} // namespace external_command
} // namespace apollo
external_command_demo(客户端)
syntax = "proto2";
package apollo.external_command;
import "modules/common_msgs/basic_msgs/header.proto";
enum ActionCommandType {
// Follow the current lane.
FOLLOW = 1;
// Change to the laft lane.
CHANGE_LEFT = 2;
// Change to the right lane.
CHANGE_RIGHT = 3;
// Pull over and stop driving.
PULL_OVER = 4;
// Stop driving smoothly in emergency case.
STOP = 5;
// Start driving after paused.
START = 6;
// Clear the input planning command to cancel planning.
CLEAR_PLANNING = 7;
// Switch to manual drive mode.
SWITCH_TO_MANUAL = 50;
// Switch to auto drive mode.
SWITCH_TO_AUTO = 51;
// Varify vin code of vehicle.
VIN_REQ = 52;
// Enter mission model
ENTER_MISSION = 53;
// Exit mission model
EXIT_MISSION = 54;
}
message ActionCommand {
optional apollo.common.Header header = 1;
// Unique identification for command.
optional int64 command_id = 2 [default = -1];
// The action command.
required ActionCommandType command = 3;
}
类型 |
描述
|
---|---|
pull_over | Follow the current lane. |
stop | Stop driving smoothly in emergency case. |
start | Start driving after paused. |
clear | Clear the input planning command to cancel planning. |
manual | Switch to manual drive mode. |
auto | Switch to auto drive mode. |
vin | Varify vin code of vehicle. |
enter_mission | Enter mission model |
exit_mission | Exit mission model |
插件ActionCommandProcessor
modules/external_command/command_processor/action_command_processor
插件的输出为外部操作指令执行后对应发布的channel信息(/apollo/planning/pad 或 /apollo/control/pad)和更新planning模块发布的命令执行状态(CommandStatus):
Channel 名称 | 类型 |
描述
|
---|---|---|
/apollo/planning/pad | apollo::planning::PadMessage | 改变planning场景行为的指令 |
/apollo/control/pad | apollo::control::PadMessage | 改变底盘驾驶模式的指令 |
/apollo/planning/command_status | apollo::external_command::CommandStatus | 更新planning模块发布的针对外部命令的执行状态 |
配置
文件路径 | 类型/结构 | 说明 |
---|---|---|
modules/external_command/command_processor/action_command_processor/conf/config.pb.txt | apollo::external_command::CommandProcessorConfig | 配置文件,外部操作命令处理器输入输出的channel或service名称等信息 |
modules/external_command/command_processor/action_command_processor/conf/special_config.pb.txt | apollo::external_command::ActionCommandConfig | 配置文件,外部操作命令处理器模块的配置 |
apollo/modules/external_command/command_processor/action_command_processor/action_command_processor.cc
bool ActionCommandProcessor::Init(const std::shared_ptr<cyber::Node>& node) {
...
// Create service for input command.
command_service_ = node->CreateService<ActionCommand, CommandStatus>(
config.input_command_name(),
[this](const std::shared_ptr<ActionCommand>& command,
std::shared_ptr<CommandStatus>& status) {
this->OnCommand(command, status);
});
// Create writers for output command.
CHECK_GT(config.output_command_name().size(), 1);
auto message_writer = MessageWriter::Instance();
planning_action_writer_ =
message_writer->RegisterMessage<apollo::planning::PadMessage>(
config.output_command_name().Get(0));
control_action_writer_ =
message_writer->RegisterMessage<apollo::control::PadMessage>(
config.output_command_name().Get(1));
// Create reader for input command status.
...
return true;
}
void ActionCommandProcessor::OnCommand(
const std::shared_ptr<ActionCommand>& command,
std::shared_ptr<CommandStatus>& status) {
...
//
switch (command->command()) {
// Send "FOLLOW" message to planning.
case external_command::ActionCommandType::FOLLOW: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::FOLLOW);
planning_action_writer_->Write(planning_message);
} break;
// Send "CHANGE_LEFT" message to planning.
case external_command::ActionCommandType::CHANGE_LEFT: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::CHANGE_LEFT);
planning_action_writer_->Write(planning_message);
} break;
// Send "CHANGE_RIGHT" message to planning.
case external_command::ActionCommandType::CHANGE_RIGHT: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::CHANGE_RIGHT);
planning_action_writer_->Write(planning_message);
} break;
// Send "PULL_OVER" message to planning.
case external_command::ActionCommandType::PULL_OVER: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::PULL_OVER);
planning_action_writer_->Write(planning_message);
} break;
// Send "STOP" message to planning.
case external_command::ActionCommandType::STOP: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::STOP);
planning_action_writer_->Write(planning_message);
} break;
// Send "CLEAR_PLANNING" message to planning.
case external_command::ActionCommandType::CLEAR_PLANNING: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::CLEAR_PLANNING);
planning_action_writer_->Write(planning_message);
status->set_status(CommandStatusType::FINISHED);
} break;
// Send "START" message to planning.
case external_command::ActionCommandType::START: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::RESUME_CRUISE);
planning_action_writer_->Write(planning_message);
} break;
// Send "SWITCH_TO_MANUAL" message to control.
case external_command::ActionCommandType::SWITCH_TO_MANUAL: {
// Use async function to wait for the chassis to be in manual mode.
cyber::Async(&ActionCommandProcessor::SwitchToManualMode, this,
module_name);
} break;
// Send "SWITCH_TO_AUTO" message to control.
case external_command::ActionCommandType::SWITCH_TO_AUTO: {
// Chassis need be switched to manual mode before switch to auto mode.
// Use async function to wait for the chassis to be in auto mode.
cyber::Async(&ActionCommandProcessor::SwitchToAutoMode, this,
module_name);
} break;
// Send "ENTER_MISSION" message to planning.
case external_command::ActionCommandType::ENTER_MISSION: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::ENTER_MISSION);
planning_action_writer_->Write(planning_message);
} break;
// Send "EXIT_MISSION" message to planning.
case external_command::ActionCommandType::EXIT_MISSION: {
planning::PadMessage planning_message;
common::util::FillHeader(module_name, &planning_message);
planning_message.set_action(planning::PadMessage::EXIT_MISSION);
planning_action_writer_->Write(planning_message);
} break;
...
}
}