严正声明:本文系作者davidhopper原创,未经许可,不得转载。

Apollo项目导航模式下,规划模块输出的轨迹点使用FLU车身坐标系(见我的另一篇博客《Apollo项目坐标系研究》),在进行当前帧规划前,需要将前一帧未行驶完轨迹点的车身坐标转换为当前帧的车身坐标,并在其中找到最为匹配的点,作为当前帧的规划起点;若在指定的误差范围内找不到匹配点,则以当前车辆位置作为新的规划起点。该过程涉及到两套FLU车身坐标系的变换。本文首先图解介绍坐标变换的公式,然后给出Apollo项目的具体变换代码。

一、坐标变换公式

1.1 问题描述

如下图所示,XOYXOYXOY是ENU全局坐标系,XoldOoldYoldX_{old}O_{old}Y_{old}Xold​Oold​Yold​与XnewOnewYnewX_{new}O_{new}Y_{new}Xnew​Onew​Ynew​是FLU车身坐标系。已知坐标原点OoldO_{old}Oold​ 在坐标系XOYXOYXOY中的坐标为(x01,y01,θ1)(x_{01}, y_{01}, \theta_{1})(x01​,y01​,θ1​),OnewO_{ new}Onew​ 在坐标系XOYXOYXOY中的坐标为(x02,y02,θ2)(x_{02}, y_{02}, \theta_{2})(x02​,y02​,θ2​)。PPP点在前一帧车身坐标系XoldOoldYoldX_{old}O_{old}Y_{old}Xold​Oold​Yold​中的坐标为(xold,yold,θold)(x_{old}, y_{old}, \theta_{old})(xold​,yold​,θold​),求解PPP点在当前帧车身坐标系XnewOnewYnewX_{ new}O_{new}Y_{new}Xnew​Onew​Ynew​中的坐标(xnew,ynew,θnew)(x_{new}, y_{new}, \theta_{new})(xnew​,ynew​,θnew​)。

1.2 公式推导

如下图所示,当前帧坐标原点OnewO_{ new}Onew​在前一帧车身坐标系XoldOoldYoldX_{old}O_{old}Y_{old}Xold​Oold​Yold​中的坐标(xd,yd,θd)(x_d, y_d, \theta_d)(xd​,yd​,θd​)可通过下述表达式计算:
xd=OoldE+EF=OoldE+DC=(x02−x01)cosθ1+(y02−y01)sinθ1(1)x_d=O_{old}E+EF=O_{old}E+DC=(x_{02}-x_{01})cos \theta_{1}+(y_{02}-y_{01})sin\theta_{1}\qquad(1) xd​=Oold​E+EF=Oold​E+DC=(x02​−x01​)cosθ1​+(y02​−y01​)sinθ1​(1)
yd=OnewC−FC=OnewC−ED=(y02−y01)cosθ1−(x02−x01)sinθ1(2)y_d=O_{ new}C-FC=O_{new}C-ED=(y_{02}-y_{01})cos \theta_{1}-(x_{02}-x_{01})sin\theta_{1}\qquad(2) yd​=Onew​C−FC=Onew​C−ED=(y02​−y01​)cosθ1​−(x02​−x01​)sinθ1​(2)
θd=θ2−θ1(3)\theta_d=\theta_2-\theta_1\qquad(3) θd​=θ2​−θ1​(3)

如下图所示,PPP点在当前帧车身坐标系XnewOnewYnewX_{ new}O_{new}Y_{new}Xnew​Onew​Ynew​中的坐标(xnew,ynew,θnew)(x_{new}, y_{new}, \theta_{new})(xnew​,ynew​,θnew​)可通过下述表达式计算:
xnew=OnewJ+JK=OnewJ+IH=(xold−xd)cosθd+(yold−yd)sinθd(4)x_{new}=O_{new}J+JK=O_{new}J+IH=(x_{old}-x_{d})cos \theta_{d}+(y_{old}-y_{d})sin\theta_{d}\qquad(4) xnew​=Onew​J+JK=Onew​J+IH=(xold​−xd​)cosθd​+(yold​−yd​)sinθd​(4)
ynew=PH−KH=PH−JI=(yold−yd)cosθd−(xold−xd)sinθd(5)y_{new}=PH-KH=PH-JI=(y_{old}-y_{d})cos \theta_{d}-(x_{old}-x_{d})sin\theta_{d}\qquad(5) ynew​=PH−KH=PH−JI=(yold​−yd​)cosθd​−(xold​−xd​)sinθd​(5)
θnew=θold−θd(6)\theta_{new}=\theta_{old}-\theta_{d}\qquad(6) θnew​=θold​−θd​(6)

