Bootstrap

【一看就会】Autoware.universe的控制部分源码梳理【三】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

control最核心的路径跟踪部分在之前的内容中讲完了(虽然讲的很烂,最后我会再出一章梳理一下)。

但是在control.launch.xml,还启动了别的控制模块,毕竟车辆不止有路径跟随一种控制。
启动的模块之前的文章中有写,在此再列一下:

轨迹跟踪(Trajectory Follower):控制车辆沿着规划轨迹前进。
车道偏离检查(Lane Departure Checker):检测车辆是否偏离车道。
换挡决策(Shift Decider):控制车辆的换挡操作。
车辆命令网关(Vehicle Command Gate):处理车辆控制命令的输入输出。
操作模式转换管理器(Operation Mode Transition Manager):管理车辆的操作模式转换。
障碍物碰撞检测(Obstacle Collision Checker):监测障碍物和碰撞检测。
自动紧急制动(Autonomous Emergency Braking):检测碰撞风险并自动启动紧急制动。
预测路径检查(Predicted Path Checker):检查车辆的预测轨迹。
控制评估(Control Evaluator):评估和监测控制系统的性能。
碰撞检测器(Collision Detector):检测可能的碰撞。

所有的这些都在control功能包里面。
control功能包下面还有18个包,具体的还是得看我之前写的https://blog.csdn.net/weixin_48386130/article/details/144890288?spm=1001.2014.3001.5501
我接下来就依次进行讲解。

对了,我为什么会开这个系列的博客,是因为Autoware.universe官方文档里面没写这部分。像是planning这部分官方有文档的大家就直接去看就行,control这部分等官方有了文档之后大家也优先看官方文档。


一、Autonomous Emergency Braking

AEB 是最后的安全保障机制,当其他避障规划都失败时,通过紧急制动来避免碰撞。

1.原理介绍

主要功能:
1.碰撞检测:使用点云数据和预测对象检测潜在碰撞
2.路径生成:基于 IMU 和 MPC 生成预测路径
3.RSS (Responsibility-Sensitive Safety) 距离计算
4.紧急制动决策

碰撞检测流程:
1.获取传感器数据(点云/预测对象)
2.生成预测路径
3.计算车辆轮廓
4.检测碰撞对象
5.计算 RSS 距离
6.决策是否紧急制动

主要参数配置:

# 关键参数
expand_width: 0.1                # 碰撞检测区域扩展宽度
path_footprint_extra_margin: 4.0 # 路径足迹额外边距
longitudinal_offset: 2.0         # 纵向偏移量
t_response: 1.0                  # 响应时间
a_ego_min: -3.0                 # 自车最小加速度
a_obj_min: -1.0                 # 障碍物最小加速度

碰撞检测逻辑:

bool AEB::hasCollision(const double current_v, const ObjectData & closest_object)
{
  // 计算 RSS 安全距离
  const double rss_dist = std::invoke([&]() {
    const double & obj_v = closest_object.velocity;
    const double & t = t_response_;
    const double pre_braking_covered_distance = std::abs(current_v) * t;
    const double braking_distance = (current_v * current_v) / (2 * std::fabs(a_ego_min_));
    const double ego_stopping_distance = pre_braking_covered_distance + braking_distance;
    // ...
    return ego_stopping_distance + obj_braking_distance + longitudinal_offset_;
  });

  // 如果实际距离小于安全距离,触发制动
  if (closest_object.distance_to_object > rss_dist) return false;
  // collision happens
  collision_data_keeper_.setCollisionData(collision_data);
  return true;
}

2.源码注释

一共两个cpp文件,源码注释如下:

node.cpp

// Copyright 2024 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 <autoware/autonomous_emergency_braking/utils.hpp>
#include <autoware/universe_utils/geometry/geometry.hpp>

#include <optional>

