SimMjcf.cpp
Go to the documentation of this file.
1#include "SimMjcf.h"
2
3#include <VirtualRobot/CollisionDetection/CollisionModel.h>
4#include <VirtualRobot/Visualization/TriMeshModel.h>
5#include <VirtualRobot/Visualization/VisualizationNode.h>
6#include <VirtualRobot/XML/mujoco/Mesh.h>
7#include <VirtualRobot/XML/mujoco/MeshConverter.h>
8#include <VirtualRobot/math/Helpers.h>
9
11
12#include "LengthScaling.h"
13
14
15using namespace armarx;
16
17SimMJCF::SimMJCF(mjcf::Document& document,
18 const LengthScaling& lengthScaling,
19 const std::string& loggingTag) :
20 document(document), scaling(lengthScaling)
21{
22 Logging::setTag(loggingTag);
23}
24
25void
26SimMJCF::includeBaseFile(const std::string& path, const std::string& relativeFrom)
27{
28 std::string absolute = path;
29 ArmarXDataPath::getAbsolutePath(path, absolute);
30
31 std::filesystem::path absol = absolute;
32 absol.relative_path();
33
34 if (std::filesystem::exists(absolute))
35 {
36 std::string relative = ArmarXDataPath::relativeTo(relativeFrom, absolute);
37 document.addInclude(relative);
38 }
39 else
40 {
41 ARMARX_WARNING << "Base MJCF file does not exist: " << absolute
42 << "\nProceeding without including the base MJCF.";
43 }
44}
45
46void
47SimMJCF::addObjectDefaults(const std::string& className)
48{
49 mjcf::DefaultClass objectClass = document.default_().getClass(className);
50
51 mjcf::Geom geom = objectClass.addChild<mjcf::Geom>();
52 geom.rgba = Eigen::Vector4f::Ones();
53
54 mjcf::Joint joint = objectClass.addChild<mjcf::Joint>();
55 joint.frictionloss = 1;
56
57 mjcf::Mesh mesh = objectClass.addChild<mjcf::Mesh>();
58 mesh.scale = scaling.milliToMeter(Eigen::Vector3f::Ones().eval());
59}
60
61void
62SimMJCF::setTimeStep(float timestep)
63{
64 document.option().timestep = timestep;
65}
66
67void
68SimMJCF::addFloor(bool enabled, const std::string& texture, const std::string& name, float size)
69{
70 if (enabled)
71 {
72 ARMARX_INFO << "Adding floor (texture: " << texture << ")";
73
74 // add default class
75 mjcf::DefaultClass defaults = document.default_().getClass(name);
76 mjcf::Geom defaultGeom = defaults.addChild<mjcf::Geom>();
77 defaultGeom.type = "plane";
78 defaultGeom.size = Eigen::Vector3f(size, size, 5);
79 defaultGeom.material = name;
80
81 // add texture
82 bool addDefaultTexture = true;
83
84 if (!texture.empty())
85 {
86 std::string absolute = texture;
87 ArmarXDataPath::getAbsolutePath(texture, absolute);
88
89 if (std::filesystem::exists(absolute))
90 {
91 document.asset().addTextureFile(name, absolute);
92 addDefaultTexture = false;
93 }
94 else
95 {
96 ARMARX_WARNING << "Texture file does not exist: " << absolute
97 << "\nProceeding with generated floor texture";
98 }
99 }
100 if (addDefaultTexture)
101 {
102 mjcf::Texture texture = document.asset().addChild<mjcf::Texture>();
103 texture.name = name;
104 texture.type = "2d";
105 texture.builtin = "checker";
106 texture.width = 512;
107 texture.height = 512;
108 texture.rgb1 = {.35f, .375f, .4f};
109 texture.rgb2 = {.10f, .150f, .2f};
110 }
111
112 // add material
113 mjcf::Material material = document.asset().addMaterial(name, name);
114 material.reflectance = 0.3f;
115 material.texrepeat = {1, 1};
116 material.texuniform = true;
117
118 // add body and geom
119 mjcf::Body body = document.worldbody().addBody(name);
120 body.childclass = name;
121
122 mjcf::Geom geom = body.addChild<mjcf::Geom>();
123 geom.name = name;
124 geom.pos = Eigen::Vector3f::Zero();
125 }
126}
127
128void
129SimMJCF::addObject(VirtualRobot::SceneObjectPtr object,
130 VirtualRobot::SceneObject::Physics::SimulationType simType,
131 const std::string& className,
132 const std::filesystem::path& meshDir)
133{
134 const std::string objectName = object->getName();
135
136 if (object->getParent())
137 {
138 ARMARX_WARNING << "Object has parent, which is currently not implemented.";
139 }
140
141 std::string meshName;
142
143 if (false && object->getVisualization())
144 {
145 ARMARX_INFO << "Has visualization";
146 ARMARX_INFO << "Visu filename: " << object->getVisualization()->getFilename();
147 ARMARX_INFO << "Num faces: " << object->getVisualization()->getNumFaces();
148 ARMARX_INFO << "Has tri mesh?: "
149 << object->getVisualization()->getTriMeshModel().operator bool();
150 ARMARX_INFO << "Primitives: " << object->getVisualization()->primitives.size();
151 }
152
153 if (object->getCollisionModel())
154 {
155 VirtualRobot::CollisionModelPtr collisionModel = object->getCollisionModel();
156
157 const std::string colModelName = collisionModel->getName();
158
159 const std::string filename = colModelName + ".msh";
160 const std::filesystem::path meshFilePath = meshDir / filename;
161
162 try
163 {
164 // does nothing if already exists
165 std::filesystem::create_directory(meshDir);
166 }
167 catch (const std::filesystem::filesystem_error& e)
168 {
169 ARMARX_ERROR << "Could not create temporary mesh dir " << meshDir << "."
170 << "\nReason: " << e.what();
171 }
172
173 if (std::filesystem::is_regular_file(meshFilePath))
174 {
175 ARMARX_VERBOSE << "Collision model " << colModelName << " already converted.";
176 }
177 else
178 {
179 VirtualRobot::TriMeshModelPtr meshModel = collisionModel->getTriMeshModel();
180 if (meshModel)
181 {
182 ARMARX_VERBOSE << "Converting collision model " << colModelName << " ("
183 << meshModel->faces.size() << " faces) ...";
184
185 VirtualRobot::mujoco::Mesh mjMesh =
186 VirtualRobot::mujoco::MeshConverter::fromVirtualRobot(*meshModel);
187 mjMesh.write(meshFilePath.string());
188 }
189 }
190
191 meshName = colModelName;
192
193 // add the mesh as asset
194 if (!document.asset().hasChild<mjcf::Mesh>("name", meshName))
195 {
196 mjcf::Mesh mesh = document.asset().addMesh(meshName, meshFilePath.string());
197 mesh.class_ = className;
198 }
199 }
200
201 mjcf::Body body = document.worldbody().addBody(objectName);
202 body.childclass = className;
203 body.pos = scaling.milliToMeter(math::Helpers::Position(object->getGlobalPose()).eval());
204 body.quat = Eigen::Quaternionf(math::Helpers::Orientation(object->getGlobalPose()));
205
206 mjcf::Geom geom = body.addGeomMesh(meshName);
207 geom.name = objectName;
208
209 if (object->getFriction() > 0)
210 {
211 Eigen::Vector3f friction = geom.friction;
212 friction(0) = object->getFriction();
213 geom.friction = friction;
214 }
215
216 mjcf::Inertial inertial = body.addInertial();
217 inertial.mass = object->getMass();
218 inertial.pos = scaling.milliToMeter(object->getCoMLocal());
219 inertial.inertiaFromMatrix(object->getInertiaMatrix());
220
221 switch (simType)
222 {
223 case VirtualRobot::SceneObject::Physics::SimulationType::eKinematic:
224 // make it a mocap body
225 body.mocap = true;
226 break;
227
228 case VirtualRobot::SceneObject::Physics::SimulationType::eDynamic:
229 // add free joint
230 {
231 mjcf::Joint joint = body.addJoint();
232 joint.name = objectName;
233 joint.type = "free";
234 }
235 break;
236
237 case VirtualRobot::SceneObject::Physics::SimulationType::eStatic:
238 case VirtualRobot::SceneObject::Physics::SimulationType::eUnknown:
239 // do nothing
240 break;
241 }
242}
static std::string relativeTo(const std::string &from, const std::string &to)
Transform an absolute filepath into a relative path of the other absolute filepath.
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
void setTag(const LogTag &tag)
Definition Logging.cpp:54
void addObject(VirtualRobot::SceneObjectPtr object, VirtualRobot::SceneObject::Physics::SimulationType simType, const std::string &className, const std::filesystem::path &meshDir)
Definition SimMjcf.cpp:129
void includeBaseFile(const std::string &path, const std::string &relativeFrom)
Definition SimMjcf.cpp:26
void setTimeStep(float timestep)
Definition SimMjcf.cpp:62
SimMJCF(mjcf::Document &document, const LengthScaling &scaling, const std::string &loggingTag="SimMJCF")
Definition SimMjcf.cpp:17
void addObjectDefaults(const std::string &className)
Definition SimMjcf.cpp:47
void addFloor(bool enabled, const std::string &texture, const std::string &name, float size)
Definition SimMjcf.cpp:68
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
Quaternion< float, 0 > Quaternionf
This file offers overloads of toIce() and fromIce() functions for STL container types.