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: Alessandro Tasora, Radu Serban
13 // =============================================================================
14 //
15 // HMMWV Reissner-shell tire subsystem
16 //
17 // =============================================================================
18 
19 #include "chrono/core/ChCubicSpline.h"
20 #include "chrono_models/vehicle/hmmwv/HMMWV_ReissnerTire.h"
21 
22 using namespace chrono::fea;
23 
24 namespace chrono {
25 namespace vehicle {
26 namespace hmmwv {
27 
28 // -----------------------------------------------------------------------------
29 // Static variables
30 // -----------------------------------------------------------------------------
31 const double HMMWV_ReissnerTire::m_tire_radius = 0.4673;
32 const double HMMWV_ReissnerTire::m_rim_radius = 0.2683;
33 const double HMMWV_ReissnerTire::m_rim_width = 0.254;
34 
35 const double HMMWV_ReissnerTire::m_alpha = 0.005;
36 const double HMMWV_ReissnerTire::m_default_pressure = 200e3;
37 
38 const double HMMWV_ReissnerTire::m_rho_0 = 0.1e4;
39 const ChVector<> HMMWV_ReissnerTire::m_E_0(0.756e10, 0.474e8, 0.474e8);
40 const double HMMWV_ReissnerTire::m_nu_0 = 0.45;
41 const ChVector<> HMMWV_ReissnerTire::m_G_0(0.1634e8, 0.1634e8, 0.1634e8);
42 const double HMMWV_ReissnerTire::m_rho_1 = 0.2639e4;
43 const ChVector<> HMMWV_ReissnerTire::m_E_1(0.18e12, 0.474e8, 0.474e8);
44 const double HMMWV_ReissnerTire::m_nu_1 = 0.45;
45 const ChVector<> HMMWV_ReissnerTire::m_G_1(0.1634e8, 0.1634e8, 0.1634e8);
46 const double HMMWV_ReissnerTire::m_rho_2 = 0.11e4;
47 const ChVector<> HMMWV_ReissnerTire::m_E_2(0.474e8, 0.474e8, 0.474e8);
48 const double HMMWV_ReissnerTire::m_nu_2 = 0.45;
49 const ChVector<> HMMWV_ReissnerTire::m_G_2(0.1634e8, 0.1634e8, 0.1634e8);
50 
51 const unsigned int HMMWV_ReissnerTire::m_num_elements_bead = 2;
52 const unsigned int HMMWV_ReissnerTire::m_num_layers_bead = 3;
53 const std::vector<double> HMMWV_ReissnerTire::m_layer_thickness_bead{{0.5e-03, 0.5e-02, 0.5e-03}};
54 const std::vector<double> HMMWV_ReissnerTire::m_ply_angle_bead{{90, 0, 90}};
55 const std::vector<int> HMMWV_ReissnerTire::m_material_id_bead{{0, 2, 0}};
56 
57 const unsigned int HMMWV_ReissnerTire::m_num_elements_sidewall = 4;
58 const unsigned int HMMWV_ReissnerTire::m_num_layers_sidewall = 3;
59 const std::vector<double> HMMWV_ReissnerTire::m_layer_thickness_sidewall{{0.5e-03, 0.1e-03, 0.5e-03}};
60 const std::vector<double> HMMWV_ReissnerTire::m_ply_angle_sidewall{{90, 0, 90}};
61 const std::vector<int> HMMWV_ReissnerTire::m_material_id_sidewall{{0, 2, 0}};
62 
63 const unsigned int HMMWV_ReissnerTire::m_num_elements_tread = 6;
64 const unsigned int HMMWV_ReissnerTire::m_num_layers_tread = 4;
65 const std::vector<double> HMMWV_ReissnerTire::m_layer_thickness_tread{{0.1e-02, 0.3e-03, 0.3e-03, 0.5e-03}};
66 const std::vector<double> HMMWV_ReissnerTire::m_ply_angle_tread{{0, -20, 20, 90}};
67 const std::vector<int> HMMWV_ReissnerTire::m_material_id_tread{{2, 1, 1, 0}};
68 
69 const int HMMWV_ReissnerTire::m_div_circumference = 90;
70 
71 const float HMMWV_ReissnerTire::m_friction = 0.9f;
72 const float HMMWV_ReissnerTire::m_restitution = 0.1f;
73 const float HMMWV_ReissnerTire::m_Young = 2.0e6f;
74 const float HMMWV_ReissnerTire::m_Poisson = 0.3f;
75 const float HMMWV_ReissnerTire::m_kn = 2.0e6f;
76 const float HMMWV_ReissnerTire::m_gn = 1.3e1f;
77 const float HMMWV_ReissnerTire::m_kt = 1.0e6f;
78 const float HMMWV_ReissnerTire::m_gt = 0;
79 
80 const unsigned int HMMWV_ReissnerTire::m_num_points = 71;
81 const double HMMWV_ReissnerTire::m_profile[71][3] = {
82     {0.000000E+00, 0.000000E+00, -1.150000E-01}, {1.428571E-02, 1.166670E-02, -1.164180E-01},
83     {2.857143E-02, 2.333330E-02, -1.192300E-01}, {4.285714E-02, 3.500000E-02, -1.230200E-01},
84     {5.714286E-02, 4.666670E-02, -1.273710E-01}, {7.142857E-02, 5.833330E-02, -1.318700E-01},
85     {8.571429E-02, 7.000000E-02, -1.361330E-01}, {1.000000E-01, 8.166670E-02, -1.399910E-01},
86     {1.142857E-01, 9.333330E-02, -1.433510E-01}, {1.285714E-01, 1.050000E-01, -1.461240E-01},
87     {1.428571E-01, 1.166670E-01, -1.482160E-01}, {1.571429E-01, 1.283330E-01, -1.495390E-01},
88     {1.714286E-01, 1.400000E-01, -1.500000E-01}, {1.857143E-01, 1.475000E-01, -1.486380E-01},
89     {2.000000E-01, 1.550000E-01, -1.457860E-01}, {2.142857E-01, 1.625000E-01, -1.419760E-01},
90     {2.285714E-01, 1.700000E-01, -1.360000E-01}, {2.428571E-01, 1.768970E-01, -1.288420E-01},
91     {2.571429E-01, 1.831090E-01, -1.216840E-01}, {2.714286E-01, 1.883940E-01, -1.145260E-01},
92     {2.857143E-01, 1.925100E-01, -1.073680E-01}, {3.000000E-01, 1.953230E-01, -1.002110E-01},
93     {3.142857E-01, 1.970380E-01, -9.305260E-02}, {3.285714E-01, 1.979260E-01, -8.589470E-02},
94     {3.428571E-01, 1.982580E-01, -7.873680E-02}, {3.571429E-01, 1.983020E-01, -7.157890E-02},
95     {3.714286E-01, 1.983090E-01, -6.442110E-02}, {3.857143E-01, 1.983540E-01, -5.726320E-02},
96     {4.000000E-01, 1.984290E-01, -5.010530E-02}, {4.142857E-01, 1.985240E-01, -4.294740E-02},
97     {4.285714E-01, 1.986300E-01, -3.578950E-02}, {4.428571E-01, 1.987380E-01, -2.863160E-02},
98     {4.571429E-01, 1.988390E-01, -2.147370E-02}, {4.714286E-01, 1.989220E-01, -1.431580E-02},
99     {4.857143E-01, 1.989790E-01, -7.157890E-03}, {5.000000E-01, 1.990000E-01, 0.000000E+00},
100     {5.142857E-01, 1.989790E-01, 7.157890E-03},  {5.285714E-01, 1.989220E-01, 1.431580E-02},
101     {5.428571E-01, 1.988390E-01, 2.147370E-02},  {5.571429E-01, 1.987380E-01, 2.863160E-02},
102     {5.714286E-01, 1.986300E-01, 3.578950E-02},  {5.857143E-01, 1.985240E-01, 4.294740E-02},
103     {6.000000E-01, 1.984290E-01, 5.010530E-02},  {6.142857E-01, 1.983540E-01, 5.726320E-02},
104     {6.285714E-01, 1.983090E-01, 6.442110E-02},  {6.428571E-01, 1.983020E-01, 7.157890E-02},
105     {6.571429E-01, 1.982580E-01, 7.873680E-02},  {6.714286E-01, 1.979260E-01, 8.589470E-02},
106     {6.857143E-01, 1.970380E-01, 9.305260E-02},  {7.000000E-01, 1.953230E-01, 1.002110E-01},
107     {7.142857E-01, 1.925100E-01, 1.073680E-01},  {7.285714E-01, 1.883940E-01, 1.145260E-01},
108     {7.428571E-01, 1.831090E-01, 1.216840E-01},  {7.571429E-01, 1.768970E-01, 1.288420E-01},
109     {7.714286E-01, 1.700000E-01, 1.360000E-01},  {7.857143E-01, 1.625000E-01, 1.419760E-01},
110     {8.000000E-01, 1.550000E-01, 1.457860E-01},  {8.142857E-01, 1.475000E-01, 1.486380E-01},
111     {8.285714E-01, 1.400000E-01, 1.500000E-01},  {8.428571E-01, 1.283330E-01, 1.495390E-01},
112     {8.571429E-01, 1.166670E-01, 1.482160E-01},  {8.714286E-01, 1.050000E-01, 1.461240E-01},
113     {8.857143E-01, 9.333330E-02, 1.433510E-01},  {9.000000E-01, 8.166670E-02, 1.399910E-01},
114     {9.142857E-01, 7.000000E-02, 1.361330E-01},  {9.285714E-01, 5.833330E-02, 1.318700E-01},
115     {9.428571E-01, 4.666670E-02, 1.273710E-01},  {9.571429E-01, 3.500000E-02, 1.230200E-01},
116     {9.714286E-01, 2.333330E-02, 1.192300E-01},  {9.857143E-01, 1.166670E-02, 1.164180E-01},
117     {1.000000E+00, 0.000000E+00, 1.150000E-01}};
118 
119 // -----------------------------------------------------------------------------
120 
HMMWV_ReissnerTire(const std::string & name)121 HMMWV_ReissnerTire::HMMWV_ReissnerTire(const std::string& name) : ChReissnerTire(name) {
122     m_div_width = 2 * (m_num_elements_bead + m_num_elements_sidewall + m_num_elements_tread);
123 
124     // Create the vector of orthotropic layer materials
125     // Initialize with (density, E_x, E_y,nu_xy, Gxy, Gxz, Gyz)
126     m_materials.resize(3);
127     m_materials[0] = chrono_types::make_shared<ChMaterialShellReissnerOrthotropic>(m_rho_0, m_E_0.x(), m_E_0.y(), m_nu_0, m_G_0.x(), m_G_0.y(), m_G_0.z());
128     m_materials[1] = chrono_types::make_shared<ChMaterialShellReissnerOrthotropic>(m_rho_1, m_E_1.x(), m_E_1.y(), m_nu_1, m_G_1.x(), m_G_1.y(), m_G_1.z());
129     m_materials[2] = chrono_types::make_shared<ChMaterialShellReissnerOrthotropic>(m_rho_2, m_E_2.x(), m_E_2.y(), m_nu_2, m_G_2.x(), m_G_2.y(), m_G_2.z());
130 
131 	auto mdamping = chrono_types::make_shared<ChDampingReissnerRayleigh>(m_materials[0]->GetElasticity(),m_alpha);
132 	m_materials[0]->SetDamping(mdamping);
133 	mdamping = chrono_types::make_shared<ChDampingReissnerRayleigh>(m_materials[1]->GetElasticity(),m_alpha);
134 	m_materials[1]->SetDamping(mdamping);
135 	mdamping = chrono_types::make_shared<ChDampingReissnerRayleigh>(m_materials[2]->GetElasticity(),m_alpha);
136 	m_materials[2]->SetDamping(mdamping);
137 
138     // Set the profile
139     m_profile_t.resize(m_num_points);
140     m_profile_x.resize(m_num_points);
141     m_profile_y.resize(m_num_points);
142     for (unsigned int i = 0; i < m_num_points; i++) {
143         m_profile_t[i] = m_profile[i][0];
144         m_profile_x[i] = m_profile[i][1];
145         m_profile_y[i] = m_profile[i][2];
146     }
147 }
148 
CreateMesh(const ChFrameMoving<> & wheel_frame,VehicleSide side)149 void HMMWV_ReissnerTire::CreateMesh(const ChFrameMoving<>& wheel_frame, VehicleSide side) {
150     // Create piece-wise cubic spline approximation of the tire profile.
151     //   x - radial direction
152     //   y - transversal direction
153     ChCubicSpline splineX(m_profile_t, m_profile_x);
154     ChCubicSpline splineY(m_profile_t, m_profile_y);
155 
156     // Create the mesh nodes.
157     // The nodes are first created in the wheel local frame, assuming Y as the tire axis,
158     // and are then transformed to the global frame.
159     for (int i = 0; i < m_div_circumference; i++) {
160         double phi = (CH_C_2PI * i) / m_div_circumference;
161         ChVector<> nrm(-std::sin(phi), 0, std::cos(phi));
162 
163         for (int j = 0; j <= m_div_width; j++) {
164             double t_prf = double(j) / m_div_width;
165             double x_prf, xp_prf, xpp_prf;
166             double y_prf, yp_prf, ypp_prf;
167             splineX.Evaluate(t_prf, x_prf, xp_prf, xpp_prf);
168             splineY.Evaluate(t_prf, y_prf, yp_prf, ypp_prf);
169 
170             // Node position with respect to rim center
171             double x = (m_rim_radius + x_prf) * std::cos(phi);
172             double y = y_prf;
173             double z = (m_rim_radius + x_prf) * std::sin(phi);
174             // Node position in global frame (actual coordinate values)
175             ChVector<> loc = wheel_frame.TransformPointLocalToParent(ChVector<>(x, y, z));
176 
177             // Node direction
178             ChVector<> tan_prf(std::cos(phi) * xp_prf, yp_prf, std::sin(phi) * xp_prf);
179             ChVector<> nrm_prf = Vcross(tan_prf, nrm).GetNormalized();
180             ChMatrix33<> mrot; mrot.Set_A_Xdir(tan_prf,nrm_prf);
181             auto node = chrono_types::make_shared<ChNodeFEAxyzrot>(ChFrame<>(loc, mrot));
182 
183             // Node velocity
184             ChVector<> vel = wheel_frame.PointSpeedLocalToParent(ChVector<>(x, y, z));
185             node->SetPos_dt(vel);
186             node->SetMass(0);
187             m_mesh->AddNode(node);
188         }
189     }
190 
191     // Create the Reissner shell elements
192     for (int i = 0; i < m_div_circumference; i++) {
193         for (int j = 0; j < m_div_width; j++) {
194             // Adjacent nodes
195             int inode0, inode1, inode2, inode3;
196             inode1 = j + i * (m_div_width + 1);
197             inode2 = j + 1 + i * (m_div_width + 1);
198             if (i == m_div_circumference - 1) {
199                 inode0 = j;
200                 inode3 = j + 1;
201             } else {
202                 inode0 = j + (i + 1) * (m_div_width + 1);
203                 inode3 = j + 1 + (i + 1) * (m_div_width + 1);
204             }
205 
206             auto node0 = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(m_mesh->GetNode(inode0));
207             auto node1 = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(m_mesh->GetNode(inode1));
208             auto node2 = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(m_mesh->GetNode(inode2));
209             auto node3 = std::dynamic_pointer_cast<ChNodeFEAxyzrot>(m_mesh->GetNode(inode3));
210 
211             // Create the element and set its nodes.
212             auto element = chrono_types::make_shared<ChElementShellReissner4>();
213             element->SetNodes(node0, node1, node2, node3);
214 
215             // Figure out the section for this element
216             int b1 = m_num_elements_bead;
217             int b2 = m_div_width - m_num_elements_bead;
218             int s1 = b1 + m_num_elements_sidewall;
219             int s2 = b2 - m_num_elements_sidewall;
220             if (j < b1 || j >= b2) {
221                 // Bead section
222                 for (unsigned int im = 0; im < m_num_layers_bead; im++) {
223                     element->AddLayer(m_layer_thickness_bead[im], CH_C_DEG_TO_RAD * m_ply_angle_bead[im],
224                                       m_materials[m_material_id_bead[im]]);
225                 }
226             } else if (j < s1 || j >= s2) {
227                 // Sidewall section
228                 for (unsigned int im = 0; im < m_num_layers_sidewall; im++) {
229                     element->AddLayer(m_layer_thickness_sidewall[im], CH_C_DEG_TO_RAD * m_ply_angle_sidewall[im],
230                                       m_materials[m_material_id_sidewall[im]]);
231                 }
232             } else {
233                 // Tread section
234                 for (unsigned int im = 0; im < m_num_layers_tread; im++) {
235                     element->AddLayer(m_layer_thickness_tread[im], CH_C_DEG_TO_RAD * m_ply_angle_tread[im],
236                                       m_materials[m_material_id_tread[im]]);
237                 }
238             }
239 
240             // Add element to mesh
241             m_mesh->AddElement(element);
242         }
243     }
244 
245     // Switch on automatic gravity
246     m_mesh->SetAutomaticGravity(true);
247 }
248 
GetConnectedNodes() const249 std::vector<std::shared_ptr<fea::ChNodeFEAbase>> HMMWV_ReissnerTire::GetConnectedNodes() const {
250     std::vector<std::shared_ptr<fea::ChNodeFEAbase>> nodes;
251 
252     for (int i = 0; i < m_div_circumference; i++) {
253         for (int j = 0; j <= m_div_width; j++) {
254             int index = j + i * (m_div_width + 1);
255             if (index % (m_div_width + 1) == 0) {
256                 nodes.push_back(std::dynamic_pointer_cast<fea::ChNodeFEAbase>(m_mesh->GetNode(index)));
257                 nodes.push_back(std::dynamic_pointer_cast<fea::ChNodeFEAbase>(m_mesh->GetNode(index + m_div_width)));
258             }
259         }
260     }
261 
262     return nodes;
263 }
264 
CreateContactMaterial()265 void HMMWV_ReissnerTire::CreateContactMaterial() {
266     m_contact_mat = chrono_types::make_shared<ChMaterialSurfaceSMC>();
267     m_contact_mat->SetFriction(m_friction);
268     m_contact_mat->SetRestitution(m_restitution);
269     m_contact_mat->SetYoungModulus(m_Young);
270     m_contact_mat->SetPoissonRatio(m_Poisson);
271     m_contact_mat->SetKn(m_kn);
272     m_contact_mat->SetGn(m_gn);
273     m_contact_mat->SetKt(m_kt);
274     m_contact_mat->SetGt(m_gt);
275 }
276 
277 }  // end namespace hmmwv
278 }  // end namespace vehicle
279 }  // end namespace chrono
280