本文使用的方法不是从内部修改ORBSLAM2源码以获取稠密点云,而是先从ZED2 sdk获取以摄像头坐标系为描述的三维点云/作为点云地图的一个子集,然后融合IMU与ORB_SLAM2进行实时定位,通过点云滤波,点云融合建图。
 
以上是在室内实验的demo,由于是纯双目,没有深度传感器,在白墙和地板上有些失真,下次等移动平台到了我会去室外实验。
 
一、获取实时坐标和点云图
 
使用ORBSLAM2获取当前姿态,同时ZED2 利用其IMU数据对速度加速度积分得出另一个姿态,考虑到ORBSLAM2的响应及时性和IMU数据的漂移,当两者数据相差较大时停止建图,等待恢复正常,否则以ORB_SLAM2的姿态信息为准,同时手动添加损失量对IMU姿态信息进行校准。在某些情况下ORB_SLAM2可能会跟丢,此时通过IMU数据积分获取迪卡尔空间位移变化量,并回到之前的位置重新确定位置。

  1. 1 if(!startTimer)
  2. 2 {
  3. 3   timeLast = ros::Time::now().toSec(); startTimer = 1;
  4. 4   ROS_ERROR("\noffect between two poseMsgs is too big, stop mapping...");
  5. 5   ROS_WARN("the offset from zed2Pose to orbPose2 is:\nx:%f y:%f z:%f \n-------------" ,carTF_zed2.pose.position.x - carTF_orb.pose.position.x ,carTF_zed2.pose.position.y - carTF_orb.pose.position.y ,carTF_zed2.pose.position.z - carTF_orb.pose.position.z);
  6. 6 }else if(timeNow = ros::Time::now().toSec() - timeLast > 10)
  7. 7 {
  8. 8   startTimer = 0;
  9. 9   timeLast = timeNow = 0;
  10. 10   ROS_WARN("Don't warry, it seems that something wrong happend, trying to fix it..."); x_bias = carTF_zed2.pose.position.x - carTF_orb.pose.position.x; y_bias = carTF_zed2.pose.position.y - carTF_orb.pose.position.y;
  11. 11   z_bias = carTF_zed2.pose.position.z - carTF_orb.pose.position.z;
  12. 12 }
这里我订阅ZED2 sdk输出的实时点云,有一点需要注意的是实时的点云和姿态信息必需要时间戳同步,不然融合出来的地图会发生很大的偏移和扭曲。使用ros message_filters管理消息同步,可以设置弱同步和强同步。

  1. 1 imu_sub = n.subscribe("/zed/zed_node/imu/data", 1, &MapBuild::imuCallback,this);
  2. 2 carTF_orb_sub = n.subscribe("/orb_slam2_stereo/pose", 1, &MapBuild::carTF_orb_Callback,this);
  3. 3 pointCloud_sub = new message_filters::Subscriber<sensor_msgs::PointCloud2> ( n, "/zed2/zed_node/point_cloud/cloud_registered", 1);
  4. 4 carTF_zed2_sub = new message_filters::Subscriber<geometry_msgs::PoseStamped> (n, "/zed2/zed_node/pose", 1);
  5. 5 sync_ = new message_filters::Synchronizer<sync_pol> (sync_pol(10), *pointCloud_sub, *carTF_zed2_sub); sync_->registerCallback(boost::bind(&MapBuild::buildMap_callback, this, _1, _2));
 
二、点云坐标系变换
 
我们当前的点云是相对摄像头坐标系的,但是建图就要将这些点转换到世界坐标系,点的坐标系变换我这里就不讲了,不懂的去看一下《机器人学导论》/题外话“英文的原汁原味”。要用到的工具当然是Eigen了。这里吐槽一下,Eigen和geometry_msgs::PoseStamped里有关四元数的写法顺序是颠倒的,大家注意一下。
  1. 1 Quaterniond quaternion(carTF_zed2.pose.orientation.w, carTF_zed2.pose.orientation.x, carTF_zed2.pose.orientation.y, carTF_zed2.pose.orientation.z);
  2. 2 Matrix3d rotation_matrix; rotation_matrix=quaternion.toRotationMatrix();
  3. 3
  4. 4 // transform the cloud link to the "map" frame
  5. 5
  6. 6 Vector3d position_transform (carTF_zed2.pose.position.x - x_bias, carTF_zed2.pose.position.y - y_bias, carTF_zed2.pose.position.z - z_bias);
  7. 7
  8. 8 for (int i=0; i<cloud_xyz->width; i++)
  9. 9 {
  10. 10   Vector3d position_(cloud_xyz->at(i).x,cloud_xyz->at(i).y,cloud_xyz->at(i).z);
  11. 11   Vector3d position = rotation_matrix*position_ + position_transform;
  12. 12   cloud_xyz->at(i).x = position[0];
  13. 13   cloud_xyz->at(i).y = position[1];
  14. 14   cloud_xyz->at(i).z = position[2];
  15. 15 }
 
三、点云滤波
 
 
可以看到,图中绿色的点云原本是墙面和窗帘,但是在边缘却有很多&amp;quot;飞点&amp;quot;
我们获取的原始点云有很多的噪声点并且密度太大,TX2吃不消,因此这里要对这些点云进行滤波,这里使用pcl的体素滤波和直通滤波。

  1. 1 // Perform the actual filtering
  2. 2 // VoxelGrid(decrease the memory occupation) & PassThrough(delete some incorrect points)
  3. 3
  4. 4 pcl::PCLPointCloud2* cloud2 = new pcl::PCLPointCloud2;
  5. 5 pcl::PCLPointCloud2ConstPtr cloudPtr(cloud2);
  6. 6 pcl_conversions::toPCL(*cloud, *cloud2);
  7. 7
  8. 8 // VoxelGrid pcl::PCLPointCloud2* cloud_filtered_1 = new pcl::PCLPointCloud2;
  9. 9 pcl::PCLPointCloud2ConstPtr cloud_filter_1_Ptr(cloud_filtered_1);
  10. 10 pcl::VoxelGrid<pcl::PCLPointCloud2> filter_1;
  11. 11 filter_1.setInputCloud (cloudPtr);
  12. 12 filter_1.setLeafSize (0.03, 0.03, 0.03); filter_1.filter(*cloud_filtered_1);
  13. 13 // PassThrough pcl::PCLPointCloud2* cloud_filtered_2 = new pcl::PCLPointCloud2; pcl::PCLPointCloud2ConstPtr cloud_filter_2_Ptr(cloud_filtered_2); pcl::PassThrough<pcl::PCLPointCloud2> filter_2; filter_2.setInputCloud (cloud_filter_1_Ptr); filter_2.setFilterFieldName ("y"); filter_2.setFilterLimits (-1.2, 1.2); // filter_2.setFilterLimitsNegative (true); filter_2.filter(*cloud_filtered_2); pcl::PCLPointCloud2 cloud_filtered_3; filter_2.setInputCloud (cloud_filter_2_Ptr); filter_2.setFilterFieldName ("z"); filter_2.setFilterLimits (-2,2);// filter_2.setFilterLimitsNegative (true); filter_2.filter(cloud_filtered_3);
四、点云融合

  1. 1 // fused the current cloud to the fused cloud
  2. 2 *cloud_xyzFused += *cloud_xyz; pcl::toROSMsg(*cloud_xyzFused, mPointcloudFusedMsg);
  3. 3 mPointcloudFusedMsg.header.frame_id = "map"; pointCloudFused_pub.publish(mPointcloudFusedMsg);
 
五、去除重复的点云
 
实验过程中不可避免的会回到某个之前来过的姿态,这个时候不能任由重复的点云在我的地图上大行其道,因此需要实时判断当前的点云是否已经添加到地图中去了,使用pcl::registration::CorrespondenceEstimation判断当前点云和地图有多少重复的点,该数目与点云总体数目之比如果大于某个阈值,则丢弃该点云。
  1. 1 pcl::registration::CorrespondenceEstimation<pcl::PointXYZRGB, pcl::PointXYZRGB> est; cloud_xyzFusedPtr = cloud_xyzFused->makeShared();
  2. 2 cloud_xyzPtr = cloud_xyz->makeShared();
  3. 3 est.setInputSource (cloud_xyzPtr);
  4. 4 est.setInputTarget (cloud_xyzFusedPtr);
  5. 5 pcl::Correspondences all_correspondences;
  6. 6 // Determine all reciprocal correspondences
  7. 7
  8. 8 est.determineReciprocalCorrespondences (all_correspondences);
  9. 9 // filter the reciprocal points cloud
  10. 10
  11. 11 if(1.0*all_correspondences.size()/cloud_xyz->width < 0.9) {
  12. 12   // fused the current cloud to the fused cloud
  13. 13   *cloud_xyzFused += *cloud_xyz; pcl::toROSMsg(*cloud_xyzFused, mPointcloudFusedMsg);
  14. 14   mPointcloudFusedMsg.header.frame_id = "map";
  15. 15   pointCloudFused_pub.publish(mPointcloudFusedMsg);
  16. 16 }
我们下期再见
./下期就有小车实际的实验了
 

