首页 > 编程语言 >【一看就会】Autoware.universe的“规划”部分源码梳理【一】

【一看就会】Autoware.universe的“规划”部分源码梳理【一】

时间:2025-01-17 12:59:16浏览次数:3  
标签:const goal universe route 路径 lanelet 源码 Autoware auto

文章目录


前言

规控不分家,control那边讲完了,这一系列将一下planning这部分。

提前设置一个问题,大家带着解决这个问题的思路去看下面的讲解:如何修改绕障轨迹

planing这部分在官方文档中已经给出了整体说明,肯定比我自己整理要好很多,见连接:https://autowarefoundation.github.io/autoware-documentation/galactic/design/autoware-architecture/planning/

这系列的文章便跟着官方说明文档,进行讲解。

补充一下文件启动流程:
1.planning_simulator.launch.xml
2.autoware.launch.xml
3.tier4_planning_component.launch.xml
4.planning.launch.xml
5.到了这里,和control那的模块节点启动不同,这里是继续启动了五个launch文件:mission_planning.launch.xml,scenario_planning.launch.xml,planning_validator.launch.xml,planning_evaluator.launch.xml,remaining_distance_time_calculator.launch.xml
6.在这五个launch文件里面,又分别启动了planning中别的launch文件。
启动流程就到这里了,再往下就没什么意思了。


一、planning实现的几个功能

在官方文档中,对planning实现的功能进行了简单说明,在此进行相关拓展。

1.规划起点到目标点的路线

目标:确定从车辆当前位置到目标目的地的最佳路径。

关键组件:

全局路径规划:使用高精度地图(如道路网络)计算最佳路线,考虑距离、交通状况和道路类型等因素。

路径点生成:生成一系列中间点(路径点),车辆需要依次经过这些点以到达目的地。

动态重规划:根据实时变化(如道路封闭、交通拥堵)不断更新路线。

在autoware中使用的路径规划算法是基于 Lanelet2 的图搜索算法——A*算法。

几种常见的路径搜索算法原理可以看我另外一篇博客。

2.规划跟随路线的轨迹

目标:生成一条平滑、可行驶的轨迹,使车辆能够沿着路线行驶。

关键组件:

局部轨迹规划:在短时间范围内生成详细的路径(如位置、速度、加速度)。

动态调整:根据障碍物、交通等动态因素实时调整轨迹。

平滑性:确保轨迹在运动学上是可行的(如避免急转弯、平滑的加速度曲线)。

3.确保车辆不与障碍物发生碰撞

目标:检测并避免与静态和动态障碍物(如行人、其他车辆、施工区域)发生碰撞。

关键组件:

障碍物检测:使用传感器(如LiDAR、摄像头、雷达)识别车辆周围的障碍物。

碰撞避免:规划与障碍物保持安全距离的轨迹。

风险评估:评估碰撞的可能性并相应调整轨迹。

4.确保车辆遵守交通规则

目标:确保车辆遵守交通法规,并在复杂环境中表现出可预测的行为。

关键组件:

交通信号灯遵守:检测并响应交通信号灯(如在红灯时停车,绿灯时通行)。

停车线和人行横道处理:在停车线前停车,并在人行横道前礼让行人。

车道遵守:遵循车道标线,避免非法变道,并遵守限速规定。

路权规则:在需要时礼让其他车辆或行人。

5.规划车辆可行的轨迹

目标:确保规划的轨迹在车辆的运动学和动力学上是可行的。

关键组件:

运动学可行性:确保车辆能够执行规划的轨迹,而不会超出其转弯半径、加速度或减速度限制。

动力学可行性:考虑车辆的动力学特性(如轮胎摩擦力、重量分布)以确保稳定性。

舒适性:规划平滑的轨迹以确保乘客舒适(如避免急加速或急刹车)。

二、全局路径生成模块——mission_planner

文件结构:文件夹下有七个cpp文件:
1.mission_planner.cpp:实现路径规划的主逻辑,负责生成和管理车辆的行驶路径。
2.route_selector.cpp:管理主路径(Main Route)和最小风险路径(MRM Route)的切换和恢复。
3. goal_pose_visualizer.cpp:可视化目标位姿,用于调试和监控。
4. service_utils.cpp:提供 ROS 服务调用的工具函数,处理异常和同步调用。
5. utility_functions.cpp:提供通用的工具函数,用于路径规划和管理的辅助操作。
6. default_planner.cpp:路径规划核心文件,实现默认的路径规划算法,基于 Lanelet2 地图生成路径。
7. arrival_checker.cpp:检查车辆是否到达目标点,并更新路径状态。

这部分的launch文件启动了三个节点:
mission_planner:主程序
route_selector
goal_pose_visualizer

接下来会依次介绍这几个文件功能。

主要关注:mission_planner.cpp和default_planner.cpp

1.mission_planner.cpp

1.输入输出:

输入

    订阅的输入:

        里程计 (~/input/odometry):车辆当前的位置和速度信息。

        操作模式状态 (~/input/operation_mode_state):车辆的操作模式(如自动驾驶模式是否启用)。

        矢量地图 (~/input/vector_map):Lanelet2 格式的地图数据。

        修改后的目标点 (~/input/modified_goal):用户或系统修改的目标点。

    服务请求:

        清除路径 (~/clear_route):清除当前路径。

        设置 Lanelet 路径 (~/set_lanelet_route):根据 Lanelet 地图生成路径。

        设置 Waypoint 路径 (~/set_waypoint_route):根据一系列航点生成路径。

输出

    发布的输出:

        路径 (~/route):规划好的路径(LaneletRoute 格式)。

        路径状态 (~/state):当前路径的状态(如 UNSET、SET、ARRIVED 等)。

        路径标记 (~/debug/route_marker):用于可视化的路径标记(如 RViz 中显示的路径)。

    服务响应:

        对路径操作(如设置路径、清除路径)的响应,包含操作是否成功的状态信息。

2.代码流程:

初始化
   |
   v
订阅输入数据(里程计、地图、操作模式等)
   |
   v
等待路径请求(服务或订阅)
   |
   v
路径规划(调用插件生成路径)
   |
   v
安全性检查(重新规划时)
   |
   v
发布路径和状态
   |
   v
检查是否到达目标点
   |
   v
更新路径状态

在这个流程中,会调用service_utils.cpp,route_selector.cpp,arrival_checker.cpp

3.源码注释

// Copyright 2019 Autoware Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mission_planner.hpp"

#include "service_utils.hpp"

#include <autoware_lanelet2_extension/utility/message_conversion.hpp>
#include <autoware_lanelet2_extension/utility/query.hpp>
#include <autoware_lanelet2_extension/utility/route_checker.hpp>
#include <autoware_lanelet2_extension/utility/utilities.hpp>

#include <autoware_map_msgs/msg/lanelet_map_bin.hpp>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>

#include <lanelet2_core/geometry/LineString.h>

#include <algorithm>
#include <utility>

