从零搭建3D激光slam框架-基于mid360雷达节点实现

目录

MID360雷达介绍

雷达SDK编译与测试

雷达驱动的修改、编译与测试

去ros的编译方式

 livox_ros_driver2的代码框架介绍

 livox_ros_driver2编译

雷达IP配置文件介绍

常见问题介绍

优化改进


MID360雷达介绍

1 硬件介绍:

livox-mid360是大疆的一款非重复扫描固态激光雷达,20万点/秒,可以调整帧率,内部自带6轴IMU,与点云实现硬件同步。售价3999,线缆399,线缆包括网线电源与串口线,网线与雷达通信负责传输雷达点云与IMU数据,电源12V2A,给雷达供电,串口用于与雷达通信,获取雷达工作状态。

                      

2 软件介绍:

       雷达软件分为上位机点云测试软件LivoxViewer_2.3.0_Win64,雷达LIVOX-SDK2(https://github.com/Livox-SDK/Livox-SDK2.git),livox-ros_driver2(https://github.com/Livox-SDK/livox_ros_driver2.git)雷达驱动ROS2节点,点云测试软件可以查看点云形态,测试点云质量和通信稳定性。雷达LIVOX-SDK2,负责从雷达通过socket获取网络包,网络包包含点云与imu数据,livox-ros_driver2 负责将livox-sdk2获取的socket网络包进行解析,解析出imu,lidar数据,填充到ros2话题消息中,填充消息有三种格式pclmsg,custommsg,sensor::pointcloud::msg,通常使用第二种自定义消息custommsg。

       livox_lidar_quick_start, 雷达快速启动程序可以用于测试雷达通信和IP地址读取,实现快速验证雷达功能和软件功能。

雷达SDK编译与测试

Liovx-SDK2编译

编译cmakelists.txt是常规的格式,直接编译即可 

mkdir build 

cd build

cmake ..

make

编译后生成依赖库 liblivox_sdk_shared.so 用于驱动的依赖,如果需要交叉编译,只需在cmakelists.txt增加交叉编译工具链声明。

同时编译后在sample目录下生成 livox_lidar_quick_start,雷达快速启动程序,用于测试雷达网络IP和数据传输。

雷达驱动的修改、编译与测试

去ros的编译方式

修改cmakelists.txt如下,包含自定义头文件目录和库目录

# judge which cmake codes to use # Copyright(c) 2020 livoxtech limited.cmake_minimum_required(VERSION 3.14)
project(livox_ros_driver2)ADD_COMPILE_OPTIONS(-std=c++17)
set(CMAKE_CXX_FLAGS "-std=c++17 -O3 -g")add_definitions(-DROOT_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/\")set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread -std=c++0x -std=c++17 -fexceptions")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/3rdparty)include_directories(/usr/include/pcl-1.12)
include_directories(/usr/include/eigen3)
include_directories(/usr/include/opencv4)# livox ros2 driver target
add_library(${PROJECT_NAME} SHAREDsrc/livox_ros_driver2.cppsrc/lddc.cppsrc/driver_node.cppsrc/lds.cppsrc/lds_lidar.cppsrc/comm/comm.cppsrc/comm/ldq.cppsrc/comm/semaphore.cppsrc/comm/lidar_imu_data_queue.cppsrc/comm/cache_index.cppsrc/comm/pub_handler.cppsrc/parse_cfg_file/parse_cfg_file.cppsrc/parse_cfg_file/parse_livox_lidar_cfg.cppsrc/call_back/lidar_common_callback.cppsrc/call_back/livox_lidar_callback.cpp
)target_link_libraries(${PROJECT_NAME}/usr/local/wy_slam_lib/livox2lib/liblivox_lidar_sdk_shared.so  )add_executable(${PROJECT_NAME}_nodesrc/livox_ros_driver2.cpp
)target_link_libraries(${PROJECT_NAME}_node /usr/local/wy_slam_lib/commonlib/libyaml-cpp.so/usr/local/wy_slam_lib/commonlib/libglog.so/usr/local/wy_slam_lib/commonlib/libgflags.so/usr/local/wy_slam_lib/commonlib/libtbb.so/usr/local/wy_slam_lib/commonlib/libtbbmalloc.so/usr/local/wy_slam_lib/commonlib/libtbbmalloc_proxy.so/usr/local/wy_slam_lib/pcllib/libpcl_filters.so/usr/local/wy_slam_lib/pcllib/libpcl_kdtree.so/usr/local/wy_slam_lib/pcllib/libpcl_common.so/usr/local/wy_slam_lib/pcllib/libpcl_registration.so/usr/local/wy_slam_lib/pcllib/libpcl_search.so/usr/local/wy_slam_lib/pcllib/libpcl_io.so/usr/local/wy_slam_lib/pcllib/libpcl_segmentation.so/home/yanyu/Downloads/livox_ros_driver2/src/livox_ros_driver2_no_ros/build/liblivox_ros_driver2.so      )

 livox_ros_driver2的代码框架介绍

