深度相机的障碍物检测

2023-05-16

深度相机的障碍物检测

这里简单备份一下,有关深度相机障碍物检测的学习内容

1. 准备相机的驱动

Ubuntu18.04+ROS+ros_astra_camera-master

采用的是astra深度相机,安装Linux驱动:ros_astra_camera-master

在这里插入图片描述

2. 图像转LaserScan

2.1 depthimage_to_laserscan

​ 下面这个包可以将深度图像数据转换为二维激光雷达常用的LaserScan消息格式。

git clone -b melodic-devel https://github.com/ros-perception/depthimage_to_laserscan.git

​ 修改一下launch文件中深度图像的话题,以及output_frame

<remap from="image"       to="/camera/depth/image_raw"/> <!-- change here for your camera depth topic name. Default: "/camera/depth/image_raw" -->
<param name="output_frame_id" type="str"    value="camera_link"/>  <!--default: camera_depth_frame. Frame id of the laser scan. -->

​ 运行以下的指令可以进行转换,最后的订阅是深度相机的消息:/camera/depth/image_raw。转换的原理可以参考这个博客:https://www.cnblogs.com/cv-pr/p/5725831.html

roslaunch depthimage_to_laserscan launchfile_sample.launch

2.2 仿真

采用中科院软件所的gazebo仿真环境,仅依靠2D激光雷达(红色)的costmap:
在这里插入图片描述

添加深度图像转换的LaserScan(白色),并添加到costmap中的障碍物层,需要修改costmap_common_params.yaml:

  observation_sources:  depth_scan #user
  depth_scan:
    data_type: LaserScan
    topic:  depth_scan #修改了depthimage_to_laserscan包发布的topic名称
    marking:  true
    clearing: true
    inf_is_valid:  true
    observation_keep_time:  0.0
    expected_update_rate: 0

在这里插入图片描述

3. costmap_depth_camera

参考:https://blog.csdn.net/robinvista/article/details/115732239

3.1 具体操作

​ 通过图像转LaserScan消息有个缺点,它只是截取了水平面的一段数据,其他高度上的数据都被忽略了。对于直上直下、上下一样粗细的简单障碍物是没有太大的问题,但是如果我们的障碍物分布是三维的,那样显然就丢失了大部分的数据。所以更安全的方法是将所有的三维点云全部投影到二维平面上,这样就能考虑三维分布。

​ 实现该功能的ROS包是costmap_depth_camera:https://github.com/tsengapola/costmap_depth_camera

​ 原作者直接对原始点云进行处理,而深度相机返回的点云数据量是及其庞大的,参考上面链接中作者的方法,采用PCL中的下采样函数对原始点云进行压缩

pcl::VoxelGrid<pcl::PointXYZI> downsample;          //创建滤波对象
downsample.setInputCloud(combined_observations);    //设置需要过滤的点云给滤波对象
downsample.setLeafSize(0.1f, 0.1f, 0.1f);        //设置滤波时创建的体素体积为1cm的立方体
downsample.filter(*combined_observations);          //执行滤波处理,存储输出

​ 可以通过设置max_obstacle_height:1.5把高出的障碍物部分排除掉,其他的障碍物正常投影到水平面。

在这里插入图片描述

3.2 实验

costmap_depth_camera需要订阅imu,而手头相机中没有imu,仅为了测试一下,就随意播放了一个imu数据包

rosbag play -l camera_imu_2022-01-25-15-35-11.bag --topic /imu

修改costmap_depth_camera.yaml中的sensor_frame以及订阅points的topic:

depth_cam: {sensor_frame: camera_link, topic: /camera/depth/points}

修改costmap_depth_camera.launch中的tf2_ros

<node pkg="tf2_ros" type="static_transform_publisher" name="baselink2camera" args="0.0 0.0 1 0 0 0 base_link camera_link" output="screen" /> 

启动launch

roslaunch costmap_depth_camera costmap_depth_camera.launch 

直接使用了原作者的map,深度相机前的障碍物信息能够实时检测到,以后再测试一下精度。

在这里插入图片描述

3.3 costmap_depth_camera代码剖析(https://blog.csdn.net/robinvista/article/details/115732239)

在这里插入图片描述

​ costmap_depth_camera包是costmap_2d的插件,从下向上看,底层的observation.h开始,observation顾名思义就是传感器的观测数据,具体来说就是深度相机输出的点云数据。简单理解,一个observation就对应一帧点云。该文件定义了一个Observation类,其成员变量主要是以下三个。既然要处理点云,首先要存储起来,存储在cloud和frustum中。一般来说,点云还有一个信息要存储,那就是传感器自己的原点位置坐标origin_,也就是点云坐标相对于哪个坐标系表示的。因为机器人移动时传感器的位置也会改变,所以要存下来。

geometry_msgs::Point origin_;
pcl::PointCloud<pcl::PointXYZI>* cloud_;
pcl::PointCloud<pcl::PointXYZ>* frustum_;

​ 此外,还有与深度相机有关的参数,如下:

double min_detect_distance_, max_detect_distance_, FOV_W_, FOV_V_;

​ Observation类主要的成员函数如下。它们都是用来对深度相机的视锥做计算的。这几个函数为什么放在Observation类中?因为每个Observation对应一帧点云,这样可以支持多个深度相机,它们在机器人上的安装位置不同,看到的视野不同,这就对应不同的视锥。

void findFrustumVertex(); //顶点
void findFrustumNormal();
void findFrustumPlane();

​ 然后是observation_buffer文件,它定义了ObservationBuffer类,这个类是基于Observation类的。它的成员变量中最重要的是个List链表observation_list_。这里为什么使用list而不用vector?因为vector适用于对象数量变化少,简单对象,随机访问频繁;list适用于对象数量变化大,对象复杂,插入和删除频繁。Observation类用来存储点云,显然数据量非常大,还要经常更新,所以list更合适。

std::list<Observation> observation_list_;

​ ObservationBuffer顾名思义,就是传感器点云数据的缓存,每接收到一帧点云数据就存到observation_list_中。至于存储多少点云取决于时间,如果点云帧的时间超过一定值就会被剔除掉,否则会一直存储造成内存溢出。这个时间范围是observation_keep_time变量决定的,如果它的值是0,则新的点云来到之后旧的点云就会被扔掉。

​ 既然ObservationBuffer类的目的是缓存,那最重要的函数就是bufferCloud(const sensor_msgs::PointCloud2& cloud)了。它的输入是一帧点云数据cloud,通过for循环把cloud里的点云存储到observation_list_里。其他几个函数都比较简单。

​ 下面是最顶层的depth_camera_obstacle_layer.cpp,它定义了DepthCameraObstacleLayer类,这个类继承自costmap_2d::CostmapLayer。既然它继承自ROS的costmap_2d包,那我们不得不研究一下costmap_2d包了。costmap_2d包是navigation导航功能包集里面的一个功能包。实际上,我们完全可以把costmap_depth_camera包下载到navigation里,然后一起编译调试。

​ depth_camera_obstacle_layer.cpp位于plugins文件夹下,它的风格与costmap_2d/plugins文件夹中的文件类似。打开obstacle_layer.cpp就能看到相同的成员,例如:

std::vector<boost::shared_ptr<costmap_depth_camera::ObservationBuffer>> observation_buffers_;  
//Used to store observations from various sensors
std::vector<boost::shared_ptr<costmap_depth_camera::ObservationBuffer>> marking_buffers_;
//Used to store observation buffers used for marking obstacles
std::vector<boost::shared_ptr<costmap_depth_camera::ObservationBuffer>> clearing_buffers_;
//Used to store observation buffers used for clearing obstacles

​ onInitialize()函数用来配置参数,给后面几个函数用。传感器的数据也在这里被回调,但是不是普通的回调函数,而是使用了带滤波功能的MessageFilter。接收到点云数据后触发回调函数pointCloud2Callback,它再调用ObservationBuffer里面的bufferCloud函数把点云数据存储起来。所以传感器数据的入口就是,pointCloud2Callback函数。它订阅的话题是:/camera/depth/color/points,这个话题名定义在costmap_depth_camera.yaml中。

​ ClearMarkingbyKdtree函数的功能是清除栅格的标记值。具体是哪个栅格?就是pc_3d_map_这个有点复杂的变量。它表示一个三维的栅格,因为深度相机扫描的区域——视锥就是三维的。变量pc_3d_map 维护的是机器人附近一定范围内的三维地图。pc-3d-map如何存储三维地图?

std::map<unsigned int, std::map<int, float>> pc_3d_map_; //unsigned int存储水平面的xy坐标,第二个std::map存储垂直方向的z轴坐标,最后一个float存储每个体素的强度信息。

​ 在ClearMarkingbyKdtree函数中,通过嵌套的两个for循环遍历pc-3d-map,三维体素地图的每个体素。pc-3d-map不是把长方体所有离散体素都存起来了,而是只保存那些被障碍物占据的体素。在遍历时,只是遍历被占据的栅格,后面的ProcessCluster函数的作用是把聚类后的点存到pc-3d-map里。然后ClearMarkingbyKdtree函数只检验上一帧被占用的那些体素(用的是上一帧点云生成的、在ProcessCluster中添加的),如果发现最新的点云数据已经不占用了,那就把这个体素从pc_3d_map中删除。

​ 其中使用了frustum_utils.isInsideFRUSTUMs函数判断这个体素中心点是不是在深度相机的视锥里面,只处理在里面的点。如果满足三个条件就清除对应体素的标记。标记的意思是,如果一个体素被标记那么所在的空间就被障碍物占据,没有标记就没有障碍物。这三个条件是:如果必须强制清空这一整帧clear-all-marking-in-this-frame = true,点的距离小于一定的清除距离number-clearing-threshold <= forced-clearing-distance ,这个点的check_radius-半径范围内的邻居点个数小于number_clearing_threshold-。

​ ClearMarkingbyKdtree与ProcessCluster这两个函数是这个包的核心。前面提到作者写这个包的初衷,就是想解决障碍物标记如何清除的问题:

Considering ray casting method can not satisfy sparse 3D space problem of clearing. 
This plugin is based on kd-tree search to clear the markings, it comprises two parts:
    - Marking pointcloud and store it using std::map.
    - Clearing marked pointcloud using kd-tree search.

​ updateBounds函数是整个包里计算量最大一个,因为点云最近邻搜索、下采样和聚类分割操作都在这里完成。下采样前面说了,用的是PCL里的pcl::VoxelGrid,近邻搜索用的是PCL里的pcl::search::KdTree,聚类用的是PCL里原始的pcl::EuclideanClusterExtraction函数。

​ http://wiki.ros.org/costmap_2d

​ 最后的updateCosts函数就是在制作二维的代价地图,存储在master_grid中。你可能会问,前面的地图数据pc_3d_map_是三维的,代价地图却是二维的,那三维到底是怎么投影到二维的呢?这个具体的操作就是:既然pc_3d_map_第一项存储的是占据体素的xy坐标索引,如果某个xy坐标对应的索引在pc_3d_map_里面,那么不管垂直方向的占据体素有几个,都认为整个xy坐标索引被占用了,相应的master_array被赋值,这样就实现了投影,很简单吧。

​ 还有一个不起眼的frustum_utils.cpp,顾名思义,这个函数是提供与视锥有关的功能函数的,例如判断一个点是不是在一个视锥里的函数isInsideFRUSTUMs。在Observation类中也有与视锥有关的函数,那为什么要分开放呢?因为Observation类中的函数依然是用来计算视锥的一些属性值的,例如视锥的8个顶点,6个平面和法向量。这些值只在实例化时被执行一次,后面都不再执行。而frustum_utils.cpp里的函数是利用视锥的属性值进行高级的计算,它是要重复运行的,所以单独存放。

​ 总结一下,这个包处理的数据都是点云数据,具体使用的消息是sensor_msgs::PointCloud2类型,大量使用PCL库,所以理论上也能用在普通的多线激光雷达上面。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度相机的障碍物检测 的相关文章

  • 自定义Rust安装路径,自定义安装Rust

    首先我们知道使用https www rust lang org zh CN tools install官方下载器下载安装的rust主要有两个文件夹 xff0c 而且会默认生成到C盘下 但是 xff0c 我们通过修改环境变量可以自定义安装路径
  • HTML基础(一)

    本文是作者在学习html过程中对知识的初步整理 1 第一个程序 span class token doctype lt DOCTYPE html gt span span class token tag span class token t
  • 结构体的数组

    结构数组 也就是结构体的数组 的组成 xff1a struct 结构名 变量名 数组大小 span class token macro property span class token directive hash span span c
  • kali详细安装教程

    vmware虚拟机下载地址 xff1a https www vmware com cn products workstation pro workstation pro evaluation html kali ISO镜像 https cd
  • Armbian (jammy) 上安装 Docker

    一 Armbian 的软件源配置 Ubuntu 的软件源配置文件是 etc apt sources list 默认注释了源码镜像以提高 apt update 速度 xff0c 如有需要可自行取消注释 deb https mirrors tu
  • c语言结构体中的冒泡排序

    题目 xff1a 使用结构体以及函数 xff0c 首先录入学生信息 xff0c 依据学生成绩 xff0c 对学生相关信息进行排序 include lt stdio h gt include lt string h gt struct stu
  • csp序列查询(C语言)

    csp序列查询 span class token macro property span class token directive hash span span class token directive keyword include
  • 数据库学习

    数据库学习 一 span class token keyword SELECT span span class token operator span span class token keyword FROM span customers
  • Spring框架-ioc和JdbcTemplate

    前提 xff1a 我们用了Mybatis时 xff0c 已经不需要再使用其他的持久层框架了 用了mybatis之后 xff0c 我们只需要写持久层接口以及sql语句即可 但是为了讲解spring中的事务 xff0c 我们把JdbcTempl
  • 发送Promise请求出现以下错误origin ‘null‘ has been blocked by CORS policy

    错误如下 Access to XMLHttpRequest at span class token string 39 http localhost 9090 data 39 span from origin span class toke
  • VB.net与VB6 调用Websocket功能的方法--Websocket For VB

    概述 Websocket 功能在现今的通信应用开发中越来越普遍 xff0c 因为Websocket的消息机制 xff0c 在应用程序进行即时通信时使用非常合适 xff0c 而且Websocket 是长连接方式 xff0c 比起以前的http
  • sql当前日期

    查询本周 从周一开始计算 1 7 从周日开始计算就删除1 7 SELECT FROM 表名 WHERE YEARWEEK date format 时间字段 39 Y m d 39 1 61 YEARWEEK now 7 查询当月 SELEC
  • 【乐视秒杀架构】每秒处理10万请求—数据库分库分表

    随着乐视硬件抢购的不断升级 xff0c 乐视集团支付面临的请求压力百倍乃至千倍的暴增 作为商品购买的最后一环 xff0c 保证用户快速稳定的完成支付尤为重要 所以在15年11月 xff0c 我们对整个支付系统进行了全面的架构升级 xff0c
  • 单点登录(SSO)

    单点登录概述 xff1a 多系统共存下 xff0c 用户在一处地方登录 xff0c 得到其他所有系统的信任 xff0c 无需再次登录 在前端用户点击登陆之后触发后端的登录接口 xff0c 用户名密码验证通过之后 xff0c 自动生成一个JW
  • 【超详细】Consul的安装的使用附多环境配置(傻瓜式教程)

    一 Consul概述 Consul 是 HashiCorp 公司推出的开源工具 xff0c 用于实现分布式系统的服务发现与配置 与其他分布式服务注册与发现的方案 xff0c Consul 的方案更 一站式 xff0c 内置了服务注册与发现框
  • 【IDEA报错总结】修改Java编译版本-maven工程

    Warning 21 17 java 从发行版 10 开始 xff0c 39 var 39 是受限制的本地变量类型 xff0c 无法用于类型声明 xff0c 也无法用作数组的元素类型 之前一直使用的JDK8 xff0c 这个项目因为需要用到
  • 建一个链表

    单独的一个类 public class LinkNode int val LinkNode next LinkNode int x val 61 x 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • 判断数据类型的5种方法

    1 typeof 可以判断数据类型 xff0c 它返回表示数据类型的字符串 xff08 返回结果只能包括number boolean string function object undefined xff09 xff1b 可以使用type
  • 用python实现给女朋友自动发微信

    女朋友说上班都不回她微信 xff0c 于是给她安排一个定时自动发微信的功能 效果预览 实现过程 一 启动微信进程二 获取微信窗口在桌面的坐标三 发送消息1 鼠标依次点击打开聊天框2 输入发送内容 四 设置定时任务 一 启动微信进程 正常情况

随机推荐

  • 7. STM32——定时器中断(1秒闪烁灯)

    STM32 定时器中断 xff08 1秒闪烁灯 xff09 基本框架1 配置定时器时钟在 stm32f10x rcc h 头文件中查找相关函数函数 2 配置定时器结构体在 stm32f10x tim h 头文件中查找相关函数函数 3 开启定
  • 10. STM32——PWM 控制舵机(超声波感应开盖垃圾桶)

    STM32 PWM 控制舵机 通用定时输出PWMPWM的工作原理PWM的模式TIM OCMode PWM1 xff08 边沿对齐模式 xff09 TIM OCMode PWM2 xff08 中央对齐模式 xff09 占空比 舵机实物图接线舵
  • Windows10下Vmware开机蓝屏解决办法,亲测有效

    前言 虚拟机蓝屏的原因有很多 xff0c 这里我结合了网上的方法测试了三种 xff0c 建议大家三种都试一下 题外话 xff1a 其中有一台虚拟机蓝屏 xff0c 我把下面三种方法都用了才解决 xff1b 而另一台虚拟机我三种方法都用却解决
  • 3. 51——LCD1602显示 字符、字符串、数字

    51 LCD1602显示 字符 字符串 数字 LCD1602简介LCD1602相关引脚LCD1602写命令 写数据相关操作图 写指令 代码写数据 代码LCD1602显示程序步骤及如何初始化显示开关控制指令进入模式设置指令功能设定指令清屏指令
  • 12. STM32——硬件IIC驱动OLED屏幕显示

    STM32 硬件IIC驱动OLED屏幕显示 OLED屏幕OLED屏幕特点OLED屏幕接线说明OLED屏幕显存OLED屏幕原理OLED屏幕常用指令OLED屏幕字模软件的使用 写命令写数据OLED 初始化 xff08 厂家提供的代码 xff09
  • 15. STM32——软件IIC驱动OLED屏幕显示字符、字符串、数字、汉字

    STM32 软件IIC驱动OLED屏幕显示 OLED屏幕写命令写内容对OLED写入一个字节设置光标启动OLED关闭OLED全屏填充 xff08 清屏 xff09 显示字符显示字符串获取次方显示数字显示中文OLED驱动代码整合代码oled h
  • 16. STM32——测量空气的温度和湿度(STM32 + DHT11温湿度 + OLED显示)

    STM32 测量空气的温度和湿度 xff08 STM32 43 DHT11温湿度 43 OLED显示 xff09 DHT11温湿度相关介绍初始化GPIOB11启动DHT11获取一个字节获取数据代码整合DHT11 hDHT11 coled h
  • 17. STM32——SPI硬件

    STM32 SPI SPI协议SPI接口SPI接口框图SPI工作原理时钟信号的相位和极性CPHA 61 0CPHA 61 1 SPI中断状态标志发送缓存器空闲标志 xff08 TXE xff09 接收缓冲器非空 RXNE 忙BUSY标志 S
  • 关于anaconda下载之后在开始菜单找不到快捷方式的问题

    这是我在安装anaconda时犯的错误 xff0c 安装之后在开始菜单没有找到关于anaconda的文件夹 jupyter notebook spyder anaconda prompt 安装了好多遍 xff0c 最后才知道方法如此简单 第
  • 对帧率、I/P率、I帧间隔的理解2021-11-16

    对帧率 I P率 I帧间隔的理解 码率就是数据传输时单位时间传送的数据位数 一般我们用的单位是kbps即千位每秒 通俗一点的理解就是取样率 xff0c 单位时间内取样率越大 xff0c 精度就越高 xff0c 处理出来的文 件就越接近原始文
  • java读取jar包内的配置文件

    java读取jar包内的配置文件 span class token class name Properties span p span class token operator 61 span span class token keywor
  • 3、Proteus仿真STM32定时器TIM2与中断来控制流水灯的定时闪烁。

    一 实验说明 本次实验建立在上两次实验上 xff0c 稍加修改 xff0c 通过TIM2定时器中断控制LED流水灯的闪烁时间 xff0c 并且增加两个按键PA1 PA2 xff0c 其中PA1控制LED流水灯的启动 xff0c 8个灯先依次
  • HDFS基础知识(个人总结)

    HDFS存储优缺点 优点 高容错 因为它有多个副本可处理大数据 文件数量可达百万 缺点 HDFS可以追加 但不能修改某一条数据 若实在想修改 只能下载下来原文件进行修改后重新上传覆盖 不适合低延迟数据访问 如毫秒级 无法高效存储大量小文件
  • 校招笔试题1

    编码题 字符串S由小写字母构成 xff0c 长度为n 定义一种操作 xff0c 每次都可以挑选字符串中任意的两个相邻字母进行交换 询问在至多交换m次之后 xff0c 字符串中最多有多少个连续的位置上的字母相同 xff1f 输入描述 第一行为
  • 【Linux】c++创建新线程执行sh脚本

    Linux c 43 43 创建新线程执行sh脚本 前情提要 Linux profile d加入循环shell脚本 xff0c 重启登录黑屏system函数可以运行 sh脚本 需要包含stdlib h因为我的 sh脚本里有循环 不能放在主程
  • pip下载路径查看,解决在pycharm导入问题

    今天在学习图表数据可视化时 xff0c 用到了pyecharts包 xff0c 在cmd中输入pip install pyecharts xff0c 显示下载成功 xff0c 如下所示 xff1a 但在pycharm中仍不能导入pyecha
  • C语言学习笔记:函数递归-斐波那契数列

    什么是递归 在数学和计算机科学中 xff0c 递归指由一种 xff08 或多种 xff09 简单的基本情况定义的一类对象或方法 xff0c 并规定其他所有情况都能被还原为其基本情况 递归就是在运行的过程中调用自己 xff0c 递归关系就是实
  • python3安装教程

    前言 xff1a 建议使用3 6版本及以上 xff0c 系统自带的python2不要卸载 xff0c 一些系统命令要用 xff0c 2和3可以共存 一 Linux安装python3 Python 3 6 8 1 查看是否已安装python3
  • windows通过xrdp协议远程centos桌面

    windows通过xrdp协议远程连接centos图形化桌面 系统远程试验环境Centos7 9远程环境检查Xrdp服务包安装开放访问端口启用远程服务开始访问测试其他注意事项 系统远程试验环境 远控端 xff1a Windows10 被控端
  • 深度相机的障碍物检测

    深度相机的障碍物检测 这里简单备份一下 xff0c 有关深度相机障碍物检测的学习内容 1 准备相机的驱动 Ubuntu18 04 43 ROS 43 ros astra camera master 采用的是astra深度相机 xff0c 安