namespace autoware::mission_planner
{

// MissionPlanner 构造函数,初始化节点
MissionPlanner::MissionPlanner(const rclcpp::NodeOptions & options)
: Node("mission_planner", options),
  arrival_checker_(this),  // 初始化到达检查器
  plugin_loader_("autoware_mission_planner", "autoware::mission_planner::PlannerPlugin"),  // 插件加载器
  tf_buffer_(get_clock()),  // TF 缓冲区
  tf_listener_(tf_buffer_),  // TF 监听器
  odometry_(nullptr),  // 初始化里程计为空
  map_ptr_(nullptr)  // 初始化地图指针为空
{
  using std::placeholders::_1;
  using std::placeholders::_2;

  // 从参数服务器获取地图帧名称
  map_frame_ = declare_parameter<std::string>("map_frame");
  // 获取重新规划路径的时间阈值
  reroute_time_threshold_ = declare_parameter<double>("reroute_time_threshold");
  // 获取重新规划路径的最小长度
  minimum_reroute_length_ = declare_parameter<double>("minimum_reroute_length");

  // 创建默认路径规划器插件实例
  planner_ =
    plugin_loader_.createSharedInstance("autoware::mission_planner::lanelet2::DefaultPlanner");
  planner_->initialize(this);  // 初始化路径规划器

  // 设置 QoS 为持久化
  const auto durable_qos = rclcpp::QoS(1).transient_local();
  // 订阅里程计信息
  sub_odometry_ = create_subscription<Odometry>(
    "~/input/odometry", rclcpp::QoS(1), std::bind(&MissionPlanner::on_odometry, this, _1));
  // 订阅操作模式状态
  sub_operation_mode_state_ = create_subscription<OperationModeState>(
    "~/input/operation_mode_state", rclcpp::QoS(1),
    std::bind(&MissionPlanner::on_operation_mode_state, this, _1));
  // 订阅矢量地图
  sub_vector_map_ = create_subscription<LaneletMapBin>(
    "~/input/vector_map", durable_qos, std::bind(&MissionPlanner::on_map, this, _1));
  // 发布路径标记
  pub_marker_ = create_publisher<MarkerArray>("~/debug/route_marker", durable_qos);

  // 注意:路由接口的回调组应该是互斥的
  // 订阅修改后的目标点
  sub_modified_goal_ = create_subscription<PoseWithUuidStamped>(
    "~/input/modified_goal", durable_qos, std::bind(&MissionPlanner::on_modified_goal, this, _1));
  // 创建清除路径服务
  srv_clear_route = create_service<ClearRoute>(
    "~/clear_route", service_utils::handle_exception(&MissionPlanner::on_clear_route, this));
  // 创建设置 Lanelet 路径服务
  srv_set_lanelet_route = create_service<SetLaneletRoute>(
    "~/set_lanelet_route",
    service_utils::handle_exception(&MissionPlanner::on_set_lanelet_route, this));
  // 创建设置 Waypoint 路径服务
  srv_set_waypoint_route = create_service<SetWaypointRoute>(
    "~/set_waypoint_route",
    service_utils::handle_exception(&MissionPlanner::on_set_waypoint_route, this));
  // 发布路径
  pub_route_ = create_publisher<LaneletRoute>("~/route", durable_qos);
  // 发布路径状态
  pub_state_ = create_publisher<RouteState>("~/state", durable_qos);

  // 节点初始化后,当准备好路由 API 时,将发布路由状态
  const auto period = rclcpp::Rate(10).period();
  data_check_timer_ = create_wall_timer(period, [this] { check_initialization(); });

  // 配置日志记录器
  logger_configure_ = std::make_unique<autoware::universe_utils::LoggerLevelConfigure>(this);
}

// 发布位姿日志
void MissionPlanner::publish_pose_log(const Pose & pose, const std::string & pose_type)
{
  const auto & p = pose.position;
  RCLCPP_INFO(
    this->get_logger(), "%s pose - x: %f, y: %f, z: %f", pose_type.c_str(), p.x, p.y, p.z);
  const auto & quaternion = pose.orientation;
  RCLCPP_INFO(
    this->get_logger(), "%s orientation - qx: %f, qy: %f, qz: %f, qw: %f", pose_type.c_str(),
    quaternion.x, quaternion.y, quaternion.z, quaternion.w);
}

// 检查初始化状态
void MissionPlanner::check_initialization()
{
  auto logger = get_logger();
  auto clock = *get_clock();

  // 如果路径规划器未准备好,等待 Lanelet 地图
  if (!planner_->ready()) {
    RCLCPP_INFO_THROTTLE(logger, clock, 5000, "waiting lanelet map... Route API is not ready.");
    return;
  }
  // 如果里程计数据未收到,等待里程计
  if (!odometry_) {
    RCLCPP_INFO_THROTTLE(logger, clock, 5000, "waiting odometry... Route API is not ready.");
    return;
  }

  // 所有数据已准备好,API 可用
  RCLCPP_DEBUG(logger, "Route API is ready.");
  change_state(RouteState::UNSET);

  // 停止定时器回调
  data_check_timer_->cancel();
  data_check_timer_ = nullptr;
}

// 里程计回调函数
void MissionPlanner::on_odometry(const Odometry::ConstSharedPtr msg)
{
  odometry_ = msg;

  // 注意:在其他状态下不要检查,因为目标可能会改变
  if (state_.state == RouteState::SET) {
    PoseStamped pose;
    pose.header = odometry_->header;
    pose.pose = odometry_->pose.pose;
    // 检查是否到达目标点
    if (arrival_checker_.is_arrived(pose)) {
      change_state(RouteState::ARRIVED);
    }
  }
}

// 操作模式状态回调函数
void MissionPlanner::on_operation_mode_state(const OperationModeState::ConstSharedPtr msg)
{
  operation_mode_state_ = msg;
}

// 地图回调函数
void MissionPlanner::on_map(const LaneletMapBin::ConstSharedPtr msg)
{
  map_ptr_ = msg;
  lanelet_map_ptr_ = std::make_shared<lanelet::LaneletMap>();
  lanelet::utils::conversion::fromBinMsg(*map_ptr_, lanelet_map_ptr_);
}

// 转换位姿到地图坐标系
Pose MissionPlanner::transform_pose(const Pose & pose, const Header & header)
{
  geometry_msgs::msg::TransformStamped transform;
  geometry_msgs::msg::Pose result;
  try {
    transform = tf_buffer_.lookupTransform(map_frame_, header.frame_id, tf2::TimePointZero);
    tf2::doTransform(pose, result, transform);
    return result;
  } catch (tf2::TransformException & error) {
    throw service_utils::TransformError(error.what());
  }
}

// 改变路径状态
void MissionPlanner::change_state(RouteState::_state_type state)
{
  state_.stamp = now();
  state_.state = state;
  pub_state_->publish(state_);
}

// 修改目标点回调函数
void MissionPlanner::on_modified_goal(const PoseWithUuidStamped::ConstSharedPtr msg)
{
  RCLCPP_INFO(get_logger(), "Received modified goal.");

  if (state_.state != RouteState::SET) {
    RCLCPP_ERROR(get_logger(), "The route hasn't set yet. Cannot reroute.");
    return;
  }
  if (!planner_->ready()) {
    RCLCPP_ERROR(get_logger(), "The planner is not ready.");
    return;
  }
  if (!odometry_) {
    RCLCPP_ERROR(get_logger(), "The vehicle pose is not received.");
    return;
  }
  if (!current_route_) {
    RCLCPP_ERROR(get_logger(), "The route has not set yet.");
    return;
  }
  if (current_route_->uuid != msg->uuid) {
    RCLCPP_ERROR(get_logger(), "Goal uuid is incorrect.");
    return;
  }

  change_state(RouteState::REROUTING);
  const auto route = create_route(*msg);

  if (route.segments.empty()) {
    cancel_route();
    change_state(RouteState::SET);
    RCLCPP_ERROR(get_logger(), "The planned route is empty.");
  }

  change_route(route);
  change_state(RouteState::SET);
  RCLCPP_INFO(get_logger(), "Changed the route with the modified goal");
}

// 清除路径服务回调函数
void MissionPlanner::on_clear_route(
  const ClearRoute::Request::SharedPtr, const ClearRoute::Response::SharedPtr res)
{
  change_route();
  change_state(RouteState::UNSET);
  res->status.success = true;
}

// 设置 Lanelet 路径服务回调函数
void MissionPlanner::on_set_lanelet_route(
  const SetLaneletRoute::Request::SharedPtr req, const SetLaneletRoute::Response::SharedPtr res)
{
  using ResponseCode = autoware_adapi_v1_msgs::srv::SetRoute::Response;
  const auto is_reroute = state_.state == RouteState::SET;

  if (state_.state != RouteState::UNSET && state_.state != RouteState::SET) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_INVALID_STATE, "The route cannot be set in the current state.");
  }
  if (!planner_->ready()) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_UNREADY, "The planner is not ready.");
  }
  if (!odometry_) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_UNREADY, "The vehicle pose is not received.");
  }
  if (is_reroute && !operation_mode_state_) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_UNREADY, "Operation mode state is not received.");
  }

  const bool is_autonomous_driving =
    operation_mode_state_ ? operation_mode_state_->mode == OperationModeState::AUTONOMOUS &&
                              operation_mode_state_->is_autoware_control_enabled
                          : false;

  if (is_reroute && is_autonomous_driving) {
    const auto reroute_availability = sub_reroute_availability_.takeData();
    if (!reroute_availability || !reroute_availability->availability) {
      throw service_utils::ServiceException(
        ResponseCode::ERROR_INVALID_STATE,
        "Cannot reroute as the planner is not in lane following.");
    }
  }

  change_state(is_reroute ? RouteState::REROUTING : RouteState::ROUTING);
  const auto route = create_route(*req);

  if (route.segments.empty()) {
    cancel_route();
    change_state(is_reroute ? RouteState::SET : RouteState::UNSET);
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_FAILED, "The planned route is empty.");
  }

  if (is_reroute && is_autonomous_driving && !check_reroute_safety(*current_route_, route)) {
    cancel_route();
    change_state(RouteState::SET);
    throw service_utils::ServiceException(
      ResponseCode::ERROR_REROUTE_FAILED, "New route is not safe. Reroute failed.");
  }

  change_route(route);
  change_state(RouteState::SET);
  res->status.success = true;

  publish_pose_log(odometry_->pose.pose, "initial");
  publish_pose_log(req->goal_pose, "goal");
}

// 设置 Waypoint 路径服务回调函数
void MissionPlanner::on_set_waypoint_route(
  const SetWaypointRoute::Request::SharedPtr req, const SetWaypointRoute::Response::SharedPtr res)
{
  using ResponseCode = autoware_adapi_v1_msgs::srv::SetRoutePoints::Response;
  const auto is_reroute = state_.state == RouteState::SET;

  if (state_.state != RouteState::UNSET && state_.state != RouteState::SET) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_INVALID_STATE, "The route cannot be set in the current state.");
  }
  if (!planner_->ready()) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_UNREADY, "The planner is not ready.");
  }
  if (!odometry_) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_UNREADY, "The vehicle pose is not received.");
  }
  if (is_reroute && !operation_mode_state_) {
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_UNREADY, "Operation mode state is not received.");
  }

  const bool is_autonomous_driving =
    operation_mode_state_ ? operation_mode_state_->mode == OperationModeState::AUTONOMOUS &&
                              operation_mode_state_->is_autoware_control_enabled
                          : false;

  if (is_reroute && is_autonomous_driving) {
    const auto reroute_availability = sub_reroute_availability_.takeData();
    if (!reroute_availability || !reroute_availability->availability) {
      throw service_utils::ServiceException(
        ResponseCode::ERROR_INVALID_STATE,
        "Cannot reroute as the planner is not in lane following.");
    }
  }

  change_state(is_reroute ? RouteState::REROUTING : RouteState::ROUTING);
  const auto route = create_route(*req);

  if (route.segments.empty()) {
    cancel_route();
    change_state(is_reroute ? RouteState::SET : RouteState::UNSET);
    throw service_utils::ServiceException(
      ResponseCode::ERROR_PLANNER_FAILED, "The planned route is empty.");
  }

  if (is_reroute && is_autonomous_driving && !check_reroute_safety(*current_route_, route)) {
    cancel_route();
    change_state(RouteState::SET);
    throw service_utils::ServiceException(
      ResponseCode::ERROR_REROUTE_FAILED, "New route is not safe. Reroute failed.");
  }

  change_route(route);
  change_state(RouteState::SET);
  res->status.success = true;

  publish_pose_log(odometry_->pose.pose, "initial");
  publish_pose_log(req->goal_pose, "goal");
}

// 改变路径
void MissionPlanner::change_route()
{
  current_route_ = nullptr;
  planner_->clearRoute();
  arrival_checker_.set_goal();

  // TODO(Takagi, Isamu): 在这里发布一个空路径
  // pub_route_->publish();
  // pub_marker_->publish();
}

// 改变路径
void MissionPlanner::change_route(const LaneletRoute & route)
{
  PoseWithUuidStamped goal;
  goal.header = route.header;
  goal.pose = route.goal_pose;
  goal.uuid = route.uuid;

  current_route_ = std::make_shared<LaneletRoute>(route);
  planner_->updateRoute(route);
  arrival_checker_.set_goal(goal);

  pub_route_->publish(route);
  pub_marker_->publish(planner_->visualize(route));
}

// 取消路径
void MissionPlanner::cancel_route()
{
  // 恢复路径规划器状态
  if (current_route_) {
    planner_->updateRoute(*current_route_);
  }
}

