Dora-rs 机器人框架学习教程(4)——速腾激光雷达驱动

2024-01-08 09:28

本文主要是介绍Dora-rs 机器人框架学习教程(4)——速腾激光雷达驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1、rslidar 雷达官方驱动
  • 2、rslidar dora 框架驱动
    • 2.1 驱动代码
    • 2.2 编译rslidar驱动
    • 2.3 编写rslidar_test.yml文件
    • 2.4 启动节点
  • 3、rslidar Debug节点
    • 3.1 新建调试程序
    • 3.2 启动节点
  • 参考资料

目标:编写一个C++节点读取速腾雷达数据。
程序的基本思路是新建一个C++ dora节点,在该节点中调用rslidar类成员函数读取雷达数据,并将数据序列化发布到dora中去。
本文使用的激光雷达是速腾 RSHELIOS 32线激光雷达
在这里插入图片描述

这里我们也参考了之前有大佬写的驱动程序的思路 github

1、rslidar 雷达官方驱动

这里需要用到速腾官方的驱动库rs_driver,因此对使用的程序简单介绍。
在 rs_driver 库中demo文件夹下提供了一个雷达数据读取范例程序 demo_online.cpp ,可在demo文件夹下创建build目录,对 demo_online.cpp 进行编译,生成可执行文件,以测试激光雷达的连线是否正确。

mkdir build
cd build
cmake ..
make
./demo_online

若出现如下信息则表示激光雷达与电脑数据链路正确。
在这里插入图片描述
程序上主要涉及到使用rs_driver库中的 **RSDriverParam ** 参数类 和 数据读取函数 processCloud()

1、RSDriverParam 类涉及激光雷达类型和端口
在这里插入图片描述
2、函数 void processCloud(void)主要是获取激光雷达数据
在这里插入图片描述

2、rslidar dora 框架驱动

2.1 驱动代码