二、坐标变换代码

坐标变换代码见modules/planning/navi_planning.cc中的NaviPlanning::RunOnce函数,具体代码如下:

void NaviPlanning::RunOnce(const LocalView& local_view,ADCTrajectory* const trajectory_pb) {// ...auto vehicle_config =ComputeVehicleConfigFromLocalization(*local_view_.localization_estimate);if (last_vehicle_config_.is_valid_ && vehicle_config.is_valid_) {auto x_diff_map = vehicle_config.x_ - last_vehicle_config_.x_;auto y_diff_map = vehicle_config.y_ - last_vehicle_config_.y_;auto cos_map_veh = std::cos(last_vehicle_config_.theta_);auto sin_map_veh = std::sin(last_vehicle_config_.theta_);auto x_diff_veh = cos_map_veh * x_diff_map + sin_map_veh * y_diff_map;auto y_diff_veh = -sin_map_veh * x_diff_map + cos_map_veh * y_diff_map;auto theta_diff = vehicle_config.theta_ - last_vehicle_config_.theta_;TrajectoryStitcher::TransformLastPublishedTrajectory(x_diff_veh, y_diff_veh, theta_diff, last_publishable_trajectory_.get());}// ...
}

其中的NaviPlanning::ComputeVehicleConfigFromLocalization函数代码为:

NaviPlanning::VehicleConfig NaviPlanning::ComputeVehicleConfigFromLocalization(const localization::LocalizationEstimate& localization) const {NaviPlanning::VehicleConfig vehicle_config;if (!localization.pose().has_position()) {return vehicle_config;}vehicle_config.x_ = localization.pose().position().x();vehicle_config.y_ = localization.pose().position().y();const auto& orientation = localization.pose().orientation();if (localization.pose().has_heading()) {vehicle_config.theta_ = localization.pose().heading();} else {vehicle_config.theta_ = common::math::QuaternionToHeading(orientation.qw(), orientation.qx(), orientation.qy(), orientation.qz());}vehicle_config.is_valid_ = true;return vehicle_config;
}

TrajectoryStitcher::TransformLastPublishedTrajectory函数位于文件modules/planning/common/trajectory_stitcher.cc中,代码如下:

void TrajectoryStitcher::TransformLastPublishedTrajectory(const double x_diff, const double y_diff, const double theta_diff,PublishableTrajectory* prev_trajectory) {if (!prev_trajectory) {return;}// R^-1double cos_theta = std::cos(theta_diff);double sin_theta = -std::sin(theta_diff);// -R^-1 * tauto tx = -(cos_theta * x_diff - sin_theta * y_diff);auto ty = -(sin_theta * x_diff + cos_theta * y_diff);std::for_each(prev_trajectory->begin(), prev_trajectory->end(),[&cos_theta, &sin_theta, &tx, &ty,&theta_diff](common::TrajectoryPoint& p) {auto x = p.path_point().x();auto y = p.path_point().y();auto theta = p.path_point().theta();auto x_new = cos_theta * x - sin_theta * y + tx;auto y_new = sin_theta * x + cos_theta * y + ty;auto theta_new =common::math::NormalizeAngle(theta - theta_diff);p.mutable_path_point()->set_x(x_new);p.mutable_path_point()->set_y(y_new);p.mutable_path_point()->set_theta(theta_new);});
}

分析代码可知,其中的坐标变换代码与第一部分推导的公式吻合。

Apollo项目导航模式下的坐标转换研究相关推荐

  1. vue项目全局配置微信分享_Vue项目history模式下微信分享总结-个人文章-SegmentFault思否...

    每回遇到微信分享都是一个坑,目前的商城项目使用vue开发,采用history的路由模式,配置微信分享又遇到了很多问题,最后终于解决了,现将解决的过程分享一下. 原文https://justyeh.to ...

  2. 百度Apollo 2.5 导航模式 使用方法

    Apollo 2.5版导航模式的使用方法 本博客参考百度apollo官方开发手册,部分进行理解修改. 导航模式--官网开发手册 在`Apollo`之前的版本中,感知.预测.导航.规划模块均依赖于高精地 ...

  3. Vue 爬坑之旅 -- history 路由模式下微信分享爬坑总结

    现在做 H5 开发,微信平台基本是一个绕不过去的坑,这里面又分为微信授权和微信分享.说它坑,主要提现在以下几个方面: 文档不够清晰详细.开发文档这块是国内所有互联网公司的通病,文档写的不清不楚,长期不 ...

  4. Intellij IDEA debug模式下项目启动慢/无法启动的事件解决过程记录

    项目无法启动了 简单的介绍一下事件过程:周一的早上,收到前端同事抛过来的一个任务,说是一个接口无法正常返回数据,于是就让他把参数发过来,我想试着在本地重现一下并且将问题修复掉,这种情况肯定是要通过de ...

  5. 关于MUI框架中,“侧滑导航“之“div模式下拉菜单“的a标签(超链接)的失效问题?

    关于MUI框架中,"侧滑导航"之"div模式下拉菜单"的a标签(超链接)的失效问题? 截图和讲解图片的顺序如下所示: 图1 图2 · 官方的截图 图3 · 官方 ...

  6. Release编译模式下,事件是否会引起内存泄漏问题初步研究

    题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...

  7. 基于敏捷模式下测试改进分析和质量研究

    测试改进分析 测试改进的策略主要有三点: 首先是要改进新功能测试的策略. 一般来说,每次短期的迭代都有新的功能加入产品中,因此针对新功能的测试方法,在短期迭代周期中需要改进.不需要编写测试用例,直接基 ...

  8. vue-cli3.x正确打包项目,解决静态资源与路由加载无效的问题,history模式下配合使用nginx运行打包后的项目

    vue-cli3.x正确打包项目,解决静态资源与路由加载无效的问题,history模式下配合使用nginx运行打包后的项目 参考文章: (1)vue-cli3.x正确打包项目,解决静态资源与路由加载无 ...

  9. Nodejs搭建前后端分离开发模式下的微信网页项目

    原文链接:<Nodejs搭建前后端分离开发模式下的微信网页项目>- 陈帅华 本文涉及对前后端分离及微信网页项目中的前端如何在本地环境中开发与调试的思考. 主要问题 1.如何配置微信公众平台 ...

最新文章

  1. Django 模板继承4.2
  2. MIUI应用权限设置
  3. MobileNet_v2
  4. 编写Thymeleaf视图以展示数据
  5. 尽管苹果打死不认 但iCloud被破解是真的:媒体亲身验证
  6. iOS 开发之获取时间到年底可能会踩到的坑
  7. Avalonia跨平台入门第十四篇之ListBox折叠列表
  8. C# 调用Windows API实现两个进程间的通信
  9. oracle临时表经常被锁_5.性能测试 - Oracle体系结构和性能优化简介
  10. MyBatis Demo 编写(1)基础功能搭建
  11. ubuntu安装atom
  12. xm list源码分析
  13. Lua 服务器Socket通信实例(转)
  14. Go语言的一些使用心得
  15. 单片机c语言实习报告,单片机C语言程序设计实训100例.pdf
  16. C++轻量级Json解析工具—TinyJson
  17. java ut_【JAVA UT】2、写UT的科学步骤
  18. (一)appium-desktop定位元素原理
  19. 解决chrome/IE浏览器被桔梗导航劫持的问题
  20. 一个技术总监的忠告:精通那么多技术为何还是做不好一个项目?

热门文章

  1. java选择题_JAVA试题及答案(50道选择题)
  2. 【Shiro】6、Shiro实现限制密码错误次数从而限制用户登录
  3. kafka sql入门
  4. 一个mos管驱动电路的分析
  5. MySQL数据类型及字段属性
  6. 研二小硕的艰难实习路
  7. IOS 证书安装详解
  8. adobe reader java_请问,如何用JAVA读PDF文件在浏览器中显示,不需要在本地系统中安装Adobe Reader。求java代码...
  9. 关于微软surface pro的介绍
  10. foxmail邮件只能显示邮件头,不能显示内容