// 创建 Lanelet 路径
LaneletRoute MissionPlanner::create_route(const SetLaneletRoute::Request & req)
{
  const auto & header = req.header;
  const auto & segments = req.segments;
  const auto & goal_pose = req.goal_pose;
  const auto & uuid = req.uuid;
  const auto & allow_goal_modification = req.allow_modification;

  return create_route(header, segments, goal_pose, uuid, allow_goal_modification);
}

// 创建 Waypoint 路径
LaneletRoute MissionPlanner::create_route(const SetWaypointRoute::Request & req)
{
  const auto & header = req.header;
  const auto & waypoints = req.waypoints;
  const auto & goal_pose = req.goal_pose;
  const auto & uuid = req.uuid;
  const auto & allow_goal_modification = req.allow_modification;

  return create_route(header, waypoints, goal_pose, uuid, allow_goal_modification);
}

// 创建路径
LaneletRoute MissionPlanner::create_route(const PoseWithUuidStamped & msg)
{
  const auto & header = msg.header;
  const auto & goal_pose = msg.pose;
  const auto & uuid = msg.uuid;
  const auto & allow_goal_modification = current_route_->allow_modification;

  return create_route(header, std::vector<Pose>(), goal_pose, uuid, allow_goal_modification);
}

// 创建 Lanelet 路径
LaneletRoute MissionPlanner::create_route(
  const Header & header, const std::vector<LaneletSegment> & segments, const Pose & goal_pose,
  const UUID & uuid, const bool allow_goal_modification)
{
  LaneletRoute route;
  route.header.stamp = header.stamp;
  route.header.frame_id = map_frame_;
  route.start_pose = odometry_->pose.pose;
  route.goal_pose = transform_pose(goal_pose, header);
  route.segments = segments;
  route.uuid = uuid;
  route.allow_modification = allow_goal_modification;
  return route;
}

// 创建 Waypoint 路径
LaneletRoute MissionPlanner::create_route(
  const Header & header, const std::vector<Pose> & waypoints, const Pose & goal_pose,
  const UUID & uuid, const bool allow_goal_modification)
{
  PlannerPlugin::RoutePoints points;
  points.push_back(odometry_->pose.pose);
  for (const auto & waypoint : waypoints) {
    points.push_back(transform_pose(waypoint, header));
  }
  points.push_back(transform_pose(goal_pose, header));

  LaneletRoute route = planner_->plan(points);
  route.header.stamp = header.stamp;
  route.header.frame_id = map_frame_;
  route.uuid = uuid;
  route.allow_modification = allow_goal_modification;
  return route;
}

// 检查重新规划路径的安全性
bool MissionPlanner::check_reroute_safety(
  const LaneletRoute & original_route, const LaneletRoute & target_route)
{
  if (
    original_route.segments.empty() || target_route.segments.empty() || !map_ptr_ ||
    !lanelet_map_ptr_ || !odometry_) {
    RCLCPP_ERROR(get_logger(), "Check reroute safety failed. Route, map or odometry is not set.");
    return false;
  }

  const auto current_velocity = odometry_->twist.twist.linear.x;

  // 如果车辆停止,不检查安全性
  if (current_velocity < 0.01) {
    return true;
  }

  auto hasSamePrimitives = [](
                             const std::vector<LaneletPrimitive> & original_primitives,
                             const std::vector<LaneletPrimitive> & target_primitives) {
    if (original_primitives.size() != target_primitives.size()) {
      return false;
    }

    for (const auto & primitive : original_primitives) {
      const auto has_same = [&](const auto & p) { return p.id == primitive.id; };
      const bool is_same =
        std::find_if(target_primitives.begin(), target_primitives.end(), has_same) !=
        target_primitives.end();
      if (!is_same) {
        return false;
      }
    }
    return true;
  };

  // =============================================================================================
  // 注意:目标路径是在车辆在原始路径上行驶时计算的,因此目标路径的第一条车道应在原始路径的车道中。
  // 所以共同段间隔匹配目标路径的开始。例外情况是如果车辆在交叉口车道上,getClosestLanelet() 可能不会返回原始路径中存在的车道。
  // 在这种情况下,共同段间隔不匹配目标车道的开始。
  // =============================================================================================
  const auto start_idx_opt =
    std::invoke([&]() -> std::optional<std::pair<size_t /* original */, size_t /* target */>> {
      for (size_t i = 0; i < original_route.segments.size(); ++i) {
        const auto & original_segment = original_route.segments.at(i).primitives;
        for (size_t j = 0; j < target_route.segments.size(); ++j) {
          const auto & target_segment = target_route.segments.at(j).primitives;
          if (hasSamePrimitives(original_segment, target_segment)) {
            return std::make_pair(i, j);
          }
        }
      }
      return std::nullopt;
    });
  if (!start_idx_opt.has_value()) {
    RCLCPP_ERROR(
      get_logger(), "Check reroute safety failed. Cannot find the start index of the route.");
    return false;
  }
  const auto [start_idx_original, start_idx_target] = start_idx_opt.value();

  // 找到与目标原语匹配的最后一个索引
  size_t end_idx_original = start_idx_original;
  size_t end_idx_target = start_idx_target;
  for (size_t i = 1; i < target_route.segments.size() - start_idx_target; ++i) {
    if (start_idx_original + i > original_route.segments.size() - 1) {
      break;
    }

    const auto & original_primitives =
      original_route.segments.at(start_idx_original + i).primitives;
    const auto & target_primitives = target_route.segments.at(start_idx_target + i).primitives;
    if (!hasSamePrimitives(original_primitives, target_primitives)) {
      break;
    }
    end_idx_original = start_idx_original + i;
    end_idx_target = start_idx_target + i;
  }

  // 在从主路径/MRM 到 MRM/主路径的第一次转换时,route_selector 请求的路径可能不是从当前车道开始的
  const bool ego_is_on_first_target_section = std::any_of(
    target_route.segments.front().primitives.begin(),
    target_route.segments.front().primitives.end(), [&](const auto & primitive) {
      const auto lanelet = lanelet_map_ptr_->laneletLayer.get(primitive.id);
      return lanelet::utils::isInLanelet(target_route.start_pose, lanelet);
    });
  if (!ego_is_on_first_target_section) {
    RCLCPP_ERROR(
      get_logger(),
      "Check reroute safety failed. Ego is not on the first section of target route.");
    return false;
  }

  // 如果目标路径的前面不是共同段的前面,则预计目标路径的前面与另一条车道冲突
  double accumulated_length = 0.0;

  if (start_idx_target != 0 && start_idx_original > 1) {
    // 计算从当前位置到共同段开始的距离
    const auto current_pose = target_route.start_pose;
    const auto primitives = original_route.segments.at(start_idx_original - 1).primitives;
    lanelet::ConstLanelets start_lanelets;
    for (const auto & primitive : primitives) {
      const auto lanelet = lanelet_map_ptr_->laneletLayer.get(primitive.id);
      start_lanelets.push_back(lanelet);
    }
    // 找到最接近的车道
    lanelet::ConstLanelet closest_lanelet;
    if (!lanelet::utils::query::getClosestLanelet(start_lanelets, current_pose, &closest_lanelet)) {
      RCLCPP_ERROR(get_logger(), "Check reroute safety failed. Cannot find the closest lanelet.");
      return false;
    }

    const auto & centerline_2d = lanelet::utils::to2D(closest_lanelet.centerline());
    const auto lanelet_point = lanelet::utils::conversion::toLaneletPoint(current_pose.position);
    const auto arc_coordinates = lanelet::geometry::toArcCoordinates(
      centerline_2d, lanelet::utils::to2D(lanelet_point).basicPoint());
    const double dist_to_current_pose = arc_coordinates.length;
    const double lanelet_length = lanelet::utils::getLaneletLength2d(closest_lanelet);
    accumulated_length = lanelet_length - dist_to_current_pose;
  } else {
    // 计算从当前位置到当前车道末端的距离
    const auto current_pose = target_route.start_pose;
    const auto primitives = original_route.segments.at(start_idx_original).primitives;
    lanelet::ConstLanelets start_lanelets;
    for (const auto & primitive : primitives) {
      const auto lanelet = lanelet_map_ptr_->laneletLayer.get(primitive.id);
      start_lanelets.push_back(lanelet);
    }
    // 找到最接近的车道
    lanelet::ConstLanelet closest_lanelet;
    if (!lanelet::utils::query::getClosestLanelet(start_lanelets, current_pose, &closest_lanelet)) {
      RCLCPP_ERROR(get_logger(), "Check reroute safety failed. Cannot find the closest lanelet.");
      return false;
    }

    const auto & centerline_2d = lanelet::utils::to2D(closest_lanelet.centerline());
    const auto lanelet_point = lanelet::utils::conversion::toLaneletPoint(current_pose.position);
    const auto arc_coordinates = lanelet::geometry::toArcCoordinates(
      centerline_2d, lanelet::utils::to2D(lanelet_point).basicPoint());
    const double dist_to_current_pose = arc_coordinates.length;
    const double lanelet_length = lanelet::utils::getLaneletLength2d(closest_lanelet);
    accumulated_length = lanelet_length - dist_to_current_pose;
  }

  // 计算从 start_idx+1 到 end_idx 的距离
  for (size_t i = start_idx_original + 1; i <= end_idx_original; ++i) {
    const auto primitives = original_route.segments.at(i).primitives;
    if (primitives.empty()) {
      break;
    }

    std::vector<double> lanelets_length(primitives.size());
    for (size_t primitive_idx = 0; primitive_idx < primitives.size(); ++primitive_idx) {
      const auto & primitive = primitives.at(primitive_idx);
      const auto & lanelet = lanelet_map_ptr_->laneletLayer.get(primitive.id);
      lanelets_length.at(primitive_idx) = (lanelet::utils::getLaneletLength2d(lanelet));
    }
    accumulated_length += *std::min_element(lanelets_length.begin(), lanelets_length.end());
  }

  // 检查目标是否在目标终端车道内
  const auto & target_end_primitives = target_route.segments.at(end_idx_target).primitives;
  const auto & target_goal = target_route.goal_pose;
  for (const auto & target_end_primitive : target_end_primitives) {
    const auto lanelet = lanelet_map_ptr_->laneletLayer.get(target_end_primitive.id);
    if (lanelet::utils::isInLanelet(target_goal, lanelet)) {
      const auto target_goal_position =
        lanelet::utils::conversion::toLaneletPoint(target_goal.position);
      const double dist_to_goal = lanelet::geometry::toArcCoordinates(
                                    lanelet::utils::to2D(lanelet.centerline()),
                                    lanelet::utils::to2D(target_goal_position).basicPoint())
                                    .length;
      const double target_lanelet_length = lanelet::utils::getLaneletLength2d(lanelet);
      // 注意:`accumulated_length` 这里包含整个 target_end_primitive 的长度,因此需要减去从目标到 target_end_primitive 末端的剩余距离
      const double remaining_dist = target_lanelet_length - dist_to_goal;
      accumulated_length = std::max(accumulated_length - remaining_dist, 0.0);
      break;
    }
  }

  // 检查安全性
  const double safety_length =
    std::max(current_velocity * reroute_time_threshold_, minimum_reroute_length_);
  if (accumulated_length > safety_length) {
    return true;
  }

  RCLCPP_WARN(
    get_logger(),
    "Length of lane where original and B target (= %f) is less than safety length (= %f), so "
    "reroute is not safe.",
    accumulated_length, safety_length);
  return false;
}
}  // namespace autoware::mission_planner

