1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2019 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Asher Elmquist
13 // =============================================================================
14 //
15 // Class for managing the Optix rendering system
16 //
17 // =============================================================================
18
19 #include "chrono_sensor/ChSensorManager.h"
20
21 #include "chrono_sensor/sensors/ChOptixSensor.h"
22 #include <iomanip>
23 #include <iostream>
24
25 namespace chrono {
26 namespace sensor {
27
ChSensorManager(ChSystem * chrono_system)28 CH_SENSOR_API ChSensorManager::ChSensorManager(ChSystem* chrono_system) : m_verbose(false), m_optix_reflections(9) {
29 // save the chrono system handle
30 m_system = chrono_system;
31 scene = chrono_types::make_shared<ChScene>();
32 m_device_list = {0};
33 }
34
~ChSensorManager()35 CH_SENSOR_API ChSensorManager::~ChSensorManager() {}
36
GetEngine(int context_id)37 CH_SENSOR_API std::shared_ptr<ChOptixEngine> ChSensorManager::GetEngine(int context_id) {
38 if (context_id < m_engines.size())
39 return m_engines[context_id];
40 std::cerr << "ERROR: index out of render group vector bounds\n";
41 return NULL;
42 }
43
Update()44 CH_SENSOR_API void ChSensorManager::Update() {
45 // update the scene
46 // scene->PackFrame(m_system);
47 //
48 // have all the optix engines update their sensor
49 for (auto pEngine : m_engines) {
50 pEngine->UpdateSensors(scene);
51 }
52
53 // have the sensormanager update all of the non-optix sensor (IMU and GPS).
54 // TODO: perhaps create a thread that takes care of this? Tradeoff since IMU should require some data from EVERY
55 // step
56 if (m_dynamics_manager)
57 m_dynamics_manager->UpdateSensors();
58 }
59
SetDeviceList(std::vector<unsigned int> device_ids)60 CH_SENSOR_API void ChSensorManager::SetDeviceList(std::vector<unsigned int> device_ids) {
61 // set the list of devices to use
62 m_device_list = device_ids;
63 }
GetDeviceList()64 CH_SENSOR_API std::vector<unsigned int> ChSensorManager::GetDeviceList() {
65 // return the list of devices being used
66 return m_device_list;
67 }
68
ReconstructScenes()69 CH_SENSOR_API void ChSensorManager::ReconstructScenes() {
70 for (auto eng : m_engines) {
71 eng->ConstructScene();
72 }
73 }
74
SetMaxEngines(int num_groups)75 CH_SENSOR_API void ChSensorManager::SetMaxEngines(int num_groups) {
76 if (num_groups > 0 && num_groups < 1000) {
77 m_allowable_groups = num_groups;
78 }
79 }
80
SetRayRecursions(int rec)81 CH_SENSOR_API void ChSensorManager::SetRayRecursions(int rec) {
82 if (rec >= 0)
83 m_optix_reflections = rec;
84 }
85
AddSensor(std::shared_ptr<ChSensor> sensor)86 CH_SENSOR_API void ChSensorManager::AddSensor(std::shared_ptr<ChSensor> sensor) {
87 // check if sensor is already in sensor list
88 if (std::find(m_sensor_list.begin(), m_sensor_list.end(), sensor) != m_sensor_list.end()) {
89 std::cerr << "WARNING: Sensor already exists in manager. Ignoring this addition\n";
90 return;
91 }
92 m_sensor_list.push_back(sensor);
93
94 if (auto pOptixSensor = std::dynamic_pointer_cast<ChOptixSensor>(sensor)) {
95 m_render_sensor.push_back(sensor);
96 //******** give each render group all sensor with same update rate *************//
97 bool found_group = false;
98
99 // add the sensor to an engine with sensor of similar update frequencies
100 for (auto engine : m_engines) {
101 if (!found_group && engine->GetSensor().size() > 0 &&
102 abs(engine->GetSensor()[0]->GetUpdateRate() - sensor->GetUpdateRate()) < 0.001) {
103 found_group = true;
104 engine->AssignSensor(pOptixSensor);
105 if (m_verbose)
106 std::cout << "Sensor added to existing engine\n";
107 }
108 }
109
110 try {
111 // create new engines only when we need them
112 if (!found_group) {
113 if (m_engines.size() < m_allowable_groups) {
114 auto engine = chrono_types::make_shared<ChOptixEngine>(
115 m_system, m_device_list[(int)m_engines.size()], m_optix_reflections,
116 m_verbose); // limits to 2 gpus, TODO: check if device supports cuda
117
118 // engine->ConstructScene();
119 engine->AssignSensor(pOptixSensor);
120
121 m_engines.push_back(engine);
122 if (m_verbose)
123 std::cout << "Created another OptiX engine. Now at: " << m_engines.size() << "\n";
124
125 } else { // if we are not allowed to create additional groups, warn the user and polute the first group
126 // std::cout << "No more allowable groups, consider allowing more groups if performace would
127 // increase\n";
128 m_engines[0]->AssignSensor(pOptixSensor);
129 if (m_verbose)
130 std::cout << "Couldn't find suitable existing OptiX engine, so adding to first engine\n";
131 }
132 }
133 }
134 catch (std::exception& e) {
135 std::cerr << "Failed to create a ChOptixEngine, with error:\n" << e.what() << "\n";
136 exit(1);
137 }
138 } else {
139 if (!m_dynamics_manager) {
140 m_dynamics_manager = chrono_types::make_shared<ChDynamicsManager>(m_system);
141 }
142
143 // add pure dynamic sensor to dynamic manager
144 m_dynamics_manager->AssignSensor(sensor);
145 }
146 }
147
148 } // namespace sensor
149 } // namespace chrono
150