namespace autoware::motion::control::autonomous_emergency_braking::utils
{
using autoware::universe_utils::Polygon2d; // 2D多边形类型
using autoware_perception_msgs::msg::PredictedObject; // 预测对象消息类型
using autoware_perception_msgs::msg::PredictedObjects; // 预测对象集合消息类型
using geometry_msgs::msg::Point; // 点消息类型
using geometry_msgs::msg::Pose; // 位姿消息类型
using geometry_msgs::msg::TransformStamped; // 时间戳变换消息类型
using geometry_msgs::msg::Vector3; // 3D向量消息类型

// 将预测对象从一个坐标系转换到另一个坐标系
PredictedObject transformObjectFrame(
  const PredictedObject & input, const geometry_msgs::msg::TransformStamped & transform_stamped)
{
  PredictedObject output = input;
  const auto & linear_twist = input.kinematics.initial_twist_with_covariance.twist.linear; // 线速度
  const auto & angular_twist = input.kinematics.initial_twist_with_covariance.twist.angular; // 角速度
  const auto & pose = input.kinematics.initial_pose_with_covariance.pose; // 初始位姿

  geometry_msgs::msg::Pose t_pose; // 变换后的位姿
  Vector3 t_linear_twist; // 变换后的线速度
  Vector3 t_angular_twist; // 变换后的角速度

  // 使用tf2库进行坐标变换
  tf2::doTransform(pose, t_pose, transform_stamped);
  tf2::doTransform(linear_twist, t_linear_twist, transform_stamped);
  tf2::doTransform(angular_twist, t_angular_twist, transform_stamped);

  // 更新输出对象的位姿和速度
  output.kinematics.initial_pose_with_covariance.pose = t_pose;
  output.kinematics.initial_twist_with_covariance.twist.linear = t_linear_twist;
  output.kinematics.initial_twist_with_covariance.twist.angular = t_angular_twist;
  return output;
}

// 将多边形对象转换为几何多边形
Polygon2d convertPolygonObjectToGeometryPolygon(
  const Pose & current_pose, const autoware_perception_msgs::msg::Shape & obj_shape)
{
  if (obj_shape.footprint.points.empty()) {
    return {}; // 如果多边形点集为空,返回空多边形
  }
  Polygon2d object_polygon;
  tf2::Transform tf_map2obj;
  fromMsg(current_pose, tf_map2obj); // 将位姿消息转换为tf2变换
  const auto obj_points = obj_shape.footprint.points; // 获取多边形点集
  object_polygon.outer().reserve(obj_points.size() + 1); // 预留空间
  for (const auto & obj_point : obj_points) {
    tf2::Vector3 obj(obj_point.x, obj_point.y, obj_point.z); // 将点转换为tf2向量
    tf2::Vector3 tf_obj = tf_map2obj * obj; // 变换到目标坐标系
    object_polygon.outer().emplace_back(tf_obj.x(), tf_obj.y()); // 添加到多边形
  }
  object_polygon.outer().push_back(object_polygon.outer().front()); // 闭合多边形
  boost::geometry::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 将圆柱体对象转换为几何多边形
Polygon2d convertCylindricalObjectToGeometryPolygon(
  const Pose & current_pose, const autoware_perception_msgs::msg::Shape & obj_shape)
{
  Polygon2d object_polygon;

  const double obj_x = current_pose.position.x; // 对象的x坐标
  const double obj_y = current_pose.position.y; // 对象的y坐标

  constexpr int n = 20; // 多边形的边数
  const double r = obj_shape.dimensions.x / 2; // 圆柱体的半径
  object_polygon.outer().reserve(n + 1); // 预留空间
  for (int i = 0; i < n; ++i) {
    object_polygon.outer().emplace_back(
      obj_x + r * std::cos(2.0 * M_PI / n * i), obj_y + r * std::sin(2.0 * M_PI / n * i)); // 计算多边形顶点
  }

  object_polygon.outer().push_back(object_polygon.outer().front()); // 闭合多边形
  boost::geometry::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 将边界框对象转换为几何多边形
Polygon2d convertBoundingBoxObjectToGeometryPolygon(
  const Pose & current_pose, const double & base_to_front, const double & base_to_rear,
  const double & base_to_width)
{
  const auto mapped_point = [](const double & length_scalar, const double & width_scalar) {
    tf2::Vector3 map;
    map.setX(length_scalar); // 设置x坐标
    map.setY(width_scalar); // 设置y坐标
    map.setZ(0.0); // 设置z坐标
    map.setW(1.0); // 设置齐次坐标
    return map;
  };

  // 设置边界框的四个顶点
  const tf2::Vector3 p1_map = std::invoke(mapped_point, base_to_front, -base_to_width);
  const tf2::Vector3 p2_map = std::invoke(mapped_point, base_to_front, base_to_width);
  const tf2::Vector3 p3_map = std::invoke(mapped_point, -base_to_rear, base_to_width);
  const tf2::Vector3 p4_map = std::invoke(mapped_point, -base_to_rear, -base_to_width);

  // 将顶点从地图坐标系转换到对象坐标系
  tf2::Transform tf_map2obj;
  tf2::fromMsg(current_pose, tf_map2obj);
  const tf2::Vector3 p1_obj = tf_map2obj * p1_map;
  const tf2::Vector3 p2_obj = tf_map2obj * p2_map;
  const tf2::Vector3 p3_obj = tf_map2obj * p3_map;
  const tf2::Vector3 p4_obj = tf_map2obj * p4_map;

  Polygon2d object_polygon;
  object_polygon.outer().reserve(5); // 预留空间
  object_polygon.outer().emplace_back(p1_obj.x(), p1_obj.y()); // 添加顶点
  object_polygon.outer().emplace_back(p2_obj.x(), p2_obj.y());
  object_polygon.outer().emplace_back(p3_obj.x(), p3_obj.y());
  object_polygon.outer().emplace_back(p4_obj.x(), p4_obj.y());

  object_polygon.outer().push_back(object_polygon.outer().front()); // 闭合多边形
  boost::geometry::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 将预测对象转换为多边形
Polygon2d convertObjToPolygon(const PredictedObject & obj)
{
  Polygon2d object_polygon{};
  if (obj.shape.type == autoware_perception_msgs::msg::Shape::CYLINDER) {
    // 如果是圆柱体,调用圆柱体转换函数
    object_polygon = utils::convertCylindricalObjectToGeometryPolygon(
      obj.kinematics.initial_pose_with_covariance.pose, obj.shape);
  } else if (obj.shape.type == autoware_perception_msgs::msg::Shape::BOUNDING_BOX) {
    // 如果是边界框,调用边界框转换函数
    const double & length_m = obj.shape.dimensions.x / 2;
    const double & width_m = obj.shape.dimensions.y / 2;
    object_polygon = utils::convertBoundingBoxObjectToGeometryPolygon(
      obj.kinematics.initial_pose_with_covariance.pose, length_m, length_m, width_m);
  } else if (obj.shape.type == autoware_perception_msgs::msg::Shape::POLYGON) {
    // 如果是多边形,调用多边形转换函数
    object_polygon = utils::convertPolygonObjectToGeometryPolygon(
      obj.kinematics.initial_pose_with_covariance.pose, obj.shape);
  } else {
    throw std::runtime_error("Unsupported shape type"); // 不支持的类型抛出异常
  }
  return object_polygon;
}

// 获取坐标系之间的变换
std::optional<geometry_msgs::msg::TransformStamped> getTransform(
  const std::string & target_frame, const std::string & source_frame,
  const tf2_ros::Buffer & tf_buffer, const rclcpp::Logger & logger)
{
  geometry_msgs::msg::TransformStamped tf_current_pose;
  try {
    // 从tf_buffer中查找变换
    tf_current_pose = tf_buffer.lookupTransform(
      target_frame, source_frame, rclcpp::Time(0), rclcpp::Duration::from_seconds(1.0));
  } catch (tf2::TransformException & ex) {
    // 如果查找失败,记录错误日志
    RCLCPP_ERROR_STREAM(
      logger, "[AEB] Failed to look up transform from " + source_frame + " to " + target_frame);
    return std::nullopt; // 返回空值
  }
  return std::make_optional(tf_current_pose); // 返回变换
}

// 从多边形填充可视化标记
void fillMarkerFromPolygon(
  const std::vector<Polygon2d> & polygons, visualization_msgs::msg::Marker & polygon_marker)
{
  for (const auto & poly : polygons) {
    for (size_t dp_idx = 0; dp_idx < poly.outer().size(); ++dp_idx) {
      const auto & boost_cp = poly.outer().at(dp_idx); // 当前点
      const auto & boost_np = poly.outer().at((dp_idx + 1) % poly.outer().size()); // 下一个点
      const auto curr_point =
        autoware::universe_utils::createPoint(boost_cp.x(), boost_cp.y(), 0.0); // 创建点
      const auto next_point =
        autoware::universe_utils::createPoint(boost_np.x(), boost_np.y(), 0.0);
      polygon_marker.points.push_back(curr_point); // 添加到标记
      polygon_marker.points.push_back(next_point);
    }
  }
}

// 从3D多边形填充可视化标记
void fillMarkerFromPolygon(
  const std::vector<Polygon3d> & polygons, visualization_msgs::msg::Marker & polygon_marker)
{
  for (const auto & poly : polygons) {
    for (size_t dp_idx = 0; dp_idx < poly.outer().size(); ++dp_idx) {
      const auto & boost_cp = poly.outer().at(dp_idx); // 当前点
      const auto & boost_np = poly.outer().at((dp_idx + 1) % poly.outer().size()); // 下一个点
      const auto curr_point =
        autoware::universe_utils::createPoint(boost_cp.x(), boost_cp.y(), boost_cp.z()); // 创建点
      const auto next_point =
        autoware::universe_utils::createPoint(boost_np.x(), boost_np.y(), boost_np.z());
      polygon_marker.points.push_back(curr_point); // 添加到标记
      polygon_marker.points.push_back(next_point);
    }
  }
}

}  // namespace autoware::motion::control::autonomous_emergency_braking::utils

主要功能说明:

    transformObjectFrame: 将预测对象从一个坐标系转换到另一个坐标系。

    convertPolygonObjectToGeometryPolygon: 将多边形对象转换为几何多边形。

    convertCylindricalObjectToGeometryPolygon: 将圆柱体对象转换为几何多边形。

    convertBoundingBoxObjectToGeometryPolygon: 将边界框对象转换为几何多边形。

    convertObjToPolygon: 根据对象类型调用相应的转换函数。

    getTransform: 获取两个坐标系之间的变换。

    fillMarkerFromPolygon: 从多边形生成可视化标记。



utils.cpp

// Copyright 2024 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 <autoware/autonomous_emergency_braking/utils.hpp>
#include <autoware/universe_utils/geometry/geometry.hpp>

#include <optional>

namespace autoware::motion::control::autonomous_emergency_braking::utils
{
using autoware::universe_utils::Polygon2d; // 2D多边形类型
using autoware_perception_msgs::msg::PredictedObject; // 预测对象消息类型
using autoware_perception_msgs::msg::PredictedObjects; // 预测对象集合消息类型
using geometry_msgs::msg::Point; // 点消息类型
using geometry_msgs::msg::Pose; // 位姿消息类型
using geometry_msgs::msg::TransformStamped; // 时间戳变换消息类型
using geometry_msgs::msg::Vector3; // 3D向量消息类型

// 将预测对象从一个坐标系转换到另一个坐标系
PredictedObject transformObjectFrame(
  const PredictedObject & input, const geometry_msgs::msg::TransformStamped & transform_stamped)
{
  PredictedObject output = input;
  const auto & linear_twist = input.kinematics.initial_twist_with_covariance.twist.linear; // 线速度
  const auto & angular_twist = input.kinematics.initial_twist_with_covariance.twist.angular; // 角速度
  const auto & pose = input.kinematics.initial_pose_with_covariance.pose; // 初始位姿

  geometry_msgs::msg::Pose t_pose; // 变换后的位姿
  Vector3 t_linear_twist; // 变换后的线速度
  Vector3 t_angular_twist; // 变换后的角速度

  // 使用tf2库进行坐标变换
  tf2::doTransform(pose, t_pose, transform_stamped);
  tf2::doTransform(linear_twist, t_linear_twist, transform_stamped);
  tf2::doTransform(angular_twist, t_angular_twist, transform_stamped);

  // 更新输出对象的位姿和速度
  output.kinematics.initial_pose_with_covariance.pose = t_pose;
  output.kinematics.initial_twist_with_covariance.twist.linear = t_linear_twist;
  output.kinematics.initial_twist_with_covariance.twist.angular = t_angular_twist;
  return output;
}

// 将多边形对象转换为几何多边形
Polygon2d convertPolygonObjectToGeometryPolygon(
  const Pose & current_pose, const autoware_perception_msgs::msg::Shape & obj_shape)
{
  if (obj_shape.footprint.points.empty()) {
    return {}; // 如果多边形点集为空,返回空多边形
  }
  Polygon2d object_polygon;
  tf2::Transform tf_map2obj;
  fromMsg(current_pose, tf_map2obj); // 将位姿消息转换为tf2变换
  const auto obj_points = obj_shape.footprint.points; // 获取多边形点集
  object_polygon.outer().reserve(obj_points.size() + 1); // 预留空间
  for (const auto & obj_point : obj_points) {
    tf2::Vector3 obj(obj_point.x, obj_point.y, obj_point.z); // 将点转换为tf2向量
    tf2::Vector3 tf_obj = tf_map2obj * obj; // 变换到目标坐标系
    object_polygon.outer().emplace_back(tf_obj.x(), tf_obj.y()); // 添加到多边形
  }
  object_polygon.outer().push_back(object_polygon.outer().front()); // 闭合多边形
  boost::geometry::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 将圆柱体对象转换为几何多边形
Polygon2d convertCylindricalObjectToGeometryPolygon(
  const Pose & current_pose, const autoware_perception_msgs::msg::Shape & obj_shape)
{
  Polygon2d object_polygon;

  const double obj_x = current_pose.position.x; // 对象的x坐标
  const double obj_y = current_pose.position.y; // 对象的y坐标

  constexpr int n = 20; // 多边形的边数
  const double r = obj_shape.dimensions.x / 2; // 圆柱体的半径
  object_polygon.outer().reserve(n + 1); // 预留空间
  for (int i = 0; i < n; ++i) {
    object_polygon.outer().emplace_back(
      obj_x + r * std::cos(2.0 * M_PI / n * i), obj_y + r * std::sin(2.0 * M_PI / n * i)); // 计算多边形顶点
  }

  object_polygon.outer().push_back(object_polygon.outer().front()); // 闭合多边形
  boost::geometry::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 将边界框对象转换为几何多边形
Polygon2d convertBoundingBoxObjectToGeometryPolygon(
  const Pose & current_pose, const double & base_to_front, const double & base_to_rear,
  const double & base_to_width)
{
  const auto mapped_point = [](const double & length_scalar, const double & width_scalar) {
    tf2::Vector3 map;
    map.setX(length_scalar); // 设置x坐标
    map.setY(width_scalar); // 设置y坐标
    map.setZ(0.0); // 设置z坐标
    map.setW(1.0); // 设置齐次坐标
    return map;
  };

  // 设置边界框的四个顶点
  const tf2::Vector3 p1_map = std::invoke(mapped_point, base_to_front, -base_to_width);
  const tf2::Vector3 p2_map = std::invoke(mapped_point, base_to_front, base_to_width);
  const tf2::Vector3 p3_map = std::invoke(mapped_point, -base_to_rear, base_to_width);
  const tf2::Vector3 p4_map = std::invoke(mapped_point, -base_to_rear, -base_to_width);

  // 将顶点从地图坐标系转换到对象坐标系
  tf2::Transform tf_map2obj;
  tf2::fromMsg(current_pose, tf_map2obj);
  const tf2::Vector3 p1_obj = tf_map2obj * p1_map;
  const tf2::Vector3 p2_obj = tf_map2obj * p2_map;
  const tf2::Vector3 p3_obj = tf_map2obj * p3_map;
  const tf2::Vector3 p4_obj = tf_map2obj * p4_map;

  Polygon2d object_polygon;
  object_polygon.outer().reserve(5); // 预留空间
  object_polygon.outer().emplace_back(p1_obj.x(), p1_obj.y()); // 添加顶点
  object_polygon.outer().emplace_back(p2_obj.x(), p2_obj.y());
  object_polygon.outer().emplace_back(p3_obj.x(), p3_obj.y());
  object_polygon.outer().emplace_back(p4_obj.x(), p4_obj.y());

  object_polygon.outer().push_back(object_polygon.outer().front()); // 闭合多边形
  boost::geometry::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 将预测对象转换为多边形
Polygon2d convertObjToPolygon(const PredictedObject & obj)
{
  Polygon2d object_polygon{};
  if (obj.shape.type == autoware_perception_msgs::msg::Shape::CYLINDER) {
    // 如果是圆柱体,调用圆柱体转换函数
    object_polygon = utils::convertCylindricalObjectToGeometryPolygon(
      obj.kinematics.initial_pose_with_covariance.pose, obj.shape);
  } else if (obj.shape.type == autoware_perception_msgs::msg::Shape::BOUNDING_BOX) {
    // 如果是边界框,调用边界框转换函数
    const double & length_m = obj.shape.dimensions.x / 2;
    const double & width_m = obj.shape.dimensions.y / 2;
    object_polygon = utils::convertBoundingBoxObjectToGeometryPolygon(
      obj.kinematics.initial_pose_with_covariance.pose, length_m, length_m, width_m);
  } else if (obj.shape.type == autoware_perception_msgs::msg::Shape::POLYGON) {
    // 如果是多边形,调用多边形转换函数
    object_polygon = utils::convertPolygonObjectToGeometryPolygon(
      obj.kinematics.initial_pose_with_covariance.pose, obj.shape);
  } else {
    throw std::runtime_error("Unsupported shape type"); // 不支持的类型抛出异常
  }
  return object_polygon;
}

// 获取坐标系之间的变换
std::optional<geometry_msgs::msg::TransformStamped> getTransform(
  const std::string & target_frame, const std::string & source_frame,
  const tf2_ros::Buffer & tf_buffer, const rclcpp::Logger & logger)
{
  geometry_msgs::msg::TransformStamped tf_current_pose;
  try {
    // 从tf_buffer中查找变换
    tf_current_pose = tf_buffer.lookupTransform(
      target_frame, source_frame, rclcpp::Time(0), rclcpp::Duration::from_seconds(1.0));
  } catch (tf2::TransformException & ex) {
    // 如果查找失败,记录错误日志
    RCLCPP_ERROR_STREAM(
      logger, "[AEB] Failed to look up transform from " + source_frame + " to " + target_frame);
    return std::nullopt; // 返回空值
  }
  return std::make_optional(tf_current_pose); // 返回变换
}

// 从2D多边形填充可视化标记
void fillMarkerFromPolygon(
  const std::vector<Polygon2d> & polygons, visualization_msgs::msg::Marker & polygon_marker)
{
  for (const auto & poly : polygons) {
    for (size_t dp_idx = 0; dp_idx < poly.outer().size(); ++dp_idx) {
      const auto & boost_cp = poly.outer().at(dp_idx); // 当前点
      const auto & boost_np = poly.outer().at((dp_idx + 1) % poly.outer().size()); // 下一个点
      const auto curr_point =
        autoware::universe_utils::createPoint(boost_cp.x(), boost_cp.y(), 0.0); // 创建点
      const auto next_point =
        autoware::universe_utils::createPoint(boost_np.x(), boost_np.y(), 0.0);
      polygon_marker.points.push_back(curr_point); // 添加到标记
      polygon_marker.points.push_back(next_point);
    }
  }
}

// 从3D多边形填充可视化标记
void fillMarkerFromPolygon(
  const std::vector<Polygon3d> & polygons, visualization_msgs::msg::Marker & polygon_marker)
{
  for (const auto & poly : polygons) {
    for (size_t dp_idx = 0; dp_idx < poly.outer().size(); ++dp_idx) {
      const auto & boost_cp = poly.outer().at(dp_idx); // 当前点
      const auto & boost_np = poly.outer().at((dp_idx + 1) % poly.outer().size()); // 下一个点
      const auto curr_point =
        autoware::universe_utils::createPoint(boost_cp.x(), boost_cp.y(), boost_cp.z()); // 创建点
      const auto next_point =
        autoware::universe_utils::createPoint(boost_np.x(), boost_np.y(), boost_np.z());
      polygon_marker.points.push_back(curr_point); // 添加到标记
      polygon_marker.points.push_back(next_point);
    }
  }
}

}  // namespace autoware::motion::control::autonomous_emergency_braking::utils

主要功能说明:

    transformObjectFrame: 将预测对象从一个坐标系转换到另一个坐标系。

    convertPolygonObjectToGeometryPolygon: 将多边形对象转换为几何多边形。

    convertCylindricalObjectToGeometryPolygon: 将圆柱体对象转换为几何多边形。

    convertBoundingBoxObjectToGeometryPolygon: 将边界框对象转换为几何多边形。

    convertObjToPolygon: 根据对象类型调用相应的转换函数。

    getTransform: 获取两个坐标系之间的变换。

    fillMarkerFromPolygon: 从多边形生成可视化标记。


二、autoware_collision_detector

这个是检测碰撞的。主要功能是检测车辆周围的障碍物并发出警告。
不会控制车辆作出动作,是一个监控系统,同时使用点云和动态物体检测,然后发出诊断信息,就是一个风险预警。
到底有那些模块会用这部分检测信息,我还不知道,等之后清楚了再来补充。
主要功能:

class CollisionDetectorNode {
  // 主要参数
  struct NodeParam {
    bool use_pointcloud;           // 是否使用点云数据
    bool use_dynamic_object;       // 是否使用动态物体检测
    double collision_distance;     // 碰撞检测距离
    double nearby_filter_radius;   // 近距离过滤半径
    double keep_ignoring_time;     // 忽略时间
  };

  // 主要检测函数
  void checkCollision() {
    // 1. 获取最近的障碍物
    const auto nearest_obstacle = getNearestObstacle();
    
    // 2. 判断是否有碰撞风险
    const auto is_obstacle_found = 
      !nearest_obstacle ? false : nearest_obstacle.get().first < node_param_.collision_distance;

    // 3. 如果是自动驾驶模式且检测到障碍物,发出警告
    if (operation_mode_ptr_->mode == OperationModeState::AUTONOMOUS && 
        (is_obstacle_found || is_obstacle_found_recently)) {
      status.level = DiagnosticStatus::ERROR;
      status.message = "collision detected";
    }
  }

就一个cpp文件,node.cpp源码注释:

// Copyright 2024 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 "autoware/collision_detector/node.hpp"

#include <autoware/universe_utils/geometry/geometry.hpp>
#include <autoware/universe_utils/ros/uuid_helper.hpp>
#include <tf2_eigen/tf2_eigen.hpp>

#include <boost/assert.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>

#include <pcl/common/transforms.h>
#include <pcl/point_cloud.h>
#include <pcl_conversions/pcl_conversions.h>

#define EIGEN_MPL2_ONLY
#include <Eigen/Core>
#include <Eigen/Geometry>

namespace autoware::collision_detector
{
namespace bg = boost::geometry;
using Point2d = bg::model::d2::point_xy<double>; // 2D点类型
using Polygon2d = bg::model::polygon<Point2d>; // 2D多边形类型
using autoware::universe_utils::createPoint; // 创建点的工具函数
using autoware::universe_utils::pose2transform; // 将位姿转换为变换的工具函数

namespace
{

// 创建一个32位精度的点
geometry_msgs::msg::Point32 createPoint32(const double x, const double y, const double z)
{
  geometry_msgs::msg::Point32 p;
  p.x = x;
  p.y = y;
  p.z = z;
  return p;
}

// 根据位姿和足迹创建对象的多边形
Polygon2d createObjPolygon(
  const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::Polygon & footprint)
{
  geometry_msgs::msg::Polygon transformed_polygon{};
  geometry_msgs::msg::TransformStamped geometry_tf{};
  geometry_tf.transform = pose2transform(pose); // 将位姿转换为变换
  tf2::doTransform(footprint, transformed_polygon, geometry_tf); // 对足迹进行坐标变换

  Polygon2d object_polygon;
  for (const auto & p : transformed_polygon.points) {
    object_polygon.outer().push_back(Point2d(p.x, p.y)); // 将点添加到多边形
  }

  bg::correct(object_polygon); // 修正多边形

  return object_polygon;
}

// 根据位姿和尺寸创建对象的多边形
Polygon2d createObjPolygon(
  const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::Vector3 & size)
{
  const double length_m = size.x / 2.0; // 长度的一半
  const double width_m = size.y / 2.0; // 宽度的一半

  geometry_msgs::msg::Polygon polygon{};

  // 添加边界框的四个顶点
  polygon.points.push_back(createPoint32(length_m, -width_m, 0.0));
  polygon.points.push_back(createPoint32(length_m, width_m, 0.0));
  polygon.points.push_back(createPoint32(-length_m, width_m, 0.0));
  polygon.points.push_back(createPoint32(-length_m, -width_m, 0.0));

  return createObjPolygon(pose, polygon); // 调用前面的函数创建多边形
}

// 为圆柱体对象创建多边形
Polygon2d createObjPolygonForCylinder(const geometry_msgs::msg::Pose & pose, const double diameter)
{
  geometry_msgs::msg::Polygon polygon{};

  const double radius = diameter * 0.5; // 半径
  // 添加六边形的顶点
  for (int i = 0; i < 6; ++i) {
    const double angle = 2.0 * M_PI * static_cast<double>(i) / 6.0; // 计算角度
    const double x = radius * std::cos(angle); // x坐标
    const double y = radius * std::sin(angle); // y坐标
    polygon.points.push_back(createPoint32(x, y, 0.0)); // 添加点
  }

  return createObjPolygon(pose, polygon); // 调用前面的函数创建多边形
}

// 创建自车多边形
Polygon2d createSelfPolygon(const VehicleInfo & vehicle_info)
{
  const double & front_m = vehicle_info.max_longitudinal_offset_m; // 前部偏移
  const double & width_left_m = vehicle_info.max_lateral_offset_m; // 左侧偏移
  const double & width_right_m = vehicle_info.min_lateral_offset_m; // 右侧偏移
  const double & rear_m = vehicle_info.min_longitudinal_offset_m; // 后部偏移

  Polygon2d ego_polygon;

  // 添加自车多边形的四个顶点
  ego_polygon.outer().push_back(Point2d(front_m, width_left_m));
  ego_polygon.outer().push_back(Point2d(front_m, width_right_m));
  ego_polygon.outer().push_back(Point2d(rear_m, width_right_m));
  ego_polygon.outer().push_back(Point2d(rear_m, width_left_m));

  bg::correct(ego_polygon); // 修正多边形

  return ego_polygon;
}
}  // namespace

// 构造函数
CollisionDetectorNode::CollisionDetectorNode(const rclcpp::NodeOptions & node_options)
: Node("collision_detector_node", node_options), updater_(this)
{
  // 参数初始化
  {
    auto & p = node_param_;
    p.use_pointcloud = this->declare_parameter<bool>("use_pointcloud"); // 是否使用点云
    p.use_dynamic_object = this->declare_parameter<bool>("use_dynamic_object"); // 是否使用动态对象
    p.collision_distance = this->declare_parameter<double>("collision_distance"); // 碰撞距离
    p.nearby_filter_radius = this->declare_parameter<double>("nearby_filter_radius"); // 附近过滤半径
    p.keep_ignoring_time = this->declare_parameter<double>("keep_ignoring_time"); // 忽略时间
    p.nearby_object_type_filters.filter_car =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_car"); // 过滤汽车
    p.nearby_object_type_filters.filter_truck =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_truck"); // 过滤卡车
    p.nearby_object_type_filters.filter_bus =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_bus"); // 过滤公交车
    p.nearby_object_type_filters.filter_trailer =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_trailer"); // 过滤拖车
    p.nearby_object_type_filters.filter_unknown =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_unknown"); // 过滤未知对象
    p.nearby_object_type_filters.filter_bicycle =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_bicycle"); // 过滤自行车
    p.nearby_object_type_filters.filter_motorcycle =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_motorcycle"); // 过滤摩托车
    p.nearby_object_type_filters.filter_pedestrian =
      this->declare_parameter<bool>("nearby_object_type_filters.filter_pedestrian"); // 过滤行人
  }

  vehicle_info_ = autoware::vehicle_info_utils::VehicleInfoUtils(*this).getVehicleInfo(); // 获取车辆信息
  last_obstacle_found_stamp_ = this->now(); // 初始化最后发现障碍物的时间戳

  // 诊断更新器
  updater_.setHardwareID("collision_detector");
  updater_.add("collision_detect", this, &CollisionDetectorNode::checkCollision); // 添加碰撞检测任务
  updater_.setPeriod(0.1); // 设置更新周期
}

// 过滤对象
PredictedObjects CollisionDetectorNode::filterObjects(const PredictedObjects & input_objects)
{
  PredictedObjects filtered_objects;
  filtered_objects.header = input_objects.header;
  filtered_objects.header.stamp = this->now();

  const rclcpp::Time current_object_time = input_objects.header.stamp;
  const rclcpp::Duration observed_objects_keep_time =
    rclcpp::Duration::from_seconds(0.5);  //  0.5秒
  const rclcpp::Duration ignored_objects_keep_time =
    rclcpp::Duration::from_seconds(10.0);  // 10秒

  // 移除过期的对象
  removeOldObjects(observed_objects_, current_object_time, observed_objects_keep_time);
  removeOldObjects(ignored_objects_, current_object_time, ignored_objects_keep_time);

  // 获取从对象坐标系到base_link的变换
  const auto transform_stamped =
    getTransform("base_link", input_objects.header.frame_id, input_objects.header.stamp, 0.5);

  if (!transform_stamped) {
    RCLCPP_ERROR(this->get_logger(), "Failed to get transform from object frame to base_link");
    return filtered_objects;
  }

  Eigen::Affine3f isometry = tf2::transformToEigen(transform_stamped.get().transform).cast<float>();

  for (const auto & object : input_objects.objects) {
    // 将对象位置转换到base_link坐标系
    Eigen::Vector3f object_position(
      object.kinematics.initial_pose_with_covariance.pose.position.x,
      object.kinematics.initial_pose_with_covariance.pose.position.y,
      object.kinematics.initial_pose_with_covariance.pose.position.z);
    Eigen::Vector3f transformed_position = isometry * object_position;

    // 计算对象与base_link的距离
    const double object_distance = transformed_position.head<2>().norm();
    const bool is_within_range = (object_distance <= node_param_.nearby_filter_radius);

    // 判断对象是否应该被排除
    bool should_be_excluded = shouldBeExcluded(object.classification.front().label);

    const bool is_within_range_and_filtering_class = is_within_range && should_be_excluded;

    // 如果对象不在范围内或不需要过滤,直接添加到结果中
    if (!is_within_range_and_filtering_class) {
      filtered_objects.objects.push_back(object);

      // 更新观察到的对象
      auto observed_it = std::find_if(
        observed_objects_.begin(), observed_objects_.end(),
        [&object](const auto & observed_object) {
          return observed_object.object_id == object.object_id;
        });
      if (observed_it != observed_objects_.end()) {
        observed_it->timestamp = current_object_time;
      } else {
        observed_objects_.push_back({object.object_id, current_object_time});
      }

      continue;
    }

    // 检查对象是否在忽略列表中
    auto ignored_it = std::find_if(
      ignored_objects_.begin(), ignored_objects_.end(), [&object](const auto & ignored_object) {
        return ignored_object.object_id == object.object_id;
      });
    const bool was_ignored = (ignored_it != ignored_objects_.end());

    // 如果对象被忽略且仍在忽略时间内,继续过滤
    if (
      was_ignored && (current_object_time - ignored_it->timestamp) <
                       rclcpp::Duration::from_seconds(node_param_.keep_ignoring_time)) {
      // 检查对象是否在观察列表中
      auto observed_it = std::find_if(
        observed_objects_.begin(), observed_objects_.end(),
        [&object](const auto & observed_object) {
          return observed_object.object_id == object.object_id;
        });
      const bool was_observed = (observed_it != observed_objects_.end());
      if (was_observed) {
        observed_it->timestamp = current_object_time;
      } else {
        // 添加到观察列表和忽略列表
        observed_objects_.push_back({object.object_id, current_object_time});
      }
      continue;
    }

    // 检查对象是否在观察列表中
    auto observed_it = std::find_if(
      observed_objects_.begin(), observed_objects_.end(), [&object](const auto & observed_object) {
        return observed_object.object_id == object.object_id;
      });
    const bool was_observed = (observed_it != observed_objects_.end());

    if (was_observed) {
      observed_it->timestamp = current_object_time;
      // 直接添加到结果中
      filtered_objects.objects.push_back(object);
    } else {
      // 添加到观察列表和忽略列表
      observed_objects_.push_back({object.object_id, current_object_time});
      ignored_objects_.push_back({object.object_id, current_object_time});
      // 继续过滤
      continue;
    }
  }

  return filtered_objects;
}

// 移除过期的对象
void CollisionDetectorNode::removeOldObjects(
  std::vector<TimestampedObject> & container, const rclcpp::Time & current_time,
  const rclcpp::Duration & duration_sec)
{
  container.erase(
    std::remove_if(
      container.begin(), container.end(),
      [&](const TimestampedObject & obj) { return (current_time - obj.timestamp) > duration_sec; }),
    container.end());
}

// 判断对象是否应该被排除
bool CollisionDetectorNode::shouldBeExcluded(
  const autoware_perception_msgs::msg::ObjectClassification::_label_type & classification) const
{
  switch (classification) {
    case autoware_perception_msgs::msg::ObjectClassification::CAR:
      return node_param_.nearby_object_type_filters.filter_car;
    case autoware_perception_msgs::msg::ObjectClassification::TRUCK:
      return node_param_.nearby_object_type_filters.filter_truck;
    case autoware_perception_msgs::msg::ObjectClassification::BUS:
      return node_param_.nearby_object_type_filters.filter_bus;
    case autoware_perception_msgs::msg::ObjectClassification::TRAILER:
      return node_param_.nearby_object_type_filters.filter_trailer;
    case autoware_perception_msgs::msg::ObjectClassification::UNKNOWN:
      return node_param_.nearby_object_type_filters.filter_unknown;
    case autoware_perception_msgs::msg::ObjectClassification::BICYCLE:
      return node_param_.nearby_object_type_filters.filter_bicycle;
    case autoware_perception_msgs::msg::ObjectClassification::MOTORCYCLE:
      return node_param_.nearby_object_type_filters.filter_motorcycle;
    case autoware_perception_msgs::msg::ObjectClassification::PEDESTRIAN:
      return node_param_.nearby_object_type_filters.filter_pedestrian;
    default:
      return false;
  }
}

// 检查碰撞
void CollisionDetectorNode::checkCollision(diagnostic_updater::DiagnosticStatusWrapper & stat)
{
  odometry_ptr_ = sub_odometry_.takeData(); // 获取当前里程计数据

  if (!odometry_ptr_) {
    RCLCPP_INFO_THROTTLE(
      this->get_logger(), *this->get_clock(), 5000 /* ms */, "waiting for current odometry...");
    return;
  }

  pointcloud_ptr_ = sub_pointcloud_.takeData(); // 获取点云数据
  object_ptr_ = sub_dynamic_objects_.takeData(); // 获取动态对象数据
  operation_mode_ptr_ = sub_operation_mode_.takeData(); // 获取操作模式数据

  if (node_param_.use_pointcloud && !pointcloud_ptr_) {
    RCLCPP_WARN_THROTTLE(
      this->get_logger(), *this->get_clock(), 5000 /* ms */, "waiting for pointcloud info...");
    return;
  }

  if (node_param_.use_dynamic_object && !object_ptr_) {
    RCLCPP_WARN_THROTTLE(
      this->get_logger(), *this->get_clock(), 5000 /* ms */, "waiting for dynamic object info...");
    return;
  }

  if (!operation_mode_ptr_) {
    RCLCPP_WARN_THROTTLE(
      this->get_logger(), *this->get_clock(), 5000 /* ms */, "waiting for operation mode info...");
    return;
  }
  filtered_object_ptr_ = std::make_shared<PredictedObjects>(filterObjects(*object_ptr_)); // 过滤对象

  const auto nearest_obstacle = getNearestObstacle(); // 获取最近的障碍物

  const auto is_obstacle_found =
    !nearest_obstacle ? false : nearest_obstacle.get().first < node_param_.collision_distance;

  if (is_obstacle_found) {
    last_obstacle_found_stamp_ = this->now(); // 更新最后发现障碍物的时间戳
  }

  const auto is_obstacle_found_recently =
    (this->now() - last_obstacle_found_stamp_).seconds() < 1.0;

  diagnostic_msgs::msg::DiagnosticStatus status;
  if (
    operation_mode_ptr_->mode == OperationModeState::AUTONOMOUS &&
    (is_obstacle_found || is_obstacle_found_recently)) {
    status.level = diagnostic_msgs::msg::DiagnosticStatus::ERROR;
    status.message = "collision detected";
    if (is_obstacle_found) {
      stat.addf("Distance to nearest neighbor object", "%lf", nearest_obstacle.get().first);
    }
  } else {
    status.level = diagnostic_msgs::msg::DiagnosticStatus::OK;
  }

  stat.summary(status.level, status.message);
}

// 获取最近的障碍物
boost::optional<Obstacle> CollisionDetectorNode::getNearestObstacle() const
{
  boost::optional<Obstacle> nearest_pointcloud{boost::none};
  boost::optional<Obstacle> nearest_object{boost::none};

  if (node_param_.use_pointcloud) {
    nearest_pointcloud = getNearestObstacleByPointCloud(); // 从点云中获取最近的障碍物
  }

  if (node_param_.use_dynamic_object) {
    nearest_object = getNearestObstacleByDynamicObject(); // 从动态对象中获取最近的障碍物
  }

  if (!nearest_pointcloud && !nearest_object) {
    return {};
  }

  if (!nearest_pointcloud) {
    return nearest_object;
  }

  if (!nearest_object) {
    return nearest_pointcloud;
  }

  return nearest_pointcloud.get().first < nearest_object.get().first ? nearest_pointcloud
                                                                     : nearest_object;
}

// 从点云中获取最近的障碍物
boost::optional<Obstacle> CollisionDetectorNode::getNearestObstacleByPointCloud() const
{
  const auto transform_stamped =
    getTransform("base_link", pointcloud_ptr_->header.frame_id, pointcloud_ptr_->header.stamp, 0.5);

  geometry_msgs::msg::Point nearest_point;
  auto minimum_distance = std::numeric_limits<double>::max();

  if (!transform_stamped) {
    return {};
  }

  Eigen::Affine3f isometry = tf2::transformToEigen(transform_stamped.get().transform).cast<float>();
  pcl::PointCloud<pcl::PointXYZ> transformed_pointcloud;
  pcl::fromROSMsg(*pointcloud_ptr_, transformed_pointcloud);
  pcl::transformPointCloud(transformed_pointcloud, transformed_pointcloud, isometry);

  const auto ego_polygon = createSelfPolygon(vehicle_info_);

  for (const auto & p : transformed_pointcloud) {
    Point2d boost_point(p.x, p.y);

    const auto distance_to_object = bg::distance(ego_polygon, boost_point);

    if (distance_to_object < minimum_distance) {
      nearest_point = createPoint(p.x, p.y, p.z);
      minimum_distance = distance_to_object;
    }
  }

  return std::make_pair(minimum_distance, nearest_point);
}

// 从动态对象中获取最近的障碍物
boost::optional<Obstacle> CollisionDetectorNode::getNearestObstacleByDynamicObject() const
{
  const auto transform_stamped = getTransform(
    filtered_object_ptr_->header.frame_id, "base_link", filtered_object_ptr_->header.stamp, 0.5);

  geometry_msgs::msg::Point nearest_point;
  auto minimum_distance = std::numeric_limits<double>::max();

  if (!transform_stamped) {
    return {};
  }

  tf2::Transform tf_src2target;
  tf2::fromMsg(transform_stamped.get().transform, tf_src2target);

  const auto ego_polygon = createSelfPolygon(vehicle_info_);

  for (const auto & object : filtered_object_ptr_->objects) {
    const auto & object_pose = object.kinematics.initial_pose_with_covariance.pose;

    tf2::Transform tf_src2object;
    tf2::fromMsg(object_pose, tf_src2object);

    geometry_msgs::msg::Pose transformed_object_pose;
    tf2::toMsg(tf_src2target.inverse() * tf_src2object, transformed_object_pose);

    const auto object_polygon = [&]() {
      switch (object.shape.type) {
        case Shape::POLYGON:
          return createObjPolygon(transformed_object_pose, object.shape.footprint);
        case Shape::CYLINDER:
          return createObjPolygonForCylinder(transformed_object_pose, object.shape.dimensions.x);
        case Shape::BOUNDING_BOX:
          return createObjPolygon(transformed_object_pose, object.shape.dimensions);
        default:
          // 不支持的类型
          RCLCPP_WARN(this->get_logger(), "Unsupported shape type: %d", object.shape.type);
          return createObjPolygon(transformed_object_pose, object.shape.dimensions);
      }
    }();

    const auto distance_to_object = bg::distance(ego_polygon, object_polygon);

    if (distance_to_object < minimum_distance) {
      nearest_point = object_pose.position;
      minimum_distance = distance_to_object;
    }
  }

  return std::make_pair(minimum_distance, nearest_point);
}

// 获取坐标系之间的变换
boost::optional<geometry_msgs::msg::TransformStamped> CollisionDetectorNode::getTransform(
  const std::string & source, const std::string & target, const rclcpp::Time & stamp,
  double duration_sec) const
{
  geometry_msgs::msg::TransformStamped transform_stamped;

  try {
    transform_stamped =
      tf_buffer_.lookupTransform(source, target, stamp, tf2::durationFromSec(duration_sec));
  } catch (const tf2::TransformException & ex) {
    return {};
  }

  return transform_stamped;
}

}  // namespace autoware::collision_detector

#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::collision_detector::CollisionDetectorNode)

三、autoware_control_validator

这个是控制验证模块,主要用于验证控制输出的合法性。
也是一个监控模块,不会去干预车辆的控制。

主要作用:
1.实时监控控制输出的合法性
2.检测异常行为(如超速、倒车)
3.发布诊断信息
4.可视化警告信息

主要监控三部分:
1.横向偏差
2.速度偏差
3.累积错误计数

class ControlValidator {
  // 验证三个主要方面
  void validate() {
    // 1. 横向偏差验证
    calc_lateral_deviation_status();
    
    // 2. 速度偏差验证
    calc_velocity_deviation_status();
    
    // 3. 累计错误计数
    validation_status_.invalid_count = 
      is_all_valid(validation_status_) ? 0 : validation_status_.invalid_count + 1;
  }
};

相关参数:

thresholds:
  max_distance_deviation: 1.0     # 最大允许横向偏差
  rolling_back_velocity: 0.5      # 倒车速度阈值
  over_velocity_offset: 2.0       # 超速偏移量
  over_velocity_ratio: 0.2        # 超速比率

diag_error_count_threshold: 0     # 连续错误计数阈值

验证内容:
1.横向偏差验证:

std::pair<double, bool> calc_lateral_deviation_status() {
  // 计算预测轨迹与参考轨迹的最大横向偏差
  auto max_distance_deviation = calc_max_lateral_distance(reference_trajectory, predicted_trajectory);
  
  // 判断是否在允许范围内
  return {max_distance_deviation, max_distance_deviation <= max_distance_deviation_threshold};
}

2.速度验证:

void calc_velocity_deviation_status() {
  // 检查是否倒车
  const bool is_rolling_back = std::signbit(vehicle_vel * target_vel) && 
                             std::abs(vehicle_vel) > rolling_back_velocity;
                             
  // 检查是否超速
  const bool is_over_velocity = std::abs(vehicle_vel) > 
    std::abs(target_vel) * (1.0 + over_velocity_ratio) + over_velocity_offset;
}

输入:

参考轨迹 (Reference Trajectory):
sub_reference_traj_ = autoware::universe_utils::InterProcessPollingSubscriber<Trajectory>::create_subscription(
  this, "~/input/reference_trajectory", 1);  // 来自规划系统的理想轨迹

预测轨迹 (Predicted Trajectory):
sub_predicted_traj_ = create_subscription<Trajectory>(
  "~/input/predicted_trajectory", 1,  // 来自控制系统的预测轨迹
  std::bind(&ControlValidator::on_predicted_trajectory, this, _1));

车辆运动学状态 (Kinematics):
sub_kinematics_ = universe_utils::InterProcessPollingSubscriber<nav_msgs::msg::Odometry>::create_subscription(
  this, "~/input/kinematics", 1);  // 车辆当前的速度、位置等状态


从 launch 文件中可以看到具体的话题映射:

<remap from="~/input/reference_trajectory" to="/planning/scenario_planning/trajectory"/>
<remap from="~/input/predicted_trajectory" to="/control/trajectory_follower/lateral/predicted_trajectory"/>
<remap from="~/input/kinematics" to="/localization/kinematic_state"/>


输出:

验证状态输出 (ControlValidatorStatus):
// 发布验证状态
pub_status_ = create_publisher<ControlValidatorStatus>("~/output/validation_status", 1);

// 状态包含:
struct ControlValidatorStatus {
  bool is_valid_max_distance_deviation;  // 横向偏差是否合法
  bool is_rolling_back;                  // 是否在倒车
  bool is_over_velocity;                 // 是否超速
  int invalid_count;                     // 连续错误计数
  double vehicle_vel;                    // 当前车速
  double target_vel;                     // 目标车速
}

诊断信息输出:
void setup_diag() {
  // 发布诊断信息
  d.add("control_validation_max_distance_deviation", [&](auto & stat) {
    set_status(stat, validation_status_.is_valid_max_distance_deviation,
      "control output is deviated from trajectory");
  });
  
  d.add("control_validation_rolling_back", ...);
  d.add("control_validation_over_velocity", ...);
}


可视化警告:
void publish_debug_info() {
  // 如果验证失败,显示警告标记
  if (!is_all_valid(validation_status_)) {
    debug_pose_publisher_->push_virtual_wall(front_pose);
    debug_pose_publisher_->push_warning_msg(front_pose, "INVALID CONTROL");
  }
}


三个cpp文件,源码注释如下,没啥需要注意看的地方,遇到实际问题再看吧:

// Copyright 2023 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 "autoware/control_validator/control_validator.hpp"

#include "autoware/control_validator/utils.hpp"
#include "autoware/motion_utils/trajectory/interpolation.hpp"
#include "autoware_vehicle_info_utils/vehicle_info_utils.hpp"

#include <nav_msgs/msg/odometry.hpp>

#include <cstdint>
#include <memory>
#include <string>

namespace autoware::control_validator
{
using diagnostic_msgs::msg::DiagnosticStatus;

// 构造函数
ControlValidator::ControlValidator(const rclcpp::NodeOptions & options)
: Node("control_validator", options), validation_params_(), vehicle_info_()
{
  using std::placeholders::_1;

  // 订阅预测轨迹
  sub_predicted_traj_ = create_subscription<Trajectory>(
    "~/input/predicted_trajectory", 1,
    std::bind(&ControlValidator::on_predicted_trajectory, this, _1));
  // 订阅车辆运动学信息
  sub_kinematics_ =
    universe_utils::InterProcessPollingSubscriber<nav_msgs::msg::Odometry>::create_subscription(
      this, "~/input/kinematics", 1);
  // 订阅参考轨迹
  sub_reference_traj_ =
    autoware::universe_utils::InterProcessPollingSubscriber<Trajectory>::create_subscription(
      this, "~/input/reference_trajectory", 1);

  // 发布验证状态
  pub_status_ = create_publisher<ControlValidatorStatus>("~/output/validation_status", 1);

  // 发布可视化标记
  pub_markers_ = create_publisher<visualization_msgs::msg::MarkerArray>("~/output/markers", 1);

  // 发布处理时间
  pub_processing_time_ =
    this->create_publisher<tier4_debug_msgs::msg::Float64Stamped>("~/debug/processing_time_ms", 1);

  // 初始化调试标记发布器
  debug_pose_publisher_ = std::make_shared<ControlValidatorDebugMarkerPublisher>(this);

  // 设置参数
  setup_parameters();

  // 设置诊断
  setup_diag();
}

// 设置参数
void ControlValidator::setup_parameters()
{
  // 诊断错误计数阈值
  diag_error_count_threshold_ = declare_parameter<int64_t>("diag_error_count_threshold");
  // 是否在终端显示状态
  display_on_terminal_ = declare_parameter<bool>("display_on_terminal");

  {
    auto & p = validation_params_;
    const std::string t = "thresholds.";
    // 最大横向偏差阈值
    p.max_distance_deviation_threshold = declare_parameter<double>(t + "max_distance_deviation");
    // 倒车速度阈值
    p.rolling_back_velocity = declare_parameter<double>(t + "rolling_back_velocity");
    // 超速偏移量
    p.over_velocity_offset = declare_parameter<double>(t + "over_velocity_offset");
    // 超速比例
    p.over_velocity_ratio = declare_parameter<double>(t + "over_velocity_ratio");
  }
  // 低通滤波器增益
  const auto lpf_gain = declare_parameter<double>("vel_lpf_gain");
  vehicle_vel_.setGain(lpf_gain);
  target_vel_.setGain(lpf_gain);

  // 是否在停止前保持速度错误
  hold_velocity_error_until_stop_ = declare_parameter<bool>("hold_velocity_error_until_stop");

  try {
    // 获取车辆信息
    vehicle_info_ = autoware::vehicle_info_utils::VehicleInfoUtils(*this).getVehicleInfo();
  } catch (...) {
    // 如果获取失败,使用默认值
    vehicle_info_.front_overhang_m = 0.5;
    vehicle_info_.wheel_base_m = 4.0;
    RCLCPP_ERROR(
      get_logger(),
      "failed to get vehicle info. use default value. vehicle_info_.front_overhang_m: %.2f, "
      "vehicle_info_.wheel_base_m: %.2f",
      vehicle_info_.front_overhang_m, vehicle_info_.wheel_base_m);
  }
}

// 设置诊断状态
void ControlValidator::set_status(
  DiagnosticStatusWrapper & stat, const bool & is_ok, const std::string & msg) const
{
  if (is_ok) {
    stat.summary(DiagnosticStatus::OK, "validated.");
  } else if (validation_status_.invalid_count < diag_error_count_threshold_) {
    const auto warn_msg = msg + " (invalid count is less than error threshold: " +
                          std::to_string(validation_status_.invalid_count) + " < " +
                          std::to_string(diag_error_count_threshold_) + ")";
    stat.summary(DiagnosticStatus::WARN, warn_msg);
  } else {
    stat.summary(DiagnosticStatus::ERROR, msg);
  }
}

// 设置诊断
void ControlValidator::setup_diag()
{
  auto & d = diag_updater_;
  d.setHardwareID("control_validator");

  std::string ns = "control_validation_";
  // 添加最大横向偏差诊断
  d.add(ns + "max_distance_deviation", [&](auto & stat) {
    set_status(
      stat, validation_status_.is_valid_max_distance_deviation,
      "control output is deviated from trajectory");
  });
  // 添加倒车诊断
  d.add(ns + "rolling_back", [&](auto & stat) {
    set_status(
      stat, !validation_status_.is_rolling_back,
      "The vehicle is rolling back. The velocity has the opposite sign to the target.");
  });
  // 添加超速诊断
  d.add(ns + "over_velocity", [&](auto & stat) {
    set_status(
      stat, !validation_status_.is_over_velocity,
      "The vehicle is over-speeding against the target.");
  });
}

// 检查数据是否准备就绪
bool ControlValidator::is_data_ready()
{
  const auto waiting = [this](const auto topic_name) {
    RCLCPP_INFO_SKIPFIRST_THROTTLE(get_logger(), *get_clock(), 5000, "waiting for %s", topic_name);
    return false;
  };

  if (!current_kinematics_) {
    return waiting(sub_kinematics_->subscriber()->get_topic_name());
  }
  if (!current_reference_trajectory_) {
    return waiting(sub_reference_traj_->subscriber()->get_topic_name());
  }
  if (!current_predicted_trajectory_) {
    return waiting(sub_predicted_traj_->get_topic_name());
  }
  return true;
}

// 处理预测轨迹的回调函数
void ControlValidator::on_predicted_trajectory(const Trajectory::ConstSharedPtr msg)
{
  stop_watch.tic();

  current_predicted_trajectory_ = msg;
  current_reference_trajectory_ = sub_reference_traj_->takeData();
  current_kinematics_ = sub_kinematics_->takeData();

  if (!is_data_ready()) return;

  debug_pose_publisher_->clear_markers();

  // 验证预测轨迹
  validate(*current_predicted_trajectory_, *current_reference_trajectory_, *current_kinematics_);

  diag_updater_.force_update();

  // 发布调试信息
  publish_debug_info();
  // 显示状态
  display_status();
}

// 发布调试信息
void ControlValidator::publish_debug_info()
{
  pub_status_->publish(validation_status_);

  if (!is_all_valid(validation_status_)) {
    geometry_msgs::msg::Pose front_pose = current_kinematics_->pose.pose;
    shift_pose(front_pose, vehicle_info_.front_overhang_m + vehicle_info_.wheel_base_m);
    debug_pose_publisher_->push_virtual_wall(front_pose);
    debug_pose_publisher_->push_warning_msg(front_pose, "INVALID CONTROL");
  }
  debug_pose_publisher_->publish();

  // 发布处理时间
  tier4_debug_msgs::msg::Float64Stamped processing_time_msg;
  processing_time_msg.stamp = get_clock()->now();
  processing_time_msg.data = stop_watch.toc();
  pub_processing_time_->publish(processing_time_msg);
}

// 验证预测轨迹
void ControlValidator::validate(
  const Trajectory & predicted_trajectory, const Trajectory & reference_trajectory,
  const Odometry & kinematics)
{
  if (predicted_trajectory.points.size() < 2) {
    RCLCPP_ERROR_THROTTLE(
      get_logger(), *get_clock(), 1000,
      "predicted_trajectory size is less than 2. Cannot validate.");
    return;
  }
  if (reference_trajectory.points.size() < 2) {
    RCLCPP_ERROR_THROTTLE(
      get_logger(), *get_clock(), 1000,
      "reference_trajectory size is less than 2. Cannot validate.");
    return;
  }

  validation_status_.stamp = get_clock()->now();

  // 计算最大横向偏差
  std::tie(
    validation_status_.max_distance_deviation, validation_status_.is_valid_max_distance_deviation) =
    calc_lateral_deviation_status(predicted_trajectory, *current_reference_trajectory_);

  // 计算速度偏差
  calc_velocity_deviation_status(*current_reference_trajectory_, kinematics);

  // 更新无效计数
  validation_status_.invalid_count =
    is_all_valid(validation_status_) ? 0 : validation_status_.invalid_count + 1;
}

// 计算最大横向偏差状态
std::pair<double, bool> ControlValidator::calc_lateral_deviation_status(
  const Trajectory & predicted_trajectory, const Trajectory & reference_trajectory) const
{
  auto max_distance_deviation =
    calc_max_lateral_distance(reference_trajectory, predicted_trajectory);
  return {
    max_distance_deviation,
    max_distance_deviation <= validation_params_.max_distance_deviation_threshold};
}

// 计算速度偏差状态
void ControlValidator::calc_velocity_deviation_status(
  const Trajectory & reference_trajectory, const Odometry & kinematics)
{
  auto & status = validation_status_;
  const auto & params = validation_params_;
  status.vehicle_vel = vehicle_vel_.filter(kinematics.twist.twist.linear.x);
  status.target_vel = target_vel_.filter(
    autoware::motion_utils::calcInterpolatedPoint(reference_trajectory, kinematics.pose.pose)
      .longitudinal_velocity_mps);

  // 判断是否倒车
  const bool is_rolling_back = std::signbit(status.vehicle_vel * status.target_vel) &&
                               std::abs(status.vehicle_vel) > params.rolling_back_velocity;
  if (
    !hold_velocity_error_until_stop_ || !status.is_rolling_back ||
    std::abs(status.vehicle_vel) < 0.05) {
    status.is_rolling_back = is_rolling_back;
  }

  // 判断是否超速
  const bool is_over_velocity =
    std::abs(status.vehicle_vel) >
    std::abs(status.target_vel) * (1.0 + params.over_velocity_ratio) + params.over_velocity_offset;
  if (
    !hold_velocity_error_until_stop_ || !status.is_over_velocity ||
    std::abs(status.vehicle_vel) < 0.05) {
    status.is_over_velocity = is_over_velocity;
  }
}

// 检查所有状态是否有效
bool ControlValidator::is_all_valid(const ControlValidatorStatus & s)
{
  return s.is_valid_max_distance_deviation && !s.is_rolling_back && !s.is_over_velocity;
}

// 显示状态
void ControlValidator::display_status()
{
  if (!display_on_terminal_) return;
  rclcpp::Clock clock{RCL_ROS_TIME};

  const auto warn = [this, &clock](const bool status, const std::string & msg) {
    if (!status) {
      RCLCPP_WARN_THROTTLE(get_logger(), clock, 1000, "%s", msg.c_str());
    }
  };

  const auto & s = validation_status_;

  warn(
    s.is_valid_max_distance_deviation,
    "predicted trajectory is too far from planning trajectory!!");
}

}  // namespace autoware::control_validator

#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::control_validator::ControlValidator)

主要功能说明:

    ControlValidator: 控制验证器节点,用于验证预测轨迹的有效性。

    setup_parameters: 设置节点参数,包括阈值和车辆信息。

    set_status: 设置诊断状态。

    setup_diag: 设置诊断更新器。

    is_data_ready: 检查数据是否准备就绪。

    on_predicted_trajectory: 处理预测轨迹的回调函数。

    validate: 验证预测轨迹的有效性。

    calc_lateral_deviation_status: 计算最大横向偏差状态。

    calc_velocity_deviation_status: 计算速度偏差状态。

    is_all_valid: 检查所有状态是否有效。

    display_status: 显示验证状态。



// 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 "autoware/control_validator/debug_marker.hpp"

#include <autoware/motion_utils/marker/marker_helper.hpp>
#include <autoware/universe_utils/ros/marker_helper.hpp>

#include <string>

using visualization_msgs::msg::Marker;

// 构造函数
ControlValidatorDebugMarkerPublisher::ControlValidatorDebugMarkerPublisher(rclcpp::Node * node)
: node_(node)
{
  // 创建调试标记发布器
  debug_viz_pub_ =
    node_->create_publisher<visualization_msgs::msg::MarkerArray>("~/debug/marker", 1);

  // 创建虚拟墙标记发布器
  virtual_wall_pub_ =
    node_->create_publisher<visualization_msgs::msg::MarkerArray>("~/virtual_wall", 1);
}

// 清除所有标记
void ControlValidatorDebugMarkerPublisher::clear_markers()
{
  marker_array_.markers.clear();
  marker_array_virtual_wall_.markers.clear();
}

// 添加警告消息标记
void ControlValidatorDebugMarkerPublisher::push_warning_msg(
  const geometry_msgs::msg::Pose & pose, const std::string & msg)
{
  // 创建默认的文本标记
  visualization_msgs::msg::Marker marker = autoware::universe_utils::createDefaultMarker(
    "map", node_->get_clock()->now(), "warning_msg", 0, Marker::TEXT_VIEW_FACING,
    autoware::universe_utils::createMarkerScale(0.0, 0.0, 1.0),
    autoware::universe_utils::createMarkerColor(1.0, 0.1, 0.1, 0.999));
  marker.lifetime = rclcpp::Duration::from_seconds(0.2); // 设置标记的生命周期
  marker.pose = pose; // 设置标记的位置
  marker.text = msg; // 设置标记的文本内容
  marker_array_virtual_wall_.markers.push_back(marker); // 将标记添加到虚拟墙标记数组中
}

// 添加虚拟墙标记
void ControlValidatorDebugMarkerPublisher::push_virtual_wall(const geometry_msgs::msg::Pose & pose)
{
  const auto now = node_->get_clock()->now();
  // 创建停止虚拟墙标记
  const auto stop_wall_marker =
    autoware::motion_utils::createStopVirtualWallMarker(pose, "control_validator", now, 0);
  // 将标记添加到虚拟墙标记数组中
  autoware::universe_utils::appendMarkerArray(stop_wall_marker, &marker_array_virtual_wall_, now);
}

// 发布所有标记
void ControlValidatorDebugMarkerPublisher::publish()
{
  debug_viz_pub_->publish(marker_array_); // 发布调试标记
  virtual_wall_pub_->publish(marker_array_virtual_wall_); // 发布虚拟墙标记
}

主要功能说明:

    ControlValidatorDebugMarkerPublisher: 调试标记发布器类,用于发布调试信息和虚拟墙标记。

    clear_markers: 清除所有标记。

    push_warning_msg: 添加警告消息标记。

    push_virtual_wall: 添加虚拟墙标记。

    publish: 发布所有标记。

// Copyright 2023 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 "autoware/control_validator/utils.hpp"

#include "autoware/motion_utils/trajectory/conversion.hpp"
#include "autoware/motion_utils/trajectory/interpolation.hpp"
#include "autoware/motion_utils/trajectory/trajectory.hpp"
#include "autoware/universe_utils/geometry/geometry.hpp"

#include <vector>

namespace autoware::control_validator
{

using autoware::motion_utils::convertToTrajectory; // 将轨迹点数组转换为轨迹
using autoware::motion_utils::convertToTrajectoryPointArray; // 将轨迹转换为轨迹点数组
using autoware_planning_msgs::msg::Trajectory; // 轨迹消息类型
using autoware_planning_msgs::msg::TrajectoryPoint; // 轨迹点消息类型
using geometry_msgs::msg::Pose; // 位姿消息类型
using TrajectoryPoints = std::vector<TrajectoryPoint>; // 轨迹点数组类型

// 沿纵向移动位姿
void shift_pose(Pose & pose, double longitudinal)
{
  const auto yaw = tf2::getYaw(pose.orientation); // 获取偏航角
  pose.position.x += std::cos(yaw) * longitudinal; // 更新x坐标
  pose.position.y += std::sin(yaw) * longitudinal; // 更新y坐标
}

/**
 * @brief 在预测轨迹中插入插值点
 * @param[inout] modified_trajectory 修改后的轨迹
 * @param[in] reference_pose 参考位姿
 * @param[in] predicted_trajectory 预测轨迹
 */
void insert_point_in_predicted_trajectory(
  TrajectoryPoints & modified_trajectory, const Pose & reference_pose,
  const TrajectoryPoints & predicted_trajectory)
{
  // 计算插值点
  const auto point_to_interpolate = autoware::motion_utils::calcInterpolatedPoint(
    convertToTrajectory(predicted_trajectory), reference_pose);
  // 将插值点插入到修改后的轨迹中
  modified_trajectory.insert(modified_trajectory.begin(), point_to_interpolate);
}

// 反转轨迹点数组
TrajectoryPoints reverse_trajectory_points(const TrajectoryPoints & trajectory_points)
{
  TrajectoryPoints reversed_trajectory_points;
  reversed_trajectory_points.reserve(trajectory_points.size()); // 预留空间
  // 反转轨迹点数组
  std::reverse_copy(
    trajectory_points.begin(), trajectory_points.end(),
    std::back_inserter(reversed_trajectory_points));
  return reversed_trajectory_points;
}

// 移除轨迹前端的点
bool remove_front_trajectory_point(
  const TrajectoryPoints & trajectory_points, TrajectoryPoints & modified_trajectory_points,
  const TrajectoryPoints & predicted_trajectory_points)
{
  bool predicted_trajectory_point_removed = false;
  for (const auto & point : predicted_trajectory_points) {
    // 如果预测轨迹点在参考轨迹的前方,则移除
    if (
      autoware::motion_utils::calcLongitudinalOffsetToSegment(
        trajectory_points, 0, point.pose.position) < 0.0) {
      modified_trajectory_points.erase(modified_trajectory_points.begin());

      predicted_trajectory_point_removed = true;
    } else {
      break;
    }
  }

  return predicted_trajectory_point_removed;
}

// 将轨迹与参考轨迹对齐
Trajectory align_trajectory_with_reference_trajectory(
  const Trajectory & trajectory, const Trajectory & predicted_trajectory)
{
  // 计算轨迹最后一段的长度
  const auto last_seg_length = autoware::motion_utils::calcSignedArcLength(
    trajectory.points, trajectory.points.size() - 2, trajectory.points.size() - 1);

  // 如果预测轨迹与参考轨迹没有重叠,返回空轨迹
  const bool & is_p_n_before_t1 =
    autoware::motion_utils::calcLongitudinalOffsetToSegment(
      trajectory.points, 0, predicted_trajectory.points.back().pose.position) < 0.0;
  const bool & is_p1_behind_t_n = autoware::motion_utils::calcLongitudinalOffsetToSegment(
                                    trajectory.points, trajectory.points.size() - 2,
                                    predicted_trajectory.points.front().pose.position) -
                                    last_seg_length >
                                  0.0;
  const bool is_no_overlapping = (is_p_n_before_t1 || is_p1_behind_t_n);

  if (is_no_overlapping) {
    return Trajectory();
  }

  // 将轨迹转换为轨迹点数组
  auto modified_trajectory_points = convertToTrajectoryPointArray(predicted_trajectory);
  auto predicted_trajectory_points = convertToTrajectoryPointArray(predicted_trajectory);
  auto trajectory_points = convertToTrajectoryPointArray(trajectory);

  // 如果预测轨迹的第一个点在参考轨迹的前方,移除这些点并插入插值点
  auto predicted_trajectory_point_removed = remove_front_trajectory_point(
    trajectory_points, modified_trajectory_points, predicted_trajectory_points);

  if (predicted_trajectory_point_removed) {
    insert_point_in_predicted_trajectory(
      modified_trajectory_points, trajectory_points.front().pose, predicted_trajectory_points);
  }

  // 如果预测轨迹的最后一个点在参考轨迹的后方,移除这些点并插入插值点
  auto reversed_predicted_trajectory_points =
    reverse_trajectory_points(predicted_trajectory_points);
  auto reversed_trajectory_points = reverse_trajectory_points(trajectory_points);
  auto reversed_modified_trajectory_points = reverse_trajectory_points(modified_trajectory_points);

  auto reversed_predicted_trajectory_point_removed = remove_front_trajectory_point(
    reversed_trajectory_points, reversed_modified_trajectory_points,
    reversed_predicted_trajectory_points);

  if (reversed_predicted_trajectory_point_removed) {
    insert_point_in_predicted_trajectory(
      reversed_modified_trajectory_points, reversed_trajectory_points.front().pose,
      reversed_predicted_trajectory_points);
  }

  // 返回对齐后的轨迹
  return convertToTrajectory(reverse_trajectory_points(reversed_modified_trajectory_points));
}

// 计算最大横向距离
double calc_max_lateral_distance(
  const Trajectory & reference_trajectory, const Trajectory & predicted_trajectory)
{
  // 对齐预测轨迹与参考轨迹
  const auto alined_predicted_trajectory =
    align_trajectory_with_reference_trajectory(reference_trajectory, predicted_trajectory);
  double max_dist = 0;
  for (const auto & point : alined_predicted_trajectory.points) {
    const auto p0 = autoware::universe_utils::getPoint(point);
    // 找到最近的轨迹段
    const size_t nearest_segment_idx =
      autoware::motion_utils::findNearestSegmentIndex(reference_trajectory.points, p0);
    // 计算横向距离
    const double temp_dist = std::abs(autoware::motion_utils::calcLateralOffset(
      reference_trajectory.points, p0, nearest_segment_idx));
    if (temp_dist > max_dist) {
      max_dist = temp_dist;
    }
  }
  return max_dist;
}

}  // namespace autoware::control_validator

主要功能说明:

    shift_pose: 沿纵向移动位姿。

    insert_point_in_predicted_trajectory: 在预测轨迹中插入插值点。

    reverse_trajectory_points: 反转轨迹点数组。

    remove_front_trajectory_point: 移除轨迹前端的点。

    align_trajectory_with_reference_trajectory: 将轨迹与参考轨迹对齐。

    calc_max_lateral_distance: 计算最大横向距离。


四、autoware_external_cmd_selector

这部分是处理外部指令的,用于在本地控制(local)和远程控制(remote)之间进行切换。
都是人工干预命令,和自动驾驶不是一条线。
本地控制就是安全员在车内的控制。
远程控制就是远程操控中心的控制。

主要作用:
1.命令源选择:在本地控制和远程控制之间切换
2.命令转发:将选中源的命令转发给执行系统
3.安全保障:
心跳检测确保控制源活跃
模式切换服务确保可控的切换过程
4.诊断监控:提供系统状态诊断信息

主要功能:

class ExternalCmdSelector {
  // 两种控制模式
  enum CommandSourceMode {
    LOCAL,   // 本地控制
    REMOTE   // 远程控制
  };
  
  // 处理不同来源的命令
  void onLocalControlCmd();   // 处理本地控制命令
  void onRemoteControlCmd();  // 处理远程控制命令
}

输入命令类型:

// 本地和远程都接收这些类型的命令
sub_local_control_cmd_      // 控制命令(速度、转向等)
sub_local_shift_cmd_        // 档位命令
sub_local_turn_signal_cmd_  // 转向灯命令
sub_local_heartbeat_        // 心跳信号

命令选择逻辑:

void onLocalControlCmd(const ExternalControlCommand::ConstSharedPtr msg) {
  // 只有在本地模式下才转发本地命令
  if (current_selector_mode_.data != CommandSourceMode::LOCAL) {
    return;
  }
  pub_control_cmd_->publish(*msg);
}

配置参数:

ros__parameters:
  update_rate: 10.0                 # 更新频率
  initial_selector_mode: "local"    # 初始模式:local或remote

这个和自动驾驶关系也不大,需要的时候再来看就行。
就一个cpp文件,源码注释:

// Copyright 2020 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 "autoware/external_cmd_selector/external_cmd_selector_node.hpp"

#include <tier4_auto_msgs_converter/tier4_auto_msgs_converter.hpp>

#include <chrono>
#include <memory>
#include <string>
#include <utility>

namespace autoware::external_cmd_selector
{
// 构造函数
ExternalCmdSelector::ExternalCmdSelector(const rclcpp::NodeOptions & node_options)
: Node("external_cmd_selector", node_options)
{
  using std::placeholders::_1;
  using std::placeholders::_2;

  // 参数
  double update_rate = declare_parameter<double>("update_rate"); // 更新频率
  std::string initial_selector_mode = declare_parameter<std::string>("initial_selector_mode"); // 初始选择模式

  // 发布器
  pub_current_selector_mode_ =
    create_publisher<CommandSourceMode>("~/output/current_selector_mode", 1); // 当前选择模式
  pub_control_cmd_ = create_publisher<ExternalControlCommand>("~/output/control_cmd", 1); // 控制命令
  pub_shift_cmd_ = create_publisher<InternalGearShift>("~/output/gear_cmd", 1); // 换挡命令
  pub_turn_signal_cmd_ = create_publisher<InternalTurnSignal>("~/output/turn_indicators_cmd", 1); // 转向灯命令
  pub_hazard_signal_cmd_ = create_publisher<InternalHazardSignal>("~/output/hazard_lights_cmd", 1); // 危险灯命令
  pub_heartbeat_ = create_publisher<InternalHeartbeat>("~/output/heartbeat", 1); // 心跳信号

  // 回调组
  callback_group_subscribers_ =
    this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); // 订阅者回调组
  callback_group_services_ =
    this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); // 服务回调组

  auto subscriber_option = rclcpp::SubscriptionOptions();
  subscriber_option.callback_group = callback_group_subscribers_;

  // 订阅者
  sub_local_control_cmd_ = create_subscription<ExternalControlCommand>(
    "~/input/local/control_cmd", 1, std::bind(&ExternalCmdSelector::onLocalControlCmd, this, _1),
    subscriber_option); // 本地控制命令
  sub_local_shift_cmd_ = create_subscription<ExternalGearShift>(
    "~/input/local/shift_cmd", 1, std::bind(&ExternalCmdSelector::onLocalShiftCmd, this, _1),
    subscriber_option); // 本地换挡命令
  sub_local_turn_signal_cmd_ = create_subscription<ExternalTurnSignal>(
    "~/input/local/turn_signal_cmd", 1,
    std::bind(&ExternalCmdSelector::onLocalTurnSignalCmd, this, _1), subscriber_option); // 本地转向灯命令
  sub_local_heartbeat_ = create_subscription<ExternalHeartbeat>(
    "~/input/local/heartbeat", 1, std::bind(&ExternalCmdSelector::onLocalHeartbeat, this, _1),
    subscriber_option); // 本地心跳信号

  sub_remote_control_cmd_ = create_subscription<ExternalControlCommand>(
    "~/input/remote/control_cmd", 1, std::bind(&ExternalCmdSelector::onRemoteControlCmd, this, _1),
    subscriber_option); // 远程控制命令
  sub_remote_shift_cmd_ = create_subscription<ExternalGearShift>(
    "~/input/remote/shift_cmd", 1, std::bind(&ExternalCmdSelector::onRemoteShiftCmd, this, _1),
    subscriber_option); // 远程换挡命令
  sub_remote_turn_signal_cmd_ = create_subscription<ExternalTurnSignal>(
    "~/input/remote/turn_signal_cmd", 1,
    std::bind(&ExternalCmdSelector::onRemoteTurnSignalCmd, this, _1), subscriber_option); // 远程转向灯命令
  sub_remote_heartbeat_ = create_subscription<ExternalHeartbeat>(
    "~/input/remote/heartbeat", 1, std::bind(&ExternalCmdSelector::onRemoteHeartbeat, this, _1),
    subscriber_option); // 远程心跳信号

  // 服务
  srv_select_external_command_ = create_service<CommandSourceSelect>(
    "~/service/select_external_command",
    std::bind(&ExternalCmdSelector::onSelectExternalCommandService, this, _1, _2),
    rmw_qos_profile_services_default, callback_group_services_); // 选择外部命令服务

  // 初始化模式
  auto convert_selector_mode = [](const std::string & mode_text) {
    if (mode_text == "local") {
      return CommandSourceMode::LOCAL; // 本地模式
    }
    if (mode_text == "remote") {
      return CommandSourceMode::REMOTE; // 远程模式
    }
    throw std::invalid_argument("unknown selector mode"); // 未知模式
  };
  current_selector_mode_.data = convert_selector_mode(initial_selector_mode); // 设置初始模式

  // 诊断更新器
  updater_.setHardwareID("external_cmd_selector");
  updater_.add("heartbeat", [](auto & stat) {
    stat.summary(diagnostic_msgs::msg::DiagnosticStatus::OK, "Alive"); // 心跳状态
  });

  // 定时器
  const auto period_ns = rclcpp::Rate(update_rate).period();
  timer_ = rclcpp::create_timer(
    this, get_clock(), period_ns, std::bind(&ExternalCmdSelector::onTimer, this),
    callback_group_subscribers_); // 定时器回调
}

// 处理本地控制命令
void ExternalCmdSelector::onLocalControlCmd(const ExternalControlCommand::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::LOCAL) {
    return; // 如果当前模式不是本地模式,则忽略
  }
  pub_control_cmd_->publish(*msg); // 发布控制命令
}

// 处理本地换挡命令
void ExternalCmdSelector::onLocalShiftCmd(const ExternalGearShift::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::LOCAL) {
    return; // 如果当前模式不是本地模式,则忽略
  }
  pub_shift_cmd_->publish(convert(*msg)); // 发布换挡命令
}

// 处理本地转向灯命令
void ExternalCmdSelector::onLocalTurnSignalCmd(const ExternalTurnSignal::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::LOCAL) {
    return; // 如果当前模式不是本地模式,则忽略
  }
  auto light_signal = tier4_auto_msgs_converter::convert(*msg); // 转换信号
  pub_turn_signal_cmd_->publish(light_signal.turn_signal); // 发布转向灯命令
  pub_hazard_signal_cmd_->publish(light_signal.hazard_signal); // 发布危险灯命令
}

// 处理本地心跳信号
void ExternalCmdSelector::onLocalHeartbeat(const ExternalHeartbeat::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::LOCAL) {
    return; // 如果当前模式不是本地模式,则忽略
  }
  pub_heartbeat_->publish(convert(*msg)); // 发布心跳信号
}

// 处理远程控制命令
void ExternalCmdSelector::onRemoteControlCmd(const ExternalControlCommand::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::REMOTE) {
    return; // 如果当前模式不是远程模式,则忽略
  }
  pub_control_cmd_->publish(*msg); // 发布控制命令
}

// 处理远程换挡命令
void ExternalCmdSelector::onRemoteShiftCmd(const ExternalGearShift::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::REMOTE) {
    return; // 如果当前模式不是远程模式,则忽略
  }
  pub_shift_cmd_->publish(convert(*msg)); // 发布换挡命令
}