#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::mission_planner::MissionPlanner)

2.route_selector.cpp

负责管理主路径(Main Route)和应急路径规划模块(MRM Route)的切换和恢复。

1.代码流程

初始化
   |
   v
订阅路径规划器的状态和路径
   |
   v
监听主路径和应急路径规划模块的服务请求
   |
   v
根据当前状态(是否处于应急风险模式)决定是否转发请求
   |
   v
在应急模式下中断主路径,激活应急路径规划模块
   |
   v
应急模式结束后,尝试恢复主路径
   |
   v
发布路径状态和路径

在功能实现中,依赖于service_utils.cpp 中的异常处理功能。

2.输入输出

输入

    服务请求:

        主路径接口:

            清除路径 (~/main/clear_route)。

            设置 Waypoint 路径 (~/main/set_waypoint_route)。

            设置 Lanelet 路径 (~/main/set_lanelet_route)。

        最小风险路径接口:

            清除路径 (~/mrm/clear_route)。

            设置 Waypoint 路径 (~/mrm/set_waypoint_route)。

            设置 Lanelet 路径 (~/mrm/set_lanelet_route)。

    订阅的输入:

        路径规划器的状态 (~/planner/state)。

        路径规划器的路径 (~/planner/route)。

输出

    发布的输出:

        主路径接口:

            路径状态 (~/main/state)。

            路径 (~/main/route)。

        最小风险路径接口:

            路径状态 (~/mrm/state)。

            路径 (~/mrm/route)。

    服务响应:

        对路径操作(如设置路径、清除路径)的响应,包含操作是否成功的状态信息。

3.源码注释

// Copyright 2024 The Autoware Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "route_selector.hpp"

#include "service_utils.hpp"

#include <array>
#include <memory>
#include <random>

namespace autoware::mission_planner::uuid
{

// 生成一个随机的 16 字节 UUID
std::array<uint8_t, 16> generate_random_id()
{
  // 使用随机设备初始化随机数引擎
  static std::independent_bits_engine<std::mt19937, 8, uint8_t> engine(std::random_device{}());
  std::array<uint8_t, 16> id;
  // 生成 16 字节的随机数作为 UUID
  std::generate(id.begin(), id.end(), std::ref(engine));
  return id;
}

// 如果 UUID 为空,则生成一个随机 UUID
UUID generate_if_empty(const UUID & uuid)
{
  // 定义一个全零的 UUID
  constexpr std::array<uint8_t, 16> zero_uuid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

  UUID result;
  // 如果输入的 UUID 是全零,则生成一个随机 UUID,否则使用输入的 UUID
  result.uuid = (uuid.uuid == zero_uuid) ? generate_random_id() : uuid.uuid;
  return result;
}

}  // namespace autoware::mission_planner::uuid

namespace autoware::mission_planner
{

// RouteInterface 构造函数,初始化时钟和状态
RouteInterface::RouteInterface(rclcpp::Clock::SharedPtr clock)
{
  clock_ = clock;
  state_.state = RouteState::UNKNOWN; // 初始状态为 UNKNOWN
}

// 获取当前路径状态
RouteState::_state_type RouteInterface::get_state() const
{
  return state_.state;
}

// 获取当前路径
std::optional<LaneletRoute> RouteInterface::get_route() const
{
  return route_;
}

// 清除当前路径
void RouteInterface::change_route()
{
  route_ = std::nullopt;
}

// 改变路径状态,并发布状态
void RouteInterface::change_state(RouteState::_state_type state)
{
  state_.stamp = clock_->now(); // 更新时间戳
  state_.state = state; // 更新状态
  pub_state_->publish(state_); // 发布状态
}

// 更新路径状态,并发布状态
void RouteInterface::update_state(const RouteState & state)
{
  state_ = state; // 更新状态
  pub_state_->publish(state_); // 发布状态
}

// 更新路径,并发布路径
void RouteInterface::update_route(const LaneletRoute & route)
{
  route_ = route; // 更新路径
  pub_route_->publish(route); // 发布路径
}

// RouteSelector 构造函数,初始化主路径和最小风险路径接口
RouteSelector::RouteSelector(const rclcpp::NodeOptions & options)
: Node("route_selector", options), main_(get_clock()), mrm_(get_clock())
{
  using std::placeholders::_1;
  using std::placeholders::_2;
  const auto service_qos = rmw_qos_profile_services_default; // 服务 QoS
  const auto durable_qos = rclcpp::QoS(1).transient_local(); // 持久化 QoS

  // 初始化主路径接口
  main_.srv_clear_route = create_service<ClearRoute>(
    "~/main/clear_route",
    service_utils::handle_exception(&RouteSelector::on_clear_route_main, this));
  main_.srv_set_waypoint_route = create_service<SetWaypointRoute>(
    "~/main/set_waypoint_route",
    service_utils::handle_exception(&RouteSelector::on_set_waypoint_route_main, this));
  main_.srv_set_lanelet_route = create_service<SetLaneletRoute>(
    "~/main/set_lanelet_route",
    service_utils::handle_exception(&RouteSelector::on_set_lanelet_route_main, this));
  main_.pub_state_ = create_publisher<RouteState>("~/main/state", durable_qos); // 发布主路径状态
  main_.pub_route_ = create_publisher<LaneletRoute>("~/main/route", durable_qos); // 发布主路径

  // 初始化最小风险路径接口
  mrm_.srv_clear_route = create_service<ClearRoute>(
    "~/mrm/clear_route", service_utils::handle_exception(&RouteSelector::on_clear_route_mrm, this));
  mrm_.srv_set_waypoint_route = create_service<SetWaypointRoute>(
    "~/mrm/set_waypoint_route",
    service_utils::handle_exception(&RouteSelector::on_set_waypoint_route_mrm, this));
  mrm_.srv_set_lanelet_route = create_service<SetLaneletRoute>(
    "~/mrm/set_lanelet_route",
    service_utils::handle_exception(&RouteSelector::on_set_lanelet_route_mrm, this));
  mrm_.pub_state_ = create_publisher<RouteState>("~/mrm/state", durable_qos); // 发布最小风险路径状态
  mrm_.pub_route_ = create_publisher<LaneletRoute>("~/mrm/route", durable_qos); // 发布最小风险路径

  // 初始化路径规划器接口
  group_ = create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); // 创建回调组
  cli_clear_route_ = create_client<ClearRoute>("~/planner/clear_route", service_qos, group_); // 清除路径客户端
  cli_set_lanelet_route_ =
    create_client<SetLaneletRoute>("~/planner/set_lanelet_route", service_qos, group_); // 设置 Lanelet 路径客户端
  cli_set_waypoint_route_ =
    create_client<SetWaypointRoute>("~/planner/set_waypoint_route", service_qos, group_); // 设置 Waypoint 路径客户端
  sub_state_ = create_subscription<RouteState>(
    "~/planner/state", durable_qos, std::bind(&RouteSelector::on_state, this, _1)); // 订阅路径状态
  sub_route_ = create_subscription<LaneletRoute>(
    "~/planner/route", durable_qos, std::bind(&RouteSelector::on_route, this, _1)); // 订阅路径

  // 设置初始状态
  main_.change_state(RouteState::INITIALIZING); // 主路径状态为初始化中
  mrm_.change_state(RouteState::INITIALIZING); // 最小风险路径状态为初始化中
  initialized_ = false; // 初始化标志为 false
  mrm_operating_ = false; // 最小风险模式标志为 false
  main_request_ = std::monostate{}; // 主路径请求初始化为空
}

// 路径状态回调函数
void RouteSelector::on_state(const RouteState::ConstSharedPtr msg)
{
  // 如果路径规划器状态为 UNSET 且未初始化,则初始化主路径和最小风险路径状态
  if (msg->state == RouteState::UNSET && !initialized_) {
    main_.change_state(RouteState::UNSET);
    mrm_.change_state(RouteState::UNSET);
    initialized_ = true; // 标记为已初始化
  }

  // 根据是否处于最小风险模式,更新主路径或最小风险路径状态
  (mrm_operating_ ? mrm_ : main_).update_state(*msg);
}

// 路径回调函数
void RouteSelector::on_route(const LaneletRoute::ConstSharedPtr msg)
{
  // 根据是否处于最小风险模式,更新主路径或最小风险路径
  (mrm_operating_ ? mrm_ : main_).update_route(*msg);
}

// 清除主路径服务回调函数
void RouteSelector::on_clear_route_main(
  ClearRoute::Request::SharedPtr req, ClearRoute::Response::SharedPtr res)
{
  // 保存请求并清除旧路径,以便从最小风险模式恢复
  main_request_ = std::monostate{};
  main_.change_route();

  // 如果处于最小风险模式,仅改变状态
  if (mrm_operating_) {
    main_.change_state(RouteState::UNSET);
    res->status.success = true;
    return;
  }

  // 如果未处于最小风险模式,则转发请求
  res->status = service_utils::sync_call(cli_clear_route_, req);
}

