ROS中使用Intel RealSense D455或L515深度相机

2023-05-16

  目的

  在ROS平台上,使用深度相机作为传感器设计自主避障机器人。

1 安装驱动

  测试环境:
  软件:Ubuntu 16.04、ROS Kinetic
  硬件:Intel RealSense D455 或 L515
  深度相机的ROS驱动安装脚本如下,这两个传感器的驱动完全一样。

#!/bin/bash
sudo apt-key adv --keyserver keys.gnupg.net --recv-key C8B3A55A6F3EFCDE || sudo apt-key adv --keyserver 
sudo add-apt-repository "deb http://realsense-hw-public.s3.amazonaws.com/Debian/apt-repo xenial main" -u
sudo apt-get update
sudo apt-get install librealsense2-dkms
sudo apt-get install librealsense2-utils
sudo apt-get install librealsense2-dev
mkdir -p ~/RealSense/src
cd ~/RealSense/src
git clone https://github.com/intel-ros/realsense.git 
git clone https://github.com/pal-robotics/ddynamic_reconfigure.git
cd ~/RealSense
catkin_make
source devel/setup.bash
roslaunch realsense2_camera rs_rgbd.launch

2 使用

  启动传感器的指令如下

roslaunch realsense2_camera rs_rgbd.launch

  这个传感器的参数通过launch文件配置,参数的含义可以看这篇博客,其中主要的有以下参数:

<arg name="enable_pointcloud"         default="true"/>   一定要设为true,否则没有点云数据输出

3 消息转换:图像转LaserScan

  下面这个包将深度图像数据转换为二维激光雷达常用的LaserScan消息格式。这个包没有kinetic版本,但是没关系,indigo版本可以在kinetic中直接使用。下图中醒目的红色点就是LaserScan点云。

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

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

rosrun depthimage_to_laserscan depthimage_to_laserscan image:=/camera/depth/image_raw

4 生成伪三维障碍物的costmap

4.1 具体操作

  通过图像转LaserScan消息有个缺点,它只截取了水平面的一段数据,其它高度上的数据都被忽略了。对于直上直下、上下一样粗细的简单障碍物是没有太大问题的,但是如果我们的障碍物分布是三维的,那这样显然丢失了大部分数据。所以更安全的方法是将所有的三维点云全部投影到二维平面,这样就能考虑三维分布。
  实现该功能的ROS包是costmap_depth_camera。但是这个包不能在kinetic版本中使用,为此我修改了程序,主要是把tf2改成了tf。关于写这个包的动机,作者是这样说的:“考虑到传统的光线投射算法不能清除稀疏的3D空间,这个插件就是为了解决这个问题,方法是用kd-tree搜索去清除标记”。如果听不懂,后面会详细解释。
  原来的版本还有一个问题:直接对原始点云进行的处理。深度相机返回的点云数据量是极其庞大的。以L515传感器为例,其一帧图像分辨率为 1024 × 768 = 786432 1024\times768=786432 1024×768=786432,相当于78万个点,当然实际大概有十几万个点。作为对比,16线的Velodyne激光雷达才只有28800个点。在如此大的点云上做最Kdtree近邻搜索,即使在笔者至强8核CPU的工控机上都卡的要死。因为Kdtree近邻搜索的计算量是与点云数量成比例的。为了解决这个问题,笔者使用了PCL中的下采样函数对原始点云进行压缩,压缩前的点云规模是10万,压缩后是5000左右,即压缩为原来的1/20。

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

  经过下采样后速度勉强达到了10Hz的更新频率。下面的试验通过设置max_obstacle_height : 1.5把高处的门框排除掉了,其它的障碍物正常投影到水平面。

4.2 costmap_depth_camera代码剖析

  costmap_depth_camera包是costmap_2d的插件,只有6个C++文件。我们从下向上看,先从底层的observation.h开始,observation顾名思义就是传感器的观测数据,具体来说就是Realsense深度相机输出的点云数据。简单的理解,一个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里(放到与costmap_2d并列的地位),然后一起编译调试。
  depth_camera_obstacle_layer.cpp位于plugins文件夹下,它的风格与costmap_2d\plugins文件夹中的文件类似,我们打开obstacle_layer.cpp就能看到相同的成员,例如:

  std::vector<boost::shared_ptr<costmap_depth_camera::ObservationBuffer> > observation_buffers_;  ///< @brief Used to store observations from various sensors
  std::vector<boost::shared_ptr<costmap_depth_camera::ObservationBuffer> > marking_buffers_;  ///< @brief Used to store observation buffers used for marking obstacles
  std::vector<boost::shared_ptr<costmap_depth_camera::ObservationBuffer> > clearing_buffers_;  ///< @brief 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_是如何存储三维地图的呢?它先用索引unsigned int存储水平面的xy坐标,再在第二个std::map存储垂直方向的z轴坐标,最后一个float存储每个体素的(点云)强度信息。

  /*Voxel structure*/
  std::map<unsigned int, std::map<int, float> > pc_3d_map_;

  在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,点的距离小于一定的清除距离pc_dis<=forced_clearing_distance_,这个点的check_radius_半径范围内的邻居点个数小于number_clearing_threshold_
  ClearMarkingbyKdtreeProcessCluster这两个函数是这个包的核心,它们都在updateBounds函数中被调用。这两个好兄弟,一个向三维地图pc_3d_map_中添加数据(ProcessCluster),一个从三维地图pc_3d_map_中去除数据(ClearMarkingbyKdtree)。几乎所有关于pc_3d_map_的操作都是由这两个函数完成的。前面提到作者写这个包的初衷,就是想解决障碍物标记如何清除的问题:

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.

  有人可能不了解标记(mark)与清除(clear)是什么意思?通过阅读costmap_2d我们知道,在ROS使用的代价地图支持这样的操作:mark操作把障碍物信息插入到costmap中,具体来说就是改变栅格中的代价值。clear操作刚好相反,从costmap中清除障碍物信息。clear的操作更复杂一点,它要找出从传感器原点开始的每条激光射线(ray)覆盖的栅格,然后将这些栅格的代价值清空(Free space)。
  updateBounds函数是整个包里计算量最大一个,因为点云最近邻搜索、下采样和聚类分割操作都在这里完成。下采样前面说了,用的是PCL里的pcl::VoxelGrid,近邻搜索用的是PCL里的pcl::search::KdTree,聚类用的是PCL里原始的pcl::EuclideanClusterExtraction函数。
  最后的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库,所以理论上也能用在普通的多线激光雷达上面。

5 真正的三维障碍物costmap

  上面的costmap其实还是二维近似的,因为用于机器人规划和碰撞检测的依然是在水平面中进行。这个github项目使用了真正的三维costmap,对复杂异形的障碍物表示更准确。但是对于性能一般的处理器来说,笔者担心计算负担会不会太大。毕竟二维障碍物运行在10Hz下已经有点捉襟见肘了。

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

ROS中使用Intel RealSense D455或L515深度相机 的相关文章

  • Sandy-Bridge CPU规格

    我能够将有关 Sandy Bridge E 架构的一些信息整合在一起 但我并不完全确定所有参数 例如L2 缓存的大小 任何人都可以确认它们都是正确的吗 我的主要来源是64 ia 32 架构 优化 手册 pdf http www intel
  • 启用/禁用硬件锁定消除

    我使用的是 glibc 2 24 版本 它包含用于使用事务同步扩展 例如 xbegin 和 xend 实现 pthread mutex lock 的锁省略路径 硬件应该支持锁省略hle我认为CPU标志是为了硬件锁消除 我使用的处理器是采用
  • IB读、IB写、OB读、OB写是什么意思?它们作为 Intel® PCM 的输出,同时监控 PCIe 带宽

    我正在尝试使用英特尔 性能计数器监视器 PCM 工具测量 NIC 设备的 PCIe 带宽 但是 我无法理解它的输出 为了测量 PCIe 带宽 我执行了二进制 pcm iio 该二进制文件有助于测量每个 PCIe 设备的监视器 PCIe 带宽
  • catkin_make 编译报错 Unable to find either executable ‘empy‘ or Python module ‘em‘...

    文章目录 写在前面 一 问题描述 二 解决方法 参考链接 写在前面 自己的测试环境 Ubuntu20 04 一 问题描述 自己安装完 anaconda 后 再次执行 catkin make 遇到如下问题 CMake Error at opt
  • AVX/SSE 轮向下浮动并返回整数向量?

    有没有办法使用 AVX SSE 获取浮点数向量 向下舍入并生成整数向量 所有底层内在方法似乎都会产生一个最终的浮点向量 这很奇怪 因为四舍五入会产生一个整数 SSE 可以根据您选择的截断 向零 或当前舍入模式 通常是 IEEE 默认模式 最
  • ROS 从 python 节点发布数组

    我是 ros python 的新手 我正在尝试从 python ros 节点发布一个一维数组 我使用 Int32MultiArray 但我无法理解多数组中布局的概念 谁能给我解释一下吗 或者还有其他方式发布数组吗 Thanks usr bi
  • 在 Fortran 中传递不连续的数组部分

    我正在使用 intel fortran 编译器和 intel mkl 进行性能检查 我将一些数组部分传递给 Fortran 77 接口 调用如下 call dgemm transa transb sz s P P a Ts tilde sz
  • *移动消除*插槽在 Intel CPU 中如何工作?

    安德烈亚斯 阿贝尔和简 雷内克讨论移动消除 in 他们的论文描述了 uCA https dl acm org doi pdf 10 1145 3524059 3532396 4 1 4 移动消除 然而 这一招消除并不总是成功的 我们开发了微
  • 英特尔编译器值得吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 非常简单 是英特尔编译器 http software intel com en us intel compilers 值得入手吗 我主要从事系统
  • 如何将两个 SSE 寄存器加在一起

    我有两个 SSE 寄存器 128 位是一个寄存器 我想将它们相加 我知道如何在其中添加相应的单词 例如我可以这样做 mm add epi16如果我在寄存器中使用 16 位字 但我想要的是类似的东西 mm add epi128 不存在 它将使
  • Xeon CPU (E5-2603) 向后内存预取

    Xeon CPU E5 2603 中的向后内存预取与向前内存预取一样快吗 我想实现一种需要对数据进行前向循环和后向循环的算法 由于每次迭代都需要上次迭代的结果 因此我无法反转循环的顺序 您可以运行实验来确定数据预取器是否能够处理前向顺序访问
  • 在 Skylake 中使用 MSR 正确禁用硬件预取

    我正在尝试禁用我的机器上的硬件预取 CPU系列 6 型号 78 型号名称 Intel R Core TM i5 6200U CPU 2 30GHz 我已经检查过 gcc march native Q help target grep Mar
  • 64位汇编介绍

    我正在寻找一篇介绍 Intel 64 位处理器和汇编的文章 x64 寄存器列表 命令语法等 供熟悉 32 位汇编的程序员使用 有点像 64 位处理器的 新增功能 The Intel 64 和 IA 32 架构软件开发人员手册 http ww
  • 将8个16位SSE寄存器转换为8位数据

    假设我有一个包含 16 位数据的 SSE 数组 1 2 3 4 5 6 7 8 现在我需要通过在前 8 个字节中仅存储 16 位数据的低字节来将此 SSE 数组转换为 8 位数据 如下所示 1 2 3 4 5 6 7 8 0 0 0 0 0
  • 如何使用汇编程序从英特尔处理器中获取随机数?

    我需要从处理器 英特尔酷睿 i3 中的英特尔随机生成器获取随机数 我不想使用任何图书馆 我想在 C 中使用汇编程序粘贴 但我不知道应该使用哪些寄存器和指令 呼叫RDRAND支持的 CPU 目前仅 Ivy Bridge 和 Haswell I
  • 存储缓冲区是否保存现代 x86 上的物理地址或虚拟地址?

    现代 Intel 和 AMD 芯片大存储缓冲区 https stackoverflow com a 54880249 149138在提交到 L1 缓存之前缓冲存储 从概念上讲 这些条目保存存储数据和存储地址 对于地址部分 这些缓冲区条目是否
  • 有没有比加0.5f并截断转换更直接的方法将float转换为int并进行舍入?

    在处理浮点数据的 C 代码中 从 float 到 int 的舍入转换相当频繁 例如 一种用途是生成转换表 考虑一下这段代码 Convert a positive float value and round to the nearest in
  • 混洗两个 __m128i 的 64 位部分的最佳方法

    我有两个 m128is a and b 我想进行洗牌 以便高 64 位a落在低 64 位dst和低 64 位b落在上64dst i e dst 0 63 a 64 127 dst 64 127 b 0 63 相当于 m128i dst mm
  • ROS中spin和rate.sleep的区别

    我是 ROS 新手 正在尝试了解这个强大的工具 我很困惑spin and rate sleep功能 谁能帮助我了解这两个功能之间的区别以及何时使用每个功能 ros spin and ros spinOnce 负责处理通信事件 例如到达的消息
  • AVX-512CD(冲突检测)与原子变量访问有何不同?

    所以我在看他们展示了如何 void Histogram const float age int const hist const int n const float group width const int m const float o

