软件篇-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办公软件篇(三)—审批流
背景 作用 迭代历程 具体实现 写在最后 背景 在前面两篇文章中,我们分别讲了组织架构和权限管理,今天我们来讲一个跟组织架构关系比较密切的功能-审批流. 审批流,通俗来说就是一个完整的审批流程,是 ...
随机推荐
- python爬虫登录保持及对http总结
[前言]这几天一直看python爬虫登录保持.实现接口太多,太乱,新手难免云山雾罩.各种get.post,深入理解一下,其实就是由于http的特性需要这些操作.http是一种无状态.不保存上次通信结果 ...
- Markdown(2)基本语法
Markdown 是一种轻量级标记语言 , 通过简单的标记语法,使文本内容具有一定的格式 . 一.段落 1. 标题 语法格式: 符号 "#" 可以标记 1~6级标题.一级标题对 ...
- PAT-1151(LCA in a Binary Tree)+最近公共祖先+二叉树的中序遍历和前序遍历
LCA in a Binary Tree PAT-1151 本题的困难在于如何在中序遍历和前序遍历已知的情况下找出两个结点的最近公共祖先. 可以利用据中序遍历和前序遍历构建树的思路,判断两个结点在根节 ...
- RabbitMQ初步使用,简洁介绍。
RabbitMQ是一种越来越流行的开源,快速消息代理,它使用Erlang编写并基于Open Telecom Platform框架构建.它实现了高级消息队列协议(AMQP),用于在进程,应用程序和服务器 ...
- 【Azure 微服务】Service Fabric, 使用ARM Template方式来更新SF集群的证书(Renew SF Certificate)
问题描述 因证书过期导致Service Fabric集群挂掉(升级无法完成,节点不可用)一文中,描述了因为证书过期而导致了SF集群不可用,并且通过命令dd-AzServiceFabricCluster ...
- JVM笔记 -- JVM的生命周期介绍
Github仓库地址:https://github.com/Damaer/JvmNote 文档地址:https://damaer.github.io/JvmNote/ JVM生命周期 启动 执行 退出 ...
- mysql数据库的数据备份,以及开启日志
导出数据: location代表需要保存的数据文件的位置,默认保存在 C:\ProgramData\MySQL\MySQL Server 5.7\Data(Windows10系统位置,其他系统位置自行 ...
- 计算异质性H值(运用arcgis和Python进行区域分析)
最近需要对ecognition分割结果进行统计分析,以此来进一步判断其分割结果中的欠分割和过分割对象,在看了一篇论文后,发现了可以用一个参数H来判断每个切割对象的异质性,由于此方法需要用到arcgis ...
- postman接口自动化测试之添加Tests检查点
一.概念 Postman的Tests本质上是JavaScript代码,通过我们编写测试代码,每一个Tests返回True,或是False,以判断接口返回的正确性. 其实,每一个Tests实际上就是一个 ...
- ch1_6_3求解移动字符串问题
import java.util.Scanner; public class ch1_6_3求解移动字符串问题 { public static void main(String[] args) { / ...