apollo_logo
6
0

星火自动驾驶大赛赛事集锦--红绿灯路口减速慢行(方法二)

交通灯场景(TRAFFIC_LIGHT)

场景描述:

当主车在监测到前方的红灯时, 主车停车在停止线前1.5-2.0米处,不得超过停止线。当红灯变为绿灯后,主车可以通过该路段,在通过交通灯区域时,主车的速度不得超过 6 m/s。

场景图示:

在交通规则中,当我们的车辆遇到红灯或者黄灯时就需要停车等待。在Apollo中设置的交通规则中也满足了这点。当我们的主车检测到前方为红或者黄灯时 (代码如下),在dreamview中的会显示以下界面:如图1 所示;同时也会在实线前多少米(看具体设置的距离,默认值为1米)外生成一道停止墙如图2所示:

图1:红灯显示 图2:停止墙

评判标准

主车未停车在停止线1.5-2.0米之间, 本场景分扣20分; 速度每超速1m/s, 本场景分扣20分, 超过停止线或者红灯状态未停止, 本场景计0分;

运行视频回放

【百度Apollo星火自动驾驶大赛城市道路预选赛——交通灯路口赛题】 https://www.bilibili.com/video/BV1Ez4y187hG/?share_source=copy_web&vd_source=c5757152d93e2f5dba69049264ebea4e

实验流程:

实验流程大纲

  1. 默认配置参数规划效果
  • 启动dreamview并观察默认配置参数下车辆遇到交通灯的仿真效果。
  1. 红绿灯场景实践:
  • a. 找到planning2.0中Traffic Rules配置的相关文件。
  • b. 根据要求,调整Traffic Rules配置参数,确保车辆停车在距离停止线2米至2.5米的位置停车。
  • c. 调整通过交叉路口的速度
  • d.保存修改后的配置参数,并重新启动planning模块。
  • e. 运行车辆规划模块,并在dreamview上观察车辆遇到红绿灯场景的停车变化和通过交叉路口速度

使用插件配置参数流程

生成和使用traffic light插件

输入配置参数同步指令,系统将自动将全局配置参数复制到profile的default目录中,然后就可以在profile目录上轻松修改配置参数。

buildtool profile config init --package planning-traffic-rules-traffic-light --profile=default

使用目录名为default的这份配置参数

aem profile use defaul

查看profile插件目录结构:

tree profiles/default/modules/planning/traffic_rules/

目录结构:

