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, Michael Taylor
13 // =============================================================================
14 //
15 // Demonstration of a continuous band track on the track test rig.
16 //
17 // =============================================================================
18 
19 #include "chrono/utils/ChUtilsInputOutput.h"
20 
21 #include "chrono_vehicle/ChVehicleModelData.h"
22 #include "chrono_vehicle/tracked_vehicle/test_rig/ChDataDriverTTR.h"
23 #include "chrono_vehicle/tracked_vehicle/test_rig/ChIrrGuiDriverTTR.h"
24 #include "chrono_vehicle/tracked_vehicle/test_rig/ChTrackTestRig.h"
25 #include "chrono_vehicle/utils/ChVehicleIrrApp.h"
26 
27 #include "chrono_models/vehicle/m113/M113_TrackAssemblyBandANCF.h"
28 #include "chrono_models/vehicle/m113/M113_TrackAssemblyBandBushing.h"
29 
30 #include "chrono_thirdparty/filesystem/path.h"
31 
32 #ifdef CHRONO_MUMPS
33 #include "chrono_mumps/ChSolverMumps.h"
34 #endif
35 
36 #ifdef CHRONO_PARDISO_MKL
37 #include "chrono_pardisomkl/ChSolverPardisoMKL.h"
38 #endif
39 
40 using namespace chrono;
41 using namespace chrono::vehicle;
42 using namespace chrono::vehicle::m113;
43 
44 using std::cout;
45 using std::endl;
46 
47 // =============================================================================
48 // USER SETTINGS
49 // =============================================================================
50 
51 // Simulation step size
52 double step_size = 1e-4;
53 
54 // Specification of test rig inputs:
55 //   'true':  use driver inputs from file
56 //   'false': use interactive Irrlicht driver
57 bool use_data_driver = true;
58 std::string driver_file("M113/test_rig/TTR_inputs.dat");
59 
60 bool use_JSON = false;
61 std::string filename("M113/track_assembly/M113_TrackAssemblyBandANCF_Left.json");
62 
63 // Linear solver (MUMPS or PARDISO_MKL)
64 ChSolver::Type solver_type = ChSolver::Type::MUMPS;
65 
66 // Output directories
67 const std::string out_dir = GetChronoOutputPath() + "TRACKBAND_TEST_RIG";
68 
69 // Verbose level
70 bool verbose_solver = false;
71 bool verbose_integrator = false;
72 
73 // Output
74 bool dbg_output = false;
75 
76 // =============================================================================
77 
78 // Callback class for inspecting contacts
79 class MyContactReporter : public ChContactContainer::ReportContactCallback {
80   public:
MyContactReporter(ChTrackTestRig * rig)81     MyContactReporter(ChTrackTestRig* rig) : m_rig(rig) {}
82 
Process()83     void Process() {
84         cout << "Report contacts" << endl;
85         m_num_contacts = 0;
86         m_num_contacts_bb = 0;
87         std::shared_ptr<MyContactReporter> shared_this(this, [](MyContactReporter*) {});
88         m_rig->GetSystem()->GetContactContainer()->ReportAllContacts(shared_this);
89         cout << "Total number contacts:        " << m_num_contacts << endl;
90         cout << "Number of body-body contacts: " << m_num_contacts_bb << endl;
91     }
92 
93   private:
OnReportContact(const ChVector<> & pA,const ChVector<> & pB,const ChMatrix33<> & plane_coord,const double & distance,const double & eff_radius,const ChVector<> & react_forces,const ChVector<> & react_torques,ChContactable * modA,ChContactable * modB)94     virtual bool OnReportContact(const ChVector<>& pA,
95                                  const ChVector<>& pB,
96                                  const ChMatrix33<>& plane_coord,
97                                  const double& distance,
98                                  const double& eff_radius,
99                                  const ChVector<>& react_forces,
100                                  const ChVector<>& react_torques,
101                                  ChContactable* modA,
102                                  ChContactable* modB) override {
103         m_num_contacts++;
104 
105         auto bodyA = dynamic_cast<ChBody*>(modA);
106         auto bodyB = dynamic_cast<ChBody*>(modB);
107         auto vertexA = dynamic_cast<fea::ChContactNodeXYZsphere*>(modA);
108         auto vertexB = dynamic_cast<fea::ChContactNodeXYZsphere*>(modB);
109         auto faceA = dynamic_cast<fea::ChContactTriangleXYZ*>(modA);
110         auto faceB = dynamic_cast<fea::ChContactTriangleXYZ*>(modB);
111 
112         if (bodyA && bodyB) {
113             cout << "  Body-Body:  " << bodyA->GetNameString() << "  " << bodyB->GetNameString() << endl;
114             m_num_contacts_bb++;
115             return true;
116         } else if (vertexA && vertexB) {
117             cout << "  Vertex-Vertex" << endl;
118         } else if (faceA && faceB) {
119             cout << "  Face-Face" << endl;
120         }
121 
122         // Continue scanning contacts
123         return true;
124     }
125 
126     int m_num_contacts;
127     int m_num_contacts_bb;
128     ChTrackTestRig* m_rig;
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     // -------------------------
137     // Create the track test rig
138     // -------------------------
139 
140     bool create_track = true;
141 
142     ChTrackTestRig* rig = nullptr;
143     if (use_JSON) {
144         rig = new ChTrackTestRig(vehicle::GetDataFile(filename), create_track, ChContactMethod::SMC);
145     } else {
146         VehicleSide side = LEFT;
147         TrackShoeType type = TrackShoeType::BAND_BUSHING;
148         BrakeType brake_type = BrakeType::SIMPLE;
149         std::shared_ptr<ChTrackAssembly> track_assembly;
150         switch (type) {
151             case TrackShoeType::BAND_BUSHING: {
152                 auto assembly = chrono_types::make_shared<M113_TrackAssemblyBandBushing>(side, brake_type);
153                 track_assembly = assembly;
154                 break;
155             }
156             case TrackShoeType::BAND_ANCF: {
157                 auto assembly = chrono_types::make_shared<M113_TrackAssemblyBandANCF>(side, brake_type);
158                 assembly->SetContactSurfaceType(ChTrackAssemblyBandANCF::ContactSurfaceType::NONE);
159                 track_assembly = assembly;
160                 break;
161             }
162             default:
163                 cout << "Track type not supported" << endl;
164                 return 1;
165         }
166 
167         rig = new ChTrackTestRig(track_assembly, create_track, ChContactMethod::SMC);
168         std::cout << "Rig uses M113 track assembly:  type " << (int)type << " side " << side << std::endl;
169     }
170 
171     // ---------------------------------------
172     // Create the vehicle Irrlicht application
173     // ---------------------------------------
174 
175     ////ChVector<> target_point = rig->GetPostPosition();
176     ////ChVector<> target_point = rig->GetTrackAssembly()->GetIdler()->GetWheelBody()->GetPos();
177     ChVector<> target_point = rig->GetTrackAssembly()->GetSprocket()->GetGearBody()->GetPos();
178 
179     ChVehicleIrrApp app(rig, L"Continuous Band Track Test Rig");
180     app.SetSkyBox();
181     app.SetSkyBox();
182     app.AddTypicalLights(irr::core::vector3df(30.f, -30.f, 100.f), irr::core::vector3df(30.f, 50.f, 100.f), 250, 130);
183     app.SetChaseCamera(ChVector<>(0.0, 0.0, 0.0), 3.0, 0.0);
184     app.SetChaseCameraPosition(target_point + ChVector<>(-2, 3, 0));
185     app.SetChaseCameraState(utils::ChChaseCamera::Free);
186     app.SetChaseCameraAngle(-CH_C_PI_2);
187     app.SetChaseCameraMultipliers(1e-4, 10);
188     app.SetTimestep(step_size);
189 
190     // -----------------------------------
191     // Create and attach the driver system
192     // -----------------------------------
193 
194     std::unique_ptr<ChDriverTTR> driver;
195     if (use_data_driver) {
196         // Driver with inputs from file
197         auto data_driver = new ChDataDriverTTR(vehicle::GetDataFile(driver_file));
198         driver = std::unique_ptr<ChDriverTTR>(data_driver);
199     } else {
200         auto irr_driver = new ChIrrGuiDriverTTR(app);
201         irr_driver->SetThrottleDelta(1.0 / 50);
202         irr_driver->SetDisplacementDelta(1.0 / 250);
203         driver = std::unique_ptr<ChDriverTTR>(irr_driver);
204     }
205 
206     rig->SetDriver(std::move(driver));
207 
208     // -----------------------------
209     // Initialize the track test rig
210     // -----------------------------
211 
212     rig->SetInitialRideHeight(0.6);
213 
214     rig->SetMaxTorque(6000);
215 
216     // Disable gravity in this simulation
217     ////rig->GetSystem()->Set_G_acc(ChVector<>(0, 0, 0));
218 
219     // Visualization settings
220     rig->SetSprocketVisualizationType(VisualizationType::PRIMITIVES);
221     rig->SetIdlerVisualizationType(VisualizationType::PRIMITIVES);
222     rig->SetRoadWheelAssemblyVisualizationType(VisualizationType::PRIMITIVES);
223     rig->SetRoadWheelVisualizationType(VisualizationType::PRIMITIVES);
224     rig->SetTrackShoeVisualizationType(VisualizationType::PRIMITIVES);
225 
226     // Control internal collisions and contact monitoring
227     ////rig->SetCollide(TrackedCollisionFlag::NONE);
228     ////rig->SetCollide(TrackedCollisionFlag::SPROCKET_LEFT | TrackedCollisionFlag::SHOES_LEFT);
229     ////rig->GetTrackAssembly()->GetSprocket()->GetGearBody()->SetCollide(false);
230 
231     rig->Initialize();
232 
233     app.AssetBindAll();
234     app.AssetUpdateAll();
235 
236     // ---------------------------------------
237     // Contact reporter object (for debugging)
238     // ---------------------------------------
239 
240     MyContactReporter reporter(rig);
241 
242     // ------------------------------
243     // Solver and integrator settings
244     // ------------------------------
245 
246 #ifndef CHRONO_PARDISO_MKL
247     if (solver_type == ChSolver::Type::PARDISO_MKL)
248         solver_type = ChSolver::Type::MUMPS;
249 #endif
250 #ifndef CHRONO_MUMPS
251     if (solver_type == ChSolver::Type::MUMPS)
252         solver_type = ChSolver::Type::PARDISO_MKL;
253 #endif
254 
255     switch (solver_type) {
256 #ifdef CHRONO_MUMPS
257         case ChSolver::Type::MUMPS: {
258             auto mumps_solver = chrono_types::make_shared<ChSolverMumps>();
259             mumps_solver->LockSparsityPattern(true);
260             mumps_solver->SetVerbose(verbose_solver);
261             rig->GetSystem()->SetSolver(mumps_solver);
262             break;
263         }
264 #endif
265 #ifdef CHRONO_PARDISO_MKL
266         case ChSolver::Type::PARDISO_MKL: {
267             auto mkl_solver = chrono_types::make_shared<ChSolverPardisoMKL>();
268             mkl_solver->LockSparsityPattern(true);
269             mkl_solver->SetVerbose(verbose_solver);
270             rig->GetSystem()->SetSolver(mkl_solver);
271             break;
272         }
273 #endif
274         default:
275             break;
276     }
277 
278     rig->GetSystem()->SetTimestepperType(ChTimestepper::Type::HHT);
279     auto integrator = std::static_pointer_cast<ChTimestepperHHT>(rig->GetSystem()->GetTimestepper());
280     integrator->SetAlpha(-0.2);
281     integrator->SetMaxiters(50);
282     integrator->SetAbsTolerances(1e-2, 1e2);
283     integrator->SetMode(ChTimestepperHHT::ACCELERATION);
284     integrator->SetStepControl(false);
285     integrator->SetModifiedNewton(true);
286     integrator->SetScaling(true);
287     integrator->SetVerbose(verbose_integrator);
288 
289     // -----------------
290     // Print model stats
291     // -----------------
292 
293     auto sys = rig->GetSystem();
294     std::vector<size_t> nassets;
295     for (auto& mesh : sys->Get_meshlist()) {
296         nassets.push_back(mesh->GetAssets().size());
297     }
298     cout << "Number of bodies:        " << sys->Get_bodylist().size() << endl;
299     cout << "Number of physics items: " << sys->Get_otherphysicslist().size() << endl;
300     cout << "Number of FEA meshes:    " << sys->Get_meshlist().size() << endl;
301     cout << "Number of assets/mesh:   ";
302     for (auto i : nassets)
303         cout << i << " ";
304     cout << endl;
305 
306     // -----------------
307     // Initialize output
308     // -----------------
309 
310     if (!filesystem::create_directory(filesystem::path(out_dir))) {
311         cout << "Error creating directory " << out_dir << endl;
312         return 1;
313     }
314 
315     // ---------------
316     // Simulation loop
317     // ---------------
318 
319     // Total execution time (for integration)
320     double total_timing = 0;
321 
322     // Initialize simulation frame counter
323     int step_number = 0;
324 
325     while (app.GetDevice()->run()) {
326         double time = rig->GetChTime();
327 
328         // Debugging output
329         if (dbg_output) {
330             const ChFrameMoving<>& c_ref = rig->GetChassisBody()->GetFrame_REF_to_abs();
331             const ChVector<>& i_pos_abs = rig->GetTrackAssembly()->GetIdler()->GetWheelBody()->GetPos();
332             const ChVector<>& s_pos_abs = rig->GetTrackAssembly()->GetSprocket()->GetGearBody()->GetPos();
333             ChVector<> i_pos_rel = c_ref.TransformPointParentToLocal(i_pos_abs);
334             ChVector<> s_pos_rel = c_ref.TransformPointParentToLocal(s_pos_abs);
335             cout << "Time: " << time << endl;
336             cout << "      idler:    " << i_pos_rel.x() << "  " << i_pos_rel.y() << "  " << i_pos_rel.z() << endl;
337             cout << "      sprocket: " << s_pos_rel.x() << "  " << s_pos_rel.y() << "  " << s_pos_rel.z() << endl;
338         }
339 
340         if (!app.GetDevice()->run())
341             break;
342 
343         // Render scene
344         app.BeginScene(true, true, irr::video::SColor(255, 140, 161, 192));
345         app.DrawAll();
346         app.EndScene();
347 
348         // Advance simulation of the rig
349         rig->Advance(step_size);
350 
351         // Update visualization app
352         app.Synchronize(rig->GetDriverMessage(), { 0, rig->GetThrottleInput(), 0 });
353         app.Advance(step_size);
354 
355         // Parse all contacts in system
356         ////reporter.Process();
357 
358         // Increment frame number
359         step_number++;
360 
361         double step_timing = rig->GetSystem()->GetTimerStep();
362         total_timing += step_timing;
363 
364         ////cout << "Step: " << step_number;
365         ////cout << "   Time: " << time;
366         ////cout << "   Number of Iterations: " << integrator->GetNumIterations();
367         ////cout << "   Step Time: " << step_timing;
368         ////cout << "   Total Time: " << total_timing;
369         ////cout << endl;
370     }
371 
372     delete rig;
373 
374     return 0;
375 }
376