软件篇-02-基于ZED 2和ORB_SLAM2的SLAM实践
本期内容如题,ZED 2的SDK功能还是挺多的,包括轨迹跟踪,实时建图等等。虽然由于是商业产品,我看不到他们的源代码,但是根据使用情况来看,ZED 2内部是采用了IMU和光学信息融合的算法,并且IMU的数据在决策权重上占了更大的比例,至于为什么我会在后文讲到。关于ORB_SALM2,它给我们提供了目前来说效果比较好的实时定位和稀疏地图构建功能,同时支持单目、双目和RGB-D摄像头的SLAM算法,但是目前来说大多数SLAM工程应用都是用来做导航避障,单单的稀疏地图并不能满足我们的要求,于是我决定充分利用两者的信息,以达到最佳的效果。
- 安装ZED 2 SDK和ORB_SLAM2
- 使用Qt Creator开发ROS工程
- 适配ORB_SALM2于双目相机ZED 2
- 创建功能包用于保存SLAM地图和三维点云图
- RVIZ、URDF配置
- 安装ZED 2 SDK和ZED 2 ROS功能包
- 安装ORB_SLAM2
$ rosdep install --from-paths src --ignore-src -r -y
$ catkin_make -DCMAKE_BUILD_TYPE=Release
$ source ./devel/setup.bash
# 后续你可能还需要以下Cmake参数 -DCATKIN_DEVEL_PREFIX=../devel -DCMAKE_INSTALL_PREFIX=../install
$ sudo vim /usr/share/applications/org.qt-project.qtcreator.desktop
$ sudo vim catkin_qi/src/CMakeLists.txt
project(catkin_qi)
#Add custom (non compiling)
targets so launch scripts and python files show up in QT Creator's project view. file(GLOB_RECURSE EXTRA_FILES */*)
# 以下的‘ROS_Packages’是我自定义的名字,到时所有功能包都会显示在该目录下 add_custom_target(ROS_Packages ALL WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} SOURCES ${EXTRA_FILES})

