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