做五金的有哪些外貿(mào)網(wǎng)站媒體軟文推廣平臺
由于Chrono的官方教程在一些細節(jié)方面解釋的并不清楚,自己做了一些嘗試,做學習總結(jié)。
1、Sensor模塊
Sensor模塊是附加模塊,需要單獨安裝。參考:【Chrono Engine學習總結(jié)】1-安裝配置與程序運行
Sensor Module Tutorial
Sensor Overview
Sensor模塊包括的內(nèi)容如下:
其中:
- Sensors模塊是核心,包括各種傳感器(IMU、GPS、相機、Lidar、Radar等),以及傳感器管理器等;
- Sensor Filters是對sensor原始數(shù)據(jù)進行濾波(我認為更準確說應該是“處理方式”),即從原始數(shù)據(jù)得到我們想要的數(shù)據(jù)。https://api.projectchrono.org/group__sensor__filters.html
- Scene是和camera相關(guān)的場景設置,例如背景色、光照等;
- 其他內(nèi)容不展開介紹。
傳感器當中,“光學”傳感器,例如相機、lidar、radar等,依賴OptiX這個庫。具體的依賴關(guān)系如下:
2、創(chuàng)建Sensor的流程
這里全部以lidar為例,進行介紹。
2.0 創(chuàng)建傳感器管理器
在chrono中,所有傳感器需要注冊在sensor manager當中,由其統(tǒng)一進行管理。
管理器的創(chuàng)建、添加一個具體的sensor、仿真時數(shù)據(jù)更新,3行代碼如下:
// 創(chuàng)建管理器
auto manager = chrono_types::make_shared<ChSensorManager>(&sys);
// 添加一個sensor:AddSensor(std::shared_ptr<ChSensor> sensor)
manager->AddSensor(lidar);
// 在仿真循環(huán)中,更新所有傳感器數(shù)據(jù):
manager->Update();
2.1 從JSON文件載入預定義好的sensor
官方提供了一些已經(jīng)定義好的sensor,包括:通用相機、VLP16雷達、HDL32雷達、通用GPS、通用IMU等,這些的調(diào)用只需要一行代碼即可實現(xiàn)創(chuàng)建。例如,直接創(chuàng)建一個VLP16的雷達:
auto vlp16 = Sensor::CreateFromJSON(GetChronoDataFile("sensor/json/Velodyne/VLP-16.json"), box_body, offset_pose);
manager->AddSensor(vlp16);
我們可以打開這個JSON文件,查看VLP16的具體參數(shù):
2.2 通過代碼方式逐步創(chuàng)建一個sensor
通過代碼方式創(chuàng)建,就是通過代碼將JSON中的格式,完全自己配置一遍,例如:
auto lidar =chrono_types::make_shared<ChLidarSensor>(box_body, // body lidar is attached toupdate_rate, // scanning rate in Hzoffset_pose, // offset pose900, // number of horizontal samples30, // number of vertical channelshorizontal_fov, // horizontal field of viewmax_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>()); // 允許后續(xù)獲取depth和intensity的filter
lidar->PushFilter(chrono_types::make_shared<ChFilterVisualize>(horizontal_samples / 2, vertical_samples * 5, "Raw Lidar Depth Data")); // 將雷達數(shù)據(jù)可視化為深度圖像的可視化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數(shù)據(jù)的filter
manager->AddSensor(lidar); // 添加lidar到管理器
可以看出,設置了一些列的filter。當然,在上面的JSON中,也有許多filter,有些filter有參數(shù),例如ChFilterLidarNoiseXYZI
,有些沒有例如ChFilterPCfromDepth
。這些filter是干什么的呢?我個人理解,這些光學傳感器獲得的原始數(shù)據(jù),需要加上這些filter之后,才具備我們平常使用這些sensor的數(shù)據(jù)格式。
例如,對于lidar來說,設置了ChFilterXYZIAccess后,才可以獲取XYZI的數(shù)據(jù);設置ChFilterLidarNoiseXYZI后,可以對XYZI增加高斯噪聲;設置ChFilterVisualizePointCloud和ChFilterVisualize后,會出現(xiàn)三維點云和二位深度圖的可視化(如下圖)。所以,filter認為是“功能實現(xiàn)途徑”比較合適。
所以:sensor的原始數(shù)據(jù)只是從光學系統(tǒng)中獲得的特性,并沒有轉(zhuǎn)化成我們希望的“傳感器數(shù)據(jù)格式”,需要通過filter進行實現(xiàn)。這些filter(對于lidar)負責添加噪聲、二維圖像可視化、三維點云可視化、獲取點云XYZI格式、獲取深度信息,(對于camera)轉(zhuǎn)灰度圖、像素噪聲等。詳細參考:【chrono::sensor::ChFilter Class Reference】
2.3 通過JSON方式自定義創(chuàng)建sensor
除了官方自定義的兩個lidar的JSON外,還可以自定義lidar的配置。就創(chuàng)建對應的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 deviationNONE // 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.// 創(chuàng)建物理仿真環(huán)境// -----------------// Create the system// -----------------ChSystemNSC sys;// 在左、右、下方各創(chuàng)建一面墻// --------------------------------------------// 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);// 創(chuàng)建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// -----------------------------------------------// 自定義代碼方式,創(chuàng)建一個lidarauto 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 toupdate_rate, // scanning rate in Hzoffset_pose, // offset pose900, // number of horizontal samples30, // number of vertical channelshorizontal_fov, // horizontal field of viewmax_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 datalidar->PushFilter(chrono_types::make_shared<ChFilterVisualize>(horizontal_samples / 2, vertical_samples * 5, "Raw Lidar Depth Data"));// Convert Depth,Intensity data to XYZI pointlidar->PushFilter(chrono_types::make_shared<ChFilterPCfromDepth>());// Add a noise model filter to the lidar sensorswitch (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 modelsbreak;} Render the point cloudlidar->PushFilter(chrono_types::make_shared<ChFilterVisualizePointCloud>(640, 480, 2, "Lidar Point Cloud"));// Access the lidar data as an XYZI bufferlidar->PushFilter(chrono_types::make_shared<ChFilterXYZIAccess>());// add sensor to the managermanager->AddSensor(lidar);// 從JSON文件直接載入VLP16雷達配置// Lidar from JSON file - Velodyne VLP-16auto 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) {// 傳感器數(shù)據(jù)更新// Will render/save/filter automaticallymanager->Update();// 系統(tǒng)動力學更新sys.DoStepDynamics(step_size);// Get the current time of the simulationch_time = (float)sys.GetChTime();}return 0;
}