Qt-ROS工程树
<?xml version="1.0"?>
<launch> <!-- launch the zed_ros_wrapper node-->
<include file="$(find zed_wrapper)/launch/zed2.launch"> </include>
<node name="orb_slam2_stereo" pkg="orb_slam2_ros" type="orb_slam2_ros_stereo" output="screen">
<remap from="image_left/image_color_rect" to="/zed2/zed_node/left/image_rect_color" />
<remap from="image_right/image_color_rect" to="/zed2/zed_node/right/image_rect_color" /> <param name="publish_pointcloud" type="bool" value="true" /> <param name="publish_pose" type="bool" value="true" /> <param name="localize_only" type="bool" value="false" /> <param name="reset_map" type="bool" value="false"/><!-- static parameters --><paramname="load_map"type="bool"value="true"/><paramname="map_file"type="string"value="/home/qi/catkin_qi/src/tx2_slam/map/bin/zed2_slam_Map.bin"/><paramname="settings_file"type="string"value="$(find tx2_slam)/config/Zed2Stereo.yaml"/><paramname="voc_file"type="string"value="$(find tx2_slam)/Vocabulary/ORBvoc.txt"/><paramname="pointcloud_frame_id"type="string"value="map"/><paramname="camera_frame_id"type="string"value="camera_link"/><paramname="min_num_kf_in_map"type="int"value="5"/></node><!-- Position respect to base frame (i.e. "base_link) --><argname="cam_pos_x"default="0.0"/><argname="cam_pos_y"default="0.0"/><argname="cam_pos_z"default="0.0"/><!-- Orientation respect to base frame (i.e. "base_link) --><argname="cam_roll"default="0.0"/><argname="cam_pitch"default="0.0"/><argname="cam_yaw"default="0.0"/><!-- ROS URDF description of the ZED --><groupif="true"><paramname="zed2_description"command="$(find xacro)/xacro '$(find tx2_slam)/urdf/zed_descr.urdf.xacro' camera_name:=tx2zed2 camera_model:=zed2 base_frame:=zed2_base_link cam_pos_x:=$(arg cam_pos_x) cam_pos_y:=$(arg cam_pos_y) cam_pos_z:=$(arg cam_pos_z) cam_roll:=$(arg cam_roll) cam_pitch:=$(arg cam_pitch) cam_yaw:=$(arg cam_yaw)"/><nodename="zed2_state_publisher"pkg="robot_state_publisher"type="robot_state_publisher"output="screen"required="true"><remapfrom="robot_description"to="zed2_description"/></node></group><!-- Launch rivz display --><nodename="rviz"pkg="rviz"type="rviz"args="-d $(find tx2_slam)/config/rviz_config.rviz"output="screen"/><nodename="MapBuild"pkg="tx2_slam"type="MapBuild"output="screen"><paramname="prefix"type="string"value="$(find tx2_slam)/map/pcd_files/"/></node></launch>
%YAML:1.0
# Camera calibration and distortion parameters (OpenCV) Camera.fx: 527.2025 Camera.fy: 527.245 Camera.cx: 618.31 Camera.cy: 367.1445 # get the rectified image from zed-ros-wrapper, so set all zero Camera.k1: 0.0 Camera.k2: 0.0 Camera.p1: 0.0 Camera.p2: 0.0 Camera.k3: 0.0 # more to see https://www.stereolabs.com/docs/video/camera-controls/ Camera.width: 2560 Camera.height: 720 Camera.fps: 30.0 # stereo baseline(m) times fx Camera.bf: 63.1965 # Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale) Camera.RGB: 1 # Close/Far threshold. Baseline times. # set it according to the actual effect ThDepth: 35 # the depth in program equal to the real depth times the DepthMapFactor #DepthMapFactor: 1000.0 #-------------------------------------------------------------------------------------------- # Stereo Rectification. Only if you need to pre-rectify the images. # Camera.fx, .fy, etc must be the same as in LEFT.P #-------------------------------------------------------------------------------------------- LEFT.height: 720 LEFT.width: 2560 LEFT.D: !!opencv-matrix rows: 1 cols: 5 dt: d data: [0.0, 0.0, 0.0, 0.0, 0.0] LEFT.K: !!opencv-matrix rows: 3 cols: 3 dt: d data: [527.2025, 0.0, 618.31, 0.0, 527.245, 367.1445, 0.0, 0.0,1.0]LEFT.R:!!opencv-matrixrows:3cols:3dt: d data:[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]LEFT.P:!!opencv-matrixrows:3cols:4dt: d data:[527.2025,0.0,618.31,0.0,0.0,527.245,367.1445,0.0,0.0,0.0,1.0,0.0]RIGHT.height:720RIGHT.width:2560RIGHT.D:!!opencv-matrixrows:1cols:5dt: d data:[0.0,0.0,0.0,0.0,0.0]RIGHT.K:!!opencv-matrixrows:3cols:3dt: d data:[527.2025,0.0,618.31,0.0,527.245,367.1445,0.0,0.0,1.0]RIGHT.R:!!opencv-matrixrows:3cols:3dt: d data:[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]RIGHT.P:!!opencv-matrixrows:3cols:4dt: d data:[527.2025,0.0,618.31,0.0,0.0,527.245,367.1445,0.0,0.0,0.0,1.0,0.0]#--------------------------------------------------------------------------------------------# ORB Parameters#--------------------------------------------------------------------------------------------# ORB Extractor: Number of features per imageORBextractor.nFeatures:1200# ORB Extractor: Scale factor between levels in the scale pyramidORBextractor.scaleFactor:1.2# ORB Extractor: Number of levels in the scale pyramidORBextractor.nLevels:8# ORB Extractor: Fast threshold# Image is divided in a grid. At each cell FAST are extracted imposing a minimum response.# Firstly we impose iniThFAST. If no corners are detected we impose a lower value minThFAST# You can lower these values if your images have low contrastORBextractor.iniThFAST:20ORBextractor.minThFAST:7
//set the Zed2 ouput
mZedParams.camera_resolution = sl::RESOLUTION::HD720;
mZedParams.camera_fps = 30;
mConnStatus = mZed.open(mZedParams);
- 保存三维点云图

