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, Justin Madsen, Daniel Melanz
13 // =============================================================================
14 //
15 // Base class for a double-A arm suspension modeled with bodies and constraints.
16 // Derived from ChSuspension, but still an abstract base class.
17 //
18 // The suspension subsystem is modeled with respect to a right-handed frame,
19 // with X pointing towards the front, Y to the left, and Z up (ISO standard).
20 // The suspension reference frame is assumed to be always aligned with that of
21 // the vehicle.  When attached to a chassis, only an offset is provided.
22 //
23 // All point locations are assumed to be given for the left half of the
24 // suspension and will be mirrored (reflecting the y coordinates) to construct
25 // the right side.
26 //
27 // =============================================================================
28 
29 #ifndef CH_DOUBLEWISHBONE_H
30 #define CH_DOUBLEWISHBONE_H
31 
32 #include <vector>
33 
34 #include "chrono_vehicle/ChApiVehicle.h"
35 #include "chrono_vehicle/wheeled_vehicle/ChSuspension.h"
36 
37 namespace chrono {
38 namespace vehicle {
39 
40 /// @addtogroup vehicle_wheeled_suspension
41 /// @{
42 
43 /// Base class for a double-A arm suspension modeled with bodies and constraints.
44 /// Derived from ChSuspension, but still an abstract base class.
45 ///
46 /// The suspension subsystem is modeled with respect to a right-handed frame,
47 /// with X pointing towards the front, Y to the left, and Z up (ISO standard).
48 /// The suspension reference frame is assumed to be always aligned with that of
49 /// the vehicle.  When attached to a chassis, only an offset is provided.
50 ///
51 /// All point locations are assumed to be given for the left half of the
52 /// suspension and will be mirrored (reflecting the y coordinates) to construct
53 /// the right side.
54 class CH_VEHICLE_API ChDoubleWishbone : public ChSuspension {
55   public:
56     virtual ~ChDoubleWishbone();
57 
58     /// Get the name of the vehicle subsystem template.
GetTemplateName()59     virtual std::string GetTemplateName() const override { return "DoubleWishbone"; }
60 
61     /// Specify whether or not this suspension can be steered.
IsSteerable()62     virtual bool IsSteerable() const final override { return true; }
63 
64     /// Specify whether or not this is an independent suspension.
IsIndependent()65     virtual bool IsIndependent() const final override { return true; }
66 
67     /// Initialize this suspension subsystem.
68     /// The suspension subsystem is initialized by attaching it to the specified chassis and (if provided) to the
69     /// specified subchassis, at the specified location (with respect to and expressed in the reference frame of the
70     /// chassis). It is assumed that the suspension reference frame is always aligned with the chassis reference frame.
71     /// If a steering subsystem is provided, the suspension tierods are to be attached to the steering's central link
72     /// body (steered suspension); otherwise they are to be attached to the chassis (non-steered suspension).
73     virtual void Initialize(
74         std::shared_ptr<ChChassis> chassis,        ///< [in] associated chassis subsystem
75         std::shared_ptr<ChSubchassis> subchassis,  ///< [in] associated subchassis subsystem (may be null)
76         std::shared_ptr<ChSteering> steering,      ///< [in] associated steering subsystem (may be null)
77         const ChVector<>& location,                ///< [in] location relative to the chassis frame
78         double left_ang_vel = 0,                   ///< [in] initial angular velocity of left wheel
79         double right_ang_vel = 0                   ///< [in] initial angular velocity of right wheel
80         ) override;
81 
82     /// Add visualization assets for the suspension subsystem.
83     /// This default implementation uses primitives.
84     virtual void AddVisualizationAssets(VisualizationType vis) override;
85 
86     /// Remove visualization assets for the suspension subsystem.
87     virtual void RemoveVisualizationAssets() override;
88 
89     /// Get the total mass of the suspension subsystem.
90     virtual double GetMass() const override;
91 
92     /// Get the current global COM location of the suspension subsystem.
93     virtual ChVector<> GetCOMPos() const override;
94 
95     /// Get the wheel track for the suspension subsystem.
96     virtual double GetTrack() override;
97 
98     /// Get a handle to the specified spring element.
GetSpring(VehicleSide side)99     std::shared_ptr<ChLinkTSDA> GetSpring(VehicleSide side) const { return m_spring[side]; }
100 
101     /// Get a handle to the specified shock (damper) element.
GetShock(VehicleSide side)102     std::shared_ptr<ChLinkTSDA> GetShock(VehicleSide side) const { return m_shock[side]; }
103 
104     /// Return current suspension forces (spring and shock) on the specified side.
105     virtual ChSuspension::Force ReportSuspensionForce(VehicleSide side) const override;
106 
107     /// Get the force in the spring element.
GetSpringForce(VehicleSide side)108     double GetSpringForce(VehicleSide side) const { return m_spring[side]->GetForce(); }
109 
110     /// Get the current length of the spring element
GetSpringLength(VehicleSide side)111     double GetSpringLength(VehicleSide side) const { return m_spring[side]->GetLength(); }
112 
113     /// Get the current deformation of the spring element.
GetSpringDeformation(VehicleSide side)114     double GetSpringDeformation(VehicleSide side) const { return m_spring[side]->GetDeformation(); }
115 
116     /// Get the force in the shock (damper) element.
GetShockForce(VehicleSide side)117     double GetShockForce(VehicleSide side) const { return m_shock[side]->GetForce(); }
118 
119     /// Get the current length of the shock (damper) element.
GetShockLength(VehicleSide side)120     double GetShockLength(VehicleSide side) const { return m_shock[side]->GetLength(); }
121 
122     /// Get the current deformation velocity of the shock (damper) element.
GetShockVelocity(VehicleSide side)123     double GetShockVelocity(VehicleSide side) const { return m_shock[side]->GetVelocity(); }
124 
125     /// Global coordinates, LCA ball joint position
Get_LCA_sph_pos(VehicleSide side)126     ChVector<> Get_LCA_sph_pos(VehicleSide side) { return m_sphericalLCA[side]->GetPos(); }
127 
128     /// Global coordinates, UCA ball joint position
Get_UCA_sph_pos(VehicleSide side)129     ChVector<> Get_UCA_sph_pos(VehicleSide side) { return m_sphericalUCA[side]->GetPos(); }
130 
131     /// Log current constraint violations.
132     virtual void LogConstraintViolations(VehicleSide side) override;
133 
134     /// Specify the suspension body on the specified side to attach a possible antirollbar subsystem.
135     /// Return the corresponding lower control arm.
GetAntirollBody(VehicleSide side)136     virtual std::shared_ptr<ChBody> GetAntirollBody(VehicleSide side) const override { return m_LCA[side]; }
137 
138     /// Log the locations of all hardpoints.
139     /// The reported locations are expressed in the suspension reference frame.
140     /// By default, these values are reported in SI units (meters), but can be
141     /// optionally reported in inches.
142     void LogHardpointLocations(const ChVector<>& ref, bool inches = false);
143 
144   protected:
145     /// Identifiers for the various hardpoints.
146     enum PointId {
147         SPINDLE,   ///< spindle location
148         UPRIGHT,   ///< upright location
149         UCA_F,     ///< upper control arm, chassis front
150         UCA_B,     ///< upper control arm, chassis back
151         UCA_U,     ///< upper control arm, upright
152         UCA_CM,    ///< upper control arm, center of mass
153         LCA_F,     ///< lower control arm, chassis front
154         LCA_B,     ///< lower control arm, chassis back
155         LCA_U,     ///< lower control arm, upright
156         LCA_CM,    ///< lower control arm, center of mass
157         SHOCK_C,   ///< shock, chassis
158         SHOCK_A,   ///< shock, lower control arm
159         SPRING_C,  ///< spring, chassis
160         SPRING_A,  ///< spring, lower control arm
161         TIEROD_C,  ///< tierod, chassis
162         TIEROD_U,  ///< tierod, upright
163         NUM_POINTS
164     };
165 
166     /// Protected constructor.
167     ChDoubleWishbone(
168         const std::string& name,            ///< [in] name of the subsystem
169         bool vehicle_frame_inertia = false  ///< [in] inertia specified in vehicle-aligned centroidal frames?
170         );
171 
172     /// Indicate whether or not inertia matrices are specified with respect to a
173     /// vehicle-aligned centroidal frame (flag=true) or with respect to the body
174     /// centroidal frame (flag=false).  Note that this function must be called
175     /// before Initialize().
SetVehicleFrameInertiaFlag(bool val)176     void SetVehicleFrameInertiaFlag(bool val) { m_vehicle_frame_inertia = val; }
177 
178     /// Indicate whether or not tirod bodies are modelled (default: false).
179     /// If false, tierods are modelled using distance constraints.
180     /// If true, rigid tierod bodies are created (in which case a derived class must provide the mass and inertia) and
181     /// connected either with kinematic joints or bushings (depending on whether or not bushing data is defined).
UseTierodBodies()182     virtual bool UseTierodBodies() const { return false; }
183 
184     /// Return the location of the specified hardpoint.
185     /// The returned location must be expressed in the suspension reference frame.
186     virtual const ChVector<> getLocation(PointId which) = 0;
187 
188     /// Return the mass of the spindle body.
189     virtual double getSpindleMass() const = 0;
190     /// Return the mass of the upper control arm body.
191     virtual double getUCAMass() const = 0;
192     /// Return the mass of the lower control body.
193     virtual double getLCAMass() const = 0;
194     /// Return the mass of the upright body.
195     virtual double getUprightMass() const = 0;
196     /// Return the mass of the tierod body.
getTierodMass()197     virtual double getTierodMass() const { return 0; }
198 
199     /// Return the moments of inertia of the spindle body.
200     virtual const ChVector<>& getSpindleInertia() const = 0;
201 
202     /// Return the moments of inertia of the upper control arm body.
203     virtual const ChVector<>& getUCAInertiaMoments() const = 0;
204     /// Return the products of inertia of the upper control arm body.
205     virtual const ChVector<>& getUCAInertiaProducts() const = 0;
206 
207     /// Return the moments of inertia of the lower control arm body.
208     virtual const ChVector<>& getLCAInertiaMoments() const = 0;
209     /// Return the products of inertia of the lower control arm body.
210     virtual const ChVector<>& getLCAInertiaProducts() const = 0;
211 
212     /// Return the moments of inertia of the upright body.
213     virtual const ChVector<>& getUprightInertiaMoments() const = 0;
214     /// Return the products of inertia of the upright body.
215     virtual const ChVector<>& getUprightInertiaProducts() const = 0;
216 
217     /// Return the moments of inertia of the tierod body.
getTierodInertia()218     virtual const ChVector<> getTierodInertia() const { return ChVector<>(0); }
219 
220     /// Return the inertia of the axle shaft.
221     virtual double getAxleInertia() const = 0;
222 
223     /// Return the radius of the upper control arm body (visualization only).
224     virtual double getUCARadius() const = 0;
225     /// Return the radius of the lower control arm body (visualization only).
226     virtual double getLCARadius() const = 0;
227     /// Return the radius of the upright body (visualization only).
228     virtual double getUprightRadius() const = 0;
229     /// Return the radius of the tierod body (visualization only).
getTierodRadius()230     virtual double getTierodRadius() const { return 0; }
231 
232     /// Return the free (rest) length of the spring element.
233     virtual double getSpringRestLength() const = 0;
234     /// Return the functor object for spring force.
235     virtual std::shared_ptr<ChLinkTSDA::ForceFunctor> getSpringForceFunctor() const = 0;
236     /// Return the functor object for shock force.
237     virtual std::shared_ptr<ChLinkTSDA::ForceFunctor> getShockForceFunctor() const = 0;
238 
239     /// Return stiffness and damping data for the UCA bushing.
240     /// Returning nullptr (default) results in using a kinematic revolute joint.
getUCABushingData()241     virtual std::shared_ptr<ChVehicleBushingData> getUCABushingData() const { return nullptr; }
242     /// Return stiffness and damping data for the LCA bushing.
243     /// Returning nullptr (default) results in using a kinematic revolute joint.
getLCABushingData()244     virtual std::shared_ptr<ChVehicleBushingData> getLCABushingData() const { return nullptr; }
245     /// Return stiffness and damping data for the tierod bushings.
246     /// Used only if tierod bodies are defined (see UseTierodBody).
247     /// Returning nullptr (default) results in using kinematic joints (spherical + universal).
getTierodBushingData()248     virtual std::shared_ptr<ChVehicleBushingData> getTierodBushingData() const { return nullptr; }
249 
250     std::shared_ptr<ChBody> m_upright[2];  ///< upright bodies (left/right)
251     std::shared_ptr<ChBody> m_UCA[2];      ///< upper control arm bodies (left/right)
252     std::shared_ptr<ChBody> m_LCA[2];      ///< lower control arm bodies (left/right)
253     std::shared_ptr<ChBody> m_tierod[2];   ///< tierod bodies, if used (left/right)
254 
255     std::shared_ptr<ChVehicleJoint> m_revoluteUCA[2];   ///< chassis-UCA revolute joints (left/right)
256     std::shared_ptr<ChVehicleJoint> m_sphericalUCA[2];  ///< upright-UCA spherical joints (left/right)
257     std::shared_ptr<ChVehicleJoint> m_revoluteLCA[2];   ///< chassis-LCA revolute joints (left/right)
258     std::shared_ptr<ChVehicleJoint> m_sphericalLCA[2];  ///< upright-LCA spherical joints (left/right)
259 
260     std::shared_ptr<ChLinkDistance> m_distTierod[2];        ///< tierod distance constraints (left/right)
261     std::shared_ptr<ChVehicleJoint> m_sphericalTierod[2];   ///< tierod-upright spherical joints (left/right)
262     std::shared_ptr<ChVehicleJoint> m_universalTierod[2];   ///< tierod-chassis universal joints (left/right)
263 
264     std::shared_ptr<ChLinkTSDA> m_shock[2];   ///< spring links (left/right)
265     std::shared_ptr<ChLinkTSDA> m_spring[2];  ///< shock links (left/right)
266 
267   private:
268     // Flag indicating that the inertia matrices for the upright and control arms
269     // are provided in vehicle-aligned centroidal frames
270     bool m_vehicle_frame_inertia;
271 
272     // Hardpoint absolute locations
273     std::vector<ChVector<>> m_pointsL;
274     std::vector<ChVector<>> m_pointsR;
275 
276     void InitializeSide(VehicleSide side,
277                         std::shared_ptr<ChChassis> chassis,
278                         std::shared_ptr<ChBody> tierod_body,
279                         const std::vector<ChVector<> >& points,
280                         double ang_vel);
281 
282     static void AddVisualizationControlArm(std::shared_ptr<ChBody> arm,
283                                            const ChVector<> pt_F,
284                                            const ChVector<> pt_B,
285                                            const ChVector<> pt_U,
286                                            double radius);
287     static void AddVisualizationUpright(std::shared_ptr<ChBody> upright,
288                                         const ChVector<> pt_C,
289                                         const ChVector<> pt_U,
290                                         const ChVector<> pt_L,
291                                         const ChVector<> pt_T,
292                                         double radius);
293     static void AddVisualizationTierod(std::shared_ptr<ChBody> tierod,
294                                        const ChVector<> pt_C,
295                                        const ChVector<> pt_U,
296                                        double radius);
297 
298     virtual void ExportComponentList(rapidjson::Document& jsonDocument) const override;
299 
300     virtual void Output(ChVehicleOutput& database) const override;
301 
302     static const std::string m_pointNames[NUM_POINTS];
303 };
304 
305 /// @} vehicle_wheeled_suspension
306 
307 }  // end namespace vehicle
308 }  // end namespace chrono
309 
310 #endif
311