// 处理远程转向灯命令
void ExternalCmdSelector::onRemoteTurnSignalCmd(const ExternalTurnSignal::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::REMOTE) {
    return; // 如果当前模式不是远程模式,则忽略
  }
  auto light_signal = tier4_auto_msgs_converter::convert(*msg); // 转换信号
  pub_turn_signal_cmd_->publish(light_signal.turn_signal); // 发布转向灯命令
  pub_hazard_signal_cmd_->publish(light_signal.hazard_signal); // 发布危险灯命令
}

// 处理远程心跳信号
void ExternalCmdSelector::onRemoteHeartbeat(const ExternalHeartbeat::ConstSharedPtr msg)
{
  if (current_selector_mode_.data != CommandSourceMode::REMOTE) {
    return; // 如果当前模式不是远程模式,则忽略
  }
  pub_heartbeat_->publish(convert(*msg)); // 发布心跳信号
}

// 处理选择外部命令服务
bool ExternalCmdSelector::onSelectExternalCommandService(
  const CommandSourceSelect::Request::SharedPtr req,
  const CommandSourceSelect::Response::SharedPtr res)
{
  current_selector_mode_.data = req->mode.data; // 更新当前选择模式
  res->success = true; // 设置响应成功
  res->message = "Success."; // 设置响应消息
  return true;
}