profiles/default/modules/planning/traffic_rules/
`-- traffic_light
`-- conf
`-- default_conf.pb.txt//traffic_light插件参数配置文件

修改插件配置参数

在工作apollo_workspace工作目录找到profiles/default/modules/planning/traffic_rules/traffic_light/conf/default_conf.pb.txt配置文件,调整红绿灯场景停止配置参数,达到我们期望路径规划效果。

(1) 使用在线编辑工具修改profiles/default/modules/planning/traffic_rules/traffic_light/conf/default_conf.pb.txt配置文件,将stop_distance 参数

在全局配置参数中找到红绿灯场景停止配置参数:

stop_distance: 1.0

将配置参数的值修改为:

stop_distance: 2.0

仿真对比:

原始

修改后

绕行距离配置实践


云实验链接:

该实践内容已经上线Apollo云实验室,开快速启动进行实践体验: https://apollo.baidu.com/community/course/9

技术详解

交通灯场景运行流程框图

一、进入TRAFFIC_LIGHT_PROTECTED场景

代码以及代码路径(节选):

.aem/envroot/opt/apollo/neo/src/modules/planning/scenarios/traffic_light_protected/conf/scenario_conf.pb.txt

start_traffic_light_scenario_distance: 5.0
#当距离红绿灯的停车道5.0米时进入TRAFFIC_LIGHT_PROTECTED场景

代码以及代码路径(节选):

.aem/envroot/opt/apollo/neo/src/modules/planning/scenarios/traffic_light_protected/traffic_light_protected_scenario.cc

如果 adc_distance_to_traffic_light 小于等于0(表示车辆已经过了交通信号灯)或者大于起始检查距离(start_check_distance),
那么就不进入交通信号灯场景,继续下一个信号灯的判断。否则进入交通信号灯场景
// enter traffic-light scenarios: based on distance only
if (adc_distance_to_traffic_light <= 0.0 ||
adc_distance_to_traffic_light > start_check_distance) {
continue;
}

交通灯场景TRAFFIC_LIGHT_PROTECTED定义了两个stage

.aem/envroot/opt/apollo/neo/share/modules/planning/scenarios/traffic_light_protected/conf/pipeline.pb.txt

stage: {
name: "TRAFFIC_LIGHT_PROTECTED_APPROACH"
type: "TrafficLightProtectedStageApproach"
enabled: true
…
}
stage: {
name: "TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE"
type: "TrafficLightProtectedStageIntersectionCruise"
enabled: true
…
}

TRAFFIC_LIGHT_PROTECTED_APPROACH和TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE的注册

代码以及代码路径(节选):

s_stage_factory_.Register(
ScenarioConfig::TRAFFIC_LIGHT_PROTECTED_APPROACH,
[](const ScenarioConfig::StageConfig& config,
const std::shared_ptr<DependencyInjector>& injector) -> Stage* {
return new TrafficLightProtectedStageApproach(config, injector);
});
s_stage_factory_.Register(
ScenarioConfig::TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE,
[](const ScenarioConfig::StageConfig& config,
const std::shared_ptr<DependencyInjector>& injector) -> Stage* {
return new TrafficLightProtectedStageIntersectionCruise(config,
injector);
});

如果自动驾驶车辆遇到交通灯为红灯

二、红绿灯检测:

代码以及代码路径(节选):

.aem/envroot/opt/apollo/neo/src/modules/planning/traffic_rules/traffic_light/traffic_light.cc

这段代码的作用是检查交通灯是否已经完成。它遍历已完成的交通灯重叠区域的ID列表,
然后将当前交通灯的ID与这些ID进行比较。如果当前交通灯的ID在已完成的交通灯重叠区域的ID列表中,
那么设置变量traffic_light_done为true,然后退出循环。
bool traffic_light_done = false;
for (const auto& done_traffic_light_overlap_id :
traffic_light_status.done_traffic_light_overlap_id()) {
if (traffic_light_overlap.object_id == done_traffic_light_overlap_id) {
traffic_light_done = true;
break;
}
}
if (traffic_light_done) {
continue;
}

2.1停止墙生成源码:

可能有小伙伴会问停止墙是如何生成的呢?停止墙的标志是什么?

首先当我们的主车确认前方交通灯不为绿灯时时,会生成停止墙,停止原因为黄/红信号灯,

代码以及代码路径(节选):

.aem/envroot/opt/apollo/neo/src/modules/planning/traffic_rules/traffic_light/traffic_light.cc

/*
函数的作用是生成一条停车决策,并将其添加到参考线信息中。当交通规则需要控制车辆停止时,
例如信号灯指示红灯时,就会生成这样的停车决策。
*/
util::BuildStopDecision(
virtual_obstacle_id, traffic_light_overlap.start_s,
config_.stop_distance(), StopReasonCode::STOP_REASON_SIGNAL,
wait_for_obstacles, Getname(), frame, reference_line_info);

2.2信号灯停止源码:

代码以及代码路径(节选):

/*
这段代码是一个交通灯保护阶段(TrafficLightProtectedStage)中的交通灯靠近阶段
(TrafficLightProtectedStageApproach)的处理函数(Process)。
首先,它遍历当前交通灯重叠区域的ID列表,并检查每个交通灯的颜色是否为绿灯。
如果存在任何一个交通灯不是绿灯,那么设置变量traffic_light_all_done为false,然后退出循环。
否则,将变量traffic_light_all_done设置为true。
如果所有交通灯都是绿灯,那么函数调用FinishStage()来结束该阶段,然后返回Stage::FINISHED状态。
否则,返回Stage::RUNNING状态,表示该阶段仍在运行中。
*/
StageResult TrafficLightProtectedStageApproach::Process(
const TrajectoryPoint& planning_init_point, Frame* frame) {
// traffic_light_all_done 用于标记是否所有交通信号灯都已处理完毕
bool traffic_light_all_done = true;
// 遍历当前交通信号灯的重叠区域
for (const auto& traffic_light_overlap_id :
context->current_traffic_light_overlap_ids) {
// 获取交通信号灯在参考线上的重叠信息
PathOverlap* current_traffic_light_overlap =
reference_line_info.GetOverlapOnReferenceLine(
traffic_light_overlap_id, ReferenceLineInfo::SIGNAL);
if (!current_traffic_light_overlap) {
continue;
}
// 设置交通信号灯不具备交通优先权
reference_line_info.SetJunctionRightOfWay(
current_traffic_light_overlap->start_s, false);
// 获取车辆前沿位置相对于交通信号灯停车线的距离
const double adc_front_edge_s = reference_line_info.AdcSlBoundary().end_s();
const double distance_adc_to_stop_line =
current_traffic_light_overlap->start_s - adc_front_edge_s;
auto signal_color = frame->GetSignal(traffic_light_overlap_id).color();
// 检查车辆到停车线的距离是否小于最大有效停车距离
if (distance_adc_to_stop_line > scenario_config.max_valid_stop_distance()) {
traffic_light_all_done = false;
break;
}
// 检查交通信号灯的颜色是否为绿色
if (signal_color != TrafficLight::GREEN) {
traffic_light_all_done = false;
break;
}
}
// 如果所有交通信号灯都已经处理完毕,则返回 FinishStage() 表示阶段已完成
if (traffic_light_all_done) {
return FinishStage();
}
// 否则,返回 result.SetStageStatus(StageStatusType::RUNNING) 表示阶段仍在运行中
return result.SetStageStatus(StageStatusType::RUNNING);
}

当主车靠近红绿灯场景时,会进入Scenario 为TRAFFIC_LIGHT_PROTECTED的红绿灯场景

自动驾驶车辆接近交通信号灯

三、进入APPROACH的stage定义

代码以及代码路径(节选):

/*
这段代码是交通灯保护阶段(TrafficLightProtectedStage)中的交通灯靠近阶段(TrafficLightProtectedStageApproach)的处理函数(Process)
*/
StageResult TrafficLightProtectedStageApproach::Process(
const TrajectoryPoint& planning_init_point, Frame* frame)
//APPROACHstage 正在运行
{
return result.SetStageStatus(StageStatusType::RUNNING);
}
/*
这段代码是交通灯保护阶段(TrafficLightProtectedStage)中的交通灯靠近阶段(TrafficLightProtectedStageApproach)的结束函数(FinishStage)。
当交通灯靠近阶段的任务完成后,该函数会将next_stage_
设置为ScenarioConfig::TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE,
表示进入交通灯保护阶段的下一个阶段TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE。
然后,它返回Stage::FINISHED状态,表示该阶段已经完成。
*/
Stage::StageStatus TrafficLightProtectedStageApproach::FinishStage()
//APPROACHstage 正在完成
{
//省略
next_stage_ = "TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE";
//进入下一个stage TRAFFIC_LIGHT_PROTECTED_INTERSECTION_CRUISE
return StageResult(StageStatusType::FINISHED);
//APPROACH的stage完成
}

自动驾驶车辆进入红绿灯交叉路口区域

四、进入INTERSECTION_CRUISE的stage定义

代码以及代码路径(节选):

这段代码是交通灯保护阶段(TrafficLightProtectedStage)中的交通灯保护交叉路口阶段(TrafficLightProtectedStageIntersectionCruise)的处理函数(Process)。
首先,它调用stage_impl_.CheckDone()函数,检查是否已经通过了交叉路口。如果已经通过了交叉路口,那么将返回true,表示该阶段已经完成。
如果该阶段已经完成,那么函数调用FinishStage()来结束该阶段,然后返回Stage::FINISHED状态。
否则,返回Stage::RUNNING状态,表示该阶段仍在运行中。
StageResult TrafficLightProtectedStageIntersectionCruise::Process(
const common::TrajectoryPoint& planning_init_point, Frame* frame) {
bool stage_done = CheckDone(*frame, injector_->planning_context(), true);
//定义交叉路口
if (stage_done)
//如果通过交叉路口
{
return FinishStage();
//INTERSECTION_CRUISE的stage完成
}
return result.SetStageStatus(StageStatusType::RUNNING);
//进入INTERSECTION_CRUISE的RUNNING
}
该函数调用FinishScenario()函数,结束整个交通灯保护阶段(TrafficLightProtectedStage),并返回Stage::FINISHED状态,表示该阶段已经完成。
StageResult TrafficLightProtectedStageIntersectionCruise::FinishStage() {
return FinishScenario();
//INTERSECTION_CRUISE的stage完成
}

交通灯场景代码修改部分

任务实现:

停车距离:

输入traffic_rules参数同步指令,系统将自动将traffic_light的配置参数复制到profile的default目录中,然后就可以在profile目录上轻松修改配置参数。

buildtool profile config init --package planning-traffic-rules-traffic-light --profile=default && aem profile use default

profiles/default/modules/planning/traffic_rules/traffic_light/conf/default_conf.pb.txt

stop_distance: 1.0
#停止距离为1.0 单位 m

代码实现(节选):

.aem/envroot/opt/apollo/neo/src/modules/planning/planning_base/common/util/common.cc

ObjectDecisionType stop;
//定义一个停止墙
auto* stop_decision = stop.mutable_stop();
//stop决策的停车原因
stop_decision->set_reason_code(stop_reason_code);
stop_decision->set_distance_s(-stop_distance);
//stop决策的停车安全距离

实现场景代码(修改参数的部分):

我们仅仅需要将配置文件TRAFFIC_LIGHT的stop_distance值改为1.5-2.0即可。

因为存在误差值,尽量取中间值。

stop_distance: 1.7
#停止距离为1.0 单位 m

3红绿灯路口限速:

3.1 生成插件文件模版

输入下述指令,在modules/planning/traffic_rules/下新建插件文件夹region_speed_limit。

buildtool create --template plugin \
--namespaces planning \
--name region-speed-limit \
--base_class_name TrafficRule modules/planning/traffic_rules/region_speed_limit \
--config_message_name RegionSpeedLimitConfig

3.2 写RegionSpeedLimit类代码文件以及配置相应BUILD文件

#include <memory>
#include "modules/planning/traffic_rules/region_speed_limit/region_speed_limit.h"
namespace apollo {
namespace planning {
/* 定义成员函数*/
using apollo::common::Status;
using apollo::hdmap::PathOverlap;
bool RegionSpeedLimit::Init(const std::string& name, const std::shared_ptr<DependencyInjector>& injector) {
if (!TrafficRule::Init(name, injector)) {
return false;
}
// Load the config this task.
return TrafficRule::LoadConfig<RegionSpeedLimitConfig>(&config_);
}
Status RegionSpeedLimit::ApplyRule(Frame* const frame, ReferenceLineInfo* const reference_line_info) {
ReferenceLine* reference_line = reference_line_info->mutable_reference_line();
const std::vector<PathOverlap>& pnc_junction_overlaps
= reference_line_info->reference_line().map_path().pnc_junction_overlaps();
for (const auto& pnc_junction_overlap : pnc_junction_overlaps) {
reference_line->AddSpeedLimit(
pnc_junction_overlap.start_s - config_.forward_buffer(),
pnc_junction_overlap.end_s + config_.backward_buffer(),
config_.limit_speed());
}
return Status::OK();
}
} // namespace planning
} // namespace apollo
  • Init()函数:初始化RegionSpeedLimit类,读取配置文件信息到config_;
  • ApplyRule()函数:traffic rule类调用接口,在运行中实际调用的函数;
  • reference_line_info->reference_line().map_path():获取道路信息,本插件获取了交汇路口信息pnc_junction_overlaps();
  • 针对交汇路口的限速功能,调用了ReferenceLine::AddSpeedLimit(double start_s, double end_s, double speed_limit),实现了在start_s处到end_s处最高速度为speed_limit的约束。
#pragma once
#include <memory>
#include "cyber/plugin_manager/plugin_manager.h"
/* 添加了相应的头文件*/
#include "modules/common/status/status.h"
#include "modules/planning/traffic_rules/region_speed_limit/proto/region_speed_limit.pb.h"
#include "modules/planning/planning_interface_base/traffic_rules_base/traffic_rule.h"
namespace apollo {
namespace planning {
class RegionSpeedLimit : public TrafficRule {
/* 声明成员函数*/
public:
bool Init(const std::string& name, const std::shared_ptr<DependencyInjector>& injector) override;
virtual ~RegionSpeedLimit() = default;
common::Status ApplyRule(Frame* const frame, ReferenceLineInfo* const reference_line_info);
void Reset() override {}
private:
RegionSpeedLimitConfig config_;
};
CYBER_PLUGIN_MANAGER_REGISTER_PLUGIN(apollo::planning::RegionSpeedLimit, TrafficRule)
} // namespace planning
} // namespace apollo

Reset()函数:插件变量重置入口,清空上一次决策对插件内变量的更改。

CYBER_PLUGIN_MANAGER_REGISTER_PLUGIN(apollo::planning::RegionSpeedLimit,TrafficRule):声明该类为插件。

BUILD文件描述了源码的构建规则以及其依赖。

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("//tools:apollo.bzl", "cyber_plugin_description")
load("//tools:apollo_package.bzl", "apollo_cc_library", "apollo_package", "apollo_plugin")
load("//tools/proto:proto.bzl", "proto_library")
load("//tools:cpplint.bzl", "cpplint")
package(default_visibility = ["//visibility:public"])
filegroup(
name = "region_speed_limit_files",
srcs = glob([
"conf/**",
]),
)
apollo_plugin(
name = "libregion_speed_limit.so",
srcs = [
"region_speed_limit.cc",
],
hdrs = [
"region_speed_limit.h",
],
description = ":plugins.xml",
deps = [
"//cyber",
# 添加该插件所需依赖
"//modules/planning/planning_interface_base:apollo_planning_planning_interface_base",
"//modules/planning/traffic_rules/region_speed_limit/proto:region_speed_limit_proto",
],
)
apollo_package()
cpplint()

load():声明编译中使用的相关依赖

filegroup():声明文件组,编译后会将其安装到相应位置。

apollo_plugin():声明编译动态库、编译源码文件、插件描述文件、依赖。

3.3 配置参数文件

syntax = "proto2";
package apollo.planning;
message RegionSpeedLimitConfig {
// 声明RegionSpeedLimitConfig中的数据结构
optional double forward_buffer = 1 [default = 3];
optional double backward_buffer = 2 [default = 2];
optional double limit_speed = 3 [default = 5];
}

region_speed_limit.proto 文件声明了该插件配置文件的数据结构。

BUILD 文件声明了该proto文件的编译规则。

3.4 写插件参数文件default_conf.pb.txt

forward_buffer: 3.0
backward_buffer: 2.0
limit_speed: 15.0

3.5 配置cyberfile.xml

<package format="2">
<name>region-speed-limit</name>
<version>local</version>
<description>
This is a demo package
</description>
<maintainer email="sample@sample.com">Apollo Developer</maintainer>
<license>Apache License 2.0</license>
<url type="website">https://www.apollo.auto/</url>
<url type="repository">https://github.com/ApolloAuto/apollo</url>
<url type="bugtracker">https://github.com/ApolloAuto/apollo/issues</url>
<type>module</type>
<src_path>//modules/planning/traffic_rules/region_speed_limit</src_path>
<builder>bazel</builder>
<depend type="binary" repo_name="cyber">cyber</depend>
<!-- add new dependency-->
<depend type="binary" repo_name="planning-interface-base">planning-interface-base</depend>
<depend>bazel-extend-tools</depend>
</package>

声明文件版本等信息

3.6修改plugins.xml:

plugin_region_speed_limit_description.xml文件修改成plugin.xml文件

<library path="modules/planning/traffic_rules/region_speed_limit/libregion_speed_limit.so">
<class type="apollo::planning::RegionSpeedLimit" base_class="apollo::planning::TrafficRule"></class>
</library>

3.7 traffic_rule_config.pb.txt中加入新增插件

将新建插件加入traffic rule配置文件中,从而使planning调用该traffic rule。

rule {
name: "BACKSIDE_VEHICLE"
type: "BacksideVehicle"
}
rule {
name: "CROSSWALK"
type: "Crosswalk"
}
rule {
name: "DESTINATION"
type: "Destination"
}
rule {
name: "KEEP_CLEAR"
type: "KeepClear"
}
rule {
name: "REFERENCE_LINE_END"
type: "ReferenceLineEnd"
}
rule {
name: "REROUTING"
type: "Rerouting"
}
rule {
name: "STOP_SIGN"
type: "StopSign"
}
rule {
name: "TRAFFIC_LIGHT"
type: "TrafficLight"
}
rule {
name: "YIELD_SIGN"
type: "YieldSign"
}
rule {
name: "REGION_SPEED_LIMIT"
type: "RegionSpeedLimit"
}

3.8 编译插件

执行以下命令编译插件

buildtool build -p modules/planning/traffic_rules/region_speed_limit/

原创声明,本文由作者授权发布于Apollo开发者社区,未经许可,不得转载。
发表评论已发表 0 条评论
登录后可评论,请前往 登录
暂无评论~快去发表自己的独特见解吧!
目录
交通灯场景(TRAFFIC_LIGHT)
场景描述:
场景图示:
评判标准
运行视频回放
实验流程:
实验流程大纲
使用插件配置参数流程
云实验链接:
技术详解
交通灯场景运行流程框图
任务实现:
3红绿灯路口限速: