当前位置: 首页 > article >正文

自动驾驶---打造自动驾驶系统之参考线平滑(四)

        各位读者朋友,大家好。本次打造的自动驾驶系统仿真系统,涉及感知,预测,规控等多个模块(以规控算法为主,包括Polynomial预测,MCTS决策算法,通行走廊Corridor构建,QP/CILQR轨迹生成求解器,LQR+PID的控制器等),同时也支持其它相关规控/感知算法的扩展(部署&开发自身感兴趣的算法),非常便捷。笔者在该系列中开发的规控算法主要依据专栏《自动驾驶Planning决策规划》中的章节逐步搭建,后续实践系列涉及的博客包括但不局限于以下内容

        《自动驾驶---打造自动驾驶系统之环境准备(一)》---已更新

        《自动驾驶---打造自动驾驶系统之定位模块开发(二)》---已更新

        《自动驾驶---打造自动驾驶系统之导航模块开发(三)》---已更新

        《自动驾驶---打造自动驾驶系统之参考线平滑开发(四)》

        《自动驾驶---打造自动驾驶系统之感知环境开发(五)》

        《自动驾驶---打造自动驾驶系统之预测模块开发(六)》

        《自动驾驶---打造自动驾驶系统之决策模块开发(七)》

        《自动驾驶---打造自动驾驶系统之轨迹生成模块开发(八)        

        《自动驾驶---打造自动驾驶系统之控制模块开发(九)》


        最终呈现的静态效果(无法直接贴视频)如下:

​1 系统环境

        笔者的环境是:Ubuntu 18.04 上安装 ROS Melodic,当然18.04以上的环境也支持。

        其它依赖库的安装参考之前的博客《自动驾驶---打造自动驾驶系统之环境准备(一)》,后续如果有遗漏,继续补充。

        当然,如果各位读者朋友感兴趣或者在此过程中遇到相关问题,欢迎私信咨询!

2 planner框架

        到目前为止,前面两节中已经分别介绍了定位和导航,已经具备开发planner的基础了,因此在开发参考线平滑之前,搭一下planner的框架。

        主要包括以下两个部分:

  • planner:planner主进程,收发上下游的ros msg,数据预处理等,并且还用于调度不同的planner(后续会扩展多种planner算法);
    • 接受感知、定位、导航以及预测等模块的信息;
    • 参考线平滑;
    • 决策;
    • 通行走廊;
    • 轨迹生成;
    • 轨迹消息发布;
  • task:planner任务管理模块,用于重规划等任务。

3 参考线平滑

        关于参考线平滑的知识(二次规划建模,公式推导,约束问题处理等),笔者在之前的博客《自动驾驶---Motion Planning之参考线Path平滑》中作过详细介绍

​        总结下来,就是在构造二次规问题的过程中考虑三个代价:(1)轨迹平滑度(2)接近参考点(3)轨迹长度;最后,再考虑约束问题,使用OSQP求解二次规划问题即可。

3.1 模块结构

        主体结构主要包括以下两个文件:

        其中,使用的是FEM(有限元)平滑方法,求解器使用OSQP。

        熟悉Apollo的朋友应该已经看出来了,没错,主要依赖的文件主要来源于Apollo。

3.2 主要代码

#include "reference_line_smooth.h"
#include "../common/log.h"