// 定时器回调
void ExternalCmdSelector::onTimer()
{
  pub_current_selector_mode_->publish(current_selector_mode_); // 发布当前选择模式
  updater_.force_update(); // 强制更新诊断
}

// 转换换挡命令
ExternalCmdSelector::InternalGearShift ExternalCmdSelector::convert(
  const ExternalGearShift & command)
{
  return tier4_auto_msgs_converter::convert(command); // 使用转换工具转换
}

// 转换心跳信号
ExternalCmdSelector::InternalHeartbeat ExternalCmdSelector::convert(
  const ExternalHeartbeat & command)
{
  return command; // 直接返回
}
}  // namespace autoware::external_cmd_selector

#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::external_cmd_selector::ExternalCmdSelector)

主要功能说明:

    ExternalCmdSelector: 外部命令选择器节点,用于选择本地或远程控制命令。

    onLocalControlCmd: 处理本地控制命令。

    onLocalShiftCmd: 处理本地换挡命令。

    onLocalTurnSignalCmd: 处理本地转向灯命令。

    onLocalHeartbeat: 处理本地心跳信号。

    onRemoteControlCmd: 处理远程控制命令。

    onRemoteShiftCmd: 处理远程换挡命令。

    onRemoteTurnSignalCmd: 处理远程转向灯命令。

    onRemoteHeartbeat: 处理远程心跳信号。

    onSelectExternalCommandService: 处理选择外部命令服务。

    onTimer: 定时器回调,发布当前选择模式并更新诊断。

    convert: 转换换挡命令和心跳信号。