新建 rslidar_driver.cc文件,将以下内容复制到文件中
(注意将include 路径 /home/dora/dora_project/dora/apis/c/node/node_api.h"替换为你电脑上的路径)

extern "C"
{
#include "/home/dora/dora_project/dora/apis/c/node/node_api.h"   
#include "/home/dora/dora_project/dora/apis/c/operator/operator_api.h"
#include "/home/dora/dora_project/dora/apis/c/operator/operator_types.h"
}#include <iostream>
#include <vector>// rs lidar driver
#include <rs_driver/api/lidar_driver.hpp>#ifdef ENABLE_PCL_POINTCLOUD
#include <rs_driver/msg/pcl_point_cloud_msg.hpp>
#else
#include <rs_driver/msg/point_cloud_msg.hpp>
#endif
typedef PointXYZI PointT;
typedef PointCloudT<PointT> PointCloudMsg;using namespace robosense::lidar;SyncQueue<std::shared_ptr<PointCloudMsg>> free_cloud_queue;
SyncQueue<std::shared_ptr<PointCloudMsg>> stuffed_cloud_queue;
//
// @brief point cloud callback function. The caller should register it to the lidar driver.
//        Via this fucntion, the driver gets an free/unused point cloud message from the caller.
// @param msg  The free/unused point cloud message.
//
std::shared_ptr<PointCloudMsg> driverGetPointCloudFromCallerCallback(void)//从free队列里面取
{// Note: This callback function runs in the packet-parsing/point-cloud-constructing thread of the driver, //       so please DO NOT do time-consuming task here.std::shared_ptr<PointCloudMsg> msg = free_cloud_queue.pop();if (msg.get() != NULL){return msg;}return std::make_shared<PointCloudMsg>();
}//
// @brief point cloud callback function. The caller should register it to the lidar driver.
//        Via this function, the driver gets/returns a stuffed point cloud message to the caller. 
// @param msg  The stuffed point cloud message.
//
void driverReturnPointCloudToCallerCallback(std::shared_ptr<PointCloudMsg> msg)//填到一个新的队列里
{// Note: This callback function runs in the packet-parsing/point-cloud-constructing thread of the driver, //       so please DO NOT do time-consuming task here. Instead, process it in caller's own thread. (see processCloud() below)stuffed_cloud_queue.push(msg);
}//
// @brief exception callback function. The caller should register it to the lidar driver.
//        Via this function, the driver inform the caller that something happens.
// @param code The error code to represent the error/warning/information
//
std::string exceptionCallback(const Error& code)//错误报告
{// Note: This callback function runs in the packet-receving and packet-parsing/point-cloud_constructing thread of the driver, //       so please DO NOT do time-consuming task here.RS_WARNING << code.toString() << RS_REND;return "";
}bool to_exit_process = false;
void processCloud(void)
{while (!to_exit_process){std::shared_ptr<PointCloudMsg> msg = stuffed_cloud_queue.popWait();//这个popwait函数是一个线程安全的队列popif (msg.get() == NULL){continue;}// Well, it is time to process the point cloud msg, even it is time-consuming.RS_MSG << "msg: " << msg->seq << " point cloud size: " << msg->points.size() << RS_REND;#if 0for (auto it = msg->points.begin(); it != msg->points.end(); it++){std::cout << std::fixed << std::setprecision(3) << "(" << it->x << ", " << it->y << ", " << it->z << ", " << (int)it->intensity << ")" << std::endl;}
#endiffree_cloud_queue.push(msg);//这里是说,上面那个#if里面的东西已经把这个点云处理完了,东西都取出来了,那这个点云实例(占内存的)我们就可以重复利用了,就空闲了,把它放入待使用区(free区)}
}
int run(void *dora_context)
{unsigned char counter = 0;//for (int i = 0; i < 20; i++)to_exit_process = false;while(!to_exit_process){void *event = dora_next_event(dora_context);if (event == NULL){printf("[c node] ERROR: unexpected end of event\n");return -1;}enum DoraEventType ty = read_dora_event_type(event);if (ty == DoraEventType_Input){// copy from rslidar driver#if 1Vec_uint8_t result;std::shared_ptr<PointCloudMsg> msg = stuffed_cloud_queue.popWait();//这个popwait函数是一个线程安全的队列popif (msg.get() == NULL){continue;}// Well, it is time to process the point cloud msg, even it is time-consuming.RS_MSG << "msg: " << msg->seq << " point cloud size: " << msg->points.size() << RS_REND;#if 0for (auto it = msg->points.begin(); it != msg->points.end(); it++){std::cout << std::fixed << std::setprecision(3) << "(" << it->x << ", " << it->y << ", " << it->z << ", " << (int)it->intensity << ")" << std::endl;}#endif//free_cloud_queue.push(msg);//这里是说,上面那个#if里面的东西已经把这个点云处理完了,东西都取出来了,那这个点云实例(占内存的)我们就可以重复利用了,就空闲了,把它放入待使用区(free区)if (sizeof(PointT) <= 16){RS_MSG << "sizeof(PointT) <= 16 " << RS_REND;size_t cloudSize = (((msg->points.size()) + 1) * 16);  // 4byte for message seq, 4bytes empty, 8byte for timestamp,// others for pointsu_int8_t* bytePointCloud = (u_int8_t*)(new PointT[cloudSize / sizeof(PointT)]);u_int32_t* seq = (u_int32_t*)bytePointCloud;*seq = msg->seq;double* timestamp = (double*)(bytePointCloud + 8);*timestamp = msg->timestamp;// PointT* point = (PointT*)(bytePointCloud + 16);// std::vector<PointT>::iterator pointPtr = msg->points.begin();// for (int i = 0; i < msg->points.size(); ++i){//   *point++ = pointPtr[i];// }memcpy(bytePointCloud+16,&(msg->points[0]),cloudSize-16);free_cloud_queue.push(msg);result.ptr = bytePointCloud;result.len = cloudSize;result.cap = cloudSize;//return result;}else if (sizeof(PointT) == 24){                                   // just write them here, I didn't test itsize_t cloudSize =((msg->points.size()) * 24);  // 24 bytes for each point, 4*3 bytes for coordinates, 1 byte for intensity, 1// byte because of byte aligned 2 bytes for rings, 8 bytes for timestampu_int8_t* bytePointCloud = (u_int8_t*)new PointT[cloudSize / sizeof(PointT)];memcpy(bytePointCloud,&(msg->points[0]),cloudSize);// PointT* point = (PointT*)(bytePointCloud);// std::vector<PointT>::iterator pointPtr = msg->points.begin();// for (int i = 0; i < msg->points.size(); ++i)// {//   *(point++) = pointPtr[i];// }free_cloud_queue.push(msg);//Vec_uint8_t result;result.ptr = bytePointCloud;result.len = cloudSize;result.cap = cloudSize;//return result;}else{std::cerr << "point size error! This may happen when your system is not byte aligned!";result = { .ptr = NULL };result.len = 0;result.cap = 0;//return result;}#endifchar* output_data = (char *)result.ptr;size_t output_data_len = result.len;counter += 1;std::string out_id = "pointcloud";size_t data_len = 1 ;int resultend=dora_send_output(dora_context, &out_id[0], out_id.length(), output_data, output_data_len);std::cout<< "dora_send_output: out_id "<<out_id<< "  out_data_len: "<<output_data_len<<std::endl;if (resultend != 0){std::cerr << "failed to send output" << std::endl;return 1;}}else if (ty == DoraEventType_Stop){printf("[c node] received stop event\n");}else{printf("[c node] received unexpected event: %d\n", ty);}free_dora_event(event);}return 0;
}int main()
{std::cout << "rslidar driver for dora " << std::endl;RSDriverParam param;                  ///< Create a parameter objectparam.input_type = InputType::ONLINE_LIDAR; //输入类型param.input_param.msop_port = 6699;   ///< Set the lidar msop port number, the default is 6699param.input_param.difop_port = 7788;  ///< Set the lidar difop port number, the default is 7788param.lidar_type = LidarType::RSHELIOS;   ///< Set the lidar type. Make sure this type is correct雷达类型param.print();//控制台输出参数信息LidarDriver<PointCloudMsg> driver;               ///< Declare the driver objectdriver.regPointCloudCallback(driverGetPointCloudFromCallerCallback, driverReturnPointCloudToCallerCallback); ///< Register the point cloud callback functionsdriver.regExceptionCallback(exceptionCallback);  ///< Register the exception callback functionif (!driver.init(param))                         ///< Call the init function{RS_ERROR << "Driver Initialize Error..." << RS_REND;return -1;}//std::thread cloud_handle_thread = std::thread(processCloud);driver.start();  ///< The driver thread will startRS_DEBUG << "RoboSense Lidar-Driver Linux online demo start......" << RS_REND;auto dora_context = init_dora_context_from_env();auto ret = run(dora_context);free_dora_context(dora_context);to_exit_process = true;driver.stop();std::cout << "exit rslidar driver ..." << std::endl;return ret;
}

上述代码中,可以通过修改变量 RSDriverParam param 的成员变量设置激光雷达的类型、端口号等参数信息。

2.2 编译rslidar驱动

clang++  rslidar_driver.cc -lm -lrt -ldl -pthread -std=c++14 -lpcap -ldora_node_api_c -L /home/dora/dora_project/dora/target/release --output build/rslidar_driver -I rs_driver/src

上述命令中 路径 “/home/dora/dora_project/dora/target/release” 需要修改为你电脑上dora源码的路径

2.3 编写rslidar_test.yml文件

nodes:#rslidar driver   node- id: rslidar_drivercustom:source: build/rslidar_driverinputs:tick: dora/timer/millis/100outputs:- pointcloud

2.4 启动节点

在终端中输入以下命令,启动代码节点

dora start rslidar_test.yml --name test

查看输出日志

dora logs test rslidar_driver

在这里插入图片描述

3、rslidar Debug节点

该节点的功能是 接收dora框架中雷达节点发布的数据,并将数据相关信息显示在log文件中,以检验驱动节点是否正确。

节点与operator的区别:节点会从main函数中进入,operator有点类似于函数调用的形式,给定一个信号量,则调用一次函数

3.1 新建调试程序

新建文件 operator_rslidar_debug.cc

注意将路径 /home/dora/dora_project/dora/apis/c/node/node_api.h"替换为你电脑上的路径

extern "C"
{
#include "/home/dora/dora_project/dora/apis/c/node/node_api.h"
#include "/home/dora/dora_project/dora/apis/c/operator/operator_api.h"
#include "/home/dora/dora_project/dora/apis/c/operator/operator_types.h"
}#include <memory>
#include <iostream>
#include <vector>
#include <string.h>
#include <cassert>class Operator
{
public:Operator();
};Operator::Operator() {}extern "C" DoraInitResult_t dora_init_operator()
{Operator *op = std::make_unique<Operator>().release();DoraInitResult_t result = {.operator_context = (void *)op};return result;
}extern "C" DoraResult_t dora_drop_operator(void *operator_context)
{delete (Operator *)operator_context;return {};
}extern "C" OnEventResult_t dora_on_event(RawEvent_t *event,const SendOutput_t *send_output,void *operator_context)
{if (event->input != NULL){// input eventInput_t *input = event->input;char *id = dora_read_input_id(input);Vec_uint8_t data = dora_read_data(input);assert(data.ptr != NULL);std::cout<< "C++ Operator (C-API) received input `" << id << "` with data: [";for (int i = 0; i < data.len; i++){std::cout << (unsigned int)data.ptr[i] << ", ";}std::cout << "]" << "input_data_len:"<< data.len <<std::endl;const char *out_id = "half-status";char *out_id_heap = strdup(out_id);size_t out_data_len = 1;uint8_t *out_data_heap = (uint8_t *)malloc(out_data_len);*out_data_heap = *data.ptr / 2;// DoraResult_t send_result = dora_send_operator_output(send_output, out_id_heap, out_data_heap, out_data_len);DoraResult_t  send_result= {};OnEventResult_t result = {.result = send_result, .status = DORA_STATUS_CONTINUE};dora_free_data(data);dora_free_input_id(id);return result;}if (event->stop){printf("C operator received stop event\n");}OnEventResult_t result = {.status = DORA_STATUS_CONTINUE};return result;
}

编译文件 注意这里链接的时候要链接到debug文件下的 dora_operator_api_c 库(完全是试出来的)

clang++ -c operator_rslidar_debug.cc -std=c++14 -o build/operator_rslidar_debug.o -fPIC
clang++ -shared build/operator_rslidar_debug.o -o build/liboperator_rslidar_debug.so -l dora_operator_api_c -L  /home/dora/dora_project/dora/target/debug 

在 rslidar_test.yml文件中添加以下内容

  - id: runtime-node-1operators:- id: operator_rslidar_debugshared-library: build/operator_rslidar_debuginputs:pointcloud: rslidar_driver/pointcloud

3.2 启动节点

dora start rslidar_test.yml --name test

查看输出日志

dora logs test runtime-node-1

通过日志文件可以看到,调试节点接收到了雷达节点发布的消息,并且识别到了ID、打印了点云数据长度
在这里插入图片描述

参考资料

[1] https://github.com/RoboSense-LiDAR/rs_driver/tree/main
[2] https://github.com/dora-rs/dora-hardware/tree/main/vendors/lidar/Robosense

dora-rs目前资料较少 欢迎大家点赞在评论区交流讨论(cenruping@vip.qq.com) O(∩_∩)O
或者加群水一波(1149897304)

这篇关于Dora-rs 机器人框架学习教程(4)——速腾激光雷达驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/583006

相关文章

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

2025版mysql8.0.41 winx64 手动安装详细教程

《2025版mysql8.0.41winx64手动安装详细教程》本文指导Windows系统下MySQL安装配置,包含解压、设置环境变量、my.ini配置、初始化密码获取、服务安装与手动启动等步骤,... 目录一、下载安装包二、配置环境变量三、安装配置四、启动 mysql 服务,修改密码一、下载安装包安装地

电脑提示d3dx11_43.dll缺失怎么办? DLL文件丢失的多种修复教程

《电脑提示d3dx11_43.dll缺失怎么办?DLL文件丢失的多种修复教程》在使用电脑玩游戏或运行某些图形处理软件时,有时会遇到系统提示“d3dx11_43.dll缺失”的错误,下面我们就来分享超... 在计算机使用过程中,我们可能会遇到一些错误提示,其中之一就是缺失某个dll文件。其中,d3dx11_4

Linux下在线安装启动VNC教程

《Linux下在线安装启动VNC教程》本文指导在CentOS7上在线安装VNC,包含安装、配置密码、启动/停止、清理重启步骤及注意事项,强调需安装VNC桌面以避免黑屏,并解决端口冲突和目录权限问题... 目录描述安装VNC安装 VNC 桌面可能遇到的问题总结描js述linux中的VNC就类似于Window

Python Web框架Flask、Streamlit、FastAPI示例详解

《PythonWeb框架Flask、Streamlit、FastAPI示例详解》本文对比分析了Flask、Streamlit和FastAPI三大PythonWeb框架:Flask轻量灵活适合传统应用... 目录概述Flask详解Flask简介安装和基础配置核心概念路由和视图模板系统数据库集成实际示例Stre

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

Linux之platform平台设备驱动详解

《Linux之platform平台设备驱动详解》Linux设备驱动模型中,Platform总线作为虚拟总线统一管理无物理总线依赖的嵌入式设备,通过platform_driver和platform_de... 目录platform驱动注册platform设备注册设备树Platform驱动和设备的关系总结在 l

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads