【Chrono Engine学习总结】5-sensor-5.1-sensor基础并创建一个lidar

由于Chrono的官方教程在一些细节方面解释的并不清楚,自己做了一些尝试,做学习总结。

1、Sensor模块

Sensor模块是附加模块,需要单独安装。参考:【Chrono Engine学习总结】1-安装配置与程序运行

Sensor Module Tutorial
Sensor Overview

Sensor模块包括的内容如下:
在这里插入图片描述
其中:

  • Sensors模块是核心,包括各种传感器(IMU、GPS、相机、Lidar、Radar等),以及传感器管理器等;
  • Sensor Filters是对sensor原始数据进行滤波(我认为更准确说应该是“处理方式”),即从原始数据得到我们想要的数据。https://api.projectchrono.org/group__sensor__filters.html
  • Scene是和camera相关的场景设置,例如背景色、光照等;
  • 其他内容不展开介绍。

传感器当中,“光学”传感器,例如相机、lidar、radar等,依赖OptiX这个库。具体的依赖关系如下:
在这里插入图片描述

2、创建Sensor的流程

这里全部以lidar为例,进行介绍。

2.0 创建传感器管理器

在chrono中,所有传感器需要注册在sensor manager当中,由其统一进行管理。

管理器的创建、添加一个具体的sensor、仿真时数据更新,3行代码如下:

// 创建管理器
auto manager = chrono_types::make_shared<ChSensorManager>(&sys);
// 添加一个sensor:AddSensor(std::shared_ptr<ChSensor> sensor)
manager->AddSensor(lidar);
// 在仿真循环中,更新所有传感器数据:
manager->Update();

2.1 从JSON文件载入预定义好的sensor

官方提供了一些已经定义好的sensor,包括:通用相机、VLP16雷达、HDL32雷达、通用GPS、通用IMU等,这些的调用只需要一行代码即可实现创建。例如,直接创建一个VLP16的雷达:

auto vlp16 = Sensor::CreateFromJSON(GetChronoDataFile("sensor/json/Velodyne/VLP-16.json"), box_body, offset_pose);
manager->AddSensor(vlp16);

我们可以打开这个JSON文件,查看VLP16的具体参数:
在这里插入图片描述

2.2 通过代码方式逐步创建一个sensor

通过代码方式创建,就是通过代码将JSON中的格式,完全自己配置一遍,例如:

auto lidar =
    chrono_types::make_shared<ChLidarSensor>(box_body,                               // body lidar is attached to
        update_rate,                            // scanning rate in Hz
        offset_pose,                            // offset pose
        900,                                    // number of horizontal samples
        30,                                     // number of vertical channels
        horizontal_fov,                         // horizontal field of view
        max_vert_angle, min_vert_angle, 100.0f  // vertical field of view
    );
lidar->SetName("Lidar Sensor 1");
lidar->SetLag(lag);
lidar->SetCollectionWindow(collection_time);

lidar->PushFilter(chrono_types::make_shared<ChFilterDIAccess>());			// 允许后续获取depth和intensity的filter
lidar->PushFilter(chrono_types::make_shared<ChFilterVisualize>(horizontal_samples / 2, vertical_samples * 5, "Raw Lidar Depth Data"));			// 将雷达数据可视化为深度图像的可视化filter
lidar->PushFilter(chrono_types::make_shared<ChFilterPCfromDepth>());		// 通过深度获取点云的filter
lidar->PushFilter(chrono_types::make_shared<ChFilterLidarNoiseXYZI>(0.01f, 0.001f, 0.001f, 0.01f));	// 对XYZI增加噪声的filter
lidar->PushFilter(chrono_types::make_shared<ChFilterVisualizePointCloud>(640, 480, 2, "Lidar Point Cloud"));		// 点云可视化的filter
lidar->PushFilter(chrono_types::make_shared<ChFilterXYZIAccess>());		// 获取XYZI数据的filter
manager->AddSensor(lidar);		// 添加lidar到管理器

