一、Apollo 环境搭建

参考链接:https://apollo.baidu.com/community/article/1239

1.1 安装aem工具

apollo 9.0.0版本的aem兼容apollo 8.0aem,请使用以下指令进行更新。

sudo apt install apollo-neo-env-manager-dev --reinstall

安装成功后,可以使用以下指令进行查看aem工具功能。

aem -h

1.2 拉取并启动docker容器

aem start_cpu

1.3 进入容器

在工作目录下进入容器进行代码的编译

aem enter

1.4 启动Dreamview

aem bootstrap start --plus

停止:

aem bootstrap stop

1.5 怎么编译代码?

以planning为例

buildtool build -p modules/planning

其他模块:
buildtool build -p modules/其他
注: 如果编译卡死可以尝试以下编译方式:

buildtool build -p modules/planning -j 4 -m 0.5 

二、日志(可不执行)

日志查看:Apollo的日志在工作目录中的【data/log/】
解决日志文件占用存储空间过大的问题

2.1日志删除

在工作目录中使用指令:

sudo rm -rf data/log/*.log.INFO.2*

注: 这里最好不要用sudo 来删除日志文件,会出现不知名的错误。请使用以下命令

rm -rf data/log/*.log.INFO.2*

2.2 修改配置

如果没有“application-pnc/modules/planning/”目录下没有planning_component包可以使用以下命令下载

buildtool install planning

然后在profile目录下同步配置参数

# 将planning的全局配置参数同步至default目录
buildtool profile config init --package planning --profile=default
# 使用default目录的配置参数
aem profile use default

用命令“ll data/log”找到日志文件的名称,然后用以下命令查看相应的日志文件的大小,这里我查看的是“planning.log.INFO.20240530-104320.95003”日志文件,当然也可以在Ubuntu的文件管理器中的属性中直接查看日志文件的大小而不是用命令的方式。

在“application-pnc/profiles/default/modules/planning/planning_component/conf”打开planning.conf文件修改配置

--enable_print_curve=true     (修改前)
--enable_print_curve=false    (修改后)

修改完后启动Dreamview,跑一个赛题,再次用同样的方法查看日志文件的大小会发现日志文件大小小了很多

三、Apollo赛题解析

3.1 第一题 车辆靠边启动

步骤一:在 https://apollo.baidu.com/community/article/1243链接下载“靠边停车baseline.tar.gz”
步骤二:在application-pnc中输入“tar -zxvf 靠边停车baseline.tar.gz”解压
步骤三:“aem enter”进入容器输入“buildtool build -p modules/planning/ ”编译
步骤四:“aem profile use default”修改配置指向路径
步骤五:“aem bootstrap start --plus”启动Dreamview

3.2 第二题 红绿灯路口——行人避让

查看包名链接:https://apollo.baidu.com/docs/apollo/latest/md_collection_2planning_2README__cn.html

3.2.1 下载相应包

使用“buildtool install planning-traffic-rules-crosswalk”下载crosswalk的包

buildtool install planning-traffic-rules-crosswalk

3.2.2 修改代码

在“/application-pnc/modules/planning/traffic_rules/crosswalk”路径下打开“crosswalk.cc”用CTRL+F搜索“is_path_cross”,找到如下代码:

 		if (is_path_cross) {
 			stop = true;
    	}
    	ADEBUG << "need_stop(between l1 & l2): obstacle_id[" << obstacle_id
           	   << "] type[" << obstacle_type_name << "] obstacle_l_distance["
               << obstacle_l_distance << "] crosswalk_id[" << crosswalk_id
               << "] USE_PREVIOUS_DECISION";
   }

然后修改为

 		if (is_path_cross) {
 			stop = true;
    	}
    	ADEBUG << "need_stop(between l1 & l2): obstacle_id[" << obstacle_id
           	   << "] type[" << obstacle_type_name << "] obstacle_l_distance["
               << obstacle_l_distance << "] crosswalk_id[" << crosswalk_id
               << "] USE_PREVIOUS_DECISION";
        stop = true;
   }
   

再CTRL+S保存代码后在终端使用该命令编译代码

buildtool build -p modules/planning/

3.2.3 配置生效

人行道(crosswalk)配置参数同步

以下命令将“planning-traffic-rules-crosswalk”包的全部配置文件同步到名为default的profile目录下(profile/default),default的名字可以自行修改,但是需要执行命令使配置生效,而且比赛的测评系统只读取名字为default的配置参数,提交代码时可以修改回来为default

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

终端输入以下命令,使名字为default(与上面命令中自己修改的名字一致)的这份配置生效

aem profile use default

使用以下两个命令查看是否配置成功

ll /apollo/modules/planning/traffic_rules/crosswalk/conf/default_conf.pb.txt
ll profiles/current

如果出现

/apollo/modules/planning/traffic_rules/crosswalk/conf/default_conf.pb.txt -> 
/apollo_workspace/profiles/current/modules/planning/traffic_rules/crosswalk/conf/default_conf.pb.txt


则说明配置成功

3.2.4 修改参数

在“/application-pnc/profiles/default/modules/planning/traffic_rules/crosswalk/conf/”路径下打开“default_conf.pb.txt”文件修改参数

stop_distance: 1.0
max_stop_deceleration: 4.0
min_pass_s_distance: 1.0
expand_s_distance: 2.0
stop_strict_l_distance: 5.0
stop_loose_l_distance: 5.0
stop_timeout: 10.0

修改为:

stop_distance: 1.2
max_stop_deceleration: 4.0
min_pass_s_distance: 1.0
expand_s_distance: 2.0
stop_strict_l_distance: 1.0
stop_loose_l_distance: 5.8
stop_timeout: 80.0

输入以下命令查看修改的配置是否生效:

cat /apollo/modules/planning/traffic_rules/crosswalk/conf/default_conf.pb.txt

3.2.5 下载并配置traffic_light包

下载并配置traffic_light包

(1)下载
buildtool install planning-traffic-rules-traffic-light
(2)配置:
buildtool profile config init --package planning-traffic-rules-traffic-light --profile=default
aem profile use default

查看配置是否成功:

ll /apollo/modules/planning/traffic_rules/traffic_light/conf/default_conf.pb.txt

3.2.6 修改traffic_light参数

修改traffic_light参数
在“/application-pnc/profiles/default/modules/planning/traffic_rules/traffic_light/conf/”路径下打开“default_conf.pb.txt”文件修改参数

enabled: true
stop_distance: 1.0
max_stop_deceleration: 4.0

修改为:

enabled: true
stop_distance: 1.2
max_stop_deceleration: 4.0

输入以下命令查看修改的配置是否生效:

cat /apollo/modules/planning/traffic_rules/traffic_light/conf/default_conf.pb.txt

3.2.7 打包

启动Dreamview,打包文件夹

tar -zcvf crosswalk.tar.gz modules/planning/ profiles/default/

3.3 第三题 路口——减速通行

参考链接:https://apollo.baidu.com/community/article/1253

3.3.1 生成插件

执行下述命令,在指定位置生成初始插件文件夹

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.3.2 使配置生效

使用以下命令使生成配置文件且使它生效

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

3.3.3 修改文件名

用指令修改文件名(也可以用VSCode手动修改):

mv modules/planning/traffic_rules/region_speed_limit/plugin_region_speed_limit_description.xml modules/planning/traffic_rules/region_speed_limit/plugins.xml
mv modules/planning/traffic_rules/region_speed_limit/conf/region_speed_limit.pb.txt modules/planning/traffic_rules/region_speed_limit/conf/default_conf.pb.txt

3.3.4 编辑代码

写RegionSpeedLimit类代码文件以及配置相应BUILD文件
1、region_speed_limit.cc

#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>& crosswalk_overlaps
            = reference_line_info->reference_line().map_path().crosswalk_overlaps();
    for (const auto& pnc_junction_overlap : crosswalk_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

2、region_speed_limit.h

#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

3、region_speed_limit/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()

4、plugins.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>

5、修改proto文件的region_speed_limit.proto

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];
}

6、default_conf.pb.txt

forward_buffer: 3.0
backward_buffer: 2.0
limit_speed: 4.0

7、配置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>

8、modules/planning/planning_component/conf/traffic_rule_config.pb.txt 和profiles/default/modules/planning/planning_component/conf/traffic_rule_config.pb.txt
如果没有planning_component包可以用命令“buildtool install planning”下载

rule {
  name: "BACKSIDE_VEHICLE"
  type: "BacksideVehicle"
}
rule {
  name: "CROSSWALK"
  type: "Crosswalk"
}
rule {
  name: "REGION_SPEED_SETTING"
  type: "RegionSpeedLimit"
}
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"
}

3.3.5 查看配置是否生效

查看配置参数是否生效:用命令查看“default_conf.pb.txt”指向的位置

ll /apollo/modules/planning/traffic_rules/region_speed_limit/conf/default_conf.pb.txt


由图可知指向的位置为源码“opt”的目录,所以需要配置生效的话,需要进行“buildtool build -p modules/planning”编译,如果指向“workspace”则不需要。可以用以下命令看参数是否修改成功

cat /opt/apollo/neo/share/modules/planning/traffic_rules/region_speed_limit/conf/default_conf.pb.txt

3.3.6 编译启动

编译插件,启动Dreamview

buildtool build -p modules/planning
aem bootstrap start --plus

3.4 人行道–跟车行驶

3.4.1 下载相关的包

用以下两个命令分别下载lane_borrow_path和path_decider的包

buildtool install planning-task-lane-borrow-path
buildtool install planning-task-path-decider

3.4.2 得80分

该场景下原本的Apollo代码并没有跟车行驶,当前车停下来的时候,该机动车绕道行驶了,而不是跟车等待,所以我们这题采取半暴力解题的方案,当跟车行驶时且前方有交叉路口和行人时,不允许借道,思路如上,我们在相应的包的代码文件lane_borrow_path/lane_borrow_path.cc中添加代码就行了。找到IsNecessaryToBorrowLane,并添加代码,由此可以使机动车不变道而停车,可以得到80分。

bool LaneBorrowPath::IsNecessaryToBorrowLane() {
    auto* mutable_path_decider_status
            = injector_->planning_context()
                      ->mutable_planning_status()
                      ->mutable_path_decider();  // 获取指向路径决策状态的可变指针 mutable_path_decider_status
    if (mutable_path_decider_status
                ->is_in_path_lane_borrow_scenario()) {  // 检查是否当前在借用车道情景中 (is_in_path_lane_borrow_scenario
                                                        // 返回 true)
        UpdateSelfPathInfo();  // 调用 UpdateSelfPathInfo 函数更新自身路径信息
        // If originally borrowing neighbor lane:
        if (use_self_lane_ >= 6) {  // 如果 use_self_lane_ 大于等于 6,表示已经使用自身车道一段时间
            // If have been able to use self-lane for some time, then switch to
            // non-lane-borrowing.
            mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(false);  // 将借用车道情景标志设置为 false
            decided_side_pass_direction_.clear();  // 清空 decided_side_pass_direction_ 向量
            AINFO << "Switch from LANE-BORROW path to SELF-LANE path.";  // 记录信息,表示从借用车道路径切换到自身车道路径。
        }
    } else {
        // If originally not borrowing neighbor lane:
        AINFO << "Blocking obstacle ID[" << mutable_path_decider_status->front_static_obstacle_id()
              << "]";  // 记录当前阻塞障碍物的 ID
        // ADC requirements check for lane-borrowing:
        if (!HasSingleReferenceLine(*frame_)) {  // 检查是否只有一个参考线
            return false;
        }
        if (!IsWithinSidePassingSpeedADC(*frame_)) {  // 检查自动驾驶车辆的速度是否在侧通速度范围内
            return false;
        }

        // Obstacle condition check for lane-borrowing:
        if (!IsBlockingObstacleFarFromIntersection(*reference_line_info_)) {  // 检查是否存在远离交叉路口的阻塞障碍物
            return false;
        }
        if (!IsLongTermBlockingObstacle()) {  // 检查是否存在长期存在的阻塞障碍物
            return false;
        }
        if (!IsBlockingObstacleWithinDestination(*reference_line_info_)) {  // 检查阻塞障碍物是否在目的地范围内
            return false;
        }
        if (!IsSidePassableObstacle(*reference_line_info_)) {  // 检查是否存在可以侧通的障碍物
            return false;
        }
		// 添加的代码
        bool has_stopped_vehicle = false;
        bool has_pedestrian = false;
        constexpr double kStoppedVehicleSpeedThreshold = 0.1;  // Define a suitable threshold

        // Loop through obstacles to check for stopped vehicles and pedestrians
        const auto& path_decision = reference_line_info_->path_decision();
        for (const auto* obstacle : path_decision->obstacles().Items()) {
            const auto& perception_obstacle = obstacle->Perception();
            double obstacle_speed = std::hypot(perception_obstacle.velocity().x(), perception_obstacle.velocity().y());

            if (perception_obstacle.type() == PerceptionObstacle::VEHICLE
                && obstacle_speed < kStoppedVehicleSpeedThreshold) {
                has_stopped_vehicle = true;
            }
            if (perception_obstacle.type() == PerceptionObstacle::PEDESTRIAN) {
                has_pedestrian = true;
            }
            if (has_stopped_vehicle && has_pedestrian) {
                AINFO << "Detected both stopped vehicle and pedestrian ahead, do not borrow lane.";
                return false;
            }
        }
        // 添加的代码到这为止
        // switch to lane-borrowing
        if (decided_side_pass_direction_.empty()) {  // 如果 decided_side_pass_direction_ 为空,表示第一次初始化侧通方向
            // first time init decided_side_pass_direction
            bool left_borrowable;
            bool right_borrowable;
            CheckLaneBorrow(
                    *reference_line_info_,
                    &left_borrowable,
                    &right_borrowable);  // 调用 CheckLaneBorrow 函数检查左右车道是否可以借用
            if (!left_borrowable && !right_borrowable) {
                mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(false);
                AINFO << "LEFT AND RIGHT LANE CAN NOT BORROW";
                return false;  // 如果两侧车道都不可借用,设置借用车道情景标志为 false
            } else {
                mutable_path_decider_status->set_is_in_path_lane_borrow_scenario(
                        true);  // 否则,设置借用车道情景标志为 true,并根据左右车道的可借用情况更新
                                // decided_side_pass_direction_
                if (left_borrowable) {
                    decided_side_pass_direction_.push_back(SidePassDirection::LEFT_BORROW);
                }
                if (right_borrowable) {
                    decided_side_pass_direction_.push_back(SidePassDirection::RIGHT_BORROW);
                }
            }
        }
        use_self_lane_ = 0;
        AINFO << "Switch from SELF-LANE path to LANE-BORROW path.";
    }
    return mutable_path_decider_status
            ->is_in_path_lane_borrow_scenario();  // 记录信息,表示从自身车道路径切换到借用车道路径
}

3.4.3 再得20分

剩下得20分是需要是机动车停在合适得距离,这里也是一个暴力解题思路,找到path_decider/path_decider.cc中相应的位置进行修改。把stop_distance修改为合适的值才能拿到剩下的20分。这里的这个停止墙是第四题的场景的停止墙,修改有效。但是如果在此代码文件中修改代码,当遇到前方有车辆的场景时,去掉这个停止墙的话,Apollo系统会自动生成别的停止墙,此时这个墙不生效,修改无效。

ObjectStop PathDecider::GenerateObjectStopDecision(const Obstacle &obstacle) const {
    ObjectStop object_stop;

    double stop_distance = 1;
    object_stop.set_reason_code(StopReasonCode::STOP_REASON_OBSTACLE);
    object_stop.set_distance_s(-stop_distance);

    const double stop_ref_s = obstacle.PerceptionSLBoundary().start_s() - stop_distance;
    const auto stop_ref_point = reference_line_info_->reference_line().GetReferencePoint(stop_ref_s);
    object_stop.mutable_stop_point()->set_x(stop_ref_point.x());
    object_stop.mutable_stop_point()->set_y(stop_ref_point.y());
    object_stop.set_stop_heading(stop_ref_point.heading());
    return object_stop;
}

3.4.4 编译启动

编译插件,启动Dreamview

buildtool build -p modules/planning
aem bootstrap start --plus

四、说到最后

如果其中有不对的地方或是需要改进的地方,欢迎您及时在评论区指正。
本文到这就结束了,谢谢大家观看,星落希望能够和大家一起进步。我们既然意识到自己的渺小,那就更应该变得强大,我们本来就是渺小的,只是从无知变得有知,你感到痛苦,是因为你在成长,面对困难,跨越困难,人生处处是精彩!

Logo

立足具身智能前沿赛道,致力于搭建全球化、开源化、全栈式技术交流与实践共创平台。

更多推荐