Apollo学习——planning模块(2)之planning_component
planning_component: 包含planning组件类和planning程序的启动以及配置文件。
1.Init流程
1、初始化依赖注入器injector_,用来缓存数据使用
//依赖注入器 数据缓存使用injector_ = std::make_shared<DependencyInjector>();
2、根据标志位FLAGS_use_navigation_mode,判断使用那种规划器
//选择规划器类型if (FLAGS_use_navigation_mode) {planning_base_ = std::make_unique<NaviPlanning>(injector_); // 基于相对地图的导航规划(适用于高速公路等简单场景)。} else {planning_base_ = std::make_unique<OnLanePlanning>(injector_); // 默认的高精地图轨迹规划器}
3、更新配置及参数
ACHECK(ComponentBase::GetProtoConfig(&config_)) // 从planning_config.pb.txt加载配置 config_就是这个文件<< "failed to load planning config file "<< ComponentBase::ConfigFilePath(); // 配置文件路径由DAG文件中的config_file_path定义。
4、planning_base初始化
// 规划器初始化// 子步骤:// 参考线线程:启动ReferenceLineProvider线程生成平滑参考线。// 场景加载:根据配置初始化交通规则和场景(如变道、借道等)。// 规划器注册:默认使用PublicRoadPlanner planning_base_->Init(config_);
5、创建读写器
reader
reader | 发布模块 | channal | 数据结构 | 功能 |
---|---|---|---|---|
planning_command_reader_ | external_command | /apollo/planning/command | PlanningCommand | |
traffic_light_reader_ | perception | /apollo/perception/traffic_light | TrafficLightDetection | |
pad_msg_reader_ | external_command | /apollo/planning/pad | PadMessage | |
story_telling_reader_ | storytelling | /apollo/storytelling | Stories | |
control_interactive_reader_ | control | /apollo/control/interactive | ControlInteractiveMsg | |
relative_map_reader_ | tool | /apollo/relative_map | MapMsg |
writer
writer | channal | 数据结构 | 功能 |
---|---|---|---|
planning_writer_ | /apollo/planning | ADCTrajectory | |
command_status_writer_ | /apollo/planning/command_status | external_command::CommandStatus |
client
client | service模块 | channal | 数据结构 | 作用 |
---|---|---|---|---|
rerouting_client_ | external_command | /apollo/external_command/lane_follow | apollo::external_command::LaneFollowCommand,external_command::CommandStatus |
代码如下:
// 创建读写器// 规划命令 由external_command模块的/apollo/planning/command发布planning_command_reader_ = node_->CreateReader<PlanningCommand>(config_.topic_config().planning_command_topic(),[this](const std::shared_ptr<PlanningCommand>& planning_command) {AINFO << "Received planning data: run planning callback."<< planning_command->header().DebugString();std::lock_guard<std::mutex> lock(mutex_);planning_command_.CopyFrom(*planning_command);});//交通灯 由/apollo/perception/traffic_light发布traffic_light_reader_ = node_->CreateReader<TrafficLightDetection>(config_.topic_config().traffic_light_detection_topic(),[this](const std::shared_ptr<TrafficLightDetection>& traffic_light) {ADEBUG << "Received traffic light data: run traffic light callback.";std::lock_guard<std::mutex> lock(mutex_);traffic_light_.CopyFrom(*traffic_light);});//Pad消息 由external_command模块的/apollo/planning/pad发布pad_msg_reader_ = node_->CreateReader<PadMessage>(config_.topic_config().planning_pad_topic(),[this](const std::shared_ptr<PadMessage>& pad_msg) {ADEBUG << "Received pad data: run pad callback.";std::lock_guard<std::mutex> lock(mutex_);pad_msg_.CopyFrom(*pad_msg);});// 如果故事包含“紧急避让”指令,规划器会生成相应的避障轨迹。 Stories来自场景管理模块story_telling_reader_ = node_->CreateReader<Stories>(config_.topic_config().story_telling_topic(),[this](const std::shared_ptr<Stories>& stories) {ADEBUG << "Received story_telling data: run story_telling callback.";std::lock_guard<std::mutex> lock(mutex_);stories_.CopyFrom(*stories);});// 接收来自控制模块或其他系统的交互指令 收到“紧急停车”指令时,规划器会立即生成减速至停车的轨迹 来自控制模块control_interactive_reader_ = node_->CreateReader<ControlInteractiveMsg>(config_.topic_config().control_interative_topic(),[this](const std::shared_ptr<ControlInteractiveMsg>&control_interactive_msg) {ADEBUG << "Received story_telling data: run story_telling callback.";std::lock_guard<std::mutex> lock(mutex_);control_interactive_msg_.CopyFrom(*control_interactive_msg);});// 仅在导航模式 启用 依赖相对地图而非高精地图 来自感知模块// 导航模式:在无高精地图区域(如停车场),使用相对地图进行局部路径规划。// 动态避障:结合实时地图数据调整轨迹以避开临时障碍物。if (FLAGS_use_navigation_mode) {relative_map_reader_ = node_->CreateReader<MapMsg>(config_.topic_config().relative_map_topic(),[this](const std::shared_ptr<MapMsg>& map_message) {ADEBUG << "Received relative map data: run relative map callback.";std::lock_guard<std::mutex> lock(mutex_);relative_map_.CopyFrom(*map_message);});}//发布轨迹planning_writer_ = node_->CreateWriter<ADCTrajectory>(config_.topic_config().planning_trajectory_topic());//创建客户端 创建重路由客户端,用于在需要重新规划路径时发送请求rerouting_client_ = node_->CreateClient<apollo::external_command::LaneFollowCommand,external_command::CommandStatus>(config_.topic_config().routing_request_topic()); // /apollo/external_command/lane_followplanning_learning_data_writer_ = node_->CreateWriter<PlanningLearningData>(config_.topic_config().planning_learning_data_topic());command_status_writer_ = node_->CreateWriter<external_command::CommandStatus>(FLAGS_planning_command_status);
2、Proc流程
1、检查路由是否正常,如果不正常调用rerouting_client_重新请求路由;
2、将接收到的数据统一存到local_view_;
3、对输入数据进行处理(向traj中添加车道线边界)并检查数据;如果异常,发布空路径返回false;
4、运行planning_base_->RunOnce(local_view_, &adc_trajectory_pb)进行路径规划。
5、对规划好的轨迹adc_trajectory_pb填充时间戳、序列号等消息。
6、设置车辆位置以及车道线信息;
7、遍历轨迹,为轨迹点增加时间信息;
8、发布规划planning_writer_->Write(adc_trajectory_pb);
9、判断状态发布状态command_status_writer_->Write(command_status);
10、记录历史数据 history->Add(adc_trajectory_pb);
代码注释:
bool PlanningComponent::Proc(const std::shared_ptr<prediction::PredictionObstacles>& prediction_obstacles,const std::shared_ptr<canbus::Chassis>& chassis,const std::shared_ptr<localization::LocalizationEstimate>& localization_estimate) {ACHECK(prediction_obstacles != nullptr);AINFO << "Received data: run planning callback................................................";// 1、check and process possible rerouting request 重路由检查 CheckRerouting();// 2、process fused input data 输入检查与数据融合: 将预测障碍物、底盘状态、定位信息融合到local_view_结构体中,供后续规划使用local_view_.prediction_obstacles = prediction_obstacles;local_view_.chassis = chassis;local_view_.localization_estimate = localization_estimate;{std::lock_guard<std::mutex> lock(mutex_);if (!local_view_.planning_command || !common::util::IsProtoEqual(local_view_.planning_command->header(), planning_command_.header())) {local_view_.planning_command = std::make_shared<PlanningCommand>(planning_command_);}}{std::lock_guard<std::mutex> lock(mutex_);local_view_.traffic_light = std::make_shared<TrafficLightDetection>(traffic_light_);local_view_.relative_map = std::make_shared<MapMsg>(relative_map_);}{std::lock_guard<std::mutex> lock(mutex_);if (!local_view_.pad_msg || !common::util::IsProtoEqual(local_view_.pad_msg->header(), pad_msg_.header())) {// Check if "CLEAR_PLANNING" PadMessage is received and process.if (pad_msg_.action() == PadMessage::CLEAR_PLANNING) {local_view_.planning_command = nullptr;planning_command_.Clear();}local_view_.pad_msg = std::make_shared<PadMessage>(pad_msg_);}}{std::lock_guard<std::mutex> lock(mutex_);local_view_.stories = std::make_shared<Stories>(stories_);}{std::lock_guard<std::mutex> lock(mutex_);if (!local_view_.control_interactive_msg || !common::util::IsProtoEqual(local_view_.control_interactive_msg->header(), control_interactive_msg_.header())) {local_view_.control_interactive_msg = std::make_shared<ControlInteractiveMsg>(control_interactive_msg_);}}//3、对输入数据进行检查 如果数据确实,反馈空路径if (!CheckInput()) {AINFO << "Input check failed";return false;}// 4、在非NO_LEARNING模式下,将输入数据(如底盘信息、障碍物预测)传递给学习模块if (config_.learning_mode() != PlanningConfig::NO_LEARNING) {// data process for online trainingmessage_process_.OnChassis(*local_view_.chassis);message_process_.OnPrediction(*local_view_.prediction_obstacles);if (local_view_.planning_command->has_lane_follow_command()) {message_process_.OnRoutingResponse(local_view_.planning_command->lane_follow_command());}message_process_.OnStoryTelling(*local_view_.stories);message_process_.OnTrafficLightDetection(*local_view_.traffic_light);message_process_.OnLocalization(*local_view_.localization_estimate);}// publish learning data frame for RL test 强化学习if (config_.learning_mode() == PlanningConfig::RL_TEST) {PlanningLearningData planning_learning_data;LearningDataFrame* learning_data_frame =injector_->learning_based_data()->GetLatestLearningDataFrame();if (learning_data_frame) {planning_learning_data.mutable_learning_data_frame()->CopyFrom(*learning_data_frame);common::util::FillHeader(node_->Name(), &planning_learning_data);planning_learning_data_writer_->Write(planning_learning_data);} else {AERROR << "fail to generate learning data frame";return false;}return true;}// 5、规划执行// 核心逻辑:// 参考线生成:基于高精地图或相对地图生成参考线。// 障碍物决策:结合预测结果进行避障决策(如停车、绕行)。// 轨迹优化:通过QP/Dynamic Programming优化路径和速度ADCTrajectory adc_trajectory_pb;// local_view_:融合了感知、定位、底盘、交通灯等实时数据的结构体。// adc_trajectory_pb:输出的轨迹容器(Protobuf格式)。planning_base_->RunOnce(local_view_, &adc_trajectory_pb);// 参考线生成 障碍物决策 轨迹优化auto start_time = adc_trajectory_pb.header().timestamp_sec();common::util::FillHeader(node_->Name(), &adc_trajectory_pb);// 填充头消息,增加序列号和时间戳// 6、设置车辆位置信息SetLocation(&adc_trajectory_pb);// 7、modify trajectory relative time due to the timestamp change in header 时间补偿处理const double dt = start_time - adc_trajectory_pb.header().timestamp_sec();for (auto& p : *adc_trajectory_pb.mutable_trajectory_point()) {//遍历轨迹点 将每个点的时间增加dtp.set_relative_time(p.relative_time() + dt);}// 8、轨迹发布与状态反馈 发布规划轨迹(ADCTrajectory)供控制模块执行planning_writer_->Write(adc_trajectory_pb);// 9、Send command execution feedback.// Error occured while executing the command. 初始化状态消息external_command::CommandStatus command_status;common::util::FillHeader(node_->Name(), &command_status);//设置状态消息的头部(模块名、时间戳)。if (nullptr != local_view_.planning_command) {command_status.set_command_id(local_view_.planning_command->command_id()); //关联当前规划命令的ID(用于多命令跟踪)。}ADCTrajectory::TrajectoryType current_trajectory_type = adc_trajectory_pb.trajectory_type();if (adc_trajectory_pb.header().status().error_code() != common::ErrorCode::OK) {command_status.set_status(external_command::CommandStatusType::ERROR); // 轨迹生成失败(如输入数据异常)。command_status.set_message(adc_trajectory_pb.header().status().msg());} else if (planning_base_->IsPlanningFinished(current_trajectory_type)) { AINFO << "Set the external_command: FINISHED";command_status.set_status(external_command::CommandStatusType::FINISHED); //规划任务完成(如到达目的地)。} else {AINFO << "Set the external_command: RUNNING";command_status.set_status(external_command::CommandStatusType::RUNNING);// 规划正常执行中。}// 反馈命令执行状态(RUNNING/FINISHED/ERROR)command_status_writer_->Write(command_status);// 10、record in history 记录历史数据 用于异常处理和数据回溯auto* history = injector_->history();history->Add(adc_trajectory_pb);return true;
}
// 重路由检查 若PlanningContext标记需要重路由,通过rerouting_client_发送请求更新路径
void PlanningComponent::CheckRerouting() {auto* rerouting = injector_->planning_context()->mutable_planning_status()->mutable_rerouting();if (!rerouting->need_rerouting()) {return;}common::util::FillHeader(node_->Name(), rerouting->mutable_lane_follow_command());auto lane_follow_command_ptr = std::make_shared<apollo::external_command::LaneFollowCommand>(rerouting->lane_follow_command());rerouting_client_->SendRequest(lane_follow_command_ptr);rerouting->set_need_rerouting(false);
}bool PlanningComponent::CheckInput() {ADCTrajectory trajectory_pb;//填充轨迹中的车辆位置和车道边界信息。SetLocation(&trajectory_pb);auto* not_ready = trajectory_pb.mutable_decision()->mutable_main_decision()->mutable_not_ready();if (local_view_.localization_estimate == nullptr) {not_ready->set_reason("localization not ready");} else if (local_view_.chassis == nullptr) {not_ready->set_reason("chassis not ready");} else if (HDMapUtil::BaseMapPtr() == nullptr) {not_ready->set_reason("map not ready");} else {// nothing}if (FLAGS_use_navigation_mode) {if (!local_view_.relative_map->has_header()) {not_ready->set_reason("relative map not ready");}} else {if (!local_view_.planning_command ||!local_view_.planning_command->has_header()) {not_ready->set_reason("planning_command not ready");}}if (not_ready->has_reason()) {AINFO << not_ready->reason() << "; skip the planning cycle.";common::util::FillHeader(node_->Name(), &trajectory_pb);planning_writer_->Write(trajectory_pb);return false;}return true;
}
//填充轨迹中的车辆位置和车道边界信息。
void PlanningComponent::SetLocation(ADCTrajectory* const ptr_trajectory_pb) {auto p = ptr_trajectory_pb->mutable_location_pose();// 从localization_estimate中提取车辆位置(x,y)p->mutable_vehice_location()->set_x(local_view_.localization_estimate->pose().position().x());p->mutable_vehice_location()->set_y(local_view_.localization_estimate->pose().position().y());// 计算车道左右边界点(用于可视化或控制模块参考)const Vec2d& adc_position = {local_view_.localization_estimate->pose().position().x(),local_view_.localization_estimate->pose().position().y()};Vec2d left_point, right_point;// ...设置左右边界点if (planning_base_->GenerateWidthOfLane(adc_position, left_point, right_point)) {p->mutable_left_lane_boundary_point()->set_x(left_point.x());p->mutable_left_lane_boundary_point()->set_y(left_point.y());p->mutable_right_lane_boundary_point()->set_x(right_point.x());p->mutable_right_lane_boundary_point()->set_y(right_point.y());}
}