#pragma once
#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl_ros/point_cloud.h>
#include <tf2_ros/buffer.h> #include <tf2_ros/transform_listener.h>
#include <tf2_eigen/tf2_eigen.h>
#include <pcl/io/pcd_io.h> class MapBuild {
public:
~MapBuild();
MapBuild();
private:
}; class PointCloudToPCD {
protected: ros::NodeHandle nh_; private: std::string prefix_; std::string filename_; bool binary_; bool compressed_; std::string fixed_frame_; tf2_ros::Buffer tf_buffer_; tf2_ros::TransformListener tf_listener_; public: std::string cloud_topic_; ros::Subscriber sub_; //////////////////////////////////////////////////////////////////////////////// // Callback void cloud_cb (const pcl::PCLPointCloud2::ConstPtr& cloud) { if ((cloud->width * cloud->height) == 0) return; ROS_INFO ("Received %d data points in frame %s with the following fields: %s", (int)cloud->width * cloud->height, cloud->header.frame_id.c_str (), pcl::getFieldsList(*cloud).c_str()); Eigen::Vector4f v = Eigen::Vector4f::Zero(); Eigen::Quaternionf q = Eigen::Quaternionf::Identity();if(!fixed_frame_.empty()){if(!tf_buffer_.canTransform(fixed_frame_, cloud->header.frame_id, pcl_conversions::fromPCL(cloud->header.stamp), ros::Duration(3.0))){ROS_WARN("Could not get transform!");return;} Eigen::Affine3d transform; transform = tf2::transformToEigen(tf_buffer_.lookupTransform(fixed_frame_, cloud->header.frame_id, pcl_conversions::fromPCL(cloud->header.stamp))); v = Eigen::Vector4f::Zero(); v.head<3>()= transform.translation().cast<float>(); q = transform.rotation().cast<float>();} std::stringstream ss;if(filename_ !=""){ ss << filename_ <<".pcd";}else{ ss << prefix_ << cloud->header.stamp <<".pcd";}ROS_INFO("Data saved to %s", ss.str().c_str()); pcl::PCDWriter writer;if(binary_){if(compressed_){ writer.writeBinaryCompressed(ss.str(),*cloud, v, q);}else{ writer.writeBinary(ss.str(),*cloud, v, q);}}else{ writer.writeASCII(ss.str(),*cloud, v, q,8);}}////////////////////////////////////////////////////////////////////////////////PointCloudToPCD():binary_(false),compressed_(false),tf_listener_(tf_buffer_){// Check if a prefix parameter is defined for output file names. ros::NodeHandle priv_nh("~");if(priv_nh.getParam("prefix", prefix_)){ROS_INFO_STREAM("PCD file prefix is: "<< prefix_);}elseif(nh_.getParam("prefix", prefix_)){ROS_WARN_STREAM("Non-private PCD prefix parameter is DEPRECATED: "<< prefix_);} priv_nh.getParam("fixed_frame", fixed_frame_); priv_nh.getParam("binary", binary_); priv_nh.getParam("compressed", compressed_); priv_nh.getParam("filename", filename_);if(binary_){if(compressed_){ROS_INFO_STREAM("Saving as binary compressed PCD");}else{ROS_INFO_STREAM("Saving as binary uncompressed PCD");}}else{ROS_INFO_STREAM("Saving as ASCII PCD");}if(filename_ !=""){ROS_INFO_STREAM("Saving to fixed filename: "<< filename_);} cloud_topic_ ="/zed2/zed_node/mapping/fused_cloud"; sub_ = nh_.subscribe(cloud_topic_,1,&PointCloudToPCD::cloud_cb,this);ROS_INFO("Listening for incoming data on topic %s", nh_.resolveName(cloud_topic_).c_str());}};
- 保存ORB_SLAM2地图
ros::init (
argc, argv, "MapBuild", ros::init_options::AnonymousName);
ros::NodeHandle n; ros::ServiceClient client = n.serviceClient<orb_slam2_ros::SaveMap>("/orb_slam2_stereo/save_map"); orb_slam2_ros::SaveMap srv; srv.request.name = "/home/qi/catkin_qi/src/tx2_slam/map/bin/zed2_slam_Map.bin";
if (client.call(srv)) { ROS_INFO("Ready to create Map"); } else { ROS_ERROR("Failed to call service SaveMap");
return 1;
}

软件篇-02-基于ZED 2和ORB_SLAM2的SLAM实践的更多相关文章
- 智能家居-3.基于esp8266的语音控制系统(软件篇)
智能家居-1.基于esp8266的语音控制系统(开篇) 智能家居-2.基于esp8266的语音控制系统(硬件篇) 智能家居-3.基于esp8266的语音控制系统(软件篇) 赞赏支持 QQ:505645 ...
- 驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统
驱动开发读书笔记. 0.02 基于EASYARM-IMX283 怎么烧写自己裁剪的linux内核?(非所有arm9通用) 手上有一块tq2440,但是不知道什么原因,没有办法烧boot进norflas ...
- OA办公软件篇(二)—权限管理
权限管理的背景 权限管理的作用 迭代历程 关键名词释义 权限管理模型 具体实现 写在最后 权限管理的背景 在OA办公软件篇(一)-组织架构一文中,我们说到组织架构是软件系统的权限体系的重要搭建依据 ...
- GSM Sniffing入门之软件篇:GSMTAP抓取与SMS(Short Message Service)
重点介绍如何利用50元左右的设备,抓包并还原SMS短信内容: ps:研究GSM Sniffing纯属个人兴趣,能抓SMS报文只是捡了个明文传输的漏子,切勿用于非法用途.就像sylvain说的,osmo ...
- Atitit.升级软件的稳定性---基于数据库实现持久化 循环队列 循环队列
Atitit.升级软件的稳定性---基于数据库实现持久化 循环队列 环形队列 1. 前言::选型(马) 1 2. 实现java.util.queue接口 1 3. 当前指针的2个实现方式 1 1.1 ...
- [知乎]老狼:深入PCI与PCIe之二:软件篇
深入PCI与PCIe之二:软件篇 https://zhuanlan.zhihu.com/p/26244141 我们前一篇文章(深入PCI与PCIe之一:硬件篇 - 知乎专栏)介绍了PCI和PCIe的硬 ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
- OA办公软件篇(一)—组织架构
OA办公软件篇(一)-组织架构 背景 作用 迭代历程 具体实现 写在最后 背景 在说组织架构之前,我们先来说说OA本身. 百度百科解释OA为:办公自动化(Office Automation,简称O ...
- OA办公软件篇(三)—审批流
背景 作用 迭代历程 具体实现 写在最后 背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...
随机推荐
- mysql索引的性能分析
[前言]上一篇博客介绍了InnoDB引擎的索引机制,主要围绕B+树的建立,目录项记录里主键和页号,到页目录下的二分法定位数据:二级索引里的主键和索引列,及其回表操作.这一篇分析一下索引的性能,围绕如何 ...
- Git:使用远程仓库
远程仓库可使用Github.Gitee,或自建Gitlab.Gogs服务器,这里使用Github. 配置本地用户名和邮箱 # 配置本地用户的用户名邮箱(保存在用户.gitconfig文件) $ git ...
- Vue.js 可排序列表 (Sortable & Searchable Tables) 组件
可排序表格 (Sortable & Searchable Tables) 在网页和表单设计中非常常用.用户可以通过点击表头对将表格以该列做顺序或降序排列,也可以利用 Search Box 对表 ...
- 操作系统---IO权限管理和敏感指令
简化版 使用IOPL设置一个特权级的用户程序对所有端口的访问权限,使用I/O位图对一个特权级的用户程序设置个性化的端口访问权限(能访问部分端口.不能访问另外的端口). 用户程序的CPL<IOPL ...
- 七种方案!探讨Redis分布式锁的正确使用姿势
前言 日常开发中,秒杀下单.抢红包等等业务场景,都需要用到分布式锁.而Redis非常适合作为分布式锁使用.本文将分七个方案展开,跟大家探讨Redis分布式锁的正确使用方式.如果有不正确的地方,欢迎大家 ...
- C# 应用 - 封装类访问 Postgresql 数据库
引入库类 连接数据库 访问数据库 1)增删改数据库 2)查数据库 数据转换 事务 1. 引入库类 引入 Npgsql.dll using Npgsql; using NpgsqlTypes; 2. 连 ...
- 三分钟教你提升应用推送的ROI
推送是App应用性价比最高也是最直接的营销运营手段,其细节颇多,非常考验运营人员的功力,本文将从ROI角度来分析怎么提升营销类推送的收益.(非IM类.系统类等功能服务型推送) 以一个日活100万的应用 ...
- BeautifulSoup爬取微博热搜榜
获取url 设定请求头 requests发出get请求 实例化BeautifulSoup对象 BeautifulSoup提取数据 import requests 2 from bs4 import B ...
- 如何使用Typora写博客
如何写博客及Typora的使用 Typora Typora是写好博客的一个重要的软件,下面我们来介绍如何安装以及使用它 安装 官网下载Typora 较慢,首先附上Typora安装包: 链接:https ...
- 接口自动化——读取Excle中遇到的问题
一.module 'openpyxl' has no attribute 'load_workbook'问题 原因:在pycharm中py文件名字为openpyxl导致 修改方法:重新对py名字进行命 ...