// 设置 Waypoint 主路径服务回调函数
void RouteSelector::on_set_waypoint_route_main(
  SetWaypointRoute::Request::SharedPtr req, SetWaypointRoute::Response::SharedPtr res)
{
  // 保存请求并清除旧路径,以便从最小风险模式恢复
  req->uuid = uuid::generate_if_empty(req->uuid); // 如果 UUID 为空,则生成一个随机 UUID
  main_request_ = req;
  main_.change_route();

  // 如果处于最小风险模式,仅改变状态
  if (mrm_operating_) {
    main_.change_state(RouteState::INTERRUPTED);
    res->status.success = true;
    return;
  }

  // 如果未处于最小风险模式,则转发请求
  res->status = service_utils::sync_call(cli_set_waypoint_route_, req);
}

// 设置 Lanelet 主路径服务回调函数
void RouteSelector::on_set_lanelet_route_main(
  SetLaneletRoute::Request::SharedPtr req, SetLaneletRoute::Response::SharedPtr res)
{
  // 保存请求并清除旧路径,以便从最小风险模式恢复
  req->uuid = uuid::generate_if_empty(req->uuid); // 如果 UUID 为空,则生成一个随机 UUID
  main_request_ = req;
  main_.change_route();

  // 如果处于最小风险模式,仅改变状态
  if (mrm_operating_) {
    main_.change_state(RouteState::INTERRUPTED);
    res->status.success = true;
    return;
  }

  // 如果未处于最小风险模式,则转发请求
  res->status = service_utils::sync_call(cli_set_lanelet_route_, req);
}

// 清除最小风险路径服务回调函数
void RouteSelector::on_clear_route_mrm(
  ClearRoute::Request::SharedPtr req, ClearRoute::Response::SharedPtr res)
{
  // 尝试恢复主路径
  res->status = resume_main_route(req);

  // 如果恢复成功,则退出最小风险模式
  if (res->status.success) {
    mrm_operating_ = false;
    mrm_.change_state(RouteState::UNSET);
  }
}

// 设置 Waypoint 最小风险路径服务回调函数
void RouteSelector::on_set_waypoint_route_mrm(
  SetWaypointRoute::Request::SharedPtr req, SetWaypointRoute::Response::SharedPtr res)
{
  // 如果 UUID 为空,则生成一个随机 UUID
  req->uuid = uuid::generate_if_empty(req->uuid);
  // 转发请求
  res->status = service_utils::sync_call(cli_set_waypoint_route_, req);

  // 如果请求成功,则进入最小风险模式
  if (res->status.success) {
    mrm_operating_ = true;
    if (main_.get_state() != RouteState::UNSET) {
      main_.change_state(RouteState::INTERRUPTED); // 中断主路径
    }
  }
}

// 设置 Lanelet 最小风险路径服务回调函数
void RouteSelector::on_set_lanelet_route_mrm(
  SetLaneletRoute::Request::SharedPtr req, SetLaneletRoute::Response::SharedPtr res)
{
  // 如果 UUID 为空,则生成一个随机 UUID
  req->uuid = uuid::generate_if_empty(req->uuid);
  // 转发请求
  res->status = service_utils::sync_call(cli_set_lanelet_route_, req);

  // 如果请求成功,则进入最小风险模式
  if (res->status.success) {
    mrm_operating_ = true;
    if (main_.get_state() != RouteState::UNSET) {
      main_.change_state(RouteState::INTERRUPTED); // 中断主路径
    }
  }
}

// 恢复主路径
ResponseStatus RouteSelector::resume_main_route(ClearRoute::Request::SharedPtr req)
{
  // 创建一个 Lanelet 路径请求
  const auto create_lanelet_request = [](const LaneletRoute & route) {
    const auto r = std::make_shared<SetLaneletRoute::Request>();
    r->header = route.header;
    r->goal_pose = route.goal_pose;
    r->segments = route.segments;
    r->uuid = route.uuid;
    r->allow_modification = route.allow_modification;
    return r;
  };

  // 创建一个 Waypoint 路径请求
  const auto create_goal_request = [](const auto & request) {
    const auto r = std::make_shared<SetWaypointRoute::Request>();
    r->header = request->header;
    r->goal_pose = request->goal_pose;
    r->uuid = request->uuid;
    r->allow_modification = request->allow_modification;
    return r;
  };

  // 如果没有主路径请求,则清除路径
  if (std::holds_alternative<std::monostate>(main_request_)) {
    return service_utils::sync_call(cli_clear_route_, req);
  }

  // 如果有主路径请求,则尝试恢复主路径
  if (const auto route = main_.get_route()) {
    const auto r = create_lanelet_request(route.value());
    const auto status = service_utils::sync_call(cli_set_lanelet_route_, r);
    if (status.success) return status;
  }

  // 如果恢复失败,则使用目标点重新规划主路径
  if (const auto request = std::get_if<WaypointRequest>(&main_request_)) {
    const auto r = create_goal_request(*request);
    return service_utils::sync_call(cli_set_waypoint_route_, r);
  }
  if (const auto request = std::get_if<LaneletRequest>(&main_request_)) {
    const auto r = create_goal_request(*request);
    return service_utils::sync_call(cli_set_waypoint_route_, r);
  }
  throw std::logic_error("route_selector: unknown main route request");
}

}  // namespace autoware::mission_planner

#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::mission_planner::RouteSelector)

3.goal_pose_visualizer

这个主要作用是负责可视化目标位置。它订阅路由消息并发布目标位置的可视化信息。

主要和与 mission_planner.cpp 和 route_selector.cpp 交互,接收路由信息并发布目标位置。

// Copyright 2020 Tier IV, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef GOAL_POSE_VISUALIZER__GOAL_POSE_VISUALIZER_HPP_
#define GOAL_POSE_VISUALIZER__GOAL_POSE_VISUALIZER_HPP_

#include <rclcpp/rclcpp.hpp> // ROS 2 C++ 客户端库

#include <autoware_planning_msgs/msg/lanelet_route.hpp> // Lanelet 路径消息类型
#include <geometry_msgs/msg/pose_stamped.hpp> // 位姿消息类型

namespace autoware::mission_planner
{

// GoalPoseVisualizer 类,用于可视化目标位姿
class GoalPoseVisualizer : public rclcpp::Node
{
public:
  // 构造函数,接受节点选项
  explicit GoalPoseVisualizer(const rclcpp::NodeOptions & node_options);

private:
  // 订阅 Lanelet 路径的订阅器
  rclcpp::Subscription<autoware_planning_msgs::msg::LaneletRoute>::SharedPtr sub_route_;
  // 发布目标位姿的发布器
  rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr pub_goal_pose_;

  // Lanelet 路径的回调函数
  void echo_back_route_callback(
    const autoware_planning_msgs::msg::LaneletRoute::ConstSharedPtr msg);
};

}  // namespace autoware::mission_planner

#endif  // GOAL_POSE_VISUALIZER__GOAL_POSE_VISUALIZER_HPP_

4. service_utils.cpp

#include "service_utils.hpp" // 引入服务工具头文件

#include <string> // 引入字符串库

namespace service_utils // 命名空间:service_utils
{

// 创建一个表示服务未准备好的异常
ServiceException ServiceUnready(const std::string & message)
{
  // 返回一个 ServiceException 对象,状态为 SERVICE_UNREADY,附带错误信息
  return ServiceException(ResponseStatus::SERVICE_UNREADY, message, false);
}

// 创建一个表示坐标转换错误的异常
ServiceException TransformError(const std::string & message)
{
  // 返回一个 ServiceException 对象,状态为 TRANSFORM_ERROR,附带错误信息
  return ServiceException(ResponseStatus::TRANSFORM_ERROR, message, false);
};

}  // namespace service_utils

5. utility_functions.cpp

实现了四个工具函数:
convert_linear_ring_to_polygon:

    将线性环(LinearRing)转换为多边形(Polygon)。

    用于处理车辆或障碍物的几何形状。

insert_marker_array:

    将一个 MarkerArray 插入到另一个 MarkerArray 中。

    用于合并可视化数据。

convertCenterlineToPoints:

    将 Lanelet 的中心线转换为点集。

    用于提取车道中心线的几何信息。

convertBasicPoint3dToPose:

    将 Lanelet 的 BasicPoint3d 转换为 Pose,并设置方向。

    用于生成目标位姿或路径点。
// Copyright 2019-2024 Autoware Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "utility_functions.hpp" // 引入工具函数头文件

#include <boost/geometry.hpp> // 引入 Boost Geometry 库,用于几何计算

#include <lanelet2_core/geometry/Lanelet.h> // 引入 Lanelet2 库,用于处理车道数据

// 将线性环(LinearRing)转换为多边形(Polygon)
autoware::universe_utils::Polygon2d convert_linear_ring_to_polygon(
  autoware::universe_utils::LinearRing2d footprint)
{
  autoware::universe_utils::Polygon2d footprint_polygon; // 创建一个多边形对象
  // 将线性环的顶点依次添加到多边形的外环中
  boost::geometry::append(footprint_polygon.outer(), footprint[0]);
  boost::geometry::append(footprint_polygon.outer(), footprint[1]);
  boost::geometry::append(footprint_polygon.outer(), footprint[2]);
  boost::geometry::append(footprint_polygon.outer(), footprint[3]);
  boost::geometry::append(footprint_polygon.outer(), footprint[4]);
  boost::geometry::append(footprint_polygon.outer(), footprint[5]);
  boost::geometry::correct(footprint_polygon); // 修正多边形的几何结构
  return footprint_polygon; // 返回转换后的多边形
}

// 将一个 MarkerArray 插入到另一个 MarkerArray 中
void insert_marker_array(
  visualization_msgs::msg::MarkerArray * a1, const visualization_msgs::msg::MarkerArray & a2)
{
  // 将 a2 的 markers 插入到 a1 的 markers 末尾
  a1->markers.insert(a1->markers.end(), a2.markers.begin(), a2.markers.end());
}

// 将 Lanelet 的中心线转换为点集
std::vector<geometry_msgs::msg::Point> convertCenterlineToPoints(const lanelet::Lanelet & lanelet)
{
  std::vector<geometry_msgs::msg::Point> centerline_points; // 创建一个点集
  // 遍历 Lanelet 的中心线,将每个点转换为 geometry_msgs::msg::Point
  for (const auto & point : lanelet.centerline()) {
    geometry_msgs::msg::Point center_point;
    center_point.x = point.basicPoint().x(); // 设置点的 x 坐标
    center_point.y = point.basicPoint().y(); // 设置点的 y 坐标
    center_point.z = point.basicPoint().z(); // 设置点的 z 坐标
    centerline_points.push_back(center_point); // 将点添加到点集中
  }
  return centerline_points; // 返回转换后的点集
}

