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 // Base class for a track assembly which consists of one sprocket, one idler,
16 // a collection of road wheel assemblies (suspensions), a collection of rollers,
17 // and a collection of track shoes.
18 //
19 // The reference frame for a vehicle follows the ISO standard: Z-axis up, X-axis
20 // pointing forward, and Y-axis towards the left of the vehicle.
21 //
22 // =============================================================================
23 
24 #include <cmath>
25 
26 #include "chrono/core/ChLog.h"
27 
28 #include "chrono_vehicle/tracked_vehicle/ChTrackAssembly.h"
29 
30 namespace chrono {
31 namespace vehicle {
32 
ChTrackAssembly(const std::string & name,VehicleSide side)33 ChTrackAssembly::ChTrackAssembly(const std::string& name, VehicleSide side)
34     : ChPart(name),
35       m_side(side),
36       m_idler_as_cylinder(true),
37       m_roller_as_cylinder(true),
38       m_roadwheel_as_cylinder(true) {}
39 
40 // -----------------------------------------------------------------------------
41 // Get the complete state for the specified track shoe.
42 // -----------------------------------------------------------------------------
GetTrackShoeState(size_t id) const43 BodyState ChTrackAssembly::GetTrackShoeState(size_t id) const {
44     BodyState state;
45 
46     state.pos = GetTrackShoePos(id);
47     state.rot = GetTrackShoeRot(id);
48     state.lin_vel = GetTrackShoeLinVel(id);
49     state.ang_vel = GetTrackShoeAngVel(id);
50 
51     return state;
52 }
53 
54 // -----------------------------------------------------------------------------
55 // Get the complete states for all track shoes.
56 // -----------------------------------------------------------------------------
GetTrackShoeStates(BodyStates & states) const57 void ChTrackAssembly::GetTrackShoeStates(BodyStates& states) const {
58     size_t num_shoes = GetNumTrackShoes();
59     assert(states.size() == num_shoes);
60 
61     for (size_t i = 0; i < num_shoes; ++i)
62         states[i] = GetTrackShoeState(i);
63 }
64 
65 // -----------------------------------------------------------------------------
66 // Initialize this track assembly subsystem.
67 // -----------------------------------------------------------------------------
Initialize(std::shared_ptr<ChChassis> chassis,const ChVector<> & location,bool create_shoes)68 void ChTrackAssembly::Initialize(std::shared_ptr<ChChassis> chassis,
69                                  const ChVector<>& location,
70                                  bool create_shoes) {
71     // Initialize the sprocket, idler, and brake
72     GetSprocket()->Initialize(chassis->GetBody(), location + GetSprocketLocation(), this);
73     m_idler->Initialize(chassis->GetBody(), location + GetIdlerLocation(), this);
74     m_brake->Initialize(chassis, GetSprocket());
75 
76     // Initialize the suspension subsystems
77     for (size_t i = 0; i < m_suspensions.size(); ++i) {
78         m_suspensions[i]->Initialize(chassis, location + GetRoadWhelAssemblyLocation(static_cast<int>(i)), this);
79     }
80 
81     // Initialize the roller subsystems
82     for (size_t i = 0; i < m_rollers.size(); ++i) {
83         m_rollers[i]->Initialize(chassis->GetBody(), location + GetRollerLocation(static_cast<int>(i)), this);
84     }
85 
86     if (!create_shoes) {
87         RemoveTrackShoes();
88         return;
89     }
90 
91     // Assemble the track. This positions all track shoes around the sprocket,
92     // road wheels, and idler. (Implemented by derived classes)
93     bool ccw = Assemble(chassis->GetBody());
94 
95     // Loop over all track shoes and allow them to connect themselves to their
96     // neighbor.
97     size_t num_shoes = GetNumTrackShoes();
98     std::shared_ptr<ChTrackShoe> next;
99     for (size_t i = 0; i < num_shoes; ++i) {
100         next = (i == num_shoes - 1) ? GetTrackShoe(0) : GetTrackShoe(i + 1);
101         GetTrackShoe(i)->Connect(next, this, chassis.get(), ccw);
102     }
103 }
104 
105 // -----------------------------------------------------------------------------
106 // -----------------------------------------------------------------------------
SetSprocketVisualizationType(VisualizationType vis)107 void ChTrackAssembly::SetSprocketVisualizationType(VisualizationType vis) {
108     GetSprocket()->SetVisualizationType(vis);
109 }
110 
SetIdlerVisualizationType(VisualizationType vis)111 void ChTrackAssembly::SetIdlerVisualizationType(VisualizationType vis) {
112     GetIdler()->SetVisualizationType(vis);
113 }
114 
SetRoadWheelAssemblyVisualizationType(VisualizationType vis)115 void ChTrackAssembly::SetRoadWheelAssemblyVisualizationType(VisualizationType vis) {
116     for (size_t i = 0; i < m_suspensions.size(); ++i) {
117         m_suspensions[i]->SetVisualizationType(vis);
118     }
119 }
120 
SetRoadWheelVisualizationType(VisualizationType vis)121 void ChTrackAssembly::SetRoadWheelVisualizationType(VisualizationType vis) {
122     for (size_t i = 0; i < m_suspensions.size(); ++i) {
123         m_suspensions[i]->GetRoadWheel()->SetVisualizationType(vis);
124     }
125 }
126 
SetRollerVisualizationType(VisualizationType vis)127 void ChTrackAssembly::SetRollerVisualizationType(VisualizationType vis) {
128     for (size_t i = 0; i < m_rollers.size(); ++i) {
129         m_rollers[i]->SetVisualizationType(vis);
130     }
131 }
132 
SetTrackShoeVisualizationType(VisualizationType vis)133 void ChTrackAssembly::SetTrackShoeVisualizationType(VisualizationType vis) {
134     SetVisualizationType(vis);
135     for (size_t i = 0; i < GetNumTrackShoes(); ++i) {
136         GetTrackShoe(i)->SetVisualizationType(vis);
137     }
138 }
139 
140 // -----------------------------------------------------------------------------
141 
SetWheelCollisionType(bool roadwheel_as_cylinder,bool idler_as_cylinder,bool roller_as_cylinder)142 void ChTrackAssembly::SetWheelCollisionType(bool roadwheel_as_cylinder,
143                                             bool idler_as_cylinder,
144                                             bool roller_as_cylinder) {
145     m_roadwheel_as_cylinder = roadwheel_as_cylinder;
146     m_idler_as_cylinder = idler_as_cylinder;
147     m_roller_as_cylinder = roller_as_cylinder;
148 }
149 
150 // -----------------------------------------------------------------------------
151 // Calculate and return the total mass of the track assembly
152 // -----------------------------------------------------------------------------
GetMass() const153 double ChTrackAssembly::GetMass() const {
154     double mass = GetSprocket()->GetMass() + m_idler->GetMass();
155     for (size_t i = 0; i < m_suspensions.size(); i++)
156         mass += m_suspensions[i]->GetMass();
157     for (size_t i = 0; i < m_rollers.size(); i++)
158         mass += m_rollers[i]->GetMass();
159     for (size_t i = 0; i < GetNumTrackShoes(); ++i)
160         mass += GetTrackShoe(i)->GetMass();
161 
162     return mass;
163 }
164 
165 // -----------------------------------------------------------------------------
166 // Update the state of this track assembly at the current time.
167 // -----------------------------------------------------------------------------
Synchronize(double time,double braking,const TerrainForces & shoe_forces)168 void ChTrackAssembly::Synchronize(double time, double braking, const TerrainForces& shoe_forces) {
169     // Zero out applied torque on sprocket axle
170     GetSprocket()->m_axle->SetAppliedTorque(0.0);
171 
172     // Apply track shoe forces
173     for (size_t i = 0; i < GetNumTrackShoes(); ++i) {
174         GetTrackShoe(i)->m_shoe->Empty_forces_accumulators();
175         GetTrackShoe(i)->m_shoe->Accumulate_force(shoe_forces[i].force, shoe_forces[i].point, false);
176         GetTrackShoe(i)->m_shoe->Accumulate_torque(shoe_forces[i].moment, false);
177     }
178 
179     // Apply braking input
180     m_brake->Synchronize(braking);
181 }
182 
183 // -----------------------------------------------------------------------------
184 // -----------------------------------------------------------------------------
SetOutput(bool state)185 void ChTrackAssembly::SetOutput(bool state) {
186     m_output = state;
187     GetSprocket()->SetOutput(state);
188     m_brake->SetOutput(state);
189     m_idler->SetOutput(state);
190     for (auto suspension : m_suspensions)
191         suspension->SetOutput(state);
192     for (auto roller : m_rollers)
193         roller->SetOutput(state);
194     if (GetNumTrackShoes() > 0)
195         GetTrackShoe(0)->SetOutput(state);
196 }
197 
198 // -----------------------------------------------------------------------------
199 // -----------------------------------------------------------------------------
ExportComponentList(rapidjson::Document & jsonDocument) const200 void ChTrackAssembly::ExportComponentList(rapidjson::Document& jsonDocument) const {
201     ChPart::ExportComponentList(jsonDocument);
202 
203     jsonDocument.AddMember("number shoes", static_cast<int>(GetNumTrackShoes()), jsonDocument.GetAllocator());
204 
205     {
206         rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
207         jsonSubDocument.SetObject();
208         GetSprocket()->ExportComponentList(jsonSubDocument);
209         jsonDocument.AddMember("sprocket", jsonSubDocument, jsonDocument.GetAllocator());
210     }
211 
212     {
213         rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
214         jsonSubDocument.SetObject();
215         m_brake->ExportComponentList(jsonSubDocument);
216         jsonDocument.AddMember("brake", jsonSubDocument, jsonDocument.GetAllocator());
217     }
218 
219     {
220         rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
221         jsonSubDocument.SetObject();
222         m_idler->ExportComponentList(jsonSubDocument);
223         jsonDocument.AddMember("idler", jsonSubDocument, jsonDocument.GetAllocator());
224     }
225 
226     rapidjson::Value suspArray(rapidjson::kArrayType);
227     for (auto suspension : m_suspensions) {
228         rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
229         jsonSubDocument.SetObject();
230         suspension->ExportComponentList(jsonSubDocument);
231         suspArray.PushBack(jsonSubDocument, jsonDocument.GetAllocator());
232     }
233     jsonDocument.AddMember("suspensions", suspArray, jsonDocument.GetAllocator());
234 
235     rapidjson::Value rollerArray(rapidjson::kArrayType);
236     for (auto roller : m_rollers) {
237         rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
238         jsonSubDocument.SetObject();
239         roller->ExportComponentList(jsonSubDocument);
240         rollerArray.PushBack(jsonSubDocument, jsonDocument.GetAllocator());
241     }
242     jsonDocument.AddMember("rollers", rollerArray, jsonDocument.GetAllocator());
243 
244     if (GetNumTrackShoes() > 0) {
245         rapidjson::Document jsonSubDocument(&jsonDocument.GetAllocator());
246         jsonSubDocument.SetObject();
247         GetTrackShoe(0)->ExportComponentList(jsonSubDocument);
248         jsonDocument.AddMember("shoe 0", jsonSubDocument, jsonDocument.GetAllocator());
249     }
250 }
251 
252 // -----------------------------------------------------------------------------
253 // -----------------------------------------------------------------------------
Output(ChVehicleOutput & database) const254 void ChTrackAssembly::Output(ChVehicleOutput& database) const {
255     if (!m_output)
256         return;
257 
258     database.WriteSection(GetSprocket()->GetName());
259     GetSprocket()->Output(database);
260 
261     database.WriteSection(m_brake->GetName());
262     m_brake->Output(database);
263 
264     database.WriteSection(m_idler->GetName());
265     m_idler->Output(database);
266 
267     for (auto suspension : m_suspensions) {
268         database.WriteSection(suspension->GetName());
269         suspension->Output(database);
270         database.WriteSection(suspension->GetRoadWheel()->GetName());
271         suspension->GetRoadWheel()->Output(database);
272     }
273 
274     for (auto roller : m_rollers) {
275         database.WriteSection(roller->GetName());
276         roller->Output(database);
277     }
278 
279     if (GetNumTrackShoes() > 0) {
280         database.WriteSection(GetTrackShoe(0)->GetName());
281         GetTrackShoe(0)->Output(database);
282     }
283 }
284 
285 // -----------------------------------------------------------------------------
286 // Log constraint violations
287 // -----------------------------------------------------------------------------
LogConstraintViolations()288 void ChTrackAssembly::LogConstraintViolations() {
289     GetLog() << "SPROCKET constraint violations\n";
290     GetSprocket()->LogConstraintViolations();
291     GetLog() << "IDLER constraint violations\n";
292     m_idler->LogConstraintViolations();
293     for (size_t i = 0; i < m_suspensions.size(); i++) {
294         GetLog() << "SUSPENSION #" << i << " constraint violations\n";
295         m_suspensions[i]->LogConstraintViolations();
296     }
297     for (size_t i = 0; i < m_rollers.size(); i++) {
298         GetLog() << "ROLLER #" << i << " constraint violations\n";
299         m_rollers[i]->LogConstraintViolations();
300     }
301 }
302 
303 }  // end namespace vehicle
304 }  // end namespace chrono
305