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: Conlain Kelly
13 // =============================================================================
14 //
15 // Parser utility class for OpenSim input files.
16 //
17 // =============================================================================
18 
19 #ifndef CH_PARSER_OPENSIM_H
20 #define CH_PARSER_OPENSIM_H
21 
22 #include <functional>
23 #include <map>
24 
25 #include "chrono/core/ChApiCE.h"
26 #include "chrono/physics/ChBodyAuxRef.h"
27 #include "chrono/physics/ChLoadContainer.h"
28 #include "chrono/physics/ChLoadsBody.h"
29 #include "chrono/physics/ChSystem.h"
30 
31 #include "chrono_thirdparty/rapidxml/rapidxml.hpp"
32 
33 namespace chrono {
34 
35 namespace utils {
36 
37 /// @addtogroup chrono_utils
38 /// @{
39 
40 /// OpenSim input file parser.
41 class ChApi ChParserOpenSim {
42   public:
43     enum VisType { PRIMITIVES, MESH, NONE };
44 
45     /// Report containing information about objects parsed from file
46     class ChApi Report {
47       public:
48         /// Information about a joint read in from OpenSim.
49         struct JointInfo {
50             std::string type;               ///< joint type as shown in osim file
51             std::shared_ptr<ChLink> joint;  ///< Chrono link (joint)
52             bool standin;                   ///< true if OpenSim joint replaced with spherical
53         };
54 
55         /// Information about a custom load created from OpenSim.
56         struct ForceInfo {
57             std::string type;                  ///< load type as shown in osim file
58             std::shared_ptr<ChLoadBase> load;  ///< Chrono load object
59         };
60 
61         std::unordered_map<std::string, std::shared_ptr<ChBodyAuxRef>> bodies;  ///< list of body information
62         std::unordered_map<std::string, JointInfo> joints;                      ///< list of joint information
63         std::unordered_map<std::string, ForceInfo> forces;                      ///< list of force information
64 
65         /// Print information on all modeling elements parsed from osim file.
66         void Print() const;
67 
68         /// Get a handle to the body with specified name.
69         /// If none exists, an empty shared pointer is returned.
70         /// Note that all bodies created by the parser are of type ChBodyAuxRef
71         /// (i.e., using a non-centroidal reference frame).
72         std::shared_ptr<ChBodyAuxRef> GetBody(const std::string& name) const;
73 
74         /// Get a handle to the joint with specified name.
75         /// If none exists, an empty shared pointer is returned.
76         /// The caller may need to downcast to the appropriate type.
77         std::shared_ptr<ChLink> GetJoint(const std::string& name) const;
78 
79         /// Get a handle to the force element with specified name.
80         /// If none exists, an empty shared pointer is returned.
81         /// The caller may need to downcast to the appropriate type.
82         std::shared_ptr<ChLoadBase> GetForce(const std::string& name) const;
83     };
84 
85     ChParserOpenSim();
~ChParserOpenSim()86     ~ChParserOpenSim() {}
87 
88     /// Set coefficient of friction.
89     /// The default value is 0.6
SetContactFrictionCoefficient(float friction_coefficient)90     void SetContactFrictionCoefficient(float friction_coefficient) { m_friction = friction_coefficient; }
91 
92     /// Set coefficient of restitution.
93     /// The default value is 0.4
SetContactRestitutionCoefficient(float restitution_coefficient)94     void SetContactRestitutionCoefficient(float restitution_coefficient) { m_restitution = restitution_coefficient; }
95 
96     /// Set contact material properties.
97     /// These values are used to calculate contact material coefficients (if the containing
98     /// system is so configured and if the SMC contact method is being used).
99     /// The default values are: Y = 2e5 and nu = 0.3
100     void SetContactMaterialProperties(float young_modulus,  ///< [in] Young's modulus of elasticity
101                                       float poisson_ratio   ///< [in] Poisson ratio
102     );
103 
104     /// Set contact material coefficients.
105     /// These values are used directly to compute contact forces (if the containing system
106     /// is so configured and if the SMC contact method is being used).
107     /// The default values are: kn=2e5, gn=40, kt=2e5, gt=20
108     void SetContactMaterialCoefficients(float kn,  ///< [in] normal contact stiffness
109                                         float gn,  ///< [in] normal contact damping
110                                         float kt,  ///< [in] tangential contact stiffness
111                                         float gt   ///< [in] tangential contact damping
112     );
113 
114     /// Enable collision between bodies in this model (default: false).
SetCollide(bool val)115     void SetCollide(bool val) { m_collide = val; }
116 
117     /// Set collision families (to disable collision between a body and its parent).
118     /// Note: automaticaly enables collision.
119     void SetCollisionFamilies(int family_1 = 1,  ///< [in] first collision family
120                               int family_2 = 2   ///< [in] second collision family
121     );
122 
123     /// Set body visualization type (default: NONE).
SetVisualizationType(VisType val)124     void SetVisualizationType(VisType val) { m_visType = val; }
125 
126     /// Enable/disable verbose parsing output (default: false).
SetVerbose(bool val)127     void SetVerbose(bool val) { m_verbose = val; }
128 
129     /// Activate actuators.
130     /// By default, any actuator read in from the osim file is inactive (zero excitation).
131     /// If enabled, all actuators will receive a constant excitation function with value 1.
132     /// The excitation function for an actuator can be specified, after parsing,
133     /// using SetExcitationFunction().
ActivateActuators(bool val)134     void ActivateActuators(bool val) { m_activate_actuators = val; }
135 
136     /// Parse the specified OpenSim input file and create the model in the given system.
137     void Parse(ChSystem& system,            ///< [in] containing Chrono system
138                const std::string& filename  ///< [in] OpenSim input file name
139     );
140 
141     /// Parse the specified OpenSim input file and create the model in a new system.
142     /// Note that the created system is not deleted in the parser's destructor;
143     /// rather, ownership is transferred to the caller.
144     ChSystem* Parse(const std::string& filename,                           ///< [in] OpenSim input file name
145                     ChContactMethod contact_method = ChContactMethod::NSC  ///< [in] contact method
146     );
147 
148     /// Get the report for this parser.
149     /// This contains the lists of bodies, joints, and forces that were created from the input osim file.
GetReport()150     const Report& GetReport() const { return m_report; }
151 
152     /// Print the parser's report.
PrintReport()153     void PrintReport() const { m_report.Print(); }
154 
155     /// Set excitation function for the actuator with the specified name.
156     /// This method should be invoked only after parsing an osim file.
157     void SetExcitationFunction(const std::string& name, std::shared_ptr<ChFunction> modulation);
158 
159   private:
160     /// Setup lambda table for body parsing
161     void initFunctionTable();
162     Report m_report;
163 
164     /// Creates load object and parses its various properties from its XML child nodes
165     bool parseForce(rapidxml::xml_node<>* bodyNode, ChSystem& system, std::shared_ptr<ChLoadContainer> container);
166 
167     /// Creates body and parses its various properties from its XML child nodes
168     bool parseBody(rapidxml::xml_node<>* bodyNode, ChSystem& system);
169 
170     // Initializes visualization shapes for bodies connected to each link
171     void initShapes(rapidxml::xml_node<>* node, ChSystem& system);
172 
173     // Get an STL vector from a string, used to make the xml parsing cleaner
174     template <typename T>
strToSTLVector(const char * string)175     static inline std::vector<T> strToSTLVector(const char* string) {
176         std::istringstream buf(string);
177         std::istream_iterator<T> beg(buf), end;
178         return std::vector<T>(beg, end);
179     }
180 
181     // Convert a space-delimited string into a ChVector
182     template <typename T>
strToChVector(const char * string)183     static inline ChVector<T> strToChVector(const char* string) {
184         auto elems = strToSTLVector<T>(string);
185         return ChVector<T>(elems.at(0), elems.at(1), elems.at(2));
186     }
187 
stringStripCStr(const char * c_str)188     static inline std::string stringStripCStr(const char* c_str) {
189         std::string str(c_str);
190         str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
191         return str;
192     }
193 
194     // Convert a lowercase string to a boolean
CStrToBool(const char * string)195     static inline bool CStrToBool(const char* string) { return stringStripCStr(string) == std::string("true"); }
196 
197     // Maps child fields of a body node to functions that handle said fields
198     std::map<std::string, std::function<void(rapidxml::xml_node<>*, std::shared_ptr<ChBodyAuxRef>)>> function_table;
199 
200     bool m_verbose;             ///< verbose output
201     VisType m_visType;          ///< body visualization type
202     bool m_collide;             ///< do bodies have collision shapes?
203     int m_family_1;             ///< first collision family
204     int m_family_2;             ///< second collision family
205     bool m_activate_actuators;  ///< are actuators activated at construction?
206 
207     float m_friction;        ///< contact coefficient of friction
208     float m_restitution;     ///< contact coefficient of restitution
209     float m_young_modulus;   ///< contact material Young modulus
210     float m_poisson_ratio;   ///< contact material Poisson ratio
211     float m_kn;              ///< normal contact stiffness
212     float m_gn;              ///< normal contact damping
213     float m_kt;              ///< tangential contact stiffness
214     float m_gt;              ///< tangential contact damping
215     std::string m_datapath;  ///< path to find visualization meshes, default is "opensim"
216 
217     // List of joints in model (loaded in order of outward, base-to-tip, traversal)
218     std::vector<std::shared_ptr<ChLink>> m_jointList;
219 };
220 
221 /// @} chrono_utils
222 
223 }  // end namespace utils
224 }  // end namespace chrono
225 
226 #endif
227