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