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