可以看出,设置了一些列的filter。当然,在上面的JSON中,也有许多filter,有些filter有参数,例如ChFilterLidarNoiseXYZI,有些没有例如ChFilterPCfromDepth。这些filter是干什么的呢?我个人理解,这些光学传感器获得的原始数据,需要加上这些filter之后,才具备我们平常使用这些sensor的数据格式。

例如,对于lidar来说,设置了ChFilterXYZIAccess后,才可以获取XYZI的数据;设置ChFilterLidarNoiseXYZI后,可以对XYZI增加高斯噪声;设置ChFilterVisualizePointCloud和ChFilterVisualize后,会出现三维点云和二位深度图的可视化(如下图)。所以,filter认为是“功能实现途径”比较合适。
在这里插入图片描述
所以:sensor的原始数据只是从光学系统中获得的特性,并没有转化成我们希望的“传感器数据格式”,需要通过filter进行实现。这些filter(对于lidar)负责添加噪声、二维图像可视化、三维点云可视化、获取点云XYZI格式、获取深度信息,(对于camera)转灰度图、像素噪声等。详细参考:【chrono::sensor::ChFilter Class Reference】

2.3 通过JSON方式自定义创建sensor

除了官方自定义的两个lidar的JSON外,还可以自定义lidar的配置。就创建对应的JSON并修改配置即可,无需多言。

3、参考代码

#include <cmath>
#include <cstdio>
#include <iomanip>
#include "chrono/assets/ChVisualShapeTriangleMesh.h"
#include "chrono/assets/ChVisualMaterial.h"
#include "chrono/assets/ChVisualShape.h"
#include "chrono/geometry/ChTriangleMeshConnected.h"
#include "chrono/physics/ChBodyEasy.h"
#include "chrono/physics/ChSystemNSC.h"
#include "chrono/utils/ChUtilsCreators.h"
#include "chrono_thirdparty/filesystem/path.h"

#include "chrono_sensor/sensors/ChLidarSensor.h"
#include "chrono_sensor/ChSensorManager.h"
#include "chrono_sensor/filters/ChFilterAccess.h"
#include "chrono_sensor/filters/ChFilterPCfromDepth.h"
#include "chrono_sensor/filters/ChFilterVisualize.h"
#include "chrono_sensor/filters/ChFilterVisualizePointCloud.h"
#include "chrono_sensor/filters/ChFilterLidarReduce.h"
#include "chrono_sensor/filters/ChFilterLidarNoise.h"
#include "chrono_sensor/filters/ChFilterSavePtCloud.h"
#include "chrono_sensor/sensors/Sensor.h"

using namespace chrono;
using namespace chrono::geometry;
using namespace chrono::sensor;

// Noise model attached to the sensor
enum NoiseModel {
    CONST_NORMAL_XYZI,  // Gaussian noise with constant mean and standard deviation
    NONE                // No noise model
};
NoiseModel noise_model = CONST_NORMAL_XYZI;

// Lidar return mode
// Either STRONGEST_RETURN, MEAN_RETURN, FIRST_RETURN, LAST_RETURN
LidarReturnMode return_mode = LidarReturnMode::STRONGEST_RETURN;

// Update rate in Hz
float update_rate = 5.f;

// Number of horizontal and vertical samples
unsigned int horizontal_samples = 4500;
unsigned int vertical_samples = 32;

// Horizontal and vertical field of view (radians)
float horizontal_fov = (float)(2 * CH_C_PI);  // 360 degree scan
float max_vert_angle = (float)CH_C_PI / 12;   // 15 degrees up
float min_vert_angle = (float)-CH_C_PI / 6;   // 30 degrees down

// Lag time
float lag = 0.f;

// Collection window for the lidar
float collection_time = 1 / update_rate;  // typically 1/update rate

// Simulation step size
double step_size = 1e-3;
// Simulation end time
float end_time = 2000.0f;
// Save lidar point clouds
bool save = false;
// Render lidar point clouds
bool vis = false;