软件篇-03-基于ORB_SLAM2手写SLAM稠密地图构建实现的更多相关文章

  1. 放弃antd table,基于React手写一个虚拟滚动的表格

    缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...

  2. [年薪60W分水岭]基于Netty手写Apache Dubbo(带注册中心和注解)

    阅读这篇文章之前,建议先阅读和这篇文章关联的内容. 1. 详细剖析分布式微服务架构下网络通信的底层实现原理(图解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...

  3. Tensorflow之基于MNIST手写识别的入门介绍

    Tensorflow是当下AI热潮下,最为受欢迎的开源框架.无论是从Github上的fork数量还是star数量,还是从支持的语音,开发资料,社区活跃度等多方面,他当之为superstar. 在前面介 ...

  4. 看了这篇你就会手写RPC框架了

    一.学习本文你能学到什么? RPC的概念及运作流程 RPC协议及RPC框架的概念 Netty的基本使用 Java序列化及反序列化技术 Zookeeper的基本使用(注册中心) 自定义注解实现特殊业务逻 ...

  5. 基于vue手写tree插件那点事

    目录 iview提供的控件 手写控件 手写控件扩展 手写控件总结 # 加入战队 微信公众号 主题 Tree树形控件在前端开发中必不可少,对于数据的展示现在网站大都采取树形展示.因为大数据全部展示出来对 ...

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

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

  7. 基于netty手写RPC框架

    代码目录结构 rpc-common存放公共类 rpc-interface为rpc调用方需要调用的接口 rpc-register提供服务的注册与发现 rpc-client为rpc调用方底层实现 rpc- ...

  8. 基于Vue手写一个下拉刷新

    当然不乏有很多下拉刷新的插件可以直接使用,但是自定义程度不强,大部分都只能改改文字,很难满足设计师的创意,譬如淘宝和京东首页那种效果,就需要自己花心思倒腾了,最近刚好有这种需求,做完了稍微总结一下,具 ...

  9. 基于springJDBC手写ORM框架

    一.添加MySQLjar包依赖 二.结构 三.文件内容 (一).bean包 1.ColumnInfo.java 2.javaFiledInfo.java 3.TableInfo.java 4.Conf ...

随机推荐

  1. 创建一个scrapy爬虫框架的项目

    第一步:打开pycharm,选择"terminal",如图所示: 第二步:在命令中端输入创建scrapy项目的命令:scrapy startproject demo (demo指的 ...

  2. GNS3通过“云”连接到虚拟机实验

    GNS3通过"云"连接到虚拟机实验并使用wireshark工具对数据分析 观看本文之前注意!!!!! 做这次实验,我所遇到的问题,会全部写在文章结尾,如果读者们遇到问题,可查看. ...

  3. C#类中的成员

    @ 目录 字段 属性 方法 构造函数 类和对象的简单解释 创建类和对象 类中成员的归属问题 字段 字段的声明与声明变量类似,可以添加访问修饰符,通常情况下字段设置为私有的,然后定义属性对字段的读写进行 ...

  4. Linux Kernel 0.12 启动简介,调试记录(Ubuntu1804, Bochs, gdb)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  5. WebSocket与即时通讯

    HTTP 协议有一个缺陷:通信只能由客户端发起!HTTP 协议做不到服务器主动向客户端推送信息.这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦.我们只能使用"轮 ...

  6. 【Azure 微服务】PowerShell中,用Connect-ServiceFabricCluster命令无法连接到sf-test.chinaeast2.cloudapp.chinacloudapi.cn:19000 问题分析

    问题描述 Azure Service Fabric提供了PowerShell的指令来进行创建,管理资源,如Get-ServiceFabricClusterHealth 获取当前集群的健康状态,但这些命 ...

  7. HDU_6693 Valentine's Day 【概率问题】

    一.题目 Valentine's Day 二.分析 假设$ s_0 $代表不开心的概率,$ s_1 $代表开心一次的概率. 那么随便取一个物品,那么它的开心概率为$ p _i $,可以推导加入之后使女 ...

  8. Ubuntu之软件包管理 (最全最精)

    Centos与Ubuntu的关系 * CentOS之前的地位:Fedora稳定版-->发布-->RHEL稳定版-->发布-->CentOS * CentOS如今的地位:Fedo ...

  9. 网络对抗技术Exp2-后门原理与实践

    后门概念 后门就是不经过正常认证流程而访问系统的通道. 哪里有后门呢? 编译器留后门 操作系统留后门 最常见的当然还是应用程序中留后门 还有就是潜伏于操作系统中或伪装为特定应用的专用后门程序. 下面是 ...

  10. Vue3教程:Vue 3 + Element Plus + Vite 2 的后台管理系统开源啦

    之前发布过一篇文章<Vue3教程:开发一个 Vue 3 + element-plus 的后台管理系统>,文中提到会开发并开源一个 Vue 3 + Element Plus 的项目供大家练手 ...