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