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 // Authors: Radu Serban, Justin Madsen, Daniel Melanz
13 // =============================================================================
14 //
15 // Main driver function for a generic vehicle, using rigid tire-terrain contact.
16 //
17 // If using the Irrlicht interface, driver inputs are obtained from the keyboard.
18 //
19 // The vehicle reference frame has Z up, X towards the front of the vehicle, and
20 // Y pointing to the left.
21 //
22 // =============================================================================
23 
24 #include <vector>
25 
26 #include "chrono/core/ChStream.h"
27 #include "chrono/core/ChRealtimeStep.h"
28 #include "chrono/physics/ChLinkDistance.h"
29 #include "chrono/utils/ChUtilsInputOutput.h"
30 
31 #include "chrono_vehicle/ChConfigVehicle.h"
32 #include "chrono_vehicle/ChVehicleModelData.h"
33 #include "chrono_vehicle/terrain/RigidTerrain.h"
34 
35 #include "chrono_models/vehicle/generic/Generic_Vehicle.h"
36 #include "chrono_models/vehicle/generic/Generic_SimplePowertrain.h"
37 #include "chrono_models/vehicle/generic/Generic_RigidTire.h"
38 #include "chrono_models/vehicle/generic/Generic_FuncDriver.h"
39 
40 #include "chrono_thirdparty/filesystem/path.h"
41 
42 #ifdef CHRONO_IRRLICHT
43 #include "chrono_vehicle/driver/ChIrrGuiDriver.h"
44 #include "chrono_vehicle/wheeled_vehicle/utils/ChWheeledVehicleIrrApp.h"
45 // specify whether the demo should actually use Irrlicht
46 #define USE_IRRLICHT
47 #endif
48 
49 // DEBUGGING:  Uncomment the following line to print shock data
50 //#define DEBUG_LOG
51 
52 using namespace chrono;
53 #ifdef USE_IRRLICHT
54 using namespace chrono::irrlicht;
55 #endif
56 using namespace chrono::vehicle;
57 using namespace chrono::vehicle::generic;
58 
59 // =============================================================================
60 
61 // Initial vehicle position
62 ChVector<> initLoc(0, 0, 1.0);
63 
64 // Initial vehicle orientation
65 ChQuaternion<> initRot(1, 0, 0, 0);
66 // ChQuaternion<> initRot(0.866025, 0, 0, 0.5);
67 // ChQuaternion<> initRot(0.7071068, 0, 0, 0.7071068);
68 // ChQuaternion<> initRot(0.25882, 0, 0, 0.965926);
69 // ChQuaternion<> initRot(0, 0, 0, 1);
70 
71 // Rigid terrain dimensions
72 double terrainHeight = 0;
73 double terrainLength = 100.0;  // size in X direction
74 double terrainWidth = 100.0;   // size in Y direction
75 
76 // Simulation step size
77 double step_size = 1e-3;
78 
79 // Time interval between two render frames
80 double render_step_size = 1.0 / 50;  // FPS = 50
81 
82 // Time interval between two output frames
83 double output_step_size = 1.0 / 1;  // once a second
84 
85 // Point on chassis tracked by the camera (Irrlicht only)
86 ChVector<> trackPoint(0.0, 0.0, 1.75);
87 
88 // Simulation length (Povray only)
89 double tend = 20.0;
90 
91 // Output directories (Povray only)
92 const std::string out_dir = GetChronoOutputPath() + "GENERIC_VEHICLE";
93 const std::string pov_dir = out_dir + "/POVRAY";
94 
95 // =============================================================================
96 
main(int argc,char * argv[])97 int main(int argc, char* argv[]) {
98     GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
99 
100     // --------------------------
101     // Create the various modules
102     // --------------------------
103 
104     // Create the vehicle: specify if chassis is fixed, the suspension type
105     // and visualization mode for the various vehicle components.
106     Generic_Vehicle vehicle(false, SuspensionTypeWV::MACPHERSON_STRUT, ChContactMethod::NSC);
107     vehicle.Initialize(ChCoordsys<>(initLoc, initRot));
108     vehicle.SetChassisVisualizationType(VisualizationType::PRIMITIVES);
109     vehicle.SetSuspensionVisualizationType(VisualizationType::PRIMITIVES);
110     vehicle.SetSteeringVisualizationType(VisualizationType::PRIMITIVES);
111     vehicle.SetWheelVisualizationType(VisualizationType::NONE);
112 
113     // Create the ground
114     RigidTerrain terrain(vehicle.GetSystem());
115     auto patch_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
116     patch_mat->SetFriction(0.9f);
117     patch_mat->SetRestitution(0.01f);
118     auto patch = terrain.AddPatch(patch_mat, ChVector<>(0, 0, 0), ChVector<>(0, 0, 1), terrainLength, terrainWidth);
119     patch->SetColor(ChColor(0.5f, 0.8f, 0.5f));
120     patch->SetTexture(vehicle::GetDataFile("terrain/textures/tile4.jpg"), 200, 200);
121     terrain.Initialize();
122 
123     // Create and initialize the powertrain system
124     auto powertrain = chrono_types::make_shared<Generic_SimplePowertrain>("powertrain");
125     vehicle.InitializePowertrain(powertrain);
126 
127     // Create the tires
128     auto tire_FL = chrono_types::make_shared<Generic_RigidTire>("FL");
129     auto tire_FR = chrono_types::make_shared<Generic_RigidTire>("FR");
130     auto tire_RL = chrono_types::make_shared<Generic_RigidTire>("RL");
131     auto tire_RR = chrono_types::make_shared<Generic_RigidTire>("RR");
132 
133     vehicle.InitializeTire(tire_FL, vehicle.GetAxle(0)->m_wheels[0], VisualizationType::PRIMITIVES);
134     vehicle.InitializeTire(tire_FR, vehicle.GetAxle(0)->m_wheels[1], VisualizationType::PRIMITIVES);
135     vehicle.InitializeTire(tire_RL, vehicle.GetAxle(1)->m_wheels[0], VisualizationType::PRIMITIVES);
136     vehicle.InitializeTire(tire_RR, vehicle.GetAxle(1)->m_wheels[1], VisualizationType::PRIMITIVES);
137 
138 #ifdef USE_IRRLICHT
139 
140     ChWheeledVehicleIrrApp app(&vehicle, L"Generic Vehicle Demo");
141 
142     app.SetSkyBox();
143     app.AddTypicalLights(irr::core::vector3df(30.f, -30.f, 100.f), irr::core::vector3df(30.f, 50.f, 100.f), 250, 130);
144     app.SetChaseCamera(trackPoint, 6.0, 0.5);
145 
146     app.SetTimestep(step_size);
147 
148     app.AssetBindAll();
149     app.AssetUpdateAll();
150 
151     /*
152     bool do_shadows = false; // shadow map is experimental
153     irr::scene::ILightSceneNode* mlight = 0;
154 
155     if (do_shadows) {
156       mlight = application.AddLightWithShadow(
157         irr::core::vector3df(10.f, 30.f, 60.f),
158         irr::core::vector3df(0.f, 0.f, 0.f),
159         150, 60, 80, 15, 512, irr::video::SColorf(1, 1, 1), false, false);
160     } else {
161       application.AddTypicalLights(
162         irr::core::vector3df(30.f, -30.f, 100.f),
163         irr::core::vector3df(30.f, 50.f, 100.f),
164         250, 130);
165     }
166 
167     if (do_shadows)
168        application.AddShadowAll();
169     */
170 
171     ChIrrGuiDriver driver(app);
172 
173     // Set the time response for steering and throttle keyboard inputs.
174     // NOTE: this is not exact, since we do not render quite at the specified FPS.
175     double steering_time = 1.0;  // time to go from 0 to +1 (or from 0 to -1)
176     double throttle_time = 1.0;  // time to go from 0 to +1
177     double braking_time = 0.3;   // time to go from 0 to +1
178     driver.SetSteeringDelta(render_step_size / steering_time);
179     driver.SetThrottleDelta(render_step_size / throttle_time);
180     driver.SetBrakingDelta(render_step_size / braking_time);
181 
182 #else
183 
184     Generic_FuncDriver driver(vehicle);
185 
186 #endif
187 
188     driver.Initialize();
189 
190 // ---------------
191 // Simulation loop
192 // ---------------
193 
194 #ifdef DEBUG_LOG
195     GetLog() << "\n\n============ System Configuration ============\n";
196     vehicle.LogHardpointLocations();
197 #endif
198 
199     // Initialize simulation frame counter and simulation time
200     int step_number = 0;
201     double time = 0;
202 
203 #ifdef USE_IRRLICHT
204 
205     ChRealtimeStepTimer realtime_timer;
206     while (app.GetDevice()->run()) {
207         // Update the position of the shadow mapping so that it follows the car
208         ////if (do_shadows) {
209         ////  ChVector<> lightaim = vehicle.GetChassisPos();
210         ////  ChVector<> lightpos = vehicle.GetChassisPos() + ChVector<>(10, 30, 60);
211         ////  irr::core::vector3df mlightpos((irr::f32)lightpos.x, (irr::f32)lightpos.y, (irr::f32)lightpos.z);
212         ////  irr::core::vector3df mlightaim((irr::f32)lightaim.x, (irr::f32)lightaim.y, (irr::f32)lightaim.z);
213         ////  application.GetEffects()->getShadowLight(0).setPosition(mlightpos);
214         ////  application.GetEffects()->getShadowLight(0).setTarget(mlightaim);
215         ////  mlight->setPosition(mlightpos);
216         ////}
217 
218         // Render scene
219         app.BeginScene(true, true, irr::video::SColor(255, 140, 161, 192));
220         app.DrawAll();
221         app.EndScene();
222 
223 #ifdef DEBUG_LOG
224         // Number of simulation steps between two output frames
225         int output_steps = (int)std::ceil(output_step_size / step_size);
226 
227         if (step_number % output_steps == 0) {
228             GetLog() << "\n\n============ System Information ============\n";
229             GetLog() << "Time = " << time << "\n\n";
230             vehicle.DebugLog(DBG_SPRINGS | DBG_SHOCKS | DBG_CONSTRAINTS);
231         }
232 #endif
233 
234         // Driver inputs
235         ChDriver::Inputs driver_inputs = driver.GetInputs();
236 
237         // Update modules (process inputs from other modules)
238         time = vehicle.GetSystem()->GetChTime();
239 
240         driver.Synchronize(time);
241         terrain.Synchronize(time);
242         vehicle.Synchronize(time, driver_inputs, terrain);
243         app.Synchronize(driver.GetInputModeAsString(), driver_inputs);
244 
245         // Advance simulation for one timestep for all modules
246         driver.Advance(step_size);
247         terrain.Advance(step_size);
248         vehicle.Advance(step_size);
249         app.Advance(step_size);
250 
251         // Increment frame number
252         step_number++;
253 
254         // Spin in place for real time to catch up
255         realtime_timer.Spin(step_size);
256     }
257 
258 #else
259 
260     // Number of simulation steps between two 3D view render frames
261     int render_steps = (int)std::ceil(render_step_size / step_size);
262 
263     int render_frame = 0;
264 
265     if (!filesystem::create_directory(filesystem::path(out_dir))) {
266         std::cout << "Error creating directory " << out_dir << std::endl;
267         return 1;
268     }
269     if (!filesystem::create_directory(filesystem::path(pov_dir))) {
270         std::cout << "Error creating directory " << pov_dir << std::endl;
271         return 1;
272     }
273 
274     char filename[100];
275 
276     while (time < tend) {
277         if (step_number % render_steps == 0) {
278             // Output render data
279             sprintf(filename, "%s/data_%03d.dat", pov_dir.c_str(), render_frame + 1);
280             utils::WriteVisualizationAssets(vehicle.GetSystem(), filename);
281             std::cout << "Output frame:   " << render_frame << std::endl;
282             std::cout << "Sim frame:      " << step_number << std::endl;
283             std::cout << "Time:           " << time << std::endl;
284             std::cout << "             throttle: " << driver.GetThrottle() << " steering: " << driver.GetSteering()
285                       << std::endl;
286             std::cout << std::endl;
287             render_frame++;
288         }
289 
290         // Driver inputs
291         ChDriver::Inputs driver_inputs = driver.GetInputs();
292 
293         // Update modules (process inputs from other modules)
294         time = vehicle.GetSystem()->GetChTime();
295 
296         driver.Synchronize(time);
297         terrain.Synchronize(time);
298         vehicle.Synchronize(time, driver_inputs, terrain);
299 
300         // Advance simulation for one timestep for all modules
301         driver.Advance(step_size);
302         terrain.Advance(step_size);
303         vehicle.Advance(step_size);
304 
305         // Increment frame number
306         step_number++;
307     }
308 
309 #endif
310 
311     return 0;
312 }
313