Velodyne 高清激光雷达 (HDL) 采集器
Velodyne HDL 是一种基于网络的 3D LiDAR 系统,每秒生成包含超过 700,000 个点的 360 度点云。
PCL 中提供的 HDL Grabber 模仿其他 Grabbers,使其几乎可以即插即用。 然而,由于 HDL 设备是基于网络的,因此在某些平台上存在一些问题。
HDL Grabber 支持原始的 HDL-64e 以及 HDL-32e。 有关这些传感器的更多信息,请访问 Velodyne 网站Velodyne’s Web Site
基本网络设置
Velodyne HDL 使用网络数据包为设备中的每个激光器提供范围和强度数据。 HDL-64e 由 64 个激光器组成,而 HDL-32e 由 32 个激光器组成。
默认情况下,HDL-64e 和 HDL-32e 在 192.168.3 子网上生成 UDP 网络数据包。 从 HDL-32e(固件版本 2)开始,用户可以自定义此网络子网。
HDL 可以直接连接到您的计算机,也可以连接到网络交换机(包括带有内置无线接入点的网络交换机)。 无论如何,您的计算机的一个网络接口卡 (NIC) [无论是有线 RJ-45 连接还是无线连接] 都需要配置为在此 192.168.3 子网上。 请查阅您的操作系统文档以了解如何执行此操作。
除了 NIC 设置之外,您可能还需要更改操作系统的防火墙规则。 HDL 在端口 2368(默认情况下)上生成数据包。 固件版本 2 的 HDL-32e 可以设置为使用不同的端口。 请查阅您的防火墙文档以在您的防火墙中打开此端口。
最后,现代 Linux 内核具有超越基本防火墙规则的高级网络攻击防护。 HDL-32e 生成的 UDP 数据包可能会被操作系统使用这些攻击防护之一过滤。 您需要为相应的 NIC 禁用 rp_filter 防护。 有关如何禁用此过滤器的更多信息,请参阅下面标题为禁用反向路径过滤器的部分Disabling Reverse Path Filter
PCAP文件
Wireshark是一种流行的网络数据包分析程序,适用于大多数平台,包括 Linux、MacOS 和 Windows。 该工具使用称为 PCAP的事实上的标准网络数据包捕获文件格式。 许多公开可用的 Velodyne HDL 数据包捕获使用此 PCAP 文件格式作为记录和回放的方式。 如果 PCL 编译时支持 PCAP,则这些 PCAP 文件可与 HDL Grabber 一起使用。
Velodyne 在其网站website上提供示例 PCAP 文件
编译支持 PCAP 的 HDL Grabber
在 Linux 上,这涉及安装 libpcap-dev (Ubuntu) 或 libpcap-devel (Fedora)。 CMake 应该找到 pcap 库,并自动配置 PCL 来使用它们。
在 Windows 上,这涉及安装 WinPCAP installer 和 WinPCAP developer’s pack。 您还需要将环境变量 PCAPDIR 设置为解压缩开发人员包的目录。 完成后,您应该能够再次运行 CMake,它应该会找到相应的文件。
注意 - 您不需要编译支持 PCAP 的 HDL Grabber。 仅当您将通过抓取器重放 PCAP 文件时才需要。
示例程序
SimpleHDLViewer.h
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/hdl_grabber.h>
#include <pcl/visualization/point_cloud_color_handlers.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/console/parse.h>
using namespace std::chrono_literals;
using namespace pcl::console;
using namespace pcl::visualization;
class SimpleHDLViewer
{
typedef pcl::PointCloud<pcl::PointXYZI> Cloud;
typedef Cloud::ConstPtr CloudConstPtr;
public:
SimpleHDLViewer(pcl::Grabber &grabber, PointCloudColorHandler<pcl::PointXYZI> &handler);
void cloud_callback(const CloudConstPtr& cloud);
void run();
private:
PCLVisualizer::Ptr cloud_viewer_;
pcl::Grabber &grabber_;
std::mutex cloud_mutex_;
CloudConstPtr cloud_;
PointCloudColorHandler<pcl::PointXYZI> &handler_;
};
SimpleHDLViewer.cpp
#include "SimpleHDLViewer.h"
SimpleHDLViewer::SimpleHDLViewer(pcl::Grabber &grabber,
PointCloudColorHandler<pcl::PointXYZI> &handler) :
cloud_viewer_(new PCLVisualizer("PCL HDL Cloud")),
grabber_(grabber),
handler_(handler)
{
}
void SimpleHDLViewer::cloud_callback(const CloudConstPtr &cloud)
{
std::lock_guard<std::mutex> lock(cloud_mutex_);
cloud_ = cloud;
}
void SimpleHDLViewer::run()
{
cloud_viewer_->addCoordinateSystem(3.0);
cloud_viewer_->setBackgroundColor(0, 0, 0);
cloud_viewer_->initCameraParameters();
cloud_viewer_->setCameraPosition(0.0, 0.0, 30.0, 0.0, 1.0, 0.0, 0);
cloud_viewer_->setCameraClipDistances(0.0, 50.0);
std::function<void (const CloudConstPtr&)> cloud_cb =
[this] (const CloudConstPtr &cloud) {cloud_callback(cloud);};
boost::signals2::connection cloud_connection = grabber_.registerCallback(cloud_cb);
grabber_.start();
while (!cloud_viewer_->wasStopped())
{
CloudConstPtr cloud;
// See if we can get a cloud
if (cloud_mutex_.try_lock())
{
cloud_.swap(cloud);
cloud_mutex_.unlock();
}
if (cloud)
{
handler_.setInputCloud(cloud);
if (!cloud_viewer_->updatePointCloud(cloud, handler_, "HDL"))
cloud_viewer_->addPointCloud(cloud, handler_, "HDL");
cloud_viewer_->spinOnce();
}
if (!grabber_.isRunning())
cloud_viewer_->spin();
std::this_thread::sleep_for(100us);
}
grabber_.stop();
cloud_connection.disconnect();
}
hdl_viewer_simple.cpp
#include "SimpleHDLViewer.h"
#include <pcl/io/vlp_grabber.h>
int main(int argc, char ** argv)
{
std::string hdlCalibration, pcapFile;
parse_argument(argc, argv, "-calibrationFile", hdlCalibration);
parse_argument(argc, argv, "-pcapFile", pcapFile);
// pcapFile = "HDL32-V2_Monterey Highway.pcap";
pcl::HDLGrabber grabber(hdlCalibration, pcapFile);
// pcl::VLPGrabber g(pcapFile);
PointCloudColorHandlerGenericField<pcl::PointXYZI> color_handler("intensity");
SimpleHDLViewer v(grabber, color_handler);
v.run();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(pcl_hdl_viewer_simple)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG -O0 -Wall -g2 -ggdb")
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
find_package(PCL 1.10 REQUIRED COMPONENTS)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
#LINK_LIBRARIES(${PCL_LIBRARIES})
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} CPP_SOURCE)
#add_executable(pcl_hdl_viewer_simple hdl_viewer_simple.cpp)
add_executable(pcl_hdl_viewer_simple ${CPP_SOURCE})
target_link_libraries(pcl_hdl_viewer_simple ${PCL_LIBRARIES} pthread)
build.sh
#!/bin/bash
CURRENT_DIR=$(cd $(dirname $0); pwd)
FILE=${CURRENT_DIR}/build
if [ ! -d "$FILE" ]; then
echo "$FILE not exist"
mkdir ${FILE}
fi
cd build
cmake ..
make
直接运行build.sh编译