diff --git a/VirtualRobot/XML/mjcf/MujocoIO.cpp b/VirtualRobot/XML/mjcf/MujocoIO.cpp index 0c509df94b72379c0334ca11ffeb0c65282e6846..b69699aa4362d499c3d3e43f8d9378bca7b0e895 100644 --- a/VirtualRobot/XML/mjcf/MujocoIO.cpp +++ b/VirtualRobot/XML/mjcf/MujocoIO.cpp @@ -19,34 +19,29 @@ MujocoIO::MujocoIO() : { } -void MujocoIO::saveMJCF(RobotPtr robot, const std::string& filename, const std::string& basePath, const std::string& meshDir) +void MujocoIO::saveMJCF(RobotPtr robot, + const std::string& filename, const std::string& basePath, + const std::string& meshRelDir) { THROW_VR_EXCEPTION_IF(!robot, "Given RobotPtr robot is null."); THROW_VR_EXCEPTION_IF(filename.empty(), "Given filename is empty."); this->robot = robot; - this->outputDirectory = basePath; - this->outputFileName = filename; - this->outputMeshRelDirectory = meshDir; + + setPaths(filename, basePath, meshRelDir); document.reset(new mjcf::Document()); document->setModelName(robot->getName()); - document->compiler()->SetAttribute("angle", "radian"); - document->compiler()->SetAttribute("balanceinertia", "true"); - - XMLElement* defaultsClass = document->addDefaultsClass(robot->getName()); - std::stringstream ss; - ss << "Add default values for " << robot->getName() << " here."; - defaultsClass->InsertFirstChild(document->NewComment(ss.str().c_str())); + makeCompiler(); + makeDefaultsGroup(); document->setNewElementClass(robot->getName(), true); - - makeEnvironment(); + addSkybox(); std::cout << "Creating bodies structure ..." << std::endl; - addNodeBodies(); + makeNodeBodies(); std::cout << "Adding meshes and geoms ..." << std::endl; addNodeBodyMeshes(); @@ -84,15 +79,55 @@ void MujocoIO::saveMJCF(RobotPtr robot, const std::string& filename, const std:: document->SaveFile((outputDirectory / outputFileName).c_str()); } +void MujocoIO::setPaths(const std::string& filename, const std::string& basePath, const std::string& meshRelDir) +{ + outputDirectory = basePath; + outputFileName = filename; + outputMeshRelDirectory = meshRelDir; + + ensureDirectoriesExist(); +} + +void MujocoIO::ensureDirectoriesExist() +{ + auto ensureDirExists = [](const fs::path& dir, const std::string& errMsgName) + { + if (!fs::is_directory(dir)) + { + std::cout << "Creating directory: " << dir << std::endl; + bool success = fs::create_directories(dir); + THROW_VR_EXCEPTION_IF(!success, "Could not create " << errMsgName << ": " << dir); + } + }; + + ensureDirExists(outputDirectory, "output directory"); + ensureDirExists(outputMeshDirectory(), "output mesh directory"); +} + +void MujocoIO::makeCompiler() +{ + document->compiler()->SetAttribute("angle", "radian"); + document->compiler()->SetAttribute("balanceinertia", "true"); +} -void MujocoIO::makeEnvironment() +void MujocoIO::makeDefaultsGroup() +{ + XMLElement* defaultsClass = document->addDefaultsClass(robot->getName()); + + std::stringstream comment; + comment << "Add default values for " << robot->getName() << " here."; + defaultsClass->InsertFirstChild(document->NewComment(comment.str().c_str())); +} + + +void MujocoIO::addSkybox() { document->addSkyboxTexture(Eigen::Vector3f(.8f, .9f, .95f), Eigen::Vector3f(.4f, .6f, .8f)); } -void MujocoIO::addNodeBodies() +void MujocoIO::makeNodeBodies() { nodeBodies.clear(); @@ -129,12 +164,10 @@ void MujocoIO::addNodeBodyMeshes() std::cout << "Node " << node->getName() << ":\t"; fs::path srcMeshPath = visualization->getFilename(); - assert(srcMeshPath.is_absolute()); fs::path dstMeshFileName = srcMeshPath.filename(); dstMeshFileName.replace_extension("stl"); - fs::path dstMeshRelPath = outputMeshRelDirectory / dstMeshFileName; - fs::path dstMeshPath = outputDirectory / dstMeshRelPath; + fs::path dstMeshPath = outputMeshDirectory() / dstMeshFileName; if (!fs::exists(dstMeshPath)) { @@ -161,7 +194,9 @@ void MujocoIO::addNodeBodyMeshes() << " -o " << dstMeshPath.string(); // run command + std::cout << "----------------------------------------------------------" << std::endl; int r = system(convertCommand.str().c_str()); + std::cout << "----------------------------------------------------------" << std::endl; if (r != 0) { std::cout << "Command returned with error: " << r << "\n" @@ -177,7 +212,8 @@ void MujocoIO::addNodeBodyMeshes() } else { - std::cout << "skipping (" << dstMeshRelPath.string() << " already exists)"; + std::cout << "skipping (" << outputMeshRelDirectory / dstMeshFileName + << " already exists)"; } std::cout << std::endl; @@ -185,7 +221,7 @@ void MujocoIO::addNodeBodyMeshes() // add asset std::string meshName = node->getName(); - document->addMeshElement(meshName, (outputDirectory/dstMeshRelPath).string()); + document->addMeshElement(meshName, fs::absolute(dstMeshPath).string()); // add geom to body XMLElement* body = nodeBodies[node->getName()]; @@ -356,4 +392,9 @@ std::vector<const mjcf::XMLElement*> MujocoIO::getAllElements(const std::string& return visitor.foundElements; } +void MujocoIO::setLengthScaling(float value) +{ + lengthScaling = value; +} + diff --git a/VirtualRobot/XML/mjcf/MujocoIO.h b/VirtualRobot/XML/mjcf/MujocoIO.h index bbe32208ad9b497650fc227b7ddd4aced4b79288..4a580b19eb3d5b9f1b2710f41955b1e4fe010414 100644 --- a/VirtualRobot/XML/mjcf/MujocoIO.h +++ b/VirtualRobot/XML/mjcf/MujocoIO.h @@ -18,31 +18,54 @@ namespace mjcf { public: + /// Constructor. MujocoIO(); - + /** + * @brief Create a Mujoco XML (MJCF) document for the given robot. + * @param robot the robot + * @param filename the output filename (without directory) + * @param basePath the output directory + * @param meshRelDir the directory relative to basePath where meshes shall be placed + */ void saveMJCF(RobotPtr robot, const std::string& filename, - const std::string& basePath, const std::string& meshDir); - + const std::string& basePath, const std::string& meshRelDir); - private: + /// Set the scaling for lenghts. + void setLengthScaling(float value); - void setPaths(const std::string& inputFilename, - const std::string& outputDirectory); - - void makeEnvironment(); + private: - void addNodeBodies(); + /// Set the output path members. + void setPaths(const std::string& filename, const std::string& basePath, + const std::string& meshRelDir); + /// Create output directories if the do not exist. + void ensureDirectoriesExist(); + + /// Make the compiler section. + void makeCompiler(); + /// Add a defaults group for the robot. + void makeDefaultsGroup(); + /// Add a skybox texture asset. + void addSkybox(); + + /// Construct the body structure corresponding to the robot nodes. + void makeNodeBodies(); + /// Add a body element for a robot node. If its parent does not exist, + /// create the parent body first. mjcf::XMLElement* addNodeBody(RobotNodePtr node); + /// Convert meshes and add mesh assets for robot nodes with visualization. void addNodeBodyMeshes(); - - + + /// Add contact exclude elements for IgnoreCollision elements. void addContactExcludes(); + /// Add actuators for all joints. void addActuators(); + /// Scale all lengths by lengthScaling. void scaleLengths(); std::vector<const mjcf::XMLElement*> getAllElements(const std::string& elemName); @@ -59,7 +82,7 @@ namespace mjcf boost::filesystem::path outputDirectory; boost::filesystem::path outputFileName; boost::filesystem::path outputMeshRelDirectory; - + boost::filesystem::path outputMeshDirectory() { return outputDirectory / outputMeshRelDirectory; } // Input diff --git a/VirtualRobot/examples/Simox2Mjcf/main.cpp b/VirtualRobot/examples/Simox2Mjcf/main.cpp index ab479ed2659045cf87ef064e868352f8290320d9..ace47c5eb1e99fc86257c710e5ea6c5f6cfdde00 100644 --- a/VirtualRobot/examples/Simox2Mjcf/main.cpp +++ b/VirtualRobot/examples/Simox2Mjcf/main.cpp @@ -78,5 +78,5 @@ int main(int argc, char* argv[]) throw; // rethrow } - //RobotIO::saveMJCF(robot, inputFilename.filename().string(), outputDir.string(), meshRelDir); + RobotIO::saveMJCF(robot, inputFilename.filename().string(), outputDir.string(), meshRelDir); }