主节点,driver_node.h/cpp,声明ros2节点,定义lidar/imu数据轮询线程。

lddc.h/cpp负责实际从处理雷达sdk接收的点云与imu数据,通过信号量进行通信,填充lidar/imu数据和时间戳到自定义数据结构或ros2话题消息中。

lds_lidar.h/cpp 调用livox-sdk,并注册雷达点云IMU数据回调函数到sdk,接收socket client_data,并通过信号量通知ROS2节点,处理与发送雷达数据。

 livox_ros_driver2编译

编译使用ros格式的编译工具链,支持ros1/ros2,新建 ws_livox_ros_driver2目录,./build.sh humble用于编译ros2格式。

编译后生成liblivox_ros_driver2.so 和雷达节点livox_ros_driver2_node 

其中雷达节点livox_ros_driver2_node依赖 liblivox_ros_driver2.so库,是ros2节点,启动后向外发送雷达数据话题和IMU话题 /livox/lidar, /livox/imu, 发布频率默认10hz, 200hz,雷达话题带基准时间戳base_time,也是每一帧第一个点的时间戳,以及每个点的时间戳偏移offset_time, 格式是uint64, 单位ns,方便进行后续时间戳对齐,以及点云畸变校准。

雷达IP配置文件介绍

MID360_config.json,包含雷达IP,雷达类型,格式等数据定义。雷达IP,可以通过机身二维码下标后两位读取和1组成三位的雷达IP地址,例如后两位为95,则雷达IP为192.168.1.195。也可以通过livox_lidar_quick_start直接获取雷达IP,写入配置文件。

{"lidar_summary_info" : {"lidar_type": 8},"MID360": {"lidar_net_info" : {"cmd_data_port": 56100,"push_msg_port": 56200,"point_data_port": 56300,"imu_data_port": 56400,"log_data_port": 56500},"host_net_info" : {"cmd_data_ip" : "192.168.1.50","cmd_data_port": 56101,"push_msg_ip": "192.168.1.50","push_msg_port": 56201,"point_data_ip": "192.168.1.50","point_data_port": 56301,"imu_data_ip" : "192.168.1.50","imu_data_port": 56401,"log_data_ip" : "","log_data_port": 56501}},"lidar_configs" : [{"ip" : "192.168.1.190","pcl_data_type" : 1,"pattern_mode" : 0,"extrinsic_parameter" : {"roll": 0.0,"pitch": 0.0,"yaw": 0.0,"x": 0,"y": 0,"z": 0}}]
}

配置文件中,雷达IP为192.168.1.190, 网络ip配置为手动192.168.1.50。 

常见问题介绍

1 雷达没数据:

检测电源是否接通,电流是否2A以上1A的无法带动,网线是否接通,电脑网卡是否选择正确,配置网络为192.168.1.1,192.168.1.50,255,255,255,0。

用viewer工具查看雷达点云是否正常。

2 雷达数据中断或降频:

用 ros2 topic bw /livox/lidar 查看带宽是否为0.4MB/s,减少其他ROS2话题的订阅,保证流量正常。

3 雷达sdk崩溃

可能与IMU时间戳有关,雷达过热,加装风扇散热。加打印日志用gdb 调试。

优化改进

1 去ros修改,去掉所有的ros 相关的头文件与代码,及编译脚本。

 去掉话题发布,用回调函数代替数据传输,增加数据传输稳定性。

2 windows下雷达imu数据获取与建图:

由于viewer可视化软件没有imu数据,以及雷达sdk仅支持linux-ubuntu下的源码开发,因此需要自行修改编译为win-x64格式,去ros后编译为win-x64版本,用回调函数直接获取雷达和IMU数据,实现windows-x64离线建图。

3 部分去ros节点代码修改如下

//
// The MIT License (MIT)
//
// Copyright (c) 2022 Livox. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//#include <iostream>
#include <chrono>
#include <vector>
#include <csignal>
#include <thread>#include "include/livox_ros_driver2.h"
#include "include/ros_headers.h"
#include "driver_node.h"
#include "lddc.h"
#include "lds_lidar.h"using namespace livox_ros;namespace livox_ros
{
bool thread_alive_ = true;
DriverNode::DriverNode()
{//DRIVER_INFO(*this, "Livox Ros Driver2 Version: %s", LIVOX_ROS_DRIVER2_VERSION_STRING);/** Init default system parameter */int xfer_format = kPointCloud2Msg;//kPclPxyziMsg;//kLivoxCustomMsg;//kPointCloud2Msg;//int multi_topic = 0;int data_src = kSourceRawLidar;double publish_freq = 10.0; /* Hz */int output_type = kOutputToRos;std::string frame_id =  "frame_default";if (publish_freq > 100.0) {publish_freq = 100.0;} else if (publish_freq < 0.5) {publish_freq = 0.5;} else {publish_freq = publish_freq;}future_ = exit_signal_.get_future();/** Lidar data distribute control and lidar data source set */lddc_ptr_ = std::make_unique<Lddc>(xfer_format, multi_topic, data_src, output_type, publish_freq, frame_id);//lddc_ptr_->SetRosNode(this);if (data_src == kSourceRawLidar) {//DRIVER_INFO(*this, "Data Source is raw lidar.");std::string user_config_path = "../config/MID360_config.json";//this->get_parameter("user_config_path", user_config_path);//DRIVER_INFO(*this, "Config file : %s", user_config_path.c_str());std::string cmdline_bd_code = "000000000000001";//this->get_parameter("cmdline_input_bd_code", cmdline_bd_code);LdsLidar *read_lidar = LdsLidar::GetInstance(publish_freq);lddc_ptr_->RegisterLds(static_cast<Lds *>(read_lidar));if ((read_lidar->InitLdsLidar(user_config_path))) {//DRIVER_INFO(*this, "Init lds lidar success!");std::cout<<" Init lds lidar success! "<<std::endl;} else {//DRIVER_ERROR(*this, "Init lds lidar fail!");std::cout<<" Init lds lidar fail! "<<std::endl;}} else {//DRIVER_ERROR(*this, "Invalid data src (%d), please check the launch file", data_src);std::cout<<" Invalid data src, please check the launch file "<<std::endl;}pointclouddata_poll_thread_ = std::make_shared<std::thread>(&DriverNode::PointCloudDataPollThread, this);imudata_poll_thread_ = std::make_shared<std::thread>(&DriverNode::ImuDataPollThread, this);
}}  // namespace livox_rosvoid DriverNode::PointCloudDataPollThread()
{std::future_status status;std::this_thread::sleep_for(std::chrono::seconds(3));do {lddc_ptr_->DistributePointCloudData();status = future_.wait_for(std::chrono::microseconds(0));} while (status == std::future_status::timeout);
}void DriverNode::ImuDataPollThread()
{std::future_status status;std::this_thread::sleep_for(std::chrono::seconds(3));do {lddc_ptr_->DistributeImuData();status = future_.wait_for(std::chrono::microseconds(0));} while (status == std::future_status::timeout);
}void SigHandle(int sig)
{std::cout << "catch sig %d" << sig << std::endl;//rclcpp::shutdown();thread_alive_=false;
}int main(int argc, char** argv)
{//rclcpp::init(argc, argv);signal(SIGINT, SigHandle);//rclcpp::NodeOptions node_options;auto livox_driver_node = std::make_shared<livox_ros::DriverNode>();//rclcpp::spin(livox_driver_node);//if (rclcpp::ok())//    rclcpp::shutdown();while(thread_alive_){usleep(10000);}return 0;
}

增加点云与IMU的回调函数到lddc.h/lddc.cpp,接收数据即可.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916716.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916716.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Spring】日志级别的分类和使用

文章目录介绍日志级别的分类日志级别的顺序日志级别的使用介绍 日志级别代表着日志信息对应问题的严重性&#xff0c;为了更快的筛选符合目标的日志信息 试想一下这样的场景&#xff0c;假设你是一家 2 万人公司的老板&#xff0c;如果每个员工的日常工作和琐碎的信息都要反馈…

【C++】第十九节—一文万字详解 | AVL树实现

好久不见&#xff0c;我是云边有个稻草人&#xff0c;偶尔中二博主与你分享C领域专业知识^(*&#xffe3;(oo)&#xffe3;)^ 《C》—本篇文章所属专栏—持续更新中—欢迎订阅~喔 目录 一、AVL的概念 二、AVL树的实现 2.1 AVL树的结构 2.2 AVL树的插入 【AVL树插入⼀个值…

【Delphi】快速理解泛型(Generics)

Delphi的泛型&#xff08;generics&#xff09;是一项强大的特性&#xff0c;它使得代码更加灵活、类型安全&#xff0c;并且可以实现各种通用的数据结构和算法。下面我将为你详细介绍Delphi中的泛型&#xff0c;包括基本概念、语法、常用实例&#xff0c;以及使用建议。Delphi…

Java Stream流的使用

获取Stream流 单列集合直接使用stream()方法 List<String> list Arrays.asList("a", "b", "c"); Stream<String> stream list.stream(); // 获取顺序流数组使用静态方法Arrays.stream() String[] array {"a", "b&…

前端实现添加水印,两种方式

一、自定义指令的方式/*需求&#xff1a;给整个页面添加背景水印。思路&#xff1a;1、使用 canvas 特性生成 base64 格式的图片文件&#xff0c;设置其字体大小&#xff0c;颜色等。2、将其设置为背景图片&#xff0c;从而实现页面或组件水印效果使用&#xff1a;设置水印文案…

使用LangChain构建法庭预定智能体:结合vLLM部署的Qwen3-32B模型

文章目录 技术架构概述 核心实现步骤 1. 配置vLLM与Qwen3-32B模型 2. 定义工具(Tools) 3. 构建Agent系统 4. 运行与交互 关键技术亮点 1. 工具调用自动化 2. Hermes解析器优势 3. 对话记忆管理 实际运行效果 性能优化建议 扩展应用场景 总结 在人工智能应用开发中,如何让大语…

vscode开发微信小程序

下载插件 插件下载位置 1.微信小程序开发工具 2.vscode weapp api 3.vscode wxml 4.vscode-wechat 创建项目 终端运行命令 cd 到要创建项目的目录执行命令&#xff1a;vue create -p dcloudio/uni-preset-vue test test就是项目名称 选择默认模板&#xff0c;回车 出现下图这…

板凳-------Mysql cookbook学习 (十二--------3_3)

https://cloud.tencent.com/developer/article/1454690 侯哥的Python分享 # 创建节点 class Node(object):def __init__(self,item):self.element itemself.next None# 创建单链表类 class SingleLinkList(object):def __init__(self):self.header Noneself.length 0# 1、判…

Flutter开发实战之CI/CD与发布流程

第12章:CI/CD与发布流程 在前面的章节中,我们学习了Flutter应用开发的各个方面,从基础UI构建到复杂的状态管理,从网络请求到本地存储。现在,我们将探讨一个同样重要但常被忽视的话题:如何将我们精心开发的应用高效、可靠地发布到各大应用商店。 想象一下,你花费了数月…

ElasticSearch 的3种数据迁移方案

在实际工作中&#xff0c;我们经常会遇到需要将自建的 Elasticsearch 迁移上云&#xff0c;或者迁移到其他 ES 集群的情况。这时&#xff0c;选择合适的数据迁移方案就显得尤为重要啦。今天就来给大家介绍三种常用的迁移方案&#xff0c;分别是 COS 快照、logstash 和 elastics…

MySQL 中的“双路排序”与“单路排序”:原理、判别与实战调优

一句话导读 ORDER BY 不能走索引时&#xff0c;MySQL 会在 Server 层做一次 filesort。内部实现分 单路&#xff08;全字段&#xff09; 与 双路&#xff08;rowid&#xff09; 两种&#xff1b;了解它们的触发条件、判别方法与调优思路&#xff0c;是 SQL 性能优化的必修课。一…

OpenLayers 综合案例-信息窗体-弹窗

看过的知识不等于学会。唯有用心总结、系统记录&#xff0c;并通过温故知新反复实践&#xff0c;才能真正掌握一二 作为一名摸爬滚打三年的前端开发&#xff0c;开源社区给了我饭碗&#xff0c;我也将所学的知识体系回馈给大家&#xff0c;助你少走弯路&#xff01; OpenLayers…

GaussDB 开发基本规范

1 集中式1.1数据库价值特性推荐特性分类特性列表说明表类型PARTITION表数据分区存储引擎行存储按行顺序存储表&#xff0c;建议点查&#xff0c;增删改操作较多场景下使用事务事务块显式启动事务单语句事务不显式启动事务&#xff0c;单语句即为事务扩容在线扩容扩节点和数据重…

工作中使用git可能遇到的场景

1.main历史发布版本出问题需要查看&#xff0c;怎么切换历史发布版本&#xff1f;git reset --hard commitid 更新本地库和代码2.A分支的代码已经做过一些功能&#xff0c;想迁移到B分支当前在A分支git checkout B &#xff08;切换到B分支&#xff09;git cherry-pick A的com…

【Spring AI】本地大型语言模型工具-Ollama

Ollama 是一个专注于在本地运行大型语言模型&#xff08;LLM&#xff09;的工具&#xff0c;支持多种开源模型&#xff08;如 Llama 3、Mistral、Gemma 等&#xff09;&#xff0c;提供简单的命令行和 API 接口。<dependency><groupId>org.springframework.ai</…

电机S加减速

STM32步进电机S型加减速算法_stm32___build__-2048 AI社区 以上&#xff0c;电机加减速说的非常清楚&#xff0c;收藏点赞&#xff01;

一、初识 Linux 与基本命令

作者&#xff1a;IvanCodes 日期&#xff1a;2025年7月28日 专栏&#xff1a;Linux教程 思维导图 一、Linux 简介 1.1 什么是 Linux? Linux 是一种自由、开源的类Unix操作系统内核&#xff0c;由林纳斯托瓦兹 (Linus Torvalds) 在1991年首次发布。我们通常所说的 “Linux 系统…

解决angular与jetty websocket 每30s自动断连的问题

背景&#xff1a;前端&#xff1a;angular 12&#xff0c;websocket接口由lib.dom.d.ts提供后端&#xff1a;java&#xff0c;websocket接口由jetty 12提供问题现象&#xff1a;前端连上server后&#xff0c;每隔30s就会断开&#xff0c;由于长时间空闲&#xff0c;会导致webso…

【机器学习深度学习】模型私有化部署与微调训练:赋能特定问题处理能力

目录 前言 一、私有化部署的背景&#xff1a;通用能力 ≠ 企业实用 暴露问题 二、微调训练的核心目的 2.1 动作一&#xff1a;私有化部署&#xff08;Private Deployment&#xff09; 2.2 动作二&#xff1a;领域微调&#xff08;Domain Fine-Tuning&#xff09; 2.3 微…

Seq2Seq学习笔记

Seq2Seq模型概述Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;是一种基于深度学习的序列生成模型&#xff0c;主要用于处理输入和输出均为序列的任务&#xff0c;如机器翻译、文本摘要、对话生成等。其核心思想是将可变长度的输入序列映射为另一个可变长度的输出序列。…