随机推荐

  • c语言向上取整计算方法

    用整数N 除以 M xff0c 要求向上取整数 1 xff09 int n 61 N 43 M 1 M xff1b 简化后就是 xff1a 2 xff09 int n 61 N 1 M 43 1 xff1b 最笨的办法 3 int n 61
  • 比std::qsort还快的快速排序(1千万整数1.7秒)——(快速排序栈溢出与递归优化)

    前几天发现老外的开源项目中事件队列中用的就是std qsort排序 xff0c 后续插入时候使用了堆方式 快速排序实际应用中是比堆排序要快的 xff0c 这主要是因为硬件层次会对数据执行高速缓存 xff0c 数据使用一二三级高速缓存比访问内
  • C#使用ProtoBuf

    1 Google ProtoBuf 经过测试 xff0c protobuf比json存储效率还是要高 xff0c 即时号称最快的fastjson也没有protobuf快 xff0c 这里为了使用 c 做一个客户端兼容 xff0c 所以也需要
  • 多线程如何实现高性能计数器(无锁)

    多线程协作免不了使用计数器 xff0c 通常的代码 xff0c c 43 43 一般会使用锁 xff0c 或者原子变量操作 xff1a std mutex mutexCounter int count void add std lock g
  • ubuntu18/20 下如何生成core文件

    ubuntu18 20 下如何生成core文件 一 设置 原理 xff1a https blog csdn net Sunnyside article details 118439302 原来在ubuntu14 ubuntu16上只需要一步
  • c++的字节序与符号位的问题

    看这样一道题 xff1a include lt stdio h gt int main void int w h int i 61 0xa1b2c3d4 char p 61 char amp i for int j 61 0 j lt 4
  • docker镜像之带vnc的ubuntu

    docker镜像 之 带vnc图形界面ubuntu 前言 xff1a 为了在图形界面中使用firefox xff0c 需要找一个带rdp或者vnc的ubuntu xff0c 最好是gnome的界面 xff0c 折腾了3天 xff0c 终于找
  • STM32中,关于中断函数调用全局变量的问题

    xfeff xfeff https blog csdn net leo liu006 article details 79334905 首先是问题的描述 xff1a 硬件单片机型号 xff0c STM32F103VET6 xff0c IDE
  • python使用selenium以及selenium-wire做质量与性能检测

    python天生就是适合用来做爬虫 xff0c 结合selenium真是如虎添翼 xff1b 1 安装库 pip install selenium pip install selenium wire 2 xff09 添加驱动 xff0c 比
  • 编写http workshop脚本从网页缓存里解析音乐

    前一篇文章 编写http workshop脚本从网站下载音乐 示范了如何使用HttpClient访问API 以及Json数据的解析 今天我们通过解析一个网页展示如何使用内置的LibXml2的功能解析HTML 提取我们关心的内容 这里随便搜了
  • pytorch环境搭建若干

    备注 xff1a 不要使用python3 11不支持 xff0c pip会说找不到合适的版本 xff1b python官网不提供旧版的下载了 xff0c 说是win7以后无法使用 xff0c 都是扯淡 xff0c 有其他地方可以下载pyth
  • ffmpeg常用方法

    FFmpeg 是一款开源的音视频处理工具 xff0c 可以处理各种格式的音视频文件 xff0c 并且可以进行格式转换 剪切 合并 添加水印等多种操作 下面是 FFmpeg 的一些常用命令及其用法 xff1a 视频转码 将一个视频文件转换为另
  • RFC2152 UTF-7 中文

    RFC2152 UTF 7 中文 翻译 xff1a 李静南 时间 xff1a 2006 03 29 EMAIL xff1a robin fox 64 sohu com 版权 xff1a 可以用于非商业用途自由转载 xff0c 但请保留本文档
  • 第九章0.4的CMakeLists.txt结构

    最开始看这一章的时候 xff0c 将CMakeLists txt部分跳过了 xff0c 没有看 后来看高博RGBD SLAM时候 xff0c 第一讲降到了cmake的用法 xff0c 发现有新的东西 xff0c 又回头看 xff1a 最原始
  • ROS 中setup.bash

    好久没写了 xff0c 最近搞了辆小车 xff0c 瞅了瞅ROS的相关内容 xff0c 没有写ROS的内容 xff0c 刚开始看 xff0c 写的话基本就成了书本粘贴 不过最近由ROS引出来的一些Linux相关的东西 xff0c 然后又回头
  • ros_hostname与ros_ip

    在ROS的环境变量中 xff0c 需要在 bashrc中设置的并不多 xff08 此处是指在wiki的基本教程中出现的 xff0c 大牛请无视 xff09 xff0c 大概只有三个 xff1a ROS MASTER URI ROS HOST
  • git图形化代码冲突处理

    当代码量少的时候使用 xff0c 使用vimdiff或者手动处理冲突 xff0c 都很方便 xff0c 但是当代码量大还是图形化处理更方便 xff0c 这里推荐使用kdiff3 首先下载kdiff3 xff0c 网上不好找的话 xff0c
  • Apache httpd 目录列表禁用配置(options indexes)

    Apache httpd服务器在缺省的情况下 xff0c 开启了基于目录列表的访问 xff0c 这是一个存在安全隐患的问题 xff0c 因此可以关闭这个功能 在Apache 2 4的版本中 xff0c 不在支持使用 indexes来配置 x
  • cmake学习笔记6-catkin的CmakeList.txt讲解

    https www jianshu com p 551d6949b49d 引用 cmake学习笔记 cmakelist txt创建项目示例 cmake的介绍和使用 Cmake实践 推荐cmake手册详解 严重推荐CMake构建系统的骨架 c
  • ROS中使用Intel RealSense D455或L515深度相机

    目的 在ROS平台上 xff0c 使用深度相机作为传感器设计自主避障机器人 1 安装驱动 测试环境 软件 xff1a Ubuntu 16 04 ROS Kinetic 硬件 xff1a Intel RealSense D455 或 L515