// 将 Lanelet 的 BasicPoint3d 转换为 Pose,并设置方向
geometry_msgs::msg::Pose convertBasicPoint3dToPose(
  const lanelet::BasicPoint3d & point, const double lane_yaw)
{
  // 创建一个 Pose 对象
  geometry_msgs::msg::Pose pose;
  // 设置 Pose 的位置
  pose.position.x = point.x(); // 设置 x 坐标
  pose.position.y = point.y(); // 设置 y 坐标
  pose.position.z = point.z(); // 设置 z 坐标

  // 设置 Pose 的方向(四元数),根据给定的 yaw 角度
  pose.orientation = autoware::universe_utils::createQuaternionFromYaw(lane_yaw);

  return pose; // 返回转换后的 Pose
}

6. default_planner.cpp

这部分是路径规划的核心。
是一个基于 Lanelet2 地图的默认路径规划器,负责根据起点和目标点生成车辆的行驶路径。

1.代码流程图

初始化
   |
   v
加载地图
   |
   v
等待路径规划请求
   |
   v
生成路径
   |
   v
检查目标点有效性
   |
   v
校正目标点高度
   |
   v
返回规划的路径
   |
   v
发布可视化标记
1.核心逻辑

其中的核心函数:PlannerPlugin::LaneletRoute DefaultPlanner::plan(const RoutePoints & points);
其中路径生成的核心调用是:route_handler_.planPathLaneletsBetweenCheckpoints(
start_check_point, goal_check_point, &path_lanelets, param_.consider_no_drivable_lanes);

参数说明:

参数说明:

    start_check_point:起点位姿。

    goal_check_point:目标点位姿。

    path_lanelets:输出的路径车道。

    param_.consider_no_drivable_lanes:是否考虑不可行驶车道。

主要逻辑为:

    输入:

        起点和目标点的位姿。

        Lanelet2 地图数据。

    路径生成步骤:

        查找起点和目标点所在的车道:

            使用 Lanelet2 的查询工具(如 getClosestLanelet)找到起点和目标点所在的车道。

        搜索路径:

            使用图搜索算法(如 Dijkstra 或 A*)在 Lanelet2 地图的车道网络中搜索从起点车道到目标车道的路径。

        生成路径车道:

            将搜索到的车道序列转换为路径车道(lanelet::ConstLanelets)。

    路径优化:

        对生成的车道序列进行优化,确保路径的平滑性和连续性。

2.输入输出

输入

    地图数据:

        通过订阅 ~/input/vector_map 话题或直接传入 LaneletMapBin 消息,加载 Lanelet2 地图。

    路径规划请求:

        通过 plan 函数传入的 RoutePoints(起点和目标点的位姿列表)。

    车辆信息:

        通过 VehicleInfo 获取车辆的几何信息(如车轮距、悬垂等)。

    参数配置:

        通过 ROS 参数服务器配置路径规划器的行为(如目标点角度阈值、是否启用目标点位姿校正等)。

输出

    规划的路径:

        返回 LaneletRoute 消息,包含路径的起点、目标点和路径段。

    可视化标记:

        发布 MarkerArray 消息,用于在 RViz 中可视化路径和目标点足迹。

    调试信息:

        发布目标点足迹的可视化标记(~/debug/goal_footprint 话题)。

3.源码注释

// Copyright 2019-2024 Autoware Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "default_planner.hpp" // 引入默认路径规划器头文件

#include "utility_functions.hpp" // 引入工具函数头文件

#include <autoware/motion_utils/trajectory/trajectory.hpp> // 引入运动规划工具库
#include <autoware/route_handler/route_handler.hpp> // 引入路径处理器库
#include <autoware/universe_utils/geometry/geometry.hpp> // 引入几何工具库
#include <autoware/universe_utils/math/normalization.hpp> // 引入数学工具库(归一化)
#include <autoware/universe_utils/math/unit_conversion.hpp> // 引入数学工具库(单位转换)
#include <autoware/universe_utils/ros/marker_helper.hpp> // 引入 ROS 可视化工具库
#include <autoware_lanelet2_extension/utility/message_conversion.hpp> // 引入 Lanelet2 消息转换工具
#include <autoware_lanelet2_extension/utility/query.hpp> // 引入 Lanelet2 查询工具
#include <autoware_lanelet2_extension/utility/utilities.hpp> // 引入 Lanelet2 工具库
#include <autoware_lanelet2_extension/visualization/visualization.hpp> // 引入 Lanelet2 可视化工具
#include <autoware_vehicle_info_utils/vehicle_info_utils.hpp> // 引入车辆信息工具库

#include <boost/geometry/algorithms/difference.hpp> // 引入 Boost Geometry 差异算法
#include <boost/geometry/algorithms/is_empty.hpp> // 引入 Boost Geometry 空集判断算法

#include <lanelet2_core/Forward.h> // 引入 Lanelet2 核心库
#include <lanelet2_core/LaneletMap.h> // 引入 Lanelet2 地图库
#include <lanelet2_core/geometry/BoundingBox.h> // 引入 Lanelet2 几何库(边界框)
#include <lanelet2_core/geometry/Lanelet.h> // 引入 Lanelet2 几何库(车道)
#include <tf2/utils.h> // 引入 TF2 工具库

#include <limits> // 引入数值极限库
#include <vector> // 引入向量库

namespace
{
using RouteSections = std::vector<autoware_planning_msgs::msg::LaneletSegment>; // 定义路径段类型

// 检查点是否在车道内
bool is_in_lane(const lanelet::ConstLanelet & lanelet, const lanelet::ConstPoint3d & point)
{
  // 计算点与车道多边形的最小距离
  const auto distance = boost::geometry::distance(
    lanelet.polygon2d().basicPolygon(), lanelet::utils::to2D(point).basicPoint());
  constexpr double th_distance = std::numeric_limits<double>::epsilon(); // 距离阈值
  return distance < th_distance; // 如果距离小于阈值,则点在车道内
}

// 检查点是否在停车位内
bool is_in_parking_space(
  const lanelet::ConstLineStrings3d & parking_spaces, const lanelet::ConstPoint3d & point)
{
  for (const auto & parking_space : parking_spaces) {
    lanelet::ConstPolygon3d parking_space_polygon;
    // 将停车位线串转换为多边形
    if (!lanelet::utils::lineStringWithWidthToPolygon(parking_space, &parking_space_polygon)) {
      continue;
    }

    // 计算点与停车位多边形的最小距离
    const double distance = boost::geometry::distance(
      lanelet::utils::to2D(parking_space_polygon).basicPolygon(),
      lanelet::utils::to2D(point).basicPoint());
    constexpr double th_distance = std::numeric_limits<double>::epsilon(); // 距离阈值
    if (distance < th_distance) {
      return true; // 如果距离小于阈值,则点在停车位内
    }
  }
  return false; // 点不在任何停车位内
}

// 检查点是否在停车场内
bool is_in_parking_lot(
  const lanelet::ConstPolygons3d & parking_lots, const lanelet::ConstPoint3d & point)
{
  for (const auto & parking_lot : parking_lots) {
    // 计算点与停车场多边形的最小距离
    const double distance = boost::geometry::distance(
      lanelet::utils::to2D(parking_lot).basicPolygon(), lanelet::utils::to2D(point).basicPoint());
    constexpr double th_distance = std::numeric_limits<double>::epsilon(); // 距离阈值
    if (distance < th_distance) {
      return true; // 如果距离小于阈值,则点在停车场内
    }
  }
  return false; // 点不在任何停车场内
}

// 将目标点投影到地图上,并返回其高度
double project_goal_to_map(
  const lanelet::ConstLanelet & lanelet_component, const lanelet::ConstPoint3d & goal_point)
{
  // 生成车道的精细中心线
  const lanelet::ConstLineString3d center_line =
    lanelet::utils::generateFineCenterline(lanelet_component);
  // 将目标点投影到中心线上
  lanelet::BasicPoint3d project = lanelet::geometry::project(center_line, goal_point.basicPoint());
  return project.z(); // 返回投影点的高度
}

// 获取最接近中心线的位姿
geometry_msgs::msg::Pose get_closest_centerline_pose(
  const lanelet::ConstLanelets & road_lanelets, const geometry_msgs::msg::Pose & point,
  autoware::vehicle_info_utils::VehicleInfo vehicle_info)
{
  lanelet::Lanelet closest_lanelet;
  // 获取最接近的车道
  if (!lanelet::utils::query::getClosestLaneletWithConstrains(
        road_lanelets, point, &closest_lanelet, 0.0)) {
    // 如果点不在任何车道内,则返回原始点
    return point;
  }

  // 生成车道的精细中心线
  const auto refined_center_line = lanelet::utils::generateFineCenterline(closest_lanelet, 1.0);
  closest_lanelet.setCenterline(refined_center_line);

  // 计算车道的偏航角
  const double lane_yaw = lanelet::utils::getLaneletAngle(closest_lanelet, point.position);

  // 找到最接近的点
  const auto nearest_idx = autoware::motion_utils::findNearestIndex(
    convertCenterlineToPoints(closest_lanelet), point.position);
  const auto nearest_point = closest_lanelet.centerline()[nearest_idx];

  // 根据车辆的左右悬垂调整点的位置
  const auto shift_length = (vehicle_info.right_overhang_m - vehicle_info.left_overhang_m) / 2.0;
  const auto delta_x = -shift_length * std::sin(lane_yaw);
  const auto delta_y = shift_length * std::cos(lane_yaw);

  lanelet::BasicPoint3d refined_point(
    nearest_point.x() + delta_x, nearest_point.y() + delta_y, nearest_point.z());

  // 将调整后的点转换为位姿
  return convertBasicPoint3dToPose(refined_point, lane_yaw);
}

}  // anonymous namespace

