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