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
13 // =============================================================================
14 //
15 // Demonstration of rendering a vehicle specified through JSON files.
16 // Uses Chrono::OpenGL and a user-specified event receiver to trigger a rebuild
17 // of the vehicle when pressing 'U'.
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 "chrono/physics/ChSystemSMC.h"
25 
26 #include "chrono_vehicle/ChVehicleModelData.h"
27 #include "chrono_vehicle/terrain/RigidTerrain.h"
28 #include "chrono_vehicle/utils/ChUtilsJSON.h"
29 #include "chrono_vehicle/wheeled_vehicle/vehicle/WheeledVehicle.h"
30 #include "chrono_vehicle/tracked_vehicle/vehicle/TrackedVehicle.h"
31 
32 #include "chrono_opengl/ChOpenGLWindow.h"
33 
34 #include "chrono_thirdparty/filesystem/path.h"
35 
36 using namespace chrono;
37 using namespace chrono::vehicle;
38 
39 // =============================================================================
40 
41 bool chassis_fixed = false;
42 bool enable_gravity = true;
43 
44 std::string vehicle_file = "hmmwv/vehicle/HMMWV_Vehicle.json";
45 std::string powertrain_file = "hmmwv/powertrain/HMMWV_ShaftsPowertrain.json";
46 std::string tire_file = "hmmwv/tire/HMMWV_TMeasyTire.json";
47 
48 ////std::string vehicle_file("M113/vehicle/M113_Vehicle_SinglePin.json");
49 ////std::string powertrain_file("M113/powertrain/M113_SimpleCVTPowertrain.json");
50 
51 // =============================================================================
52 
CreateVehicle(ChSystem * sys,bool is_wheeled)53 ChVehicle* CreateVehicle(ChSystem* sys, bool is_wheeled) {
54     if (is_wheeled) {
55         // Create the wheeled vehicle system
56         auto vehicle = new WheeledVehicle(sys, vehicle::GetDataFile(vehicle_file));
57         vehicle->Initialize(ChCoordsys<>(ChVector<>(0, 0, 0.75), QUNIT));
58         vehicle->GetChassis()->SetFixed(chassis_fixed);
59         vehicle->SetChassisVisualizationType(VisualizationType::MESH);
60         vehicle->SetSuspensionVisualizationType(VisualizationType::PRIMITIVES);
61         vehicle->SetSteeringVisualizationType(VisualizationType::PRIMITIVES);
62         vehicle->SetWheelVisualizationType(VisualizationType::MESH);
63 
64         // Create and initialize the powertrain system
65         auto powertrain = ReadPowertrainJSON(vehicle::GetDataFile(powertrain_file));
66         vehicle->InitializePowertrain(powertrain);
67 
68         // Create and initialize the tires
69         for (auto& axle : vehicle->GetAxles()) {
70             for (auto& wheel : axle->GetWheels()) {
71                 auto tire = ReadTireJSON(vehicle::GetDataFile(tire_file));
72                 vehicle->InitializeTire(tire, wheel, VisualizationType::MESH);
73             }
74         }
75 
76         return vehicle;
77     } else {
78         // Create the tracked vehicle system
79         auto vehicle = new TrackedVehicle(sys, vehicle::GetDataFile(vehicle_file));
80         vehicle->Initialize(ChCoordsys<>(ChVector<>(0, 0, 0.85), QUNIT));
81         vehicle->GetChassis()->SetFixed(chassis_fixed);
82         vehicle->SetChassisVisualizationType(VisualizationType::MESH);
83         vehicle->SetSprocketVisualizationType(VisualizationType::MESH);
84         vehicle->SetIdlerVisualizationType(VisualizationType::MESH);
85         vehicle->SetRoadWheelAssemblyVisualizationType(VisualizationType::MESH);
86         vehicle->SetRoadWheelVisualizationType(VisualizationType::MESH);
87         vehicle->SetTrackShoeVisualizationType(VisualizationType::MESH);
88 
89         // Create and initialize the powertrain system
90         auto powertrain = ReadPowertrainJSON(vehicle::GetDataFile(powertrain_file));
91         vehicle->InitializePowertrain(powertrain);
92 
93         return vehicle;
94     }
95 }
96 
97 // =============================================================================
98 
99 class EventCB : public opengl::ChOpenGLEventCB {
100   public:
EventCB(ChVehicle * & vehicle,bool is_wheeled)101     EventCB(ChVehicle*& vehicle, bool is_wheeled) : m_vehicle(vehicle), m_is_wheeled(is_wheeled), m_chassis_vis(true) {}
102 
CallbackKeyboard(GLFWwindow * window,int key,int scancode,int action,int mode)103     virtual bool CallbackKeyboard(GLFWwindow* window, int key, int scancode, int action, int mode) override {
104         switch (key) {
105             case 'U': {
106                 std::cout << "Update..." << std::endl;
107                 auto sys = m_vehicle->GetSystem();
108                 delete m_vehicle;
109                 m_vehicle = nullptr;
110                 m_vehicle = CreateVehicle(sys, m_is_wheeled);
111                 return true;
112             }
113             case 'X':
114                 m_chassis_vis = !m_chassis_vis;
115                 m_vehicle->SetChassisVisualizationType(m_chassis_vis ? VisualizationType::MESH
116                                                                      : VisualizationType::NONE);
117                 return true;
118             default:
119                 return false;
120         }
121     }
122 
CallbackMouseButton(GLFWwindow * window,int button,int action,int mods)123     virtual bool CallbackMouseButton(GLFWwindow* window, int button, int action, int mods) override { return false; }
CallbackMousePos(GLFWwindow * window,double x,double y)124     virtual bool CallbackMousePos(GLFWwindow* window, double x, double y) override { return false; }
125 
126     ChVehicle*& m_vehicle;
127     bool m_is_wheeled;
128     bool m_chassis_vis;
129 };
130 
131 // =============================================================================
132 
main(int argc,char * argv[])133 int main(int argc, char* argv[]) {
134     GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
135 
136     // Peek in vehicle JSON file and infer type
137     rapidjson::Document d;
138     ReadFileJSON(vehicle::GetDataFile(vehicle_file), d);
139     assert(!d.IsNull());
140     assert(d.HasMember("Type"));
141     assert(d.HasMember("Template"));
142     std::string type = d["Type"].GetString();
143     assert(type.compare("Vehicle") == 0);
144     std::string subtype = d["Template"].GetString();
145     bool is_wheeled = (subtype.compare("WheeledVehicle") == 0);
146 
147     // Create containing system and vehicle
148     ChSystemSMC sys;
149     sys.Set_G_acc(enable_gravity ? ChVector<>(0, 0, -9.81) : VNULL);
150     auto vehicle = CreateVehicle(&sys, is_wheeled);
151 
152     // (Constant) driver inputs
153     ChDriver::Inputs driver_inputs;
154     driver_inputs.m_braking = 1;
155     driver_inputs.m_steering = 0;
156     driver_inputs.m_throttle = 0;
157 
158     // Create the terrain
159     RigidTerrain terrain(&sys);
160     if (enable_gravity) {
161         MaterialInfo minfo;
162         minfo.mu = 0.9f;
163         minfo.cr = 0.01f;
164         minfo.Y = 2e7f;
165         auto patch_mat = minfo.CreateMaterial(sys.GetContactMethod());
166         auto patch = terrain.AddPatch(patch_mat, ChVector<>(0, 0, 0), ChVector<>(0, 0, 1), 10, 5);
167         terrain.Initialize();
168     }
169 
170     // Initialize OpenGL
171     double factor = (is_wheeled ? 3.0 : 5.0);
172     opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
173     gl_window.Initialize(1280, 720, "JSON visualization", &sys);
174     gl_window.SetCamera(factor * ChVector<>(-1, -1, 0.75), ChVector<>(0, 0, 0.5), ChVector<>(0, 0, 1));
175     gl_window.SetRenderMode(opengl::SOLID);
176     gl_window.EnableHUD(false);
177 
178     // Attache event receiver (use key 'U' to trigger a vehicle update)
179     EventCB my_receiver(vehicle, is_wheeled);
180     gl_window.SetUserEventReceiver(&my_receiver);
181 
182     // Simulation loop
183     double step_size = 2e-3;
184 
185     // Dummy (not needed)
186     TerrainForces shoe_forces_left;
187     TerrainForces shoe_forces_right;
188     if (!is_wheeled) {
189         shoe_forces_left.resize(static_cast<TrackedVehicle*>(vehicle)->GetNumTrackShoes(LEFT));
190         shoe_forces_right.resize(static_cast<TrackedVehicle*>(vehicle)->GetNumTrackShoes(RIGHT));
191     }
192 
193     while (gl_window.Active()) {
194         gl_window.Render();
195 
196         if (!vehicle)
197             continue;
198 
199         // Update modules (process inputs from other modules)
200         double time = vehicle->GetSystem()->GetChTime();
201         terrain.Synchronize(time);
202         if (is_wheeled)
203             static_cast<WheeledVehicle*>(vehicle)->Synchronize(time, driver_inputs, terrain);
204         else
205             static_cast<TrackedVehicle*>(vehicle)->Synchronize(time, driver_inputs, shoe_forces_left,
206                                                                shoe_forces_right);
207 
208         // Advance simulation for one timestep for all modules
209         terrain.Advance(step_size);
210         vehicle->Advance(step_size);
211         sys.DoStepDynamics(step_size);
212     }
213 
214     delete vehicle;
215     return 0;
216 }
217