1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 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 // Author: Radu Serban
13 // =============================================================================
14 //
15 // Chrono::Vehicle demo program for simulating a HMMWV vehicle on SCM deformable
16 // terrain.
17 //
18 // The global reference frame has Z up.
19 // All units SI.
20 // =============================================================================
21
22 #include <cstdio>
23 #include <cmath>
24 #include <vector>
25
26 #include "chrono/utils/ChUtilsInputOutput.h"
27
28 #include "chrono_vehicle/ChVehicleModelData.h"
29 #include "chrono_vehicle/ChDriver.h"
30 #include "chrono_vehicle/terrain/SCMDeformableTerrain.h"
31 #include "chrono_vehicle/terrain/RigidTerrain.h"
32 #include "chrono_vehicle/wheeled_vehicle/utils/ChWheeledVehicleIrrApp.h"
33
34 #include "chrono_models/vehicle/hmmwv/HMMWV.h"
35
36 #include "chrono_thirdparty/filesystem/path.h"
37
38 #include "chrono_sensor/sensors/ChCameraSensor.h"
39 #include "chrono_sensor/ChSensorManager.h"
40 #include "chrono_sensor/filters/ChFilterVisualize.h"
41 #include "chrono_sensor/utils/ChVisualMaterialUtils.h"
42
43 using namespace chrono;
44 using namespace chrono::collision;
45 using namespace chrono::irrlicht;
46 using namespace chrono::vehicle;
47 using namespace chrono::vehicle::hmmwv;
48 using namespace chrono::sensor;
49
50 using std::cout;
51 using std::endl;
52
53 // =============================================================================
54 // USER SETTINGS
55 // =============================================================================
56
57 // -----------------------------------------------------------------------------
58 // Terrain parameters
59 // -----------------------------------------------------------------------------
60
61 double terrainLength = 16.0; // size in X direction
62 double terrainWidth = 8.0; // size in Y direction
63 double delta = 0.05; // SCM grid spacing
64
65 // -----------------------------------------------------------------------------
66 // Vehicle parameters
67 // -----------------------------------------------------------------------------
68
69 // Type of tire (controls both contact and visualization)
70 enum class TireType { CYLINDRICAL, LUGGED };
71 TireType tire_type = TireType::LUGGED;
72
73 // Tire contact material properties
74 float Y_t = 1.0e6f;
75 float cr_t = 0.1f;
76 float mu_t = 0.8f;
77
78 // Initial vehicle position and orientation
79 ChVector<> initLoc(-5, -2, 0.6);
80 ChQuaternion<> initRot(1, 0, 0, 0);
81
82 // -----------------------------------------------------------------------------
83 // Camera parameters
84 // -----------------------------------------------------------------------------
85
86 // Update Rate in Hz
87 float update_rate = 60.0f;
88
89 // Image width and height
90 unsigned int image_width = 1920;
91 unsigned int image_height = 1080;
92
93 // Camera's horizontal field of view
94 float fov = (float)(CH_C_PI / 3);
95
96 // Lag (in seconds) between sensing and when data becomes accessible
97 float lag = 0;
98
99 // Exposure (in seconds) of each image
100 float exposure_time = 0;
101
102 // -----------------------------------------------------------------------------
103 // Simulation parameters
104 // -----------------------------------------------------------------------------
105
106 // Simulation step size
107 double step_size = 3e-3;
108
109 // Time interval between two render frames (1/FPS)
110 double render_step_size = 1.0 / 100;
111
112 // Point on chassis tracked by the camera
113 ChVector<> trackPoint(0.0, 0.0, 1.75);
114
115 // Output directories
116 const std::string out_dir = GetChronoOutputPath() + "HMMWV_DEF_SOIL";
117 const std::string img_dir = out_dir + "/IMG";
118 const std::string sens_dir = out_dir + "/SENSOR_OUTPUT";
119
120 // Visualization output
121 bool img_output = false;
122
123 // Simulation end time
124 float end_time = 20.0f;
125
126 // Save camera images
127 bool save = false;
128
129 // Render camera images
130 bool vis = true;
131
132 // =============================================================================
133
134 class MyDriver : public ChDriver {
135 public:
MyDriver(ChVehicle & vehicle,double delay)136 MyDriver(ChVehicle& vehicle, double delay) : ChDriver(vehicle), m_delay(delay) {}
~MyDriver()137 ~MyDriver() {}
138
Synchronize(double time)139 virtual void Synchronize(double time) override {
140 m_throttle = 0;
141 m_steering = 0;
142 m_braking = 0;
143
144 double eff_time = time - m_delay;
145
146 // Do not generate any driver inputs for a duration equal to m_delay.
147 if (eff_time < 0)
148 return;
149
150 if (eff_time > 0.2)
151 m_throttle = 0.7;
152 else
153 m_throttle = 3.5 * eff_time;
154
155 if (eff_time < 2)
156 m_steering = 0;
157 else
158 m_steering = 0.6 * std::sin(CH_C_2PI * (eff_time - 2) / 6);
159 }
160
161 private:
162 double m_delay;
163 };
164
165 // =============================================================================
166
CreateLuggedGeometry(std::shared_ptr<ChBody> wheel_body,std::shared_ptr<ChMaterialSurfaceSMC> wheel_material)167 void CreateLuggedGeometry(std::shared_ptr<ChBody> wheel_body, std::shared_ptr<ChMaterialSurfaceSMC> wheel_material) {
168 std::string lugged_file("hmmwv/lugged_wheel_section.obj");
169 geometry::ChTriangleMeshConnected lugged_mesh;
170 ChConvexDecompositionHACDv2 lugged_convex;
171 utils::LoadConvexMesh(vehicle::GetDataFile(lugged_file), lugged_mesh, lugged_convex);
172 int num_hulls = lugged_convex.GetHullCount();
173
174 auto coll_model = wheel_body->GetCollisionModel();
175 coll_model->ClearModel();
176
177 // Assemble the tire contact from 15 segments, properly offset.
178 // Each segment is further decomposed in convex hulls.
179 for (int iseg = 0; iseg < 15; iseg++) {
180 ChQuaternion<> rot = Q_from_AngAxis(iseg * 24 * CH_C_DEG_TO_RAD, VECT_Y);
181 for (int ihull = 0; ihull < num_hulls; ihull++) {
182 std::vector<ChVector<> > convexhull;
183 lugged_convex.GetConvexHullResult(ihull, convexhull);
184 coll_model->AddConvexHull(wheel_material, convexhull, VNULL, rot);
185 }
186 }
187
188 // Add a cylinder to represent the wheel hub.
189 coll_model->AddCylinder(wheel_material, 0.223, 0.223, 0.126);
190 coll_model->BuildModel();
191
192 // Visualization
193 auto trimesh = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
194 trimesh->LoadWavefrontMesh(vehicle::GetDataFile("hmmwv/lugged_wheel.obj"), false, false);
195
196 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
197 trimesh_shape->SetMesh(trimesh);
198 trimesh_shape->SetName("lugged_wheel");
199 trimesh_shape->SetStatic(true);
200 wheel_body->AddAsset(trimesh_shape);
201
202 auto vis_mat = chrono_types::make_shared<ChVisualMaterial>();
203 vis_mat->SetDiffuseColor({.3, .3, .3});
204 vis_mat->SetSpecularColor({.1f, .1f, .1f});
205 trimesh_shape->material_list.push_back(vis_mat);
206
207 auto mcolor = chrono_types::make_shared<ChColorAsset>(0.3f, 0.3f, 0.3f);
208 wheel_body->AddAsset(mcolor);
209 }
210
211 // =============================================================================
212
main(int argc,char * argv[])213 int main(int argc, char* argv[]) {
214 GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
215
216 // --------------------
217 // Create HMMWV vehicle
218 // --------------------
219 HMMWV_Full my_hmmwv;
220 my_hmmwv.SetContactMethod(ChContactMethod::SMC);
221 my_hmmwv.SetChassisFixed(false);
222 my_hmmwv.SetInitPosition(ChCoordsys<>(initLoc, initRot));
223 my_hmmwv.SetPowertrainType(PowertrainModelType::SHAFTS);
224 my_hmmwv.SetDriveType(DrivelineTypeWV::AWD);
225 switch (tire_type) {
226 case TireType::CYLINDRICAL:
227 my_hmmwv.SetTireType(TireModelType::RIGID_MESH);
228 break;
229 case TireType::LUGGED:
230 my_hmmwv.SetTireType(TireModelType::RIGID);
231 break;
232 }
233
234 my_hmmwv.Initialize();
235
236 my_hmmwv.SetChassisVisualizationType(VisualizationType::NONE);
237
238 // -----------------------------------------------------------
239 // Set tire contact material, contact model, and visualization
240 // -----------------------------------------------------------
241 auto wheel_material = chrono_types::make_shared<ChMaterialSurfaceSMC>();
242 wheel_material->SetFriction(mu_t);
243 wheel_material->SetYoungModulus(Y_t);
244 wheel_material->SetRestitution(cr_t);
245
246 switch (tire_type) {
247 case TireType::CYLINDRICAL:
248 my_hmmwv.SetTireVisualizationType(VisualizationType::MESH);
249 break;
250 case TireType::LUGGED:
251 my_hmmwv.SetTireVisualizationType(VisualizationType::NONE);
252 for (auto& axle : my_hmmwv.GetVehicle().GetAxles()) {
253 CreateLuggedGeometry(axle->m_wheels[0]->GetSpindle(), wheel_material);
254 CreateLuggedGeometry(axle->m_wheels[1]->GetSpindle(), wheel_material);
255 }
256 }
257
258 // --------------------
259 // Create driver system
260 // --------------------
261 MyDriver driver(my_hmmwv.GetVehicle(), 0.5);
262 driver.Initialize();
263
264 // ------------------
265 // Create the terrain
266 // ------------------
267 ChSystem* system = my_hmmwv.GetSystem();
268
269 SCMDeformableTerrain terrain(system);
270 terrain.SetSoilParameters(2e6, // Bekker Kphi
271 0, // Bekker Kc
272 1.1, // Bekker n exponent
273 0, // Mohr cohesive limit (Pa)
274 30, // Mohr friction limit (degrees)
275 0.01, // Janosi shear coefficient (m)
276 2e8, // Elastic stiffness (Pa/m), before plastic yield
277 3e4 // Damping (Pa s/m), proportional to negative vertical speed (optional)
278 );
279 terrain.GetMesh()->SetWireframe(false);
280
281 ////terrain.SetBulldozingFlow(true); // inflate soil at the border of the rut
282 ////terrain.SetBulldozingParameters(55, // angle of friction for erosion of displaced material at rut border
283 //// 0.8, // displaced material vs downward pressed material.
284 //// 5, // number of erosion refinements per timestep
285 //// 10); // number of concentric vertex selections subject to erosion
286
287 // Optionally, enable moving patch feature (single patch around vehicle chassis)
288 terrain.AddMovingPatch(my_hmmwv.GetChassisBody(), ChVector<>(0, 0, 0), ChVector<>(5, 3, 1));
289
290 // Optionally, enable moving patch feature (multiple patches around each wheel)
291 ////for (auto& axle : my_hmmwv.GetVehicle().GetAxles()) {
292 //// terrain.AddMovingPatch(axle->m_wheels[0]->GetSpindle(), ChVector<>(0, 0, 0), ChVector<>(1, 0.5, 1));
293 //// terrain.AddMovingPatch(axle->m_wheels[1]->GetSpindle(), ChVector<>(0, 0, 0), ChVector<>(1, 0.5, 1));
294 ////}
295
296 ////terrain.SetTexture(vehicle::GetDataFile("terrain/textures/grass.jpg"), 80, 16);
297 ////terrain.SetPlotType(vehicle::SCMDeformableTerrain::PLOT_PRESSURE_YELD, 0, 30000.2);
298 terrain.SetPlotType(vehicle::SCMDeformableTerrain::PLOT_SINKAGE, 0, 0.1);
299
300 terrain.Initialize(terrainLength, terrainWidth, delta);
301
302 auto vis_mat = chrono_types::make_shared<ChVisualMaterial>();
303 vis_mat->SetSpecularColor({.1f, .1f, .1f});
304 vis_mat->SetRoughness(1);
305 vis_mat->SetKdTexture(GetChronoDataFile("sensor/textures/grass_texture.jpg"));
306 terrain.GetMesh()->material_list.push_back(vis_mat);
307
308 // ---------------------------------------
309 // Create the vehicle Irrlicht application
310 // ---------------------------------------
311 ChWheeledVehicleIrrApp app(&my_hmmwv.GetVehicle(), L"HMMWV Deformable Soil Demo");
312 app.SetSkyBox();
313 app.AddTypicalLights(irr::core::vector3df(30.f, -30.f, 100.f), irr::core::vector3df(30.f, 50.f, 100.f), 250, 130);
314 app.SetChaseCamera(trackPoint, 6.0, 0.5);
315 app.SetTimestep(step_size);
316 app.AssetBindAll();
317 app.AssetUpdateAll();
318
319 // -----------------
320 // Initialize output
321 // -----------------
322 if (!filesystem::create_directory(filesystem::path(out_dir))) {
323 std::cout << "Error creating directory " << out_dir << std::endl;
324 return 1;
325 }
326 if (img_output) {
327 if (!filesystem::create_directory(filesystem::path(img_dir))) {
328 std::cout << "Error creating directory " << img_dir << std::endl;
329 return 1;
330 }
331 }
332
333 // Create the sensor manager
334 auto manager = chrono_types::make_shared<ChSensorManager>(my_hmmwv.GetSystem());
335
336 // Set lights
337 float intensity = 1.0;
338 manager->scene->AddPointLight({20, 20, 30}, {intensity, intensity, intensity}, 5000);
339
340 // Set up Camera
341 chrono::ChFrame<double> offset_pose1({-8, 0, 3}, Q_from_AngAxis(.2, {0, 1, 0}));
342 auto cam =
343 chrono_types::make_shared<ChCameraSensor>(my_hmmwv.GetChassisBody(), update_rate, offset_pose1, image_width,
344 image_height, fov, 1, CameraLensModelType::PINHOLE, false);
345 cam->SetName("Camera Sensor");
346 cam->SetLag(lag);
347 cam->SetCollectionWindow(exposure_time);
348
349 // Renders the image at current point in the filter graph
350 if (vis)
351 cam->PushFilter(chrono_types::make_shared<ChFilterVisualize>(int(image_width * 3 / 4),
352 int(image_height * 3 / 4), "SCM Camera"));
353
354 // Provides the host access to this RGBA8_buffer
355 // cam->PushFilter(chrono_types::make_shared<ChFilterRGBA8Access>());
356
357 // if (save)
358 // cam->PushFilter(chrono_types::make_shared<ChFilterSave>(sens_dir + "/cam/"));
359
360 // Add sensor to the manager
361 manager->AddSensor(cam);
362
363 // ---------------
364 // Simulation loop
365 // ---------------
366 std::cout << "Total vehicle mass: " << my_hmmwv.GetTotalMass() << std::endl;
367
368 // Solver settings.
369 system->SetSolverMaxIterations(50);
370
371 // Number of simulation steps between two 3D view render frames
372 int render_steps = (int)std::ceil(render_step_size / step_size);
373
374 // Initialize simulation frame counter
375 int step_number = 0;
376 int render_frame = 0;
377
378 ChTimer<> timer;
379
380 while (app.GetDevice()->run()) {
381 double time = system->GetChTime();
382
383 if (step_number == 800) {
384 std::cout << "\nstart timer at t = " << time << std::endl;
385 timer.start();
386 }
387 if (step_number == 1400) {
388 timer.stop();
389 std::cout << "stop timer at t = " << time << std::endl;
390 std::cout << "elapsed: " << timer() << std::endl;
391 std::cout << "\nSCM stats for last step:" << std::endl;
392 terrain.PrintStepStatistics(std::cout);
393 }
394
395 // Render scene
396 app.BeginScene(true, true, irr::video::SColor(255, 140, 161, 192));
397 app.DrawAll();
398 tools::drawColorbar(0, 0.1, "Sinkage", app.GetDevice(), 30);
399 app.EndScene();
400
401 if (img_output && step_number % render_steps == 0) {
402 char filename[100];
403 sprintf(filename, "%s/img_%03d.jpg", img_dir.c_str(), render_frame + 1);
404 app.WriteImageToFile(filename);
405 render_frame++;
406 }
407
408 // Driver inputs
409 ChDriver::Inputs driver_inputs = driver.GetInputs();
410
411 // Update modules
412 driver.Synchronize(time);
413 terrain.Synchronize(time);
414 my_hmmwv.Synchronize(time, driver_inputs, terrain);
415 app.Synchronize("", driver_inputs);
416
417 manager->Update();
418
419 // Advance dynamics
420 system->DoStepDynamics(step_size);
421 app.Advance(step_size);
422
423 // Increment frame number
424 step_number++;
425 }
426
427 return 0;
428 }
429