namespace autoware::mission_planner::lanelet2
{

// 初始化默认路径规划器的通用部分
void DefaultPlanner::initialize_common(rclcpp::Node * node)
{
  is_graph_ready_ = false; // 标记图未准备好
  node_ = node; // 保存节点指针

  const auto durable_qos = rclcpp::QoS(1).transient_local();
  // 创建目标点足迹的调试标记发布器
  pub_goal_footprint_marker_ =
    node_->create_publisher<MarkerArray>("~/debug/goal_footprint", durable_qos);

  // 获取车辆信息
  vehicle_info_ = autoware::vehicle_info_utils::VehicleInfoUtils(*node_).getVehicleInfo();
  // 声明参数
  param_.goal_angle_threshold_deg = node_->declare_parameter<double>("goal_angle_threshold_deg");
  param_.enable_correct_goal_pose = node_->declare_parameter<bool>("enable_correct_goal_pose");
  param_.consider_no_drivable_lanes = node_->declare_parameter<bool>("consider_no_drivable_lanes");
  param_.check_footprint_inside_lanes =
    node_->declare_parameter<bool>("check_footprint_inside_lanes");
}

// 初始化默认路径规划器(通过订阅地图)
void DefaultPlanner::initialize(rclcpp::Node * node)
{
  initialize_common(node);
  // 创建地图订阅器
  map_subscriber_ = node_->create_subscription<LaneletMapBin>(
    "~/input/vector_map", rclcpp::QoS{10}.transient_local(),
    std::bind(&DefaultPlanner::map_callback, this, std::placeholders::_1));
}

// 初始化默认路径规划器(通过传入地图消息)
void DefaultPlanner::initialize(rclcpp::Node * node, const LaneletMapBin::ConstSharedPtr msg)
{
  initialize_common(node);
  map_callback(msg); // 直接处理地图消息
}

// 检查路径规划器是否准备好
bool DefaultPlanner::ready() const
{
  return is_graph_ready_; // 返回图是否准备好的标志
}

// 地图回调函数
void DefaultPlanner::map_callback(const LaneletMapBin::ConstSharedPtr msg)
{
  route_handler_.setMap(*msg); // 设置路径处理器中的地图
  is_graph_ready_ = true; // 标记图已准备好
}

// 可视化路径
PlannerPlugin::MarkerArray DefaultPlanner::visualize(const LaneletRoute & route) const
{
  lanelet::ConstLanelets route_lanelets; // 路径车道
  lanelet::ConstLanelets end_lanelets; // 结束车道
  lanelet::ConstLanelets goal_lanelets; // 目标车道

  // 遍历路径段,提取车道信息
  for (const auto & route_section : route.segments) {
    for (const auto & lane_id : route_section.primitives) {
      auto lanelet = route_handler_.getLaneletsFromId(lane_id.id);
      route_lanelets.push_back(lanelet);
      if (route_section.preferred_primitive.id == lane_id.id) {
        goal_lanelets.push_back(lanelet); // 目标车道
      } else {
        end_lanelets.push_back(lanelet); // 结束车道
      }
    }
  }

  // 定义颜色
  const std_msgs::msg::ColorRGBA cl_route =
    autoware::universe_utils::createMarkerColor(0.8, 0.99, 0.8, 0.15);
  const std_msgs::msg::ColorRGBA cl_ll_borders =
    autoware::universe_utils::createMarkerColor(1.0, 1.0, 1.0, 0.999);
  const std_msgs::msg::ColorRGBA cl_end =
    autoware::universe_utils::createMarkerColor(0.2, 0.2, 0.4, 0.05);
  const std_msgs::msg::ColorRGBA cl_goal =
    autoware::universe_utils::createMarkerColor(0.2, 0.4, 0.4, 0.05);

  // 创建路径标记数组
  visualization_msgs::msg::MarkerArray route_marker_array;
  insert_marker_array(
    &route_marker_array,
    lanelet::visualization::laneletsBoundaryAsMarkerArray(route_lanelets, cl_ll_borders, false));
  insert_marker_array(
    &route_marker_array, lanelet::visualization::laneletsAsTriangleMarkerArray(
                           "route_lanelets", route_lanelets, cl_route));
  insert_marker_array(
    &route_marker_array,
    lanelet::visualization::laneletsAsTriangleMarkerArray("end_lanelets", end_lanelets, cl_end));
  insert_marker_array(
    &route_marker_array,
    lanelet::visualization::laneletsAsTriangleMarkerArray("goal_lanelets", goal_lanelets, cl_goal));

  return route_marker_array; // 返回路径标记数组
}

// 可视化调试足迹
visualization_msgs::msg::MarkerArray DefaultPlanner::visualize_debug_footprint(
  autoware::universe_utils::LinearRing2d goal_footprint)
{
  visualization_msgs::msg::MarkerArray msg;
  // 创建默认标记
  auto marker = autoware::universe_utils::createDefaultMarker(
    "map", rclcpp::Clock().now(), "goal_footprint", 0, visualization_msgs::msg::Marker::LINE_STRIP,
    autoware::universe_utils::createMarkerScale(0.05, 0.0, 0.0),
    autoware::universe_utils::createMarkerColor(0.99, 0.99, 0.2, 1.0));
  marker.lifetime = rclcpp::Duration::from_seconds(2.5); // 设置标记的生命周期

  // 添加足迹的点
  marker.points.push_back(
    autoware::universe_utils::createPoint(goal_footprint[0][0], goal_footprint[0][1], 0.0));
  marker.points.push_back(
    autoware::universe_utils::createPoint(goal_footprint[1][0], goal_footprint[1][1], 0.0));
  marker.points.push_back(
    autoware::universe_utils::createPoint(goal_footprint[2][0], goal_footprint[2][1], 0.0));
  marker.points.push_back(
    autoware::universe_utils::createPoint(goal_footprint[3][0], goal_footprint[3][1], 0.0));
  marker.points.push_back(
    autoware::universe_utils::createPoint(goal_footprint[4][0], goal_footprint[4][1], 0.0));
  marker.points.push_back(
    autoware::universe_utils::createPoint(goal_footprint[5][0], goal_footprint[5][1], 0.0));
  marker.points.push_back(marker.points.front()); // 闭合足迹

  msg.markers.push_back(marker); // 添加标记到数组
  return msg; // 返回标记数组
}

// 获取从起始车道到指定距离内的所有后续车道
lanelet::ConstLanelets next_lanelets_up_to(
  const lanelet::ConstLanelet & start_lanelet, const double up_to_distance,
  const route_handler::RouteHandler & route_handler)
{
  lanelet::ConstLanelets lanelets;
  if (up_to_distance <= 0.0) {
    return lanelets;
  }
  // 获取当前车道的后续车道
  for (const auto & next_lane : route_handler.getNextLanelets(start_lanelet)) {
    lanelets.push_back(next_lane);
    // 递归获取后续车道的后续车道
    const auto next_lanelets = next_lanelets_up_to(
      next_lane, up_to_distance - lanelet::geometry::length2d(next_lane), route_handler);
    lanelets.insert(lanelets.end(), next_lanelets.begin(), next_lanelets.end());
  }
  return lanelets;
}

// 检查目标足迹是否在车道内
bool DefaultPlanner::check_goal_footprint_inside_lanes(
  const lanelet::ConstLanelet & current_lanelet, const lanelet::ConstLanelets & path_lanelets,
  const universe_utils::Polygon2d & goal_footprint) const
{
  universe_utils::MultiPolygon2d ego_lanes;
  universe_utils::Polygon2d poly;
  // 遍历路径车道,提取车道的多边形
  for (const auto & ll : path_lanelets) {
    const auto left_shoulder = route_handler_.getLeftShoulderLanelet(ll);
    if (left_shoulder) {
      boost::geometry::convert(left_shoulder->polygon2d().basicPolygon(), poly);
      ego_lanes.push_back(poly);
    }
    const auto right_shoulder = route_handler_.getRightShoulderLanelet(ll);
    if (right_shoulder) {
      boost::geometry::convert(right_shoulder->polygon2d().basicPolygon(), poly);
      ego_lanes.push_back(poly);
    }
    boost::geometry::convert(ll.polygon2d().basicPolygon(), poly);
    ego_lanes.push_back(poly);
  }
  // 获取当前车道的后续车道
  const auto next_lanelets =
    next_lanelets_up_to(current_lanelet, vehicle_info_.max_longitudinal_offset_m, route_handler_);
  for (const auto & ll : next_lanelets) {
    boost::geometry::convert(ll.polygon2d().basicPolygon(), poly);
    ego_lanes.push_back(poly);
  }

  // 检查目标足迹是否在车道内
  universe_utils::MultiPolygon2d difference;
  boost::geometry::difference(goal_footprint, ego_lanes, difference);
  return boost::geometry::is_empty(difference); // 如果差异为空,则目标足迹在车道内
}

// 检查目标点是否有效
bool DefaultPlanner::is_goal_valid(
  const geometry_msgs::msg::Pose & goal, const lanelet::ConstLanelets & path_lanelets)
{
  const auto logger = node_->get_logger();

  const auto goal_lanelet_pt = lanelet::utils::conversion::toLaneletPoint(goal.position);

  // 检查目标点是否在肩道内
  lanelet::Lanelet closest_shoulder_lanelet;
  const auto shoulder_lanelets = route_handler_.getShoulderLaneletsAtPose(goal);
  if (lanelet::utils::query::getClosestLanelet(
        shoulder_lanelets, goal, &closest_shoulder_lanelet)) {
    const auto lane_yaw = lanelet::utils::getLaneletAngle(closest_shoulder_lanelet, goal.position);
    const auto goal_yaw = tf2::getYaw(goal.orientation);
    const auto angle_diff = autoware::universe_utils::normalizeRadian(lane_yaw - goal_yaw);
    const double th_angle = autoware::universe_utils::deg2rad(param_.goal_angle_threshold_deg);
    if (std::abs(angle_diff) < th_angle) {
      return true; // 目标点在肩道内且角度符合要求
    }
  }
  lanelet::ConstLanelet closest_lanelet;
  const auto road_lanelets_at_goal = route_handler_.getRoadLaneletsAtPose(goal);
  if (!lanelet::utils::query::getClosestLanelet(road_lanelets_at_goal, goal, &closest_lanelet)) {
    // 如果目标点不在任何车道内,则查找最近的车道
    const lanelet::BasicPoint2d goal_point{goal.position.x, goal.position.y};
    auto closest_dist = std::numeric_limits<double>::max();
    const auto closest_road_lanelet_found =
      route_handler_.getLaneletMapPtr()->laneletLayer.nearestUntil(
        goal_point, [&](const auto & bbox, const auto & ll) {
          // 通过增加距离搜索最近的车道
          if (lanelet::geometry::distance2d(bbox, goal_point) > closest_dist)
            return true;  // 停止搜索
          const auto dist = lanelet::geometry::distance2d(goal_point, ll.polygon2d());
          if (route_handler_.isRoadLanelet(ll) && dist < closest_dist) {
            closest_dist = dist;
            closest_lanelet = ll;
          }
          return false;  // 继续搜索
        });
    if (!closest_road_lanelet_found) return false; // 如果未找到车道,则目标点无效
  }

  // 获取车辆的足迹
  const auto local_vehicle_footprint = vehicle_info_.createFootprint();
  autoware::universe_utils::LinearRing2d goal_footprint =
    transformVector(local_vehicle_footprint, autoware::universe_utils::pose2transform(goal));
  pub_goal_footprint_marker_->publish(visualize_debug_footprint(goal_footprint));
  const auto polygon_footprint = convert_linear_ring_to_polygon(goal_footprint);

  // 检查目标足迹是否超出车道(如果目标点不在停车场内)
  if (
    param_.check_footprint_inside_lanes &&
    !check_goal_footprint_inside_lanes(closest_lanelet, path_lanelets, polygon_footprint) &&
    !is_in_parking_lot(
      lanelet::utils::query::getAllParkingLots(route_handler_.getLaneletMapPtr()),
      lanelet::utils::conversion::toLaneletPoint(goal.position))) {
    RCLCPP_WARN(logger, "Goal's footprint exceeds lane!");
    return false; // 目标足迹超出车道
  }

  // 检查目标点是否在车道内
  if (is_in_lane(closest_lanelet, goal_lanelet_pt)) {
    const auto lane_yaw = lanelet::utils::getLaneletAngle(closest_lanelet, goal.position);
    const auto goal_yaw = tf2::getYaw(goal.orientation);
    const auto angle_diff = autoware::universe_utils::normalizeRadian(lane_yaw - goal_yaw);

    const double th_angle = autoware::universe_utils::deg2rad(param_.goal_angle_threshold_deg);
    if (std::abs(angle_diff) < th_angle) {
      return true; // 目标点在车道内且角度符合要求
    }
  }

  // 检查目标点是否在停车位内
  const auto parking_spaces =
    lanelet::utils::query::getAllParkingSpaces(route_handler_.getLaneletMapPtr());
  if (is_in_parking_space(parking_spaces, goal_lanelet_pt)) {
    return true; // 目标点在停车位内
  }

  // 检查目标点是否在停车场内
  const auto parking_lots =
    lanelet::utils::query::getAllParkingLots(route_handler_.getLaneletMapPtr());
  return is_in_parking_lot(parking_lots, goal_lanelet_pt); // 目标点在停车场内
}

// 规划路径
PlannerPlugin::LaneletRoute DefaultPlanner::plan(const RoutePoints & points)
{
  const auto logger = node_->get_logger();

  // 打印路径规划的点
  std::stringstream log_ss;
  for (const auto & point : points) {
    log_ss << "x: " << point.position.x << " "
           << "y: " << point.position.y << std::endl;
  }
  RCLCPP_DEBUG_STREAM(
    logger, "start planning route with check points: " << std::endl
                                                       << log_ss.str());

  LaneletRoute route_msg;
  RouteSections route_sections;

  lanelet::ConstLanelets all_route_lanelets;
  for (std::size_t i = 1; i < points.size(); i++) {
    const auto start_check_point = points.at(i - 1);
    const auto goal_check_point = points.at(i);
    lanelet::ConstLanelets path_lanelets;
    // 规划两个检查点之间的路径车道
    if (!route_handler_.planPathLaneletsBetweenCheckpoints(
          start_check_point, goal_check_point, &path_lanelets, param_.consider_no_drivable_lanes)) {
      RCLCPP_WARN(logger, "Failed to plan route.");
      return route_msg; // 如果规划失败,则返回空路径
    }

    // 将规划的车道添加到路径中
    for (const auto & lane : path_lanelets) {
      if (!all_route_lanelets.empty() && lane.id() == all_route_lanelets.back().id()) continue;
      all_route_lanelets.push_back(lane);
    }
  }
  route_handler_.setRouteLanelets(all_route_lanelets); // 设置路径车道
  route_sections = route_handler_.createMapSegments(all_route_lanelets); // 创建路径段

  auto goal_pose = points.back();
  if (param_.enable_correct_goal_pose) {
    // 如果启用了目标点位姿校正,则获取最接近中心线的位姿
    goal_pose = get_closest_centerline_pose(
      lanelet::utils::query::laneletLayer(route_handler_.getLaneletMapPtr()), goal_pose,
      vehicle_info_);
  }

  // 检查目标点是否有效
  if (!is_goal_valid(goal_pose, all_route_lanelets)) {
    RCLCPP_WARN(logger, "Goal is not valid! Please check position and angle of goal_pose");
    return route_msg; // 如果目标点无效,则返回空路径
  }

  // 检查路径是否循环
  if (route_handler::RouteHandler::isRouteLooped(route_sections)) {
    RCLCPP_WARN(logger, "Loop detected within route!");
    return route_msg; // 如果路径循环,则返回空路径
  }

  // 校正目标点的高度
  const auto refined_goal = refine_goal_height(goal_pose, route_sections);
  RCLCPP_DEBUG(logger, "Goal Pose Z : %lf", refined_goal.position.z);

  // 设置路径消息
  route_msg.start_pose = points.front(); // 起点位姿
  route_msg.goal_pose = refined_goal; // 目标点位姿
  route_msg.segments = route_sections; // 路径段
  return route_msg; // 返回路径消息
}

// 校正目标点的高度
geometry_msgs::msg::Pose DefaultPlanner::refine_goal_height(
  const Pose & goal, const RouteSections & route_sections)
{
  const auto goal_lane_id = route_sections.back().preferred_primitive.id;
  const auto goal_lanelet = route_handler_.getLaneletsFromId(goal_lane_id);
  const auto goal_lanelet_pt = lanelet::utils::conversion::toLaneletPoint(goal.position);
  const auto goal_height = project_goal_to_map(goal_lanelet, goal_lanelet_pt);

  Pose refined_goal = goal;
  refined_goal.position.z = goal_height; // 设置校正后的高度
  return refined_goal;
}

// 更新路径
void DefaultPlanner::updateRoute(const PlannerPlugin::LaneletRoute & route)
{
  route_handler_.setRoute(route); // 设置路径处理器中的路径
}

// 清除路径
void DefaultPlanner::clearRoute()
{
  route_handler_.clearRoute(); // 清除路径处理器中的路径
}

}  // namespace autoware::mission_planner::lanelet2

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(
  autoware::mission_planner::lanelet2::DefaultPlanner, autoware::mission_planner::PlannerPlugin)

7. arrival_checker.cpp

是一个用于检查车辆是否到达目标点的工具类。它的核心功能是:

设置目标点:支持设置目标点位姿和 UUID(唯一标识符)。

检查到达状态:

    检查车辆是否接近目标点(距离和角度是否符合要求)。

    检查车辆是否已停止。

源码注释

// Copyright 2022 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "arrival_checker.hpp" // 引入到达检查器头文件

#include <autoware/universe_utils/geometry/geometry.hpp> // 引入几何工具库
#include <autoware/universe_utils/math/normalization.hpp> // 引入数学工具库(归一化)
#include <autoware/universe_utils/math/unit_conversion.hpp> // 引入数学工具库(单位转换)

#include <tf2/utils.h> // 引入 TF2 工具库

namespace autoware::mission_planner
{

// 构造函数,初始化到达检查器
ArrivalChecker::ArrivalChecker(rclcpp::Node * node) : vehicle_stop_checker_(node)
{
  // 从参数服务器读取角度阈值(单位为度),并转换为弧度
  const double angle_deg = node->declare_parameter<double>("arrival_check_angle_deg");
  angle_ = autoware::universe_utils::deg2rad(angle_deg);

  // 从参数服务器读取距离阈值
  distance_ = node->declare_parameter<double>("arrival_check_distance");

  // 从参数服务器读取持续时间阈值
  duration_ = node->declare_parameter<double>("arrival_check_duration");
}

// 清除目标点
void ArrivalChecker::set_goal()
{
  // 清除当前目标点
  goal_with_uuid_ = std::nullopt;
}

// 设置目标点
void ArrivalChecker::set_goal(const PoseWithUuidStamped & goal)
{
  // 设置新的目标点,并忽略与之前目标点 UUID 不匹配的修改
  goal_with_uuid_ = goal;
}

// 检查车辆是否到达目标点
bool ArrivalChecker::is_arrived(const PoseStamped & pose) const
{
  // 如果没有目标点,则返回未到达
  if (!goal_with_uuid_) {
    return false;
  }
  const auto goal = goal_with_uuid_.value();

  // 检查目标点和车辆位姿的坐标系是否一致
  if (goal.header.frame_id != pose.header.frame_id) {
    return false;
  }

  // 检查车辆与目标点的距离是否小于阈值
  if (distance_ < autoware::universe_utils::calcDistance2d(pose.pose, goal.pose)) {
    return false;
  }

  // 检查车辆与目标点的角度差是否小于阈值
  const double yaw_pose = tf2::getYaw(pose.pose.orientation); // 获取车辆的偏航角
  const double yaw_goal = tf2::getYaw(goal.pose.orientation); // 获取目标点的偏航角
  const double yaw_diff = autoware::universe_utils::normalizeRadian(yaw_pose - yaw_goal); // 计算角度差
  if (angle_ < std::fabs(yaw_diff)) {
    return false; // 如果角度差大于阈值,则返回未到达
  }

  // 检查车辆是否已停止
  return vehicle_stop_checker_.isVehicleStopped(duration_);
}

}  // namespace autoware::mission_planner

总结

主要把全局路径生成模块给讲完了,下一章继续往后讲,其中有很多实现是基于Lanelet2 高精地图的,这部分会在这个系列讲完之后单独出一版。

标签:const,goal,universe,route,路径,lanelet,源码,Autoware,auto
From: https://blog.csdn.net/weixin_48386130/article/details/145140674

相关文章