int main(int argc, char* argv[]) {
    GetLog() << "Copyright (c) 2019 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
    chrono::SetChronoDataPath("E:/codeGit/chrono/chrono/build/data/");              // change the default data loading path.
		
		// 创建物理仿真环境
    // -----------------
    // Create the system
    // -----------------
    ChSystemNSC sys;
		
		// 在左、右、下方各创建一面墙
    // --------------------------------------------
    // add a few box bodies to be sensed by a lidar
    // --------------------------------------------
    auto box_body = chrono_types::make_shared<ChBodyEasyBox>(100, 100, 1, 1000, true, false);
    box_body->SetPos({ 0, 0, -1 });
    box_body->SetBodyFixed(true);
    sys.Add(box_body);
    auto box_body_1 = chrono_types::make_shared<ChBodyEasyBox>(100, 1, 100, 1000, true, false);
    box_body_1->SetPos({ 0, -10, -3 });
    box_body_1->SetBodyFixed(true);
    sys.Add(box_body_1);
    auto box_body_2 = chrono_types::make_shared<ChBodyEasyBox>(100, 1, 100, 1000, true, false);
    box_body_2->SetPos({ 0, 10, -3 });
    box_body_2->SetBodyFixed(true);
    sys.Add(box_body_2);
    
		// 创建sensor管理器
    // -----------------------
    // Create a sensor manager
    // -----------------------
    auto manager = chrono_types::make_shared<ChSensorManager>(&sys);
    manager->SetVerbose(false);

    // -----------------------------------------------
    // Create a lidar and add it to the sensor manager
    // -----------------------------------------------
    // 自定义代码方式,创建一个lidar
    auto offset_pose = chrono::ChFrame<double>({ -4, 0, 1 }, Q_from_AngAxis(0, { 0, 1, 0 }));
    auto lidar =
        chrono_types::make_shared<ChLidarSensor>(box_body,                               // body lidar is attached to
            update_rate,                            // scanning rate in Hz
            offset_pose,                            // offset pose
            900,                                    // number of horizontal samples
            30,                                     // number of vertical channels
            horizontal_fov,                         // horizontal field of view
            max_vert_angle, min_vert_angle, 100.0f  // vertical field of view
        );
    lidar->SetName("Lidar Sensor 1");
    lidar->SetLag(lag);
    lidar->SetCollectionWindow(collection_time);
		// 添加相应的滤波器filter
    // Renders the raw lidar data
    lidar->PushFilter(chrono_types::make_shared<ChFilterVisualize>(horizontal_samples / 2, vertical_samples * 5, "Raw Lidar Depth Data"));
    // Convert Depth,Intensity data to XYZI point
    lidar->PushFilter(chrono_types::make_shared<ChFilterPCfromDepth>());
    // Add a noise model filter to the lidar sensor
    switch (noise_model) {
    case CONST_NORMAL_XYZI:
        lidar->PushFilter(chrono_types::make_shared<ChFilterLidarNoiseXYZI>(0.1f, 0.001f, 0.001f, 0.01f));
        break;
    case NONE:
        // Don't add any noise models
        break;
    }
     Render the point cloud
    lidar->PushFilter(chrono_types::make_shared<ChFilterVisualizePointCloud>(640, 480, 2, "Lidar Point Cloud"));
    // Access the lidar data as an XYZI buffer
    lidar->PushFilter(chrono_types::make_shared<ChFilterXYZIAccess>());
    // add sensor to the manager
    manager->AddSensor(lidar);

		// 从JSON文件直接载入VLP16雷达配置
    // Lidar from JSON file - Velodyne VLP-16
    auto vlp16 = Sensor::CreateFromJSON(GetChronoDataFile("sensor/json/Velodyne/VLP-16.json"), box_body, offset_pose);
    manager->AddSensor(vlp16);

    float ch_time = 0.0;
    std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
    while (ch_time < end_time) {

        // 传感器数据更新
        // Will render/save/filter automatically
        manager->Update();

        // 系统动力学更新
        sys.DoStepDynamics(step_size);

        // Get the current time of the simulation
        ch_time = (float)sys.GetChTime();
    }

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL数据库⑧_索引(概念+理解+操作)

目录 1. 索引的概念和价值 1.1 索引的概念 1.2 索引的价值 2. 磁盘的概念 2.1 磁盘的结构 2.2 操作系统与磁盘交互的基本单位 2.3 MySQL与磁盘交互的基本单位 3. 索引的理解 3.1 主键索引现象和推导 3.2 索引采用的数据结构&#xff1a;B树 3.3 聚簇索引和非聚簇索引…

Java并发基础:DelayQueue全面解析!

内容概要 DelayQueue类专为处理延迟任务设计&#xff0c;它允许开发者将任务与指定的延迟时间关联&#xff0c;并在任务到期时自动处理&#xff0c;从而避免了不必要的轮询和资源浪费&#xff0c;此外&#xff0c;DelayQueue内部基于优先队列实现&#xff0c;确保最先到期的任…

蓝桥杯每日一题------背包问题(三)

前言 之前求的是在特点情况下选择一些物品让其价值最大&#xff0c;这里求的是方案数以及具体的方案。 背包问题求方案数 既然要求方案数&#xff0c;那么就需要一个新的数组来记录方案数。动态规划步骤如下&#xff0c; 定义dp数组 第一步&#xff1a;缩小规模。考虑n个物品…

ubuntu22.04@laptop OpenCV Get Started: 007_color_spaces

ubuntu22.04laptop OpenCV Get Started: 007_color_spaces 1. 源由2. 颜色空间2.1 RGB颜色空间2.2 LAB颜色空间2.3 YCrCb颜色空间2.4 HSV颜色空间 3 代码工程结构3.1 C应用Demo3.2 Python应用Demo 4. 重点分析4.1 interactive_color_detect4.2 interactive_color_segment4.3 da…

【MySQL】学习约束和使用图形化界面创建表

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-iqtbME2KmWpQFQSt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

调用讯飞火星AI大模型WebAPI

调用讯飞火星AI大模型 记录一次调用讯飞AI大模型的过程 官方文档 首先&#xff0c;去官网申请资格&#xff0c;获得必要秘钥等 再编写url&#xff0c;该url存在编码要求&#xff0c;具体看官网url编写 具体代码如下&#xff1a; getWebsocketUrl() {return new Promise((resol…

Peter算法小课堂—区间模型

Peter Pan来啦…… 最大不重叠区间数 二话不说&#xff0c;先来一道题 大家想想怎么贪心&#xff1f;我们可以将每一个美食摊位抽象成一个区间&#xff0c;区间左端点为开始排队时间&#xff0c;右端点为结束排队时间。其中&#xff0c;时间信息可以用数轴表示。 额……我们…

golang集成sentry: go-redis

网上没有找到go-redis集成sentry的库&#xff0c; 所以我简单实现了一个 代码&#xff1a; https://github.com/Shujie-Tan/go-redis-sentry 使用方法&#xff1a; import (redis_sentry "github.com/Shujie-Tan/go-redis-sentry" ) rdb : redis.NewClient(&re…

linux---内存管理

一 虚拟内存 即使是现代操作系统中&#xff0c;内存依然是计算机中很宝贵的资源&#xff0c;看看你电脑几个T固态硬盘&#xff0c;再看看内存大小就知道了。 为了充分利用和管理系统内存资源&#xff0c;Linux采用虚拟内存管理技术&#xff0c;利用虚拟内存技术让每个进程都有…

Linux网络编程——tcp套接字

文章目录 主要代码关于构造listen监听accepttelnet测试读取信息掉线重连翻译服务器演示 本章Gitee仓库&#xff1a;tcp套接字 主要代码 客户端&#xff1a; #pragma once#include"Log.hpp"#include<iostream> #include<cstring>#include<sys/wait.h…

162基于matlab的多尺度和谱峭度算法对振动信号进行降噪处理

基于matlab的多尺度和谱峭度算法对振动信号进行降噪处理&#xff0c;选择信号峭度最大的频段进行滤波&#xff0c;输出多尺度谱峭度及降噪结果。程序已调通&#xff0c;可直接运行。 162 matlab 信号处理 多尺度谱峭度 (xiaohongshu.com)

Acwing---844.走迷宫

走迷宫 1.题目2.基本思想3.代码实现 1.题目 给定一个 nm 的二维整数数组&#xff0c;用来表示一个迷宫&#xff0c;数组中只包含 0 或 1&#xff0c;其中 0 表示可以走的路&#xff0c;1 表示不可通过的墙壁。最初&#xff0c;有 一个人位于左上角 (1,1)处&#xff0c;已知该…

实景剧本杀小程序:创新体验,沉浸式推理乐趣

随着科技的飞速发展&#xff0c;人们对于娱乐方式的追求也在不断升级。传统的桌面剧本杀游戏已经不能满足玩家的需求&#xff0c;他们渴望更加真实、刺激的游戏体验。正是这种需求推动下&#xff0c;实景剧本杀小程序应运而生&#xff0c;为玩家带来前所未有的推理乐趣。 实景…

图表自动化开篇

目录 前言&#xff1a; 使用 Canvas 或者 SVG 渲染 选择哪种渲染器 代码触发 ECharts 中组件的行为 前言&#xff1a; 图表自动化一直以来是自动化测试中的痛点&#xff0c;也是难点&#xff0c;痛点在于目前越来越多公司开始构建自己的BI报表平台但是没有合适的自动化测试…

docker 1:介绍

docker 1&#xff1a;介绍 docker解决哪些问题&#xff1a; 传统APP在安装到不同电脑的时候可能会遇到依赖问题&#xff0c;比如缺少VS 20xx&#xff0c;软件无法运行”的情况。docker使用容器技术将软件 依赖​打包为image包发布&#xff0c;解决了依赖问题。docker有一个官…

勒索攻击风起云涌,Sodinokibi深度分析

前言 Sodinokibi勒索病毒&#xff0c;又称为REvil勒索病毒&#xff0c;这款勒索病毒最早在国内被发现是2019年4月份&#xff0c;笔者在早期分析这款勒索病毒的时候就发现它与其他勒索病毒不同&#xff0c;于是被笔者称为GandCrab勒索病毒的“接班人”&#xff0c;为什么它是Ga…

在面试中如何回复擅长vue还是react

当面试官问及这个问题的时候&#xff0c;我们需要思考面试官是否是在乎你是掌握vue还是react吗&#xff1f;&#xff1f;&#xff1f; 在大前端的一个环境下&#xff0c;当前又有AI人工智能的加持辅助&#xff0c;我们是不是要去思考企业在进行前端岗位人员需求的时候&#xf…

C++ bfs再探迷宫游戏(五十五)【第二篇】

今天我们用bfs解决迷宫游戏。 1.再探迷宫游戏 前面我们已经接触过了迷宫游戏&#xff0c;并且学会了如何使用 DFS 来解决迷宫最短路问题。用 DFS 求解迷宫最短路有一个很大的缺点&#xff0c;需要枚举所有可能的路径&#xff0c;读入的地图一旦很大&#xff0c;可能的搜索方案…

[VulnHub靶机渗透] Nyx

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

C# CAD2016获取数据操作BlockTableRecord、Polyline、DBObject

一、数据操作说明 //DBObject 基础类 DBObject dbObj (DBObject)tr.GetObject(outerId, OpenMode.ForRead); //Polyline 线段类 Polyline outerPolyline (Polyline)tr.GetObject(outerId, OpenMode.ForRead); //BlockTableRecord 块表类 BlockTableRecord modelSpace (Bloc…