五、autoware_joy_controller

这个是手柄控制模块,支持多种游戏手柄来控制车辆。
负责在自动驾驶和手动控制之间切换,并提供手动控制功能。
和上面的那个选择控制源模块配合使用,两个功能包具体的工作流程如下:

joy_controller 将手柄输入转换为控制命令
命令发送到 external_cmd_selector
external_cmd_selector 根据当前模式选择是否转发这些命令

支持的手柄类型:

joy_type: 
  - DS4    # PlayStation 4手柄
  - G29    # Logitech G29方向盘
  - P65    # P65手柄
  - XBOX   # Xbox手柄

主要控制功能:

void AutowareJoyControllerNode::onTimer() {
  // 基本控制
  publishControlCommand();      // 发布控制命令(转向、加速、制动)
  publishExternalControlCommand(); // 发布外部控制命令
  
  // 特殊功能
  publishShift();              // 换挡
  publishTurnSignal();         // 转向灯
  publishGateMode();           // 控制模式切换
  publishAutowareEngage();     // Autoware使能控制
  publishVehicleEngage();      // 车辆使能控制
}

关键参数配置:

ros__parameters:
  update_rate: 10.0           # 更新频率
  accel_ratio: 3.0           # 加速比例
  brake_ratio: 5.0           # 制动比例
  steer_ratio: 0.5           # 转向比例
  max_forward_velocity: 20.0  # 最大前进速度
  max_backward_velocity: 3.0  # 最大后退速度

控制模式:

// 两种控制模式
GateMode::AUTO      // 自动驾驶模式
GateMode::EXTERNAL  // 手动控制模式

// 可以通过手柄切换模式
void publishGateMode() {
  if (prev_gate_mode_ == GateMode::AUTO) {
    gate_mode.data = GateMode::EXTERNAL;
  }
}

就是一个遥控模块,需要的时候再来看。
就一个cpp文件,源码注释如下:

// Copyright 2020 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
//
//     <url id="ctv28g1gem4fc97r3g0" type="url" status="parsed" title="Apache License, Version 2.0" wc="10467">http://www.apache.org/licenses/LICENSE-2.0</url> 
//
// 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 "autoware/joy_controller/joy_controller.hpp"
#include "autoware/joy_controller/joy_converter/ds4_joy_converter.hpp"
#include "autoware/joy_controller/joy_converter/g29_joy_converter.hpp"
#include "autoware/joy_controller/joy_converter/p65_joy_converter.hpp"
#include "autoware/joy_controller/joy_converter/xbox_joy_converter.hpp"

#include <tier4_api_utils/tier4_api_utils.hpp>

#include <algorithm>
#include <memory>
#include <string>

// 命名空间声明
namespace
{
    // 使用autoware::joy_controller命名空间中的类型
    using autoware::joy_controller::GateModeType;
    using autoware::joy_controller::GearShiftType;
    using autoware::joy_controller::TurnSignalType;
    using GearShift = tier4_external_api_msgs::msg::GearShift;
    using TurnSignal = tier4_external_api_msgs::msg::TurnSignal;
    using GateMode = tier4_control_msgs::msg::GateMode;

    // 获取上一个档位
    GearShiftType getUpperShift(const GearShiftType & shift)
    {
        // 根据当前档位返回上一个档位
        if (shift == GearShift::NONE) {
            return GearShift::PARKING;
        }
        if (shift == GearShift::PARKING) {
            return GearShift::REVERSE;
        }
        if (shift == GearShift::REVERSE) {
            return GearShift::NEUTRAL;
        }
        if (shift == GearShift::NEUTRAL) {
            return GearShift::DRIVE;
        }
        if (shift == GearShift::DRIVE) {
            return GearShift::LOW;
        }
        if (shift == GearShift::LOW) {
            return GearShift::LOW;
        }

        return GearShift::NONE;
    }

    // 获取下一个档位
    GearShiftType getLowerShift(const GearShiftType & shift)
    {
        // 根据当前档位返回下一个档位
        if (shift == GearShift::NONE) {
            return GearShift::PARKING;
        }
        if (shift == GearShift::PARKING) {
            return GearShift::PARKING;
        }
        if (shift == GearShift::REVERSE) {
            return GearShift::PARKING;
        }
        if (shift == GearShift::NEUTRAL) {
            return GearShift::REVERSE;
        }
        if (shift == GearShift::DRIVE) {
            return GearShift::NEUTRAL;
        }
        if (shift == GearShift::LOW) {
            return GearShift::DRIVE;
        }

        return GearShift::NONE;
    }

    // 获取档位名称
    const char * getShiftName(const GearShiftType & shift)
    {
        // 根据档位类型返回对应的名称
        if (shift == GearShift::NONE) {
            return "NONE";
        }
        if (shift == GearShift::PARKING) {
            return "PARKING";
        }
        if (shift == GearShift::REVERSE) {
            return "REVERSE";
        }
        if (shift == GearShift::NEUTRAL) {
            return "NEUTRAL";
        }
        if (shift == GearShift::DRIVE) {
            return "DRIVE";
        }
        if (shift == GearShift::LOW) {
            return "LOW";
        }

        return "NOT_SUPPORTED";
    }

    // 获取转向灯名称
    const char * getTurnSignalName(const TurnSignalType & turn_signal)
    {
        // 根据转向灯类型返回对应的名称
        if (turn_signal == TurnSignal::NONE) {
            return "NONE";
        }
        if (turn_signal == TurnSignal::LEFT) {
            return "LEFT";
        }
        if (turn_signal == TurnSignal::RIGHT) {
            return "RIGHT";
        }
        if (turn_signal == TurnSignal::HAZARD) {
            return "HAZARD";
        }

        return "NOT_SUPPORTED";
    }

    // 获取门模式名称
    const char * getGateModeName(const GateModeType & gate_mode)
    {
        // 根据门模式类型返回对应的名称
        using tier4_control_msgs::msg::GateMode;

        if (gate_mode == GateMode::AUTO) {
            return "AUTO";
        }
        if (gate_mode == GateMode::EXTERNAL) {
            return "EXTERNAL";
        }

        return "NOT_SUPPORTED";
    }

    // 计算映射值
    double calcMapping(const double input, const double sensitivity)
    {
        // 根据输入值和灵敏度计算映射值
        const double exponent = 1.0 / (std::max(0.001, std::min(1.0, sensitivity)));
        return std::pow(input, exponent);
    }

}  // namespace

// autoware::joy_controller命名空间
namespace autoware::joy_controller
{
    // 乔伊控制器节点类
    void AutowareJoyControllerNode::onJoy()
    {
        // 获取乔伊消息
        const auto msg = sub_joy_.takeData();
        if (!msg) {
            return;
        }

        // 更新最后接收到乔伊消息的时间
        last_joy_received_time_ = msg->header.stamp;
        // 根据乔伊类型创建对应的乔伊转换器
        if (joy_type_ == "G29") {
            joy_ = std::make_shared<const G29JoyConverter>(*msg);
        } else if (joy_type_ == "DS4") {
            joy_ = std::make_shared<const DS4JoyConverter>(*msg);
        } else if (joy_type_ == "XBOX") {
            joy_ = std::make_shared<const XBOXJoyConverter>(*msg);
        } else {
            joy_ = std::make_shared<const P65JoyConverter>(*msg);
        }

        // 处理档位相关操作
        if (joy_->shift_up() || joy_->shift_down() || joy_->shift_drive() || joy_->shift_reverse()) {
            publishShift();
        }

        // 处理转向灯相关操作
        if (joy_->turn_signal_left() || joy_->turn_signal_right() || joy_->clear_turn_signal()) {
            publishTurnSignal();
        }

        // 处理门模式相关操作
        if (joy_->gate_mode()) {
            publishGateMode();
        }

        // 处理自动驾驶相关操作
        if (joy_->autoware_engage() || joy_->autoware_disengage()) {
            publishAutowareEngage();
        }

        // 处理车辆相关操作
        if (joy_->vehicle_engage() || joy_->vehicle_disengage()) {
            publishVehicleEngage();
        }

        // 处理紧急停止相关操作
        if (joy_->emergency_stop()) {
            sendEmergencyRequest(true);
        }

        // 处理清除紧急停止相关操作
        if (joy_->clear_emergency_stop()) {
            sendEmergencyRequest(false);
        }
    }

    // 处理里程计消息
    void AutowareJoyControllerNode::onOdometry()
    {
        // 如果是原始控制模式,则直接返回
        if (raw_control_) {
            return;
        }

        // 获取里程计消息
        const auto msg = sub_odom_.takeData();
        if (!msg) {
            return;
        }

        // 创建并更新里程计消息
        auto twist = std::make_shared<geometry_msgs::msg::TwistStamped>();
        twist->header = msg->header;
        twist->twist = msg->twist.twist;

        twist_ = twist;
    }

    // 检查数据是否准备好
    bool AutowareJoyControllerNode::isDataReady()
    {
        // 检查乔伊消息是否准备好
        {
            if (!joy_) {
                RCLCPP_WARN_THROTTLE(
                    get_logger(), *get_clock(), std::chrono::milliseconds(5000).count(),
                    "waiting for joy msg...");
                return false;
            }

            // 检查乔伊消息是否超时
            constexpr auto timeout = 2.0;
            const auto time_diff = this->now() - last_joy_received_time_;
            if (time_diff.seconds() > timeout) {
                RCLCPP_WARN_THROTTLE(
                    get_logger(), *get_clock(), std::chrono::milliseconds(5000).count(),
                    "joy msg is timeout");
                return false;
            }
        }

        // 检查里程计消息是否准备好
        if (!raw_control_) {
            if (!twist_) {
                RCLCPP_WARN_THROTTLE(
                    get_logger(), *get_clock(), std::chrono::milliseconds(5000).count(),
                    "waiting for twist msg...");
                return false;
            }

            // 检查里程计消息是否超时
            constexpr auto timeout = 0.5;
            const auto time_diff = this->now() - twist_->header.stamp;
            if (time_diff.seconds() > timeout) {
                RCLCPP_WARN_THROTTLE(
                    get_logger(), *get_clock(), std::chrono::milliseconds(5000).count(),
                    "twist msg is timeout");
                return false;
            }
        }

        return true;
    }

    // 定时器回调函数
    void AutowareJoyControllerNode::onTimer()
    {
        // 处理里程计消息
        onOdometry();
        // 处理乔伊消息
        onJoy();

        // 如果数据没有准备好,则直接返回
        if (!isDataReady()) {
            return;
        }

        // 发布控制命令
        publishControlCommand();
        // 发布外部控制命令
        publishExternalControlCommand();
        // 发布心跳消息
        publishHeartbeat();
    }

    // 发布控制命令
    void AutowareJoyControllerNode::publishControlCommand()
    {
        // 创建控制命令消息
        autoware_control_msgs::msg::Control cmd;
        cmd.stamp = this->now();
        {
            // 计算转向角度和转向角速度
            cmd.lateral.steering_tire_angle = steer_ratio_ * joy_->steer();
            cmd.lateral.steering_tire_rotation_rate = steering_angle_velocity_;

            // 处理加速操作
            if (joy_->accel()) {
                cmd.longitudinal.acceleration = accel_ratio_ * joy_->accel();
                cmd.longitudinal.velocity =
                    twist_->twist.linear.x + velocity_gain_ * cmd.longitudinal.acceleration;
                cmd.longitudinal.velocity =
                    std::min(cmd.longitudinal.velocity, static_cast<float>(max_forward_velocity_));
            }

            // 处理制动操作
            if (joy_->brake()) {
                cmd.longitudinal.velocity = 0.0;
                cmd.longitudinal.acceleration = -brake_ratio_ * joy_->brake();
            }

            // 处理反向加速操作
            if (joy_->accel() && joy_->brake()) {
                cmd.longitudinal.acceleration = backward_accel_ratio_ * joy_->accel();
                cmd.longitudinal.velocity =
                    twist_->twist.linear.x - velocity_gain_ * cmd.longitudinal.acceleration;
                cmd.longitudinal.velocity =
                    std::max(cmd.longitudinal.velocity, static_cast<float>(-max_backward_velocity_));
            }
        }

        // 发布控制命令消息
        pub_control_command_->publish(cmd);
        prev_control_command_ = cmd;
    }

    // 发布外部控制命令
    void AutowareJoyControllerNode::publishExternalControlCommand()
    {
        // 创建外部控制命令消息
        tier4_external_api_msgs::msg::ControlCommandStamped cmd_stamped;
        cmd_stamped.stamp = this->now();
        {
            auto & cmd = cmd_stamped.control;

            // 计算转向角度和转向角速度
            cmd.steering_angle = steer_ratio_ * joy_->steer();
            cmd.steering_angle_velocity = steering_angle_velocity_;
            // 计算油门和制动值
            cmd.throttle =
                accel_ratio_ * calcMapping(static_cast<double>(joy_->accel()), accel_sensitivity_);
            cmd.brake = brake_ratio_ * calcMapping(static_cast<double>(joy_->brake()), brake_sensitivity_);
        }

        // 发布外部控制命令消息
        pub_external_control_command_->publish(cmd_stamped);
        prev_external_control_command_ = cmd_stamped.control;
    }

    // 发布档位消息
    void AutowareJoyControllerNode::publishShift()
    {
        // 创建档位消息
        tier4_external_api_msgs::msg::GearShiftStamped gear_shift;
        gear_shift.stamp = this->now();

        // 处理档位相关操作
        if (joy_->shift_up()) {
            gear_shift.gear_shift.data = getUpperShift(prev_shift_);
        }

        if (joy_->shift_down()) {
            gear_shift.gear_shift.data = getLowerShift(prev_shift_);
        }

        if (joy_->shift_drive()) {
            gear_shift.gear_shift.data = GearShift::DRIVE;
        }

        if (joy_->shift_reverse()) {
            gear_shift.gear_shift.data = GearShift::REVERSE;
        }

        // 打印档位信息
        RCLCPP_INFO(get_logger(), "GearShift::%s", getShiftName(gear_shift.gear_shift.data));

        // 发布档位消息
        pub_shift_->publish(gear_shift);
        prev_shift_ = gear_shift.gear_shift.data;
    }

    // 发布转向灯消息
    void AutowareJoyControllerNode::publishTurnSignal()
    {
        // 创建转向灯消息
        tier4_external_api_msgs::msg::TurnSignalStamped turn_signal;
        turn_signal.stamp = this->now();

        // 处理转向灯相关操作
        if (joy_->turn_signal_left() && joy_->turn_signal_right()) {
            turn_signal.turn_signal.data = TurnSignal::HAZARD;
        } else if (joy_->turn_signal_left()) {
            turn_signal.turn_signal.data = TurnSignal::LEFT;
        } else if (joy_->turn_signal_right()) {
            turn_signal.turn_signal.data = TurnSignal::RIGHT;
        }

        if (joy_->clear_turn_signal()) {
            turn_signal.turn_signal.data = TurnSignal::NONE;
        }

        // 打印转向灯信息
        RCLCPP_INFO(get_logger(), "TurnSignal::%s", getTurnSignalName(turn_signal.turn_signal.data));

        // 发布转向灯消息
        pub_turn_signal_->publish(turn_signal);
    }

    // 发布门模式消息
    void AutowareJoyControllerNode::publishGateMode()
    {
        // 创建门模式消息
        tier4_control_msgs::msg::GateMode gate_mode;

        // 处理门模式相关操作
        if (prev_gate_mode_ == GateMode::AUTO) {
            gate_mode.data = GateMode::EXTERNAL;
        }

        if (prev_gate_mode_ == GateMode::EXTERNAL) {
            gate_mode.data = GateMode::AUTO;
        }

        // 打印门模式信息
        RCLCPP_INFO(get_logger(), "GateMode::%s", getGateModeName(gate_mode.data));

        // 发布门模式消息
        pub_gate_mode_->publish(gate_mode);
        prev_gate_mode_ = gate_mode.data;
    }

    // 发布心跳消息
    void AutowareJoyControllerNode::publishHeartbeat()
    {
        // 创建心跳消息
        tier4_external_api_msgs::msg::Heartbeat heartbeat;
        heartbeat.stamp = this->now();
        // 发布心跳消息
        pub_heartbeat_->publish(heartbeat);
    }

    // 发送紧急停止请求
    void AutowareJoyControllerNode::sendEmergencyRequest(bool emergency)
    {
        // 打印紧急停止信息
        RCLCPP_INFO(get_logger(), "%s emergency stop", emergency ? "Set" : "Clear");

        // 创建紧急停止请求
        auto request = std::make_shared<tier4_external_api_msgs::srv::SetEmergency::Request>();
        request->emergency = emergency;

        // 发送紧急停止请求
        client_emergency_stop_->async_send_request(
            request,
            [this](rclcpp::Client<tier4_external_api_msgs::srv::SetEmergency>::SharedFuture result) {
                auto response = result.get();
                if (tier4_api_utils::is_success(response->status)) {
                    RCLCPP_INFO(get_logger(), "service succeeded");
                } else {
                    RCLCPP_WARN(get_logger(), "service failed: %s", response->status.message.c_str());
                }
            });
    }

    // 发布自动驾驶启动/停止请求
    void AutowareJoyControllerNode::publishAutowareEngage()
    {
        // 创建自动驾驶启动/停止请求
        auto req = std::make_shared<tier4_external_api_msgs::srv::Engage::Request>();
        if (joy_->autoware_engage()) {
            req->engage = true;
            RCLCPP_INFO(get_logger(), "Autoware Engage");
        }

        if (joy_->autoware_disengage()) {
            req->engage = false;
            RCLCPP_INFO(get_logger(), "Autoware Disengage");
        }

        // 检查服务是否可用
        if (!client_autoware_engage_->service_is_ready()) {
            RCLCPP_WARN(get_logger(), "%s is unavailable", client_autoware_engage_->get_service_name());
            return;
        }

        // 发送自动驾驶启动/停止请求
        client_autoware_engage_->async_send_request(
            req, [this](rclcpp::Client<tier4_external_api_msgs::srv::Engage>::SharedFuture result) {
                RCLCPP_INFO(
                    get_logger(), "%s: %d, %s", client_autoware_engage_->get_service_name(),
                    result.get()->status.code, result.get()->status.message.c_str());
            });
    }

    // 发布车辆启动/停止请求
    void AutowareJoyControllerNode::publishVehicleEngage()
    {
        // 创建车辆启动/停止请求
        autoware_vehicle_msgs::msg::Engage engage;

        if (joy_->vehicle_engage()) {
            engage.engage = true;
            RCLCPP_INFO(get_logger(), "Vehicle Engage");
        }

        if (joy_->vehicle_disengage()) {
            engage.engage = false;
            RCLCPP_INFO(get_logger(), "Vehicle Disengage");
        }

        // 发布车辆启动/停止请求
        pub_vehicle_engage_->publish(engage);
    }

    // 初始化定时器
    void AutowareJoyControllerNode::initTimer(double period_s)
    {
        // 将周期转换为纳秒
        const auto period_ns =
            std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double>(period_s));
        // 创建定时器
        timer_ = rclcpp::create_timer(
            this, get_clock(), period_ns, std::bind(&AutowareJoyControllerNode::onTimer, this));
    }

    // 构造函数
    AutowareJoyControllerNode::AutowareJoyControllerNode(const rclcpp::NodeOptions & node_options)
        : Node("autoware_joy_controller", node_options)
    {
        // 获取参数
        joy_type_ = declare_parameter<std::string>("joy_type");
        update_rate_ = declare_parameter<double>("update_rate");
        accel_ratio_ = declare_parameter<double>("accel_ratio");
        brake_ratio_ = declare_parameter<double>("brake_ratio");
        steer_ratio_ = declare_parameter<double>("steer_ratio");
        steering_angle_velocity_ = declare_parameter<double>("steering_angle_velocity");
        accel_sensitivity_ = declare_parameter<double>("accel_sensitivity");
        brake_sensitivity_ = declare_parameter<double>("brake_sensitivity");
        raw_control_ = declare_parameter<bool>("control_command.raw_control");
        velocity_gain_ = declare_parameter<double>("control_command.velocity_gain");
        max_forward_velocity_ = declare_parameter<double>("control_command.max_forward_velocity");
        max_backward_velocity_ = declare_parameter<double>("control_command.max_backward_velocity");
        backward_accel_ratio_ = declare_parameter<double>("control_command.backward_accel_ratio");

        // 打印乔伊类型信息
        RCLCPP_INFO(get_logger(), "Joy type: %s", joy_type_.c_str());

        // 创建回调组
        callback_group_services_ =
            this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);

        // 创建订阅者
        if (raw_control_) {
            twist_ = std::make_shared<geometry_msgs::msg::TwistStamped>();
        }

        // 创建发布者
        pub_control_command_ =
            this->create_publisher<autoware_control_msgs::msg::Control>("output/control_command", 1);
        pub_external_control_command_ =
            this->create_publisher<tier4_external_api_msgs::msg::ControlCommandStamped>(
                "output/external_control_command", 1);
        pub_shift_ =
            this->create_publisher<tier4_external_api_msgs::msg::GearShiftStamped>("output/shift", 1);
        pub_turn_signal_ = this->create_publisher<tier4_external_api_msgs::msg::TurnSignalStamped>(
            "output/turn_signal", 1);
        pub_gate_mode_ = this->create_publisher<tier4_control_msgs::msg::GateMode>("output/gate_mode", 1);
        pub_heartbeat_ =
            this->create_publisher<tier4_external_api_msgs::msg::Heartbeat>("output/heartbeat", 1);
        pub_vehicle_engage_ =
            this->create_publisher<autoware_vehicle_msgs::msg::Engage>("output/vehicle_engage", 1);

        // 创建服务客户端
        client_emergency_stop_ = this->create_client<tier4_external_api_msgs::srv::SetEmergency>(
            "service/emergency_stop", rmw_qos_profile_services_default, callback_group_services_);
        while (!client_emergency_stop_->wait_for_service(std::chrono::seconds(1))) {
            if (!rclcpp::ok()) {
                RCLCPP_ERROR(get_logger(), "Interrupted while waiting for service.");
                rclcpp::shutdown();
                return;
            }
            RCLCPP_INFO(get_logger(), "Waiting for emergency_stop service connection...");
        }

        client_autoware_engage_ =
            this->create_client<tier4_external_api_msgs::srv::Engage>("service/autoware_engage");

        // 初始化定时器
        initTimer(1.0 / update_rate_);
    }
}  // namespace autoware::joy_controller

// 注册节点宏
#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::joy_controller::AutowareJoyControllerNode)

六、autoware_lane_departure_checker

是否偏离车道检测,检测完之后发布检测信息,再由别的模块接收。
这个模块不会进行车辆控制。

主要功能&输入&输出

主要功能:

主要作用:
1. 实时监控车辆位置
2.预警可能的车道偏离
3.检测实际的车道偏离
4.检测边界线越线


主要检测类型:
ros__parameters:
  # 三种检测模式
  will_out_of_lane_checker: false    # 是否即将偏离车道
  out_of_lane_checker: false         # 是否已经偏离车道
  boundary_departure_checker: true    # 是否越过边界线

关键检测参数:

# 检测阈值
footprint_margin_scale: 1.0          # 车辆轮廓边界裕度
max_lateral_deviation: 2.0           # 最大横向偏差
max_longitudinal_deviation: 2.0      # 最大纵向偏差
max_yaw_deviation_deg: 60.0         # 最大偏航角偏差

主要检测功能:
void LaneDepartureChecker::update() {
  // 1. 轨迹偏差检测
  output.trajectory_deviation = calcTrajectoryDeviation(
    reference_trajectory, current_pose);
    
  // 2. 车道偏离检测
  output.is_out_of_lane = isOutOfLane(
    candidate_lanelets, vehicle_footprint);
    
  // 3. 边界越线检测
  output.will_cross_boundary = willCrossBoundary(
    vehicle_footprints, uncrossable_boundaries);
}


安全功能:
// 计算制动距离
double calcBrakingDistance(
  const double velocity,
  const double max_deceleration,
  const double delay_time)
{
  return (velocity * velocity) / (2.0 * max_deceleration) + 
         delay_time * velocity;
}



输入:

定位信息:
// 车辆当前位置和状态
"~/input/odometry": "/localization/kinematic_state"

地图信息:
// Lanelet2地图数据
"~/input/lanelet_map_bin": "/map/vector_map"

规划轨迹:
// 参考轨迹和预测轨迹
"~/input/reference_trajectory": "/planning/scenario_planning/trajectory"
"~/input/predicted_trajectory": "/control/trajectory_follower/predicted_trajectory"

路径信息:
// 规划路径
"~/input/route": "/planning/mission_planning/route"

配置参数:
# 检测参数
footprint_margin_scale: 1.0     # 车辆轮廓边界裕度
max_lateral_deviation: 2.0      # 最大横向偏差
max_longitudinal_deviation: 2.0 # 最大纵向偏差
boundary_types_to_detect: [curbstone]  # 需要检测的边界类型



输出:

诊断状态 (Diagnostic Status):
void checkLaneDeparture(DiagnosticStatusWrapper & stat) {
  // 车道偏离状态
  if (output_.is_out_of_lane) {
    stat.summary(DiagnosticStatus::ERROR, "vehicle is out of lane!");
  }
  // 轨迹偏差状态
  if (output_.trajectory_deviation.lateral_deviation > param_.max_lateral_deviation) {
    stat.summary(DiagnosticStatus::ERROR, "lateral deviation is too large!");
  }
}

检测结果 (Output):
struct Output {
  bool will_leave_lane;           // 是否即将偏离车道
  bool is_out_of_lane;           // 是否已偏离车道
  bool will_cross_boundary;      // 是否将越过边界
  
  PoseDeviation trajectory_deviation;  // 轨迹偏差信息
  std::vector<LinearRing2d> vehicle_footprints;  // 车辆轮廓
}


可视化信息:
// 发布可视化标记
visualization_msgs::msg::MarkerArray createDebugMarkerArray() {
  // 显示车道线
  marker_array.markers.push_back(createLaneletMarker());
  
  // 显示车辆轮廓
  marker_array.markers.push_back(createVehicleFootprintMarker());
  
  // 显示偏差信息
  marker_array.markers.push_back(createDeviationMarker());
}


处理时间信息:
// 发布处理时间
pub_processing_time_ = create_publisher<Float64Stamped>(
  "~/debug/processing_time_ms", 1);


2.源码注释

三个cpp文件。

lane_departure_checker_node.cpp

// Copyright 2020 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
//
//     <url id="" type="url" status="" title="" wc="">http://www.apache.org/licenses/LICENSE-2.0</url> 
//
// 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 "autoware/lane_departure_checker/lane_departure_checker_node.hpp"

#include <autoware/universe_utils/math/unit_conversion.hpp>
#include <autoware/universe_utils/ros/marker_helper.hpp>
#include <autoware/universe_utils/system/stop_watch.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_lanelet2_extension/visualization/visualization.hpp>

#include <autoware_planning_msgs/msg/lanelet_segment.hpp>

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

// 使用命名空间中的函数
using autoware::universe_utils::rad2deg;

// 命名空间声明
namespace
{
    // 使用autoware_planning_msgs命名空间中的类型
    using autoware_planning_msgs::msg::LaneletSegment;

    // 将三角形转换为点
    std::array<geometry_msgs::msg::Point, 3> triangle2points(
        const geometry_msgs::msg::Polygon & triangle)
    {
        std::array<geometry_msgs::msg::Point, 3> points;
        for (size_t i = 0; i < 3; ++i) {
            const auto & p = triangle.points.at(i);

            geometry_msgs::msg::Point point;
            point.x = static_cast<double>(p.x);
            point.y = static_cast<double>(p.y);
            point.z = static_cast<double>(p.z);
            points.at(i) = point;
        }
        return points;
    }

    // 获取路线车道
    std::map<lanelet::Id, lanelet::ConstLanelet> getRouteLanelets(
        const lanelet::LaneletMapPtr & lanelet_map,
        const lanelet::routing::RoutingGraphPtr & routing_graph,
        const autoware_planning_msgs::msg::LaneletRoute::ConstSharedPtr & route_ptr,
        const double vehicle_length)
    {
        std::map<lanelet::Id, lanelet::ConstLanelet> route_lanelets;

        bool is_route_valid = lanelet::utils::route::isRouteValid(*route_ptr, lanelet_map);
        if (!is_route_valid) {
            return route_lanelets;
        }

        // 添加前路线段的前车道以防止检测错误
        {
            const auto extension_length = 2 * vehicle_length;

            for (const auto & primitive : route_ptr->segments.front().primitives) {
                const auto lane_id = primitive.id;
                for (const auto & lanelet_sequence : lanelet::utils::query::getPrecedingLaneletSequences(
                         routing_graph, lanelet_map->laneletLayer.get(lane_id), extension_length)) {
                    for (const auto & preceding_lanelet : lanelet_sequence) {
                        route_lanelets[preceding_lanelet.id()] = preceding_lanelet;
                    }
                }
            }
        }

        for (const auto & route_section : route_ptr->segments) {
            for (const auto & primitive : route_section.primitives) {
                const auto lane_id = primitive.id;
                route_lanelets[lane_id] = lanelet_map->laneletLayer.get(lane_id);
            }
        }

        // 添加最后路线段的后车道以防止检测错误
        {
            const auto extension_length = 2 * vehicle_length;

            for (const auto & primitive : route_ptr->segments.back().primitives) {
                const auto lane_id = primitive.id;
                for (const auto & lanelet_sequence : lanelet::utils::query::getSucceedingLaneletSequences(
                         routing_graph, lanelet_map->laneletLayer.get(lane_id), extension_length)) {
                    for (const auto & succeeding_lanelet : lanelet_sequence) {
                        route_lanelets[succeeding_lanelet.id()] = succeeding_lanelet;
                    }
                }
            }
        }

        return route_lanelets;
    }

    // 更新参数
    template <typename T>
    void update_param(
        const std::vector<rclcpp::Parameter> & parameters, const std::string & name, T & value)
    {
        auto it = std::find_if(
            parameters.cbegin(), parameters.cend(),
            [&name](const rclcpp::Parameter & parameter) { return parameter.get_name() == name; });
        if (it != parameters.cend()) {
            value = it->template get_value<T>();
        }
    }

}  // namespace

// autoware::lane_departure_checker命名空间
namespace autoware::lane_departure_checker
{
    // 车道偏离检查器节点类
    LaneDepartureCheckerNode::LaneDepartureCheckerNode(const rclcpp::NodeOptions & options)
        : Node("lane_departure_checker_node", options)
    {
        using std::placeholders::_1;

        // 启用功能
        node_param_.will_out_of_lane_checker = declare_parameter<bool>("will_out_of_lane_checker");
        node_param_.out_of_lane_checker = declare_parameter<bool>("out_of_lane_checker");
        node_param_.boundary_departure_checker = declare_parameter<bool>("boundary_departure_checker");

        // 节点参数
        node_param_.update_rate = declare_parameter<double>("update_rate");
        node_param_.visualize_lanelet = declare_parameter<bool>("visualize_lanelet");
        node_param_.include_right_lanes = declare_parameter<bool>("include_right_lanes");
        node_param_.include_left_lanes = declare_parameter<bool>("include_left_lanes");
        node_param_.include_opposite_lanes = declare_parameter<bool>("include_opposite_lanes");
        node_param_.include_conflicting_lanes = declare_parameter<bool>("include_conflicting_lanes");

        // 边界偏离检查器
        node_param_.boundary_types_to_detect =
            declare_parameter<std::vector<std::string>>("boundary_types_to_detect");

        // 车辆信息
        const auto vehicle_info = autoware::vehicle_info_utils::VehicleInfoUtils(*this).getVehicleInfo();
        vehicle_length_m_ = vehicle_info.vehicle_length_m;

        // 核心参数
        param_.footprint_margin_scale = declare_parameter<double>("footprint_margin_scale");
        param_.footprint_extra_margin = declare_parameter<double>("footprint_extra_margin");
        param_.resample_interval = declare_parameter<double>("resample_interval");
        param_.max_deceleration = declare_parameter<double>("max_deceleration");
        param_.delay_time = declare_parameter<double>("delay_time");
        param_.max_lateral_deviation = declare_parameter<double>("max_lateral_deviation");
        param_.max_longitudinal_deviation = declare_parameter<double>("max_longitudinal_deviation");
        param_.max_yaw_deviation_deg = declare_parameter<double>("max_yaw_deviation_deg");
        param_.ego_nearest_dist_threshold = declare_parameter<double>("ego_nearest_dist_threshold");
        param_.ego_nearest_yaw_threshold = declare_parameter<double>("ego_nearest_yaw_threshold");
        param_.min_braking_distance = declare_parameter<double>("min_braking_distance");

        // 参数回调
        set_param_res_ =
            add_on_set_parameters_callback(std::bind(&LaneDepartureCheckerNode::onParameter, this, _1));

        // 核心
        lane_departure_checker_ = std::make_unique<LaneDepartureChecker>();
        lane_departure_checker_->setParam(param_, vehicle_info);

        // 发布者
        processing_time_publisher_ =
            this->create_publisher<tier4_debug_msgs::msg::Float64Stamped>("~/debug/processing_time_ms", 1);
        // 无操作

        // 诊断更新器
        updater_.setHardwareID("lane_departure_checker");

        updater_.add("lane_departure", this, &LaneDepartureCheckerNode::checkLaneDeparture);

        updater_.add("trajectory_deviation", this, &LaneDepartureCheckerNode::checkTrajectoryDeviation);

        // 定时器
        const auto period_ns = rclcpp::Rate(node_param_.update_rate).period();
        timer_ = rclcpp::create_timer(
            this, get_clock(), period_ns, std::bind(&LaneDepartureCheckerNode::onTimer, this));
    }

    // 检查数据是否准备好
    bool LaneDepartureCheckerNode::isDataReady()
    {
        if (!current_odom_) {
            RCLCPP_INFO_THROTTLE(get_logger(), *get_clock(), 5000, "waiting for current_twist msg...");
            return false;
        }

        if (!lanelet_map_) {
            RCLCPP_INFO_THROTTLE(get_logger(), *get_clock(), 5000, "waiting for lanelet_map msg...");
            return false;
        }

        if (!route_) {
            RCLCPP_INFO_THROTTLE(get_logger(), *get_clock(), 5000, "waiting for route msg...");
            return false;
        }

        if (!reference_trajectory_) {
            RCLCPP_INFO_THROTTLE(
                get_logger(), *get_clock(), 5000, "waiting for reference_trajectory msg...");
            return false;
        }

        if (!predicted_trajectory_) {
            RCLCPP_INFO_THROTTLE(
                get_logger(), *get_clock(), 5000, "waiting for predicted_trajectory msg...");
            return false;
        }

        if (!operation_mode_) {
            RCLCPP_INFO_THROTTLE(get_logger(), *get_clock(), 5000, "waiting for operation_mode msg...");
            return false;
        }

        if (!control_mode_) {
            RCLCPP_INFO_THROTTLE(get_logger(), *get_clock(), 5000, "waiting for control_mode msg...");
            return false;
        }

        return true;
    }

    // 检查数据是否超时
    bool LaneDepartureCheckerNode::isDataTimeout()
    {
        const auto now = this->now();

        constexpr double th_pose_timeout = 1.0;
        const auto pose_time_diff = rclcpp::Time(current_odom_->header.stamp) - now;
        if (pose_time_diff.seconds() > th_pose_timeout) {
            RCLCPP_WARN_THROTTLE(get_logger(), *get_clock(), 5000, "pose is timeout...");
            return true;
        }

        return false;
    }

    // 检查数据是否有效
    bool LaneDepartureCheckerNode::isDataValid()
    {
        if (reference_trajectory_->points.empty()) {
            RCLCPP_ERROR_THROTTLE(
                get_logger(), *get_clock(), 5000, "reference_trajectory is empty. Not expected!");
            return false;
        }

        if (predicted_trajectory_->points.empty()) {
            RCLCPP_ERROR_THROTTLE(
                get_logger(), *get_clock(), 5000, "predicted_trajectory is empty. Not expected!");
            return false;
        }

        return true;
    }

    // 定时器回调函数
    void LaneDepartureCheckerNode::onTimer()
    {
        std::map<std::string, double> processing_time_map;
        autoware::universe_utils::StopWatch<std::chrono::milliseconds> stop_watch;
        stop_watch.tic("Total");

        current_odom_ = sub_odom_.takeData();
        route_ = sub_route_.takeData();
        reference_trajectory_ = sub_reference_trajectory_.takeData();
        predicted_trajectory_ = sub_predicted_trajectory_.takeData();
        operation_mode_ = sub_operation_mode_.takeData();
        control_mode_ = sub_control_mode_.takeData();

        const auto lanelet_map_bin_msg = sub_lanelet_map_bin_.takeData();
        if (lanelet_map_bin_msg) {
            lanelet_map_ = std::make_shared<lanelet::LaneletMap>();
            lanelet::utils::conversion::fromBinMsg(
                *lanelet_map_bin_msg, lanelet_map_, &traffic_rules_, &routing_graph_);

            // 获取所有路肩车道
            lanelet::ConstLanelets all_lanelets = lanelet::utils::query::laneletLayer(lanelet_map_);
            shoulder_lanelets_ = lanelet::utils::query::shoulderLanelets(all_lanelets);
        }

        if (!isDataReady()) {
            return;
        }

        if (isDataTimeout()) {
            return;
        }

        if (!isDataValid()) {
            return;
        }

        processing_time_map["Node: checkData"] = stop_watch.toc(true);

        // 为了等待地图和路线都准备好,这里不使用回调函数
        if (last_route_ != route_ && !route_->segments.empty()) {
            std::map<lanelet::Id, lanelet::ConstLanelet>::iterator itr;

            auto map_route_lanelets_ =
                getRouteLanelets(lanelet_map_, routing_graph_, route_, vehicle_length_m_);

            lanelet::ConstLanelets shared_lanelets_tmp;

            for (itr = map_route_lanelets_.begin(); itr != map_route_lanelets_.end(); ++itr) {
                const auto shared_lanelet = getAllSharedLineStringLanelets(
                    itr->second, node_param_.include_right_lanes, node_param_.include_left_lanes,
                    node_param_.include_opposite_lanes, node_param_.include_conflicting_lanes, true);
                shared_lanelets_tmp.insert(
                    shared_lanelets_tmp.end(), shared_lanelet.begin(), shared_lanelet.end());
            }
            for (const auto & lanelet : shared_lanelets_tmp) {
                map_route_lanelets_[lanelet.id()] = lanelet;
            }
            route_lanelets_.clear();
            for (itr = map_route_lanelets_.begin(); itr != map_route_lanelets_.end(); ++itr) {
                route_lanelets_.push_back(itr->second);
            }
            last_route_ = route_;
        }
        processing_time_map["Node: getRouteLanelets"] = stop_watch.toc(true);

        input_.current_odom = current_odom_;
        input_.lanelet_map = lanelet_map_;
        input_.route = route_;
        input_.route_lanelets = route_lanelets_;
        input_.shoulder_lanelets = shoulder_lanelets_;
        input_.reference_trajectory = reference_trajectory_;
        input_.predicted_trajectory = predicted_trajectory_;
        input_.boundary_types_to_detect = node_param_.boundary_types_to_detect;
        processing_time_map["Node: setInputData"] = stop_watch.toc(true);

        output_ = lane_departure_checker_->update(input_);
        processing_time_map["Node: update"] = stop_watch.toc(true);

        updater_.force_update();
        processing_time_map["Node: updateDiagnostics"] = stop_watch.toc(true);

        {
            const auto & deviation = output_.trajectory_deviation;
            debug_publisher_.publish<tier4_debug_msgs::msg::Float64Stamped>(
                "deviation/lateral", deviation.lateral);
            debug_publisher_.publish<tier4_debug_msgs::msg::Float64Stamped>("deviation/yaw", deviation.yaw);
            debug_publisher_.publish<tier4_debug_msgs::msg::Float64Stamped>(
                "deviation/yaw_deg", rad2deg(deviation.yaw));
        }
        processing_time_map["Node: publishTrajectoryDeviation"] = stop_watch.toc(true);

        debug_publisher_.publish<visualization_msgs::msg::MarkerArray>(
            std::string("marker_array"), createMarkerArray());
        processing_time_map["Node: publishDebugMarker"] = stop_watch.toc(true);

        // 合并处理时间映射
        for (const auto & m : output_.processing_time_map) {
            processing_time_map["Core: " + m.first] = m.second;
        }

        processing_time_map["Total"] = stop_watch.toc("Total");
        processing_diag_publisher_.publish(processing_time_map);
        tier4_debug_msgs::msg::Float64Stamped processing_time_msg;
        processing_time_msg.stamp = get_clock()->now();
        processing_time_msg.data = processing_time_map["Total"];
        processing_time_publisher_->publish(processing_time_msg);
    }

    // 参数回调函数
    rcl_interfaces::msg::SetParametersResult LaneDepartureCheckerNode::onParameter(
        const std::vector<rclcpp::Parameter> & parameters)
    {
        rcl_interfaces::msg::SetParametersResult result;
        result.successful = true;
        result.reason = "success";

        try {
            // 启用功能
            update_param(parameters, "will_out_of_lane_checker", node_param_.will_out_of_lane_checker);
            update_param(parameters, "out_of_lane_checker", node_param_.out_of_lane_checker);
            update_param(parameters, "boundary_departure_checker", node_param_.boundary_departure_checker);

            // 节点
            update_param(parameters, "visualize_lanelet", node_param_.visualize_lanelet);
            update_param(parameters, "include_right_lanes", node_param_.include_right_lanes);
            update_param(parameters, "include_left_lanes", node_param_.include_left_lanes);
            update_param(parameters, "include_opposite_lanes", node_param_.include_opposite_lanes);
            update_param(parameters, "include_conflicting_lanes", node_param_.include_conflicting_lanes);
            update_param(parameters, "boundary_departure_checker", node_param_.boundary_departure_checker);
            update_param(parameters, "boundary_types_to_detect", node_param_.boundary_types_to_detect);

            // 核心
            update_param(parameters, "footprint_margin_scale", param_.footprint_margin_scale);
            update_param(parameters, "footprint_extra_margin", param_.footprint_extra_margin);
            update_param(parameters, "resample_interval", param_.resample_interval);
            update_param(parameters, "max_deceleration", param_.max_deceleration);
            update_param(parameters, "delay_time", param_.delay_time);
            update_param(parameters, "min_braking_distance", param_.min_braking_distance);

            if (lane_departure_checker_) {
                lane_departure_checker_->setParam(param_);
            }
        } catch (const rclcpp::exceptions::InvalidParameterTypeException & e) {
            result.successful = false;
            result.reason = e.what();
        }

        return result;
    }

    // 检查车道偏离
    void LaneDepartureCheckerNode::checkLaneDeparture(
        diagnostic_updater::DiagnosticStatusWrapper & stat)
    {
        using DiagStatus = diagnostic_msgs::msg::DiagnosticStatus;
        int8_t level = DiagStatus::OK;
        std::string msg = "OK";

        if (output_.will_leave_lane && node_param_.will_out_of_lane_checker) {
            level = DiagStatus::WARN;
            msg = "vehicle will leave lane";
        }

        if (output_.is_out_of_lane && node_param_.out_of_lane_checker) {
            level = DiagStatus::ERROR;
            msg = "vehicle is out of lane";
        }

        if (output_.will_cross_boundary && node_param_.boundary_departure_checker) {
            level = DiagStatus::ERROR;
            msg = "vehicle will cross boundary";
        }

        stat.summary(level, msg);
    }

    // 检查轨迹偏差
    void LaneDepartureCheckerNode::checkTrajectoryDeviation(
        diagnostic_updater::DiagnosticStatusWrapper & stat)
    {
        using DiagStatus = diagnostic_msgs::msg::DiagnosticStatus;
        using ControlModeStatus = autoware_vehicle_msgs::msg::ControlModeReport;
        using OperationModeStatus = autoware_adapi_v1_msgs::msg::OperationModeState;

        int8_t level = DiagStatus::OK;

        if (std::abs(output_.trajectory_deviation.lateral) >= param_.max_lateral_deviation) {
            level = DiagStatus::ERROR;
        }

        if (std::abs(output_.trajectory_deviation.longitudinal) >= param_.max_longitudinal_deviation) {
            level = DiagStatus::ERROR;
        }

        if (std::abs(rad2deg(output_.trajectory_deviation.yaw)) >= param_.max_yaw_deviation_deg) {
            level = DiagStatus::ERROR;
        }

        std::string msg = "OK";
        if (
            level == DiagStatus::ERROR && operation_mode_->mode == OperationModeStatus::AUTONOMOUS &&
            control_mode_->mode == ControlModeStatus::AUTONOMOUS) {
            msg = "trajectory deviation is too large";
        } else {
            level = DiagStatus::OK;
        }

        stat.addf("max lateral deviation", "%.3f", param_.max_lateral_deviation);
        stat.addf("lateral deviation", "%.3f", output_.trajectory_deviation.lateral);

        stat.addf("max longitudinal deviation", "%.3f", param_.max_longitudinal_deviation);
        stat.addf("longitudinal deviation", "%.3f", output_.trajectory_deviation.longitudinal);

        stat.addf("max yaw deviation", "%.3f", param_.max_yaw_deviation_deg);
        stat.addf("yaw deviation", "%.3f", rad2deg(output_.trajectory_deviation.yaw));

        stat.summary(level, msg);
    }

    // 创建标记数组
    visualization_msgs::msg::MarkerArray LaneDepartureCheckerNode::createMarkerArray() const
    {
        using autoware::universe_utils::createDefaultMarker;
        using autoware::universe_utils::createMarkerColor;
        using autoware::universe_utils::createMarkerScale;

        visualization_msgs::msg::MarkerArray marker_array;

        const auto base_link_z = current_odom_->pose.pose.position.z;

        if (node_param_.visualize_lanelet) {
            // 路线车道
            {
                auto marker = createDefaultMarker(
                    "map", this->now(), "route_lanelets", 0, visualization_msgs::msg::Marker::TRIANGLE_LIST,
                    createMarkerScale(1.0, 1.0, 1.0), createMarkerColor(0.0, 0.5, 0.5, 0.5));

                for (const auto & lanelet : input_.route_lanelets) {
                    std::vector<geometry_msgs::msg::Polygon> triangles;
                    lanelet::visualization::lanelet2Triangle(lanelet, &triangles);

                    for (const auto & triangle : triangles) {
                        for (const auto & point : triangle2points(triangle)) {
                            marker.points.push_back(point);
                            marker.colors.push_back(marker.color);
                        }
                    }
                }

                marker_array.markers.push_back(marker);
            }

            // 候选车道
            {
                auto marker = createDefaultMarker(
                    "map", this->now(), "candidate_lanelets", 0, visualization_msgs::msg::Marker::TRIANGLE_LIST,
                    createMarkerScale(1.0, 1.0, 1.0), createMarkerColor(1.0, 1.0, 0.0, 0.5));

                for (const auto & lanelet : output_.candidate_lanelets) {
                    std::vector<geometry_msgs::msg::Polygon> triangles;
                    lanelet::visualization::lanelet2Triangle(lanelet, &triangles);

                    for (const auto & triangle : triangles) {
                        for (const auto & point : triangle2points(triangle)) {
                            marker.points.push_back(point);
                            marker.colors.push_back(marker.color);
                        }
                    }
                }

                marker_array.markers.push_back(marker);
            }
        }

        if (output_.resampled_trajectory.size() >= 2) {
            // 重采样轨迹线
            {
                auto marker = createDefaultMarker(
                    "map", this->now(), "resampled_trajectory_line", 0,
                    visualization_msgs::msg::Marker::LINE_STRIP, createMarkerScale(0.05, 0, 0),
                    createMarkerColor(1.0, 1.0, 1.0, 0.999));

                for (const auto & p : output_.resampled_trajectory) {
                    marker.points.push_back(p.pose.position);
                    marker.colors.push_back(marker.color);
                }

                marker_array.markers.push_back(marker);
            }

            // 重采样轨迹点
            {
                auto marker = createDefaultMarker(
                    "map", this->now(), "resampled_trajectory_points", 0,
                    visualization_msgs::msg::Marker::SPHERE_LIST, createMarkerScale(0.1, 0.1, 0.1),
                    createMarkerColor(0.0, 1.0, 0.0, 0.999));

                for (const auto & p : output_.resampled_trajectory) {
                    marker.points.push_back(p.pose.position);
                    marker.colors.push_back(marker.color);
                }

                marker_array.markers.push_back(marker);
            }
        }

        // 车辆足迹
        {
            const auto color_ok = createMarkerColor(0.0, 1.0, 0.0, 0.5);
            const auto color_will_leave_lane = createMarkerColor(0.5, 0.5, 0.0, 0.5);
            const auto color_is_out_of_lane = createMarkerColor(1.0, 0.0, 0.0, 0.5);

            auto color = color_ok;
            if (output_.will_leave_lane) {
                color = color_will_leave_lane;
            }
            if (output_.is_out_of_lane) {
                color = color_is_out_of_lane;
            }

            auto marker = createDefaultMarker(
                "map", this->now(), "vehicle_footprints", 0, visualization_msgs::msg::Marker::LINE_LIST,
                createMarkerScale(0.05, 0, 0), color);

            for (const auto & vehicle_footprint : output_.vehicle_footprints) {
                for (size_t i = 0; i < vehicle_footprint.size() - 1; ++i) {
                    const auto p1 = vehicle_footprint.at(i);
                    const auto p2 = vehicle_footprint.at(i + 1);

                    marker.points.push_back(toMsg(p1.to_3d(base_link_z)));
                    marker.points.push_back(toMsg(p2.to_3d(base_link_z)));
                }
            }

            marker_array.markers.push_back(marker);
        }

        return marker_array;
    }

    // 获取所有共享线字符串车道
    lanelet::ConstLanelets LaneDepartureCheckerNode::getAllSharedLineStringLanelets(
        const lanelet::ConstLanelet & current_lane, const bool is_right, const bool is_left,
        const bool is_opposite, const bool is_conflicting, const bool & invert_opposite)
    {
        lanelet::ConstLanelets shared{current_lane};

        if (is_right) {
            const lanelet::ConstLanelets all_right_lanelets =
                getAllRightSharedLinestringLanelets(current_lane, is_opposite, invert_opposite);
            shared.insert(shared.end(), all_right_lanelets.begin(), all_right_lanelets.end());
        }

        if (is_left) {
            const lanelet::ConstLanelets all_left_lanelets =
                getAllLeftSharedLinestringLanelets(current_lane, is_opposite, invert_opposite);
            shared.insert(shared.end(), all_left_lanelets.begin(), all_left_lanelets.end());
        }

        if (is_conflicting) {
            const auto conflicting_lanelets =
                lanelet::utils::getConflictingLanelets(routing_graph_, current_lane);
            shared.insert(shared.end(), conflicting_lanelets.begin(), conflicting_lanelets.end());
        }
        return shared;
    }

    // 获取所有右侧共享线字符串车道
    lanelet::ConstLanelets LaneDepartureCheckerNode::getAllRightSharedLinestringLanelets(
        const lanelet::ConstLanelet & lane, const bool & include_opposite, const bool & invert_opposite)
    {
        lanelet::ConstLanelets linestring_shared;
        auto lanelet_at_right = getRightLanelet(lane);
        auto lanelet_at_right_opposite = getRightOppositeLanelets(lane);
        while (lanelet_at_right) {
            linestring_shared.push_back(lanelet_at_right.get());
            lanelet_at_right = getRightLanelet(lanelet_at_right.get());
            if (!lanelet_at_right) {
                break;
            }
            lanelet_at_right_opposite = getRightOppositeLanelets(lanelet_at_right.get());
        }

        if (!lanelet_at_right_opposite.empty() && include_opposite) {
            if (invert_opposite) {
                linestring_shared.push_back(lanelet_at_right_opposite.front().invert());
            } else {
                linestring_shared.push_back(lanelet_at_right_opposite.front());
            }
            auto lanelet_at_left = getLeftLanelet(lanelet_at_right_opposite.front());
            while (lanelet_at_left) {
                if (invert_opposite) {
                    linestring_shared.push_back(lanelet_at_left.get().invert());
                } else {
                    linestring_shared.push_back(lanelet_at_left.get());
                }
                lanelet_at_left = getLeftLanelet(lanelet_at_left.get());
            }
        }
        return linestring_shared;
    }

    // 获取所有左侧共享线字符串车道
    lanelet::ConstLanelets LaneDepartureCheckerNode::getAllLeftSharedLinestringLanelets(
        const lanelet::ConstLanelet & lane, const bool & include_opposite, const bool & invert_opposite)
    {
        lanelet::ConstLanelets linestring_shared;
        auto lanelet_at_left = getLeftLanelet(lane);
        auto lanelet_at_left_opposite = getLeftOppositeLanelets(lane);
        while (lanelet_at_left) {
            linestring_shared.push_back(lanelet_at_left.get());
            lanelet_at_left = getLeftLanelet(lanelet_at_left.get());
            if (!lanelet_at_left) {
                break;
            }
            lanelet_at_left_opposite = getLeftOppositeLanelets(lanelet_at_left.get());
        }

        if (!lanelet_at_left_opposite.empty() && include_opposite) {
            if (invert_opposite) {
                linestring_shared.push_back(lanelet_at_left_opposite.front().invert());
            } else {
                linestring_shared.push_back(lanelet_at_left_opposite.front());
            }
            auto lanelet_at_right = getRightLanelet(lanelet_at_left_opposite.front());
            while (lanelet_at_right) {
                if (invert_opposite) {
                    linestring_shared.push_back(lanelet_at_right.get().invert());
                } else {
                    linestring_shared.push_back(lanelet_at_right.get());
                }
                lanelet_at_right = getRightLanelet(lanelet_at_right.get());
            }
        }
        return linestring_shared;
    }

    // 获取左侧车道
    boost::optional<lanelet::ConstLanelet> LaneDepartureCheckerNode::getLeftLanelet(
        const lanelet::ConstLanelet & lanelet)
    {
        // 可路由车道
        const auto & left_lane = routing_graph_->left(lanelet);
        if (left_lane) {
            return left_lane;
        }

        // 不可路由车道(例如,变道不可行)
        const auto & adjacent_left_lane = routing_graph_->adjacentLeft(lanelet);
        return adjacent_left_lane;
    }

    // 获取左侧对向车道
    lanelet::Lanelets LaneDepartureCheckerNode::getLeftOppositeLanelets(
        const lanelet::ConstLanelet & lanelet)
    {
        const auto opposite_candidate_lanelets =
            lanelet_map_->laneletLayer.findUsages(lanelet.leftBound().invert());

        lanelet::Lanelets opposite_lanelets;
        for (const auto & candidate_lanelet : opposite_candidate_lanelets) {
            if (candidate_lanelet.rightBound().id() == lanelet.leftBound().id()) {
                continue;
            }

            opposite_lanelets.push_back(candidate_lanelet);
        }

        return opposite_lanelets;
    }

    // 获取右侧车道
    boost::optional<lanelet::ConstLanelet> LaneDepartureCheckerNode::getRightLanelet(
        const lanelet::ConstLanelet & lanelet) const
    {
        // 可路由车道
        const auto & right_lane = routing_graph_->right(lanelet);
        if (right_lane) {
            return right_lane;
        }

        // 不可路由车道(例如,变道不可行)
        const auto & adjacent_right_lane = routing_graph_->adjacentRight(lanelet);
        return adjacent_right_lane;
    }

    // 获取右侧对向车道
    lanelet::Lanelets LaneDepartureCheckerNode::getRightOppositeLanelets(
        const lanelet::ConstLanelet & lanelet)
    {
        const auto opposite_candidate_lanelets =
            lanelet_map_->laneletLayer.findUsages(lanelet.rightBound().invert());

        lanelet::Lanelets opposite_lanelets;
        for (const auto & candidate_lanelet : opposite_candidate_lanelets) {
            if (candidate_lanelet.leftBound().id() == lanelet.rightBound().id()) {
                continue;
            }

            opposite_lanelets.push_back(candidate_lanelet);
        }

        return opposite_lanelets;
    }

}  // namespace autoware::lane_departure_checker

// 注册节点宏
#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::lane_departure_checker::LaneDepartureCheckerNode)

lane_departure_checker.cpp

// Copyright 2020 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
//
//     <url id="ctv3lkcr4djh7of05mjg" type="url" status="parsed" title="Apache License, Version 2.0" wc="10467">http://www.apache.org/licenses/LICENSE-2.0</url> 
//
// 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 "autoware/lane_departure_checker/lane_departure_checker.hpp"

#include "autoware/lane_departure_checker/utils.hpp"

#include <autoware/motion_utils/trajectory/trajectory.hpp>
#include <autoware/universe_utils/math/normalization.hpp>
#include <autoware/universe_utils/math/unit_conversion.hpp>
#include <autoware/universe_utils/system/stop_watch.hpp>

#include <boost/geometry.hpp>

#include <lanelet2_core/geometry/Polygon.h>
#include <tf2/utils.h>

#include <algorithm>
#include <vector>

// 使用命名空间中的函数
using autoware::motion_utils::calcArcLength;
using autoware::universe_utils::LinearRing2d;
using autoware::universe_utils::LineString2d;
using autoware::universe_utils::MultiPoint2d;
using autoware::universe_utils::MultiPolygon2d;
using autoware::universe_utils::Point2d;

// 命名空间声明
namespace
{
    // 使用autoware_planning_msgs命名空间中的类型
    using autoware_planning_msgs::msg::Trajectory;
    using autoware_planning_msgs::msg::TrajectoryPoint;
    using TrajectoryPoints = std::vector<TrajectoryPoint>;
    using geometry_msgs::msg::Point;

    // 计算制动距离
    double calcBrakingDistance(
        const double abs_velocity, const double max_deceleration, const double delay_time)
    {
        return (abs_velocity * abs_velocity) / (2.0 * max_deceleration) + delay_time * abs_velocity;
    }

    // 检查点是否在任何车道内
    bool isInAnyLane(const lanelet::ConstLanelets & candidate_lanelets, const Point2d & point)
    {
        for (const auto & ll : candidate_lanelets) {
            if (boost::geometry::within(point, ll.polygon2d().basicPolygon())) {
                return true;
            }
        }

        return false;
    }

    // 从足迹创建凸包
    LinearRing2d createHullFromFootprints(const std::vector<LinearRing2d> & footprints)
    {
        MultiPoint2d combined;
        for (const auto & footprint : footprints) {
            for (const auto & p : footprint) {
                combined.push_back(p);
            }
        }

        LinearRing2d hull;
        boost::geometry::convex_hull(combined, hull);

        return hull;
    }

    // 获取候选车道
    lanelet::ConstLanelets getCandidateLanelets(
        const lanelet::ConstLanelets & route_lanelets,
        const std::vector<LinearRing2d> & vehicle_footprints)
    {
        lanelet::ConstLanelets candidate_lanelets;

        // 查找在足迹凸包内的车道
        const auto footprint_hull = createHullFromFootprints(vehicle_footprints);
        for (const auto & route_lanelet : route_lanelets) {
            const auto poly = route_lanelet.polygon2d().basicPolygon();
            if (!boost::geometry::disjoint(poly, footprint_hull)) {
                candidate_lanelets.push_back(route_lanelet);
            }
        }

        return candidate_lanelets;
    }

}  // namespace