namespace planning {

ReferenceLineSmooth::ReferenceLineSmooth(const PlannerOpenSpaceConfig& planner_open_space_config){
    planner_open_space_config_ = planner_open_space_config;
}

bool ReferenceLineSmooth::SetPathProfile(
    const std::vector<std::pair<double, double>>& point2d,
    DiscretizedPath* raw_path_points) {
  CHECK_NOTNULL(raw_path_points);
  raw_path_points->clear();
  // Compute path profile
  std::vector<double> headings;
  std::vector<double> kappas;
  std::vector<double> dkappas;
  std::vector<double> accumulated_s;
  if (!DiscretePointsMath::ComputePathProfile(
          point2d, &headings, &accumulated_s, &kappas, &dkappas)) {
    return false;
  }
  CHECK_EQ(point2d.size(), headings.size());
  CHECK_EQ(point2d.size(), kappas.size());
  CHECK_EQ(point2d.size(), dkappas.size());
  CHECK_EQ(point2d.size(), accumulated_s.size());

  // Load into path point
  size_t points_size = point2d.size();
  for (size_t i = 0; i < points_size; ++i) {
    common::PathPoint path_point;
    path_point.set_x(point2d[i].first);
    path_point.set_y(point2d[i].second);
    path_point.set_theta(headings[i]);
    path_point.set_s(accumulated_s[i]);
    path_point.set_kappa(kappas[i]);
    path_point.set_dkappa(dkappas[i]);
    raw_path_points->push_back(std::move(path_point));
  }

  return true;
}

size_t ReferenceLineSmooth::FindNearestPoint(const LocalView& local_view){
    size_t index = 0;
    double pos_x = local_view.localization.odom_x;
    double pos_y = local_view.localization.odom_y;
    size_t points_size = local_view.route.poses.size();
    if(points_size > 1){
        double min_distance = std::hypot(pos_x - local_view.route.poses[index].pose.position.x,
                                         pos_y - local_view.route.poses[index].pose.position.y);
        for(size_t i = 1; i < points_size; i++){
            double distance = std::hypot(pos_x - local_view.route.poses[i].pose.position.x,
                                         pos_y - local_view.route.poses[i].pose.position.y);
            if(distance < min_distance ){
                index  = i;
                min_distance = distance;
            }
        }
    }

    return index;
}

bool ReferenceLineSmooth::ReferLineSmoothProc(const LocalView& local_view){

    size_t nearest_index = FindNearestPoint(local_view);
    size_t min_index = 0;
    size_t max_index = 0;
    if(nearest_index > 10){
        min_index = nearest_index - 10;
    }
    max_index = min_index + 100;

    size_t route_size = local_view.route.poses.size();
    max_index = std::min(route_size, max_index);

    DiscretizedPath warm_start_path;
    double accumulated_s = 0.0;
    common::math::Vec2d last_path_point(local_view.route.poses[0].pose.position.x,
            local_view.route.poses[0].pose.position.y);
    for (size_t i = min_index; i < max_index; ++i) {
      double x = local_view.route.poses[i].pose.position.x;
      double y = local_view.route.poses[i].pose.position.y;
      common::math::Vec2d cur_path_point(x, y);
      accumulated_s += cur_path_point.DistanceTo(last_path_point);
      common::PathPoint path_point;
      path_point.set_x(x);
      path_point.set_y(y);
      path_point.set_theta(0.0);
      path_point.set_s(accumulated_s);
      warm_start_path.push_back(std::move(path_point));
      last_path_point = cur_path_point;
    }

    std::vector<double> default_bounds(warm_start_path.size(), 2.0);

    if(Smooth(warm_start_path, default_bounds)){
        return true;
    } else{
        return false;
    }
}

bool ReferenceLineSmooth::Smooth(const DiscretizedPath& raw_path_points,
                                 const std::vector<double>& bounds){
    FemPosDeviationSmoother fem_pos_smoother(
        planner_open_space_config_.iterative_anchoring_smoother_config()
            .fem_pos_deviation_smoother_config());

    std::vector<std::pair<double, double>> raw_point2d;
    std::vector<double> flexible_bounds;
    for (const auto& path_point : raw_path_points) {
      raw_point2d.emplace_back(path_point.x(), path_point.y());
    }
    flexible_bounds = bounds;
    std::vector<std::pair<double, double>> smoothed_point2d;
    std::vector<double> opt_x;
    std::vector<double> opt_y;
    if (!fem_pos_smoother.Solve(raw_point2d, flexible_bounds, &opt_x, &opt_y)) {
      AINFO << "Smoothing path fails";
      return false;
    }

    if (opt_x.size() < 2 || opt_y.size() < 2) {
      AINFO << "Return by fem_pos_smoother is wrong. Size smaller than 2 ";
      return false;
    }

    CHECK_EQ(opt_x.size(), opt_y.size());

    size_t point_size = opt_x.size();
    smoothed_point2d.clear();
    for (size_t i = 0; i < point_size; ++i) {
      smoothed_point2d.emplace_back(opt_x[i], opt_y[i]);
    }
    DiscretizedPath smoothed_path_points;
    if (!SetPathProfile(smoothed_point2d, &smoothed_path_points)) {
      AINFO << "Set path profile fails";
      return false;
    }

    smoothed_path_points_ = smoothed_path_points;

    return true;
}
} // namespace planning

3.3 呈现效果

        通过参考线平滑后,最终呈现的效果如下图所示:

4 量产

        平滑之后的参考线,只有trajectory point的信息,比如 x ,y,s,theta,kappa等信息,对于正常的仿真已经足够,但如果在量产中是不够的,其中主要缺少的是左右边界的宽度及属性,为后续corridor的生成做一点点准备,因此在量产中,每一个参考线上的点还会包括左右边界信息(通常这些边界信息来源于地图和感知)

  • left_bound_type(车道线实线,车道线虚线,路沿等),left_bound_width(车道宽度);
  • right_bound_type,right_bound_width;


http://www.kler.cn/a/613735.html

相关文章:

  • gitee 常用指令
  • springboot的跨域是什么?遇到跨域问题如何解决?
  • 华宇TAS应用中间件与晓窗科技智慧校园管理一体化平台完成兼容互认证
  • linux ACL权限控制之用户权限控制程序设计
  • 使用Python和OpenCV进行指纹识别与验证
  • Resume全栈项目(二)(.React+Ts)
  • 【漫话机器学习系列】166.向量(Vectors)
  • ubuntu 创建新用户
  • Flink Credit-based机制解析
  • 数字化攻防战场的进化论:红蓝对抗训练如何重塑网络安全范式
  • PTA 7-16 一元多项式求导
  • Axure项目实战:智慧城市APP(六)市民互动(动态面板、显示与隐藏)
  • 【Linux-驱动开发-模块的加载和卸载】
  • 【深度学习】训练集、测试集、验证集、过拟合、欠拟合详解
  • WebRTC简介及应用
  • 【Git】--- Git远程操作 标签管理
  • Anaconda Jupyter 默认启动位置修改
  • javaWeb Router
  • Python面试题库-持续更新中
  • Android 图片裁剪 压缩等处理记录