From Mesh, into MeshManager, via SDF to a model in a world: how?
Howdy folks,
I am trying to get to the bottom of how exactly a mesh is loaded in Gazebo.
I am working on a Gazebo Plugin that generates trees procedurally such that I can create a forest where each tree's geometry/shape is unique (more or less).
I have figured out how to convert a procedurally generated tree to a Mesh, and then add this Mesh to MeshManager:
gazebo::common::Mesh * treeMesh = procTreeFunction();
treeMesh->SetName("Tree_1234");
gazebo::common::MeshManager::Instance()->AddMesh(treeMesh);
But what I am currently struggling with what to do next in order to see this tree in my Gazebo world, and what follows is questionable and is what I need some help with.
So next I am creating an SDF model string:
modelStr << "<sdf version='" << SDF_VERSION << "'>"
"<model name='" Tree_1234 "'>"
"<pose>" << pose << "</pose>"
"<link name='link'>"
"<velocity_decay>"
"<linear>0.01</linear>"
"<angular>0.01</angular>"
"</velocity_decay>"
"<inertial><mass>" << _mass << "</mass>"
"<inertia>"
"<ixx>" << Ixx << "</ixx>"
"<iyy>" << Iyy << "</iyy>"
"<izz>" << Izz << "</izz>"
"<ixy>" << 0.0 << "</ixy>"
"<ixz>" << 0.0 << "</ixz>"
"<iyz>" << 0.0 << "</iyz>"
"</inertia>"
"</inertial>"
"<collision name='collision'>"
"<geometry>"
"<mesh>"
"<uri>" Tree_1234 "</uri>"
"</mesh>"
"</geometry>"
"</collision>"
"<visual name='visual'>"
"<geometry>"
"<mesh>"
"<uri>" Tree_1234 "</uri>"
"</mesh>"
"</geometry>"
"<material>"
"<ambient>" << _materialAmbient[0] << " " << _materialAmbient[1] << " " << _materialAmbient[2] << " " << _materialAmbient[3] <<"</ambient>"
"<diffuse>" << _materialDiffuse[0] << " " << _materialDiffuse[1] << " " << _materialDiffuse[2] << " " << _materialDiffuse[3] <<"</diffuse>"
"<specular>" << _materialSpecular[0] << " " << _materialSpecular[1] << " " << _materialSpecular[2] << " " << _materialSpecular[3] <<"</specular>"
"<emissive>" << _materialEmissive[0] << " " << _materialEmissive[1] << " " << _materialEmissive[2] << " " << _materialEmissive[3] <<"</emissive>"
"</material>"
"</visual>"
"</link>"
"</model>"
"</sdf>";
And then I add the model to my world
sdf::SDF sdfDescription.SetFromString(modelStr.str());
_parent->InsertModelSDF(sdfDescription);
However, instead of seeing a tree, I am seeing a cube (that appears to be a unit cube of 1 m^3). The cuboid is rendered in the correct material settings and at the right location. It's just not a tree :)
Does anyone have an idea what I might be doing wrong?
Thanks in advance!!
Galto
It's awesome that you're doing this! Do you see any errors when running in verbose mode? Anything about not finding the geometry?
Thanks for your suggestion. So, when I run it in verbose mode I get a whole bunch of these: [Err] [Visual.cc:2726] No mesh specified [Err] [Visual.cc:2366] No mesh found, setting mesh to a unit box One for each procedural object that I pushed in a MeshManager instance from my plugin. Otherwise it's clean. Alright, I'll keep on digging... but any clues, ideas, advice....are always greatly appreciated
Looking at the code in Visual.cc (Gazebo 7.1) - it seems when it encounters geometry that is tagged as "mesh", it automatically presumes that this is a mesh that was loaded from a file (e.g. collada). In my case, I am generating the mesh from code in my plugin and then I give it a name, e.g. "Tree_1234, and then I push it in the MeshManager. Then it subsequently is looking for a file called "Tree_1234" in Visual.cc, but it doesn't exist as a file, and as such turns it in unit box. Could it be?
What you write in the SDF URI is supposed to be a file. There may be hacky ways to get it to work with programmatically generated meshes but that is not the intended use. I haven't looked enough at the code to suggest hacky ways of doing it, but I'd be trying not to use SDF.
The hack that I am currently am contemplating is to simply generate an .STL file for each procedurally generated object. It's far from ideal, but if the objects are static it just means a little bit of waiting at the start (and perhaps checking if the model file already exists as to avoid re-generating meshes). What alternatives are there to SDF? Thanks!
The alternative I'd look at is trying to reproduce whatever `InsertModelSDF` is doing, but using your own mesh instead. Makes sense? Also note that if you're creating the mesh on the server, the client has no way of knowing about it.
a-ha :) (I just had my little aha moment there, thank you!) .... So what you are suggesting of doing is to boldly go beyond writing a plugin, and actually editing some of the core Gazebo code? What parts of the code constitutes server and client code in the repository?
It would be ideal if you could do it from a plugin, I'd hope changing the source code wouldn't be necessary. The reason why the client wouldn't know about a mesh you create on the server is that they run on separate processes. With mesh files, both server and client know where to look for them and they are loaded twice. I don't think there is a trivial way for you to tell the client about a mesh created programmatically.
So we basically need to be able to send a Mesh object from server to client via some IPC method. Could this be done using any of the plugin types (sytem, visual, gui, ...?). Now I wonder in what parts plugins operate in: in the server or client, or both?
World, Model, Sensor plugins act on the server, Visual plugins have one instance on the server (so cameras can see it) and another on the client. GUI plugins are client-only. System plugins can run on both, I believe, but as separate instances of the plugin. I've never tried using IPC like that