// autoware::lane_departure_checker命名空间
namespace autoware::lane_departure_checker
{
    // 更新车道偏离检查器
    Output LaneDepartureChecker::update(const Input & input)
    {
        Output output{};

        autoware::universe_utils::StopWatch<std::chrono::milliseconds> stop_watch;

        // 计算轨迹偏差
        output.trajectory_deviation = calcTrajectoryDeviation(
            *input.reference_trajectory, input.current_odom->pose.pose, param_.ego_nearest_dist_threshold,
            param_.ego_nearest_yaw_threshold);
        output.processing_time_map["calcTrajectoryDeviation"] = stop_watch.toc(true);

        // 计算制动距离
        {
            constexpr double min_velocity = 0.01;
            const auto & raw_abs_velocity = std::abs(input.current_odom->twist.twist.linear.x);
            const auto abs_velocity = raw_abs_velocity < min_velocity ? 0.0 : raw_abs_velocity;

            const auto braking_distance = std::max(
                param_.min_braking_distance,
                calcBrakingDistance(abs_velocity, param_.max_deceleration, param_.delay_time));

            // 重采样轨迹并裁剪
            output.resampled_trajectory = utils::cutTrajectory(
                utils::resampleTrajectory(*input.predicted_trajectory, param_.resample_interval),
                braking_distance);
            output.processing_time_map["resampleTrajectory"] = stop_watch.toc(true);
        }

        // 创建车辆足迹
        output.vehicle_footprints = utils::createVehicleFootprints(
            input.current_odom->pose, output.resampled_trajectory, *vehicle_info_ptr_,
            param_.footprint_margin_scale);
        output.processing_time_map["createVehicleFootprints"] = stop_watch.toc(true);

        // 创建车辆通过区域
        output.vehicle_passing_areas = createVehiclePassingAreas(output.vehicle_footprints);
        output.processing_time_map["createVehiclePassingAreas"] = stop_watch.toc(true);

        // 获取候选车道
        const auto candidate_road_lanelets =
            getCandidateLanelets(input.route_lanelets, output.vehicle_footprints);
        const auto candidate_shoulder_lanelets =
            getCandidateLanelets(input.shoulder_lanelets, output.vehicle_footprints);
        output.candidate_lanelets = candidate_road_lanelets;
        output.candidate_lanelets.insert(
            output.candidate_lanelets.end(), candidate_shoulder_lanelets.begin(),
            candidate_shoulder_lanelets.end());

        output.processing_time_map["getCandidateLanelets"] = stop_watch.toc(true);

        // 检查车辆是否会离开车道
        output.will_leave_lane = willLeaveLane(output.candidate_lanelets, output.vehicle_footprints);
        output.processing_time_map["willLeaveLane"] = stop_watch.toc(true);

        // 检查车辆是否已经偏离车道
        output.is_out_of_lane = isOutOfLane(output.candidate_lanelets, output.vehicle_footprints.front());
        output.processing_time_map["isOutOfLane"] = stop_watch.toc(true);

        // 检查车辆是否会穿过边界
        const double max_search_length_for_boundaries =
            calcMaxSearchLengthForBoundaries(*input.predicted_trajectory);
        const auto uncrossable_boundaries = extractUncrossableBoundaries(
            *input.lanelet_map, input.predicted_trajectory->points.front().pose.position,
            max_search_length_for_boundaries, input.boundary_types_to_detect);
        output.will_cross_boundary = willCrossBoundary(output.vehicle_footprints, uncrossable_boundaries);
        output.processing_time_map["willCrossBoundary"] = stop_watch.toc(true);

        return output;
    }

    // 检查路径是否会离开车道
    bool LaneDepartureChecker::checkPathWillLeaveLane(
        const lanelet::ConstLanelets & lanelets, const PathWithLaneId & path) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        // 创建车辆足迹
        std::vector<LinearRing2d> vehicle_footprints =
            utils::createVehicleFootprints(path, *vehicle_info_ptr_, param_.footprint_extra_margin);
        // 获取候选车道
        lanelet::ConstLanelets candidate_lanelets = getCandidateLanelets(lanelets, vehicle_footprints);
        // 检查车辆是否会离开车道
        return willLeaveLane(candidate_lanelets, vehicle_footprints);
    }

    // 计算轨迹偏差
    PoseDeviation LaneDepartureChecker::calcTrajectoryDeviation(
        const Trajectory & trajectory, const geometry_msgs::msg::Pose & pose, const double dist_threshold,
        const double yaw_threshold)
    {
        // 查找最近点
        const auto nearest_idx = autoware::motion_utils::findFirstNearestIndexWithSoftConstraints(
            trajectory.points, pose, dist_threshold, yaw_threshold);
        // 计算偏差
        return autoware::universe_utils::calcPoseDeviation(trajectory.points.at(nearest_idx).pose, pose);
    }

    // 创建车辆通过区域
    std::vector<LinearRing2d> LaneDepartureChecker::createVehiclePassingAreas(
        const std::vector<LinearRing2d> & vehicle_footprints)
    {
        // 创建相邻车辆足迹的凸包
        std::vector<LinearRing2d> areas;
        for (size_t i = 0; i < vehicle_footprints.size() - 1; ++i) {
            const auto & footprint1 = vehicle_footprints.at(i);
            const auto & footprint2 = vehicle_footprints.at(i + 1);
            areas.push_back(createHullFromFootprints({footprint1, footprint2}));
        }

        return areas;
    }

    // 检查车辆是否会离开车道
    bool LaneDepartureChecker::willLeaveLane(
        const lanelet::ConstLanelets & candidate_lanelets,
        const std::vector<LinearRing2d> & vehicle_footprints) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        // 检查每个车辆足迹是否在候选车道内
        for (const auto & vehicle_footprint : vehicle_footprints) {
            if (isOutOfLane(candidate_lanelets, vehicle_footprint)) {
                return true;
            }
        }

        return false;
    }

    // 从路径获取车道
    std::vector<std::pair<double, lanelet::Lanelet>> LaneDepartureChecker::getLaneletsFromPath(
        const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        // 获取足迹凸包的基本多边形
        std::vector<LinearRing2d> vehicle_footprints =
            utils::createVehicleFootprints(path, *vehicle_info_ptr_, param_.footprint_extra_margin);
        LinearRing2d footprint_hull = createHullFromFootprints(vehicle_footprints);

        lanelet::BasicPolygon2d footprint_hull_basic_polygon = toBasicPolygon2D(footprint_hull);

        // 查找与足迹凸包相交的所有车道
        return lanelet::geometry::findWithin2d(
            lanelet_map_ptr->laneletLayer, footprint_hull_basic_polygon, 0.0);
    }

    // 获取路径的融合车道多边形
    std::optional<autoware::universe_utils::Polygon2d>
    LaneDepartureChecker::getFusedLaneletPolygonForPath(
        const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        const auto lanelets_distance_pair = getLaneletsFromPath(lanelet_map_ptr, path);
        if (lanelets_distance_pair.empty()) return std::nullopt;

        // 将车道融合成一个基本多边形
        autoware::universe_utils::MultiPolygon2d lanelet_unions;
        autoware::universe_utils::MultiPolygon2d result;

        for (size_t i = 0; i < lanelets_distance_pair.size(); ++i) {
            const auto & route_lanelet = lanelets_distance_pair.at(i).second;
            const auto & p = route_lanelet.polygon2d().basicPolygon();
            autoware::universe_utils::Polygon2d poly = toPolygon2D(p);
            boost::geometry::union_(lanelet_unions, poly, result);
            lanelet_unions = result;
            result.clear();
        }

        if (lanelet_unions.empty()) return std::nullopt;
        return lanelet_unions.front();
    }

    // 更新路径的融合车道多边形
    bool LaneDepartureChecker::updateFusedLaneletPolygonForPath(
        const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path,
        std::vector<lanelet::Id> & fused_lanelets_id,
        std::optional<autoware::universe_utils::Polygon2d> & fused_lanelets_polygon) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        const auto lanelets_distance_pair = getLaneletsFromPath(lanelet_map_ptr, path);
        if (lanelets_distance_pair.empty()) return false;

        autoware::universe_utils::MultiPolygon2d lanelet_unions;
        autoware::universe_utils::MultiPolygon2d result;

        if (fused_lanelets_polygon) lanelet_unions.push_back(fused_lanelets_polygon.value());

        for (size_t i = 0; i < lanelets_distance_pair.size(); ++i) {
            const auto & route_lanelet = lanelets_distance_pair.at(i).second;
            bool id_exist = std::any_of(
                fused_lanelets_id.begin(), fused_lanelets_id.end(),
                [&](const auto & id) { return id == route_lanelet.id(); });

            if (id_exist) continue;

            const auto & p = route_lanelet.polygon2d().basicPolygon();
            autoware::universe_utils::Polygon2d poly = toPolygon2D(p);
            boost::geometry::union_(lanelet_unions, poly, result);
            lanelet_unions = result;
            result.clear();
            fused_lanelets_id.push_back(route_lanelet.id());
        }

        if (lanelet_unions.empty()) {
            fused_lanelets_polygon = std::nullopt;
            return false;
        }

        fused_lanelets_polygon = lanelet_unions.front();
        return true;
    }

    // 检查路径是否会离开车道
    bool LaneDepartureChecker::checkPathWillLeaveLane(
        const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        // 检查足迹是否完全包含在融合车道多边形内
        const std::vector<LinearRing2d> vehicle_footprints =
            utils::createVehicleFootprints(path, *vehicle_info_ptr_, param_.footprint_extra_margin);
        const auto fused_lanelets_polygon = getFusedLaneletPolygonForPath(lanelet_map_ptr, path);
        if (!fused_lanelets_polygon) return true;
        return !std::all_of(
            vehicle_footprints.begin(), vehicle_footprints.end(),
            [&fused_lanelets_polygon](const auto & footprint) {
                return boost::geometry::within(footprint, fused_lanelets_polygon.value());
            });
    }

    // 检查路径是否会离开车道
    bool LaneDepartureChecker::checkPathWillLeaveLane(
        const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path,
        std::vector<lanelet::Id> & fused_lanelets_id,
        std::optional<autoware::universe_utils::Polygon2d> & fused_lanelets_polygon) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        const std::vector<LinearRing2d> vehicle_footprints =
            utils::createVehicleFootprints(path, *vehicle_info_ptr_, param_.footprint_extra_margin);

        auto is_all_footprints_within = [&](const auto & polygon) {
            return std::all_of(
                vehicle_footprints.begin(), vehicle_footprints.end(),
                [&polygon](const auto & footprint) { return boost::geometry::within(footprint, polygon); });
        };

        // 如果车道多边形存在且所有足迹都在其内,则路径不会离开车道
        if (fused_lanelets_polygon && is_all_footprints_within(fused_lanelets_polygon.value())) {
            return false;
        }

        // 更新当前路径的车道多边形
        if (!updateFusedLaneletPolygonForPath(
                lanelet_map_ptr, path, fused_lanelets_id, fused_lanelets_polygon)) {
            // 如果更新失败,则假设路径会离开车道
            return true;
        }

        // 检查任何足迹是否在更新后的车道多边形外
        return !is_all_footprints_within(fused_lanelets_polygon.value());
    }

    // 裁剪车道外的点
    PathWithLaneId LaneDepartureChecker::cropPointsOutsideOfLanes(
        const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path, const size_t end_index,
        std::vector<lanelet::Id> & fused_lanelets_id,
        std::optional<autoware::universe_utils::Polygon2d> & fused_lanelets_polygon)
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        PathWithLaneId temp_path;

        // 更新当前路径的车道多边形
        if (
            path.points.empty() || !updateFusedLaneletPolygonForPath(
                                     lanelet_map_ptr, path, fused_lanelets_id, fused_lanelets_polygon)) {
            return temp_path;
        }

        const auto vehicle_footprints =
            utils::createVehicleFootprints(path, *vehicle_info_ptr_, param_.footprint_extra_margin);

        {
            universe_utils::ScopedTimeTrack st2(
                "check if footprint is within fused_lanelets_polygon", *time_keeper_);

            size_t idx = 0;
            std::for_each(
                vehicle_footprints.begin(), vehicle_footprints.end(), [&](const auto & footprint) {
                    if (idx > end_index || boost::geometry::within(footprint, fused_lanelets_polygon.value())) {
                        temp_path.points.push_back(path.points.at(idx));
                    }
                    ++idx;
                });
        }
        PathWithLaneId cropped_path = path;
        cropped_path.points = temp_path.points;
        return cropped_path;
    }

    // 检查车辆是否已经偏离车道
    bool LaneDepartureChecker::isOutOfLane(
        const lanelet::ConstLanelets & candidate_lanelets, const LinearRing2d & vehicle_footprint)
    {
        for (const auto & point : vehicle_footprint) {
            if (!isInAnyLane(candidate_lanelets, point)) {
                return true;
            }
        }

        return false;
    }

    // 计算边界的最大搜索长度
    double LaneDepartureChecker::calcMaxSearchLengthForBoundaries(const Trajectory & trajectory) const
    {
        const double max_ego_lon_length = std::max(
            std::abs(vehicle_info_ptr_->max_longitudinal_offset_m),
            std::abs(vehicle_info_ptr_->min_longitudinal_offset_m));
        const double max_ego_lat_length = std::max(
            std::abs(vehicle_info_ptr_->max_lateral_offset_m),
            std::abs(vehicle_info_ptr_->min_lateral_offset_m));
        const double max_ego_search_length = std::hypot(max_ego_lon_length, max_ego_lat_length);
        return calcArcLength(trajectory.points) + max_ego_search_length;
    }

    // 提取不可穿越的边界
    SegmentRtree LaneDepartureChecker::extractUncrossableBoundaries(
        const lanelet::LaneletMap & lanelet_map, const geometry_msgs::msg::Point & ego_point,
        const double max_search_length, const std::vector<std::string> & boundary_types_to_detect)
    {
        const auto has_types =
            [](const lanelet::ConstLineString3d & ls, const std::vector<std::string> & types) {
                constexpr auto no_type = "";
                const auto type = ls.attributeOr(lanelet::AttributeName::Type, no_type);
                return (type != no_type && std::find(types.begin(), types.end(), type) != types.end());
            };

        SegmentRtree uncrossable_segments_in_range;
        LineString2d line;
        const auto ego_p = Point2d{ego_point.x, ego_point.y};
        for (const auto & ls : lanelet_map.lineStringLayer) {
            if (has_types(ls, boundary_types_to_detect)) {
                line.clear();
                for (const auto & p : ls) line.push_back(Point2d{p.x(), p.y()});
                for (auto segment_idx = 0LU; segment_idx + 1 < line.size(); ++segment_idx) {
                    const Segment2d segment = {line[segment_idx], line[segment_idx + 1]};
                    if (boost::geometry::distance(segment, ego_p) < max_search_length) {
                        uncrossable_segments_in_range.insert(segment);
                    }
                }
            }
        }
        return uncrossable_segments_in_range;
    }

    // 检查车辆是否会穿过边界
    bool LaneDepartureChecker::willCrossBoundary(
        const std::vector<LinearRing2d> & vehicle_footprints,
        const SegmentRtree & uncrossable_segments) const
    {
        universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);

        for (const auto & footprint : vehicle_footprints) {
            std::vector<Segment2d> intersection_result;
            uncrossable_segments.query(
                boost::geometry::index::intersects(footprint), std::back_inserter(intersection_result));
            if (!intersection_result.empty()) {
                return true;
            }
        }
        return false;
    }

    // 将线性环转换为基本多边形
    lanelet::BasicPolygon2d LaneDepartureChecker::toBasicPolygon2D(
        const LinearRing2d & footprint_hull) const
    {
        lanelet::BasicPolygon2d basic_polygon;
        for (const auto & point : footprint_hull) {
            Eigen::Vector2d p(point.x(), point.y());
            basic_polygon.push_back(p);
        }
        return basic_polygon;
    }

    // 将基本多边形转换为多边形
    autoware::universe_utils::Polygon2d LaneDepartureChecker::toPolygon2D(
        const lanelet::BasicPolygon2d & poly) const
    {
        autoware::universe_utils::Polygon2d polygon;
        auto & outer = polygon.outer();

        for (const auto & p : poly) {
            autoware::universe_utils::Point2d p2d(p.x(), p.y());
            outer.push_back(p2d);
        }
        boost::geometry::correct(polygon);
        return polygon;
    }

}  // namespace autoware::lane_departure_checker

utils.cpp

// Copyright 2024 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
//
//     <url id="ctv3o3n2cre5rs2pcht0" type="url" status="parsed" title="Apache License, Version 2.0" wc="10467">http://www.apache.org/licenses/LICENSE-2.0</url> 
//
// 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 "autoware/lane_departure_checker/utils.hpp"

#include <autoware/universe_utils/geometry/geometry.hpp>

#include <boost/geometry.hpp>

// 命名空间声明
namespace
{
    // 定义足迹边距结构体
    struct FootprintMargin
    {
        double lon;  // 纵向边距
        double lat;  // 横向边距
    };

    // 计算足迹边距
    FootprintMargin calcFootprintMargin(
        const geometry_msgs::msg::PoseWithCovariance & covariance, const double scale)
    {
        // 获取协方差矩阵
        const auto Cov_in_map = covariance.covariance;
        Eigen::Matrix2d Cov_xy_map;
        Cov_xy_map << Cov_in_map[0 * 6 + 0], Cov_in_map[0 * 6 + 1], Cov_in_map[1 * 6 + 0],
            Cov_in_map[1 * 6 + 1];

        // 获取车辆偏航角
        const double yaw_vehicle = tf2::getYaw(covariance.pose.orientation);

        // 将协方差矩阵从地图坐标系转换到车辆坐标系
        Eigen::Matrix2d R_map2vehicle;
        R_map2vehicle << std::cos(-yaw_vehicle), -std::sin(-yaw_vehicle), std::sin(-yaw_vehicle),
            std::cos(-yaw_vehicle);
        const Eigen::Matrix2d Cov_xy_vehicle = R_map2vehicle * Cov_xy_map * R_map2vehicle.transpose();

        // 计算纵向和横向边距
        return FootprintMargin{Cov_xy_vehicle(0, 0) * scale, Cov_xy_vehicle(1, 1) * scale};
    }
}  // namespace

// autoware::lane_departure_checker::utils命名空间
namespace autoware::lane_departure_checker::utils
{
    // 裁剪轨迹
    TrajectoryPoints cutTrajectory(const TrajectoryPoints & trajectory, const double length)
    {
        if (trajectory.empty()) {
            return {};
        }

        TrajectoryPoints cut;

        double total_length = 0.0;
        auto last_point = autoware::universe_utils::fromMsg(trajectory.front().pose.position);
        auto end_it = std::next(trajectory.cbegin());
        for (; end_it != trajectory.cend(); ++end_it) {
            const auto remain_distance = length - total_length;

            // 超出长度
            if (remain_distance <= 0) {
                break;
            }

            const auto & new_pose = end_it->pose;
            const auto new_point = autoware::universe_utils::fromMsg(new_pose.position);
            const auto points_distance = boost::geometry::distance(last_point.to_2d(), new_point.to_2d());

            // 需要插值
            if (remain_distance <= points_distance) {
                const Eigen::Vector3d p_interpolated =
                    last_point + remain_distance * (new_point - last_point).normalized();

                TrajectoryPoint p;
                p.pose.position.x = p_interpolated.x();
                p.pose.position.y = p_interpolated.y();
                p.pose.position.z = p_interpolated.z();
                p.pose.orientation = new_pose.orientation;

                cut.push_back(p);
                break;
            }

            total_length += points_distance;
            last_point = new_point;
        }
        cut.insert(cut.begin(), trajectory.begin(), end_it);

        return cut;
    }

    // 重采样轨迹
    TrajectoryPoints resampleTrajectory(const Trajectory & trajectory, const double interval)
    {
        if (trajectory.points.size() < 2) {
            return trajectory.points;
        }

        TrajectoryPoints resampled;

        resampled.push_back(trajectory.points.front());
        auto prev_point = autoware::universe_utils::fromMsg(trajectory.points.front().pose.position);
        for (size_t i = 1; i < trajectory.points.size() - 1; ++i) {
            const auto & traj_point = trajectory.points.at(i);

            const auto next_point = autoware::universe_utils::fromMsg(traj_point.pose.position);

            if (boost::geometry::distance(prev_point.to_2d(), next_point.to_2d()) >= interval) {
                resampled.push_back(traj_point);
            }

            prev_point = next_point;
        }
        resampled.push_back(trajectory.points.back());

        return resampled;
    }

    // 创建车辆足迹
    std::vector<LinearRing2d> createVehicleFootprints(
        const geometry_msgs::msg::PoseWithCovariance & covariance, const TrajectoryPoints & trajectory,
        const autoware::vehicle_info_utils::VehicleInfo & vehicle_info,
        const double footprint_margin_scale)
    {
        // 根据协方差计算纵向和横向边距
        const auto margin = calcFootprintMargin(covariance, footprint_margin_scale);

        // 在base_link坐标系中创建车辆足迹
        const auto local_vehicle_footprint = vehicle_info.createFootprint(margin.lat, margin.lon);

        // 在每个轨迹点上创建车辆足迹
        std::vector<LinearRing2d> vehicle_footprints;
        for (const auto & p : trajectory) {
            vehicle_footprints.push_back(
                transformVector(local_vehicle_footprint, autoware::universe_utils::pose2transform(p.pose)));
        }

        return vehicle_footprints;
    }

    // 创建车辆足迹
    std::vector<LinearRing2d> createVehicleFootprints(
        const PathWithLaneId & path, const autoware::vehicle_info_utils::VehicleInfo & vehicle_info,
        const double footprint_extra_margin)
    {
        // 在base_link坐标系中创建车辆足迹
        const auto local_vehicle_footprint = vehicle_info.createFootprint(footprint_extra_margin);

        // 在每个路径点上创建车辆足迹
        std::vector<LinearRing2d> vehicle_footprints;
        for (const auto & p : path.points) {
            vehicle_footprints.push_back(transformVector(
                local_vehicle_footprint, autoware::universe_utils::pose2transform(p.point.pose)));
        }

        return vehicle_footprints;
    }
}  // namespace autoware::lane_departure_checker::utils


总结

先到这里,下一篇继续,要不太长了。

;