使用OMPL内置的infoRRTstar算法模块和FCL碰撞检测库实现当前点和目标点的轨迹规划,
因为我们的SLAM底盘轨迹是二维的,这样说可能不太准确,你可以说它的轨迹在给定小的区域内是二维的,因为野外/室外的地面有坡度和沟壑,所以我们要做的是二维RRT。
有关RRT的论文维基百科已经列的很全了:
 
核心思想就是利用快速随机搜索树从当前点出发,迭代生出树枝,利用FCL检测树枝生长的方向是否有障碍物,有的话最后生成的路径将不会包括该路径,所以最后连接当前点和目标点的轨迹是collisionless的。至于轨迹是不是最优,infoRRTstar已经对传统RRT算法做了优化,轨迹规划的效果很大的取决于用户在API中对轨迹生成时间的限制,只要时间足够长,两点之间没有障碍物的话得出来的都是一条直线。这个“足够长的时间”具体是多长,又取决于设置的rrtRange步长和两点之间的距离,我们可以根据系统对实时性的要求具体设置。

  • 效果图
下面的白色坐标系是我写的上位机里的二维俯视图,用的是qcustomplot,不错,推荐一下。点云是在真实环境中采的。
 
 
黄色点就是环境,红点为当前点,蓝色为目标点
 
 
RVIZ中的OctoMap
  • 将pointcloud点云转化为OctoMap,用于碰撞检测
我这里加了个 "groundHeightMax" 是为了滤去地面的一部分点云,防止其影响轨迹规划,"carTF_zed2.pose.position.z"是涉及到相对位置。使用八叉树地图减小内存占用。
"std::shared_ptr" 智能指针是C++ 11的东西,如果编译出错的注意了。"tree_obj" 就是FCL检测是否碰撞的环境对象,另一个对象就是我们的SLAM底盘了。
// turn the pcl cloud to fcl::CollisionGeometry after octree
// updtae the octomap octomap::OcTree* treeOctomapPtr = new octomap::OcTree( 0.05 );


for(auto p:pclCloud->points) {
  if(p.z > groundHeightMax + carTF_zed2.pose.position.z) treeOctomapPtr->updateNode
  ( octomap::point3d(p.x, p.y, p.z), true );
  }
  treeOctomapPtr->updateInnerOccupancy();
  fcl::OcTree<float>* tree = new fcl::OcTree<float>(std::shared_ptr<const octomap::OcTree>(treeOctomapPtr));
  tree_obj = std::shared_ptr<fcl::CollisionGeometry<float>>(tree);
  • 设置OMPL轨迹规划限制空间
"bounds_hmin" 和 "bounds_hmax"设置世界坐标系的高度范围,也应该是相对于底盘的高度空间。
// set the bounds for the R^3 part of SE(3)
ompl::base::RealVectorBounds bounds(3);
// set X-Y-Z dimensions bound
bounds.setLow(0,bounds_lmin);
bounds.setHigh(0,bounds_lmax);
bounds.setLow(1,bounds_wmin);
bounds.setHigh(1,bounds_wmax);
bounds.setLow(2,bounds_hmin);
bounds.setHigh(2,bounds_hmax);
  • 使用FCL检测当前状态是否碰撞
bool Navigation::isStateValid(const ompl::base::State *state) 
{

// cast the abstract state type to the type we expect const ompl::base::SE3StateSpace::StateType *se3state = state->as<ompl::base::SE3StateSpace::StateType>();

// extract the first component of the state and cast it to what we expect const ompl::base::RealVectorStateSpace::StateType *pos = se3state->as<ompl::base::RealVectorStateSpace::StateType>(0); // extract the second component of the state and cast it to what we expect const ompl::base::SO3StateSpace::StateType *rot = se3state->as<ompl::base::SO3StateSpace::StateType>(1); fcl::CollisionObject<float> treeObj((tree_obj)); fcl::CollisionObject<float> slamCarObject(slamCar); // check validity of state defined by pos & rot fcl::Vector3f translation(pos->values[0],pos->values[1],pos->values[2]); fcl::Quaternionf rotation(rot->w, rot->x, rot->y, rot->z); slamCarObject.setTransform(rotation, translation); fcl::CollisionRequest<float>requestType(1,false,1,false); fcl::CollisionResult<float> collisionResult; fcl::collide(&slamCarObject,&treeObj, requestType, collisionResult);return(!collisionResult.isCollision());}
在下面的代码将FCL和OMPL相联系,这里的 "std::placeholders::_1"是一个占位符。
si = ompl::base::SpaceInformationPtr(new ompl::base::SpaceInformation(space));

si->setStateValidityChecker(std::bind(&Navigation::isStateValid, this, std::placeholders::_1 ));
  • 一切设置好后就可以开始计算路径了
这个"rrtSolutionTimeLimit" 就是我在上文中说到的时间限制。这里我另外加了个异常处理。
ompl::base::PlannerStatus solved; 

try
{

  solved = plan->solve(rrtSolutionTimeLimit);
}
catch(ompl::Exception e)
{
  ROS_WARN("Error occourred: %s", e.what());
}
然后获取路径,这里的SE3和SO3分别是特殊欧式群和特殊正交群,说的直白一点在这里代表的就是齐次变换和旋转矩阵。下面的是优化的路径,优化后轨迹会更加平滑,当然点也会更多。
ompl::geometric::PathSimplifier* pathBSpline = new ompl::geometric::PathSimplifier(si); 

path_smooth = new ompl::geometric::PathGeometric(dynamic_cast<const ompl::geometric::PathGeometric&>(*pdef->getSolutionPath()));
pathBSpline->smoothBSpline(*path_smooth,3);

// ROS_INFO("Smoothed Path:"); // path_smooth->print(std::cout); smooth_msg.header.stamp = ros::Time::now(); smooth_msg.header.frame_id = "map"; for (std::size_t idx = 0; idx < path_smooth->getStateCount (); idx++) { // cast the abstract state type to the type we expect const ompl::base::SE3StateSpace::StateType *se3state = path_smooth->getState(idx)->as<ompl::base::SE3StateSpace::StateType>(); // extract the first component of the state and cast it to what we expect const ompl::base::RealVectorStateSpace::StateType *pos = se3state->as<ompl::base::RealVectorStateSpace::StateType>(0); // extract the second component of the state and cast it to what we expect const ompl::base::SO3StateSpace::StateType *rot = se3state->as<ompl::base::SO3StateSpace::StateType>(1); geometry_msgs::PoseStamped point; point.pose.position.x = pos->values[0]; point.pose.position.y = pos->values[1]; point.pose.position.z = pos->values[2]; point.pose.orientation.x = rot->x; point.pose.orientation.y = rot->y; point.pose.orientation.z = rot->z; point.pose.orientation.w = rot->w; smooth_msg.poses.push_back(point);}

软件篇-04-OMPL和FCL用于SLAM轨迹规划的更多相关文章

  1. 软件篇-03-基于ORB_SLAM2手写SLAM稠密地图构建实现

    本文使用的方法不是从内部修改ORBSLAM2源码以获取稠密点云,而是先从ZED2 sdk获取以摄像头坐标系为描述的三维点云/作为点云地图的一个子集,然后融合IMU与ORB_SLAM2进行实时定位,通过 ...

  2. 软件篇-05-融合ORB_SLAM2和IMU闭环控制SLAM底盘运动轨迹

      前面我们已经得到了当前底盘在世界坐标系中的位姿,这个位姿是通过融合ORB_SLAM2位姿和IMU积分得到的,在当前位姿已知的case下,给SLAM小车设置一个goal,我这里是通过上位机设置,然后 ...

  3. GSM Sniffing入门之软件篇:GSMTAP抓取与SMS(Short Message Service)

    重点介绍如何利用50元左右的设备,抓包并还原SMS短信内容: ps:研究GSM Sniffing纯属个人兴趣,能抓SMS报文只是捡了个明文传输的漏子,切勿用于非法用途.就像sylvain说的,osmo ...

  4. [知乎]老狼:深入PCI与PCIe之二:软件篇

    深入PCI与PCIe之二:软件篇 https://zhuanlan.zhihu.com/p/26244141 我们前一篇文章(深入PCI与PCIe之一:硬件篇 - 知乎专栏)介绍了PCI和PCIe的硬 ...

  5. OA办公软件篇(一)—组织架构

    OA办公软件篇(一)-组织架构 背景 作用 迭代历程 具体实现 写在最后   背景 在说组织架构之前,我们先来说说OA本身. 百度百科解释OA为:办公自动化(Office Automation,简称O ...

  6. OA办公软件篇(三)—审批流

    背景 作用 迭代历程 具体实现 写在最后   背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...

  7. iOS系列 基础篇 04 探究视图生命周期

    iOS系列 基础篇 04 探究视图生命周期 视图是应用的一个重要的组成部份,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻. 以视图的四种状态为基础,我们来系统了解一下视 ...

  8. 智能家居-3.基于esp8266的语音控制系统(软件篇)

    智能家居-1.基于esp8266的语音控制系统(开篇) 智能家居-2.基于esp8266的语音控制系统(硬件篇) 智能家居-3.基于esp8266的语音控制系统(软件篇) 赞赏支持 QQ:505645 ...

  9. OA办公软件篇(二)—权限管理

    权限管理的背景 权限管理的作用 迭代历程 关键名词释义 权限管理模型 具体实现 写在最后   权限管理的背景 在OA办公软件篇(一)-组织架构一文中,我们说到组织架构是软件系统的权限体系的重要搭建依据 ...

随机推荐

  1. Lua C++交互 应用实例步骤(UserData使用)

    一.配置Lua C++交互环境 1.下载Lua 包环境 地址: https://www.lua.org/download.html ,我们这里用的是5.4.2版本. 2.新建C++ 控制台应用程序 3 ...

  2. STL容器整理

    1.vector c++STL中的可变长度数组,主要支持操作有:建立,添加到末尾,返回长度,调整大小,定义迭代器及对迭代器的具体操作.具体如下: 1.建立一个元素类型为int的可变长度数组v,最开始N ...

  3. Git:本地仓库管理

    git log:查看 commit 提交历史 git log --pretty=oneline:简化log输出内容 git reflog:查看每一次命令的历史记录 版本回退 git reset HEA ...

  4. windows上传ipa文件到苹果开发者中心的教程

    转: windows上传ipa文件到苹果开发者中心的教程 我们在苹果开发者中心上架ios app的时候,需要使用xcode或transporter先上传ipa文件到开发者中心. 但是假如我们只是H5开 ...

  5. JavaScript实现动态添加员工

    html代码: <div id="empAdd"> <fieldset> <legend><strong>添加员工</stro ...

  6. Kubernetes - Kubelet TLS Bootstrapping

    一.简单说明 写这个的初衷是自己搜索TLS Bootstrapping的时候没有搜到自己想要的东西,因为TLS Bootstrapping经过很多版本之后也发生了一些变化,所以网上很多也是老的内容了. ...

  7. POJ-2031(最小生成树+kruskal)

    Building a Space Station POJ-2031 注意,这里的输出需要是%f型而不是%lf型的,否则wa. #include<iostream> #include< ...

  8. HDOJ-6656(数论+逆元)

    Kejin Player HDOJ-6656 设f[i]为从i升级到i+1期望需要的金钱,由于每级都是能倒退或者升级到i+1,所以询问从l,r的期望金钱可以直接前缀和,那么推导每一级升级需要的期望钱也 ...

  9. Ubuntu小配置

    Ubuntu 拍摄快照 在虚拟机安装好.配置号后各拍摄一次快照,并存储. 可在虚拟机出错后回滚 Root用户 Ubuntu默认不能以 Root用户身份直接登录 因此,正常操作时在需要调用 root权限 ...

  10. KL散度相关理解以及视频推荐

    以下内容基于对[中字]信息熵,交叉熵,KL散度介绍||机器学习的信息论基础这个视频的理解,请务必先看几遍这个视频. 假设一个事件可能有多种结果,每一种结果都有其发生的概率,概率总和为1,也即一个数据分 ...