|
| 1 | +\page migrationsdf |
| 2 | + |
| 3 | +# Migration from Gazebo classic: SDF |
| 4 | + |
| 5 | +Both Gazebo classic and Ignition Gazebo support [SDF](http://sdformat.org/) |
| 6 | +files to describe the simulation to be loaded. An SDF file defines the world |
| 7 | +environment, the robot's characteristics and what plugins to load. |
| 8 | + |
| 9 | +Despite using the same description format, users will note that the same SDF |
| 10 | +file may behave differently for each simulator. This tutorial will |
| 11 | +explain how to write SDF files in a way that they're as reusable by both |
| 12 | +simulators as possible. It will also explain when you'll need to use separate |
| 13 | +files for each simulator. |
| 14 | + |
| 15 | +The minimum required versions to use this guide are: |
| 16 | + |
| 17 | +* Gazebo 11.2.0 |
| 18 | +* Igniton Citadel |
| 19 | + |
| 20 | +## URIs |
| 21 | + |
| 22 | +SDF files use URIs to refer to resources from other files, such as meshes and |
| 23 | +nested models. These are some of the SDF tags that take URIs: |
| 24 | + |
| 25 | +* `<include><uri>` |
| 26 | +* `<mesh><uri>` |
| 27 | +* `<material><pbr><...><*_map>` (only on Ignition) |
| 28 | +* `<actor><skin><filename>` |
| 29 | +* `<actor><animation><filename>` |
| 30 | + |
| 31 | +Here are the recommended ways to use URIs from most recommended to least: |
| 32 | + |
| 33 | +### Ignition Fuel URL |
| 34 | + |
| 35 | +It's possible to use URLs of resources on |
| 36 | +[Ignition Fuel](https://app.ignitionrobotics.org) within any of the tags |
| 37 | +above and both simulators will be able to load it. |
| 38 | + |
| 39 | +For example, this world can be loaded into both simulators: |
| 40 | + |
| 41 | +``` |
| 42 | +<sdf version="1.7"> |
| 43 | + <world name="demo"> |
| 44 | + <!-- Included light --> |
| 45 | + <include> |
| 46 | + <uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Sun</uri> |
| 47 | + </include> |
| 48 | +
|
| 49 | + <!-- Included model --> |
| 50 | + <include> |
| 51 | + <uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Ground Plane</uri> |
| 52 | + </include> |
| 53 | +
|
| 54 | + <model name="Radio"> |
| 55 | + <pose>3 -1.5 0 0 0 0</pose> |
| 56 | + <static>true</static> |
| 57 | + <link name="link"> |
| 58 | + <collision name="collision"> |
| 59 | + <geometry> |
| 60 | + <!-- Collision mesh --> |
| 61 | + <mesh> |
| 62 | + <uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Radio/4/files/meshes/Radio.dae</uri> |
| 63 | + </mesh> |
| 64 | + </geometry> |
| 65 | + </collision> |
| 66 | + <visual name="visual"> |
| 67 | + <geometry> |
| 68 | + <!-- Visual mesh --> |
| 69 | + <mesh> |
| 70 | + <uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Radio/4/files/meshes/Radio.dae</uri> |
| 71 | + </mesh> |
| 72 | + </geometry> |
| 73 | + </visual> |
| 74 | + </link> |
| 75 | + </model> |
| 76 | +
|
| 77 | + <actor name="actor_talking"> |
| 78 | + <skin> |
| 79 | + <filename>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/actor - relative paths/tip/files/meshes/talk_b.dae</filename> |
| 80 | + <scale>1.0</scale> |
| 81 | + </skin> |
| 82 | + <animation name="talk_b"> |
| 83 | + <filename>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/actor - relative paths/tip/files/meshes/talk_b.dae</filename> |
| 84 | + <scale>1.0</scale> |
| 85 | + </animation> |
| 86 | + <script> |
| 87 | + <loop>true</loop> |
| 88 | + <auto_start>true</auto_start> |
| 89 | + <trajectory id="0" type="talk_b"> |
| 90 | + <waypoint> |
| 91 | + <time>0</time> |
| 92 | + <pose>2 -2 0.5 0 0 0</pose> |
| 93 | + </waypoint> |
| 94 | + <waypoint> |
| 95 | + <time>5</time> |
| 96 | + <pose>2 -2 0.5 0 0 0</pose> |
| 97 | + </waypoint> |
| 98 | + </trajectory> |
| 99 | + </script> |
| 100 | + </actor> |
| 101 | +
|
| 102 | + </world> |
| 103 | +</sdf> |
| 104 | +``` |
| 105 | + |
| 106 | +\note The actor's vertical pose will be different on both simulators. |
| 107 | + That's because a hardcoded offset was removed on Ignition and |
| 108 | + maintained on Gazebo classic for backwards compatibility. |
| 109 | + |
| 110 | +### Path relative to the SDF file |
| 111 | + |
| 112 | +It's possible to use relative paths within SDF files to refer to other files |
| 113 | +in the same directory. This is recommended when creating files that work |
| 114 | +together and need to be relocatable. |
| 115 | + |
| 116 | +For example, consider the following directory structure: |
| 117 | + |
| 118 | +``` |
| 119 | +/home/username/ |
| 120 | +├── world.sdf |
| 121 | +└── models |
| 122 | + └── model1 |
| 123 | + ├── model.sdf |
| 124 | + └── meshes |
| 125 | + └── mesh.dae |
| 126 | +``` |
| 127 | + |
| 128 | +The world `world.sdf` can include `model1` as follows: |
| 129 | + |
| 130 | +`<include>models/model1</include>` |
| 131 | + |
| 132 | +And `model.sdf` can refer to `mesh.dae` as: |
| 133 | + |
| 134 | +`<uri>meshes/mesh.dae</uri>` |
| 135 | + |
| 136 | +### Path relative to an environment variable |
| 137 | + |
| 138 | +This method is useful if you don't know where the files will be located |
| 139 | +with respect to each other, and you have some control over the simulation's |
| 140 | +runtime environment. On either simulator, you can refer to resources relative |
| 141 | +to paths set on an environment variable. |
| 142 | + |
| 143 | +Each simulator uses a different environment variable: |
| 144 | + |
| 145 | +* Gazebo classic: |
| 146 | + * `GAZEBO_MODEL_PATH` for models |
| 147 | + * `GAZEBO_RESOURCE_PATH` for worlds and some rendering resources |
| 148 | +* Ignition Gazebo: |
| 149 | + * `IGN_GAZEBO_RESOURCE_PATH` for worlds, models and other resources |
| 150 | + |
| 151 | +For example, if you have the file structure above, you can set the environment |
| 152 | +variable to `/home/username/models`: |
| 153 | + |
| 154 | +``` |
| 155 | +export GAZEBO_MODEL_PATH=/home/username/models |
| 156 | +export GAZEBO_RESOURCE_PATH=/home/username/models |
| 157 | +export IGN_GAZEBO_RESOURCE_PATH=/home/username/models |
| 158 | +``` |
| 159 | + |
| 160 | +And inside `world.sdf` include the model with: |
| 161 | + |
| 162 | +`<include>model://model1</include>` |
| 163 | + |
| 164 | +Also, `model.sdf` can refer to `mesh.dae` as: |
| 165 | + |
| 166 | +`<uri>model://model1/meshes/mesh.dae</uri>` |
| 167 | + |
| 168 | +On both situations, the `model://` prefix will be substituted by |
| 169 | +`/home/username/models`. |
| 170 | + |
| 171 | +You can also set several lookup paths separating them with `:`, for example: |
| 172 | + |
| 173 | +`export IGN_GAZEBO_RESOURCE_PATH=/home/username/models:/home/username/another_project/models` |
| 174 | + |
| 175 | +### Absolute paths |
| 176 | + |
| 177 | +Finally, both simulators will accept absolute paths, for example: |
| 178 | + |
| 179 | +`<include>/home/username/models/model1</include>` |
| 180 | + |
| 181 | +This method is not recommended, because the file most likely won't work if |
| 182 | +copied to a different computer. It also becomes inconvenient to move files to |
| 183 | +different directories. |
| 184 | + |
| 185 | +## Plugins |
| 186 | + |
| 187 | +Plugins are binary files compiled to use with a specific simulator. Plugins |
| 188 | +for Gazebo classic and Ignition Gazebo aren't usually compatible, so plugins |
| 189 | +will need to be specified for each simulator separately. |
| 190 | + |
| 191 | +It's important to note that for both simulators, plugins compiled against |
| 192 | +a major version of the simulator can't be loaded by other major versions. |
| 193 | +The shared libraries will usually have the same name, so it's important to make |
| 194 | +sure you're loading the correct plugins. |
| 195 | + |
| 196 | +### Official plugins |
| 197 | + |
| 198 | +Both simulators are installed with several built-in plugins. |
| 199 | +[Gazebo classic's plugins](https://github.com/osrf/gazebo/tree/gazebo11/plugins) |
| 200 | +and |
| 201 | +[Ignition Gazebo's plugins](https://github.com/ignitionrobotics/ign-gazebo/tree/ign-gazebo3/src/systems) |
| 202 | +have different file names. For example, to use Gazebo classic's differential drive |
| 203 | +plugin, the user can refer to it as follows: |
| 204 | + |
| 205 | +``` |
| 206 | +<model ...> |
| 207 | + <plugin filename="libDiffDrivePlugin.so" name="any_custom_name"> |
| 208 | + ... |
| 209 | + </plugin> |
| 210 | +</model> |
| 211 | +``` |
| 212 | + |
| 213 | +On Ignition, that would be: |
| 214 | + |
| 215 | +``` |
| 216 | +<model ...> |
| 217 | + <plugin filename="ignition-gazebo-diff-drive-system" |
| 218 | + name="ignition::gazebo::systems::DiffDrive"> |
| 219 | + ... |
| 220 | + </plugin> |
| 221 | +</model> |
| 222 | +``` |
| 223 | + |
| 224 | +Note that besides the different file name, Ignition also requires the C++ class |
| 225 | +to be defined in the `name` attribute. |
| 226 | + |
| 227 | +Also keep in mind that plugins that offer similar functionality may accept |
| 228 | +different parameters for each simulator. Be sure to check the documentation of |
| 229 | +each plugin before using it. |
| 230 | + |
| 231 | +### Custom plugins |
| 232 | + |
| 233 | +To load custom plugins, users need to set environment variables to the directory |
| 234 | +where that plugin is located. The variables are different for each simulator: |
| 235 | + |
| 236 | +* Gazebo classic: |
| 237 | + * `GAZEBO_PLUGIN_PATH` for all plugin types. |
| 238 | +* Ignition Gazebo: |
| 239 | + * `IGN_GAZEBO_SYSTEM_PLUGIN_PATH` for Ignition Gazebo systems (world, model, |
| 240 | + sensor and visual plugins). |
| 241 | + * `IGN_GUI_PLUGIN_PATH` for GUI plugins. |
| 242 | + |
| 243 | +### Keeping plugins separate |
| 244 | + |
| 245 | +Trying to load a plugin from one simulator into the other will: |
| 246 | + |
| 247 | +* Print an error message if the simulator can't find the plugin |
| 248 | +* Potentially crash if the simulator can find the plugin and tries to load it |
| 249 | + |
| 250 | +That's why it's recommended not to specify plugins for both simulators |
| 251 | +side-by-side on the same file. Instead, keep separate files and inject the plugins as |
| 252 | +needed. |
| 253 | + |
| 254 | +There isn't a built-in mechanism on SDFormat to inject plugins into files yet, |
| 255 | +but users can make use of templating tools like [ERB](erb_template.html) |
| 256 | +and [xacro](http://wiki.ros.org/xacro) to generate SDF files with the correct plugins. |
| 257 | + |
| 258 | +### Default plugins |
| 259 | + |
| 260 | +Ignition Gazebo is more modular than Gazebo classic, so most features are optional. |
| 261 | +For example, by default, Ignition will load all the system plugins defined on |
| 262 | +the `~/.ignition/gazebo/server.config` file and all GUI plugins defined on the |
| 263 | +`~/.ignition/gazebo/gui.config` file. But the user can always remove plugins from |
| 264 | +those files, or choose different ones by adding `<plugin>` tags to the SDF file. |
| 265 | +(For more details, see the [Server configuration tutorial](server_config.html) |
| 266 | +and the [GUI configuration tutorial](gui_config.html)). |
| 267 | + |
| 268 | +This is important to keep in mind when migrating your SDF files, because files |
| 269 | +that worked on Gazebo classic may need more plugins on Ignition. |
| 270 | + |
| 271 | +## Materials |
| 272 | + |
| 273 | +Ignition does not support Ogre material files like Classic does, because Ignition |
| 274 | +Gazebo can be used with multiple rendering engines. Therefore, materials defined |
| 275 | +within a `<script>` aren't supported on Ignition, for example: |
| 276 | + |
| 277 | +``` |
| 278 | + <material> |
| 279 | + <script> |
| 280 | + <uri>model://number1/materials/scripts</uri> |
| 281 | + <uri>model://number1/materials/textures</uri> |
| 282 | + <name>Number/One</name> |
| 283 | + </script> |
| 284 | + </material> |
| 285 | +``` |
| 286 | + |
| 287 | +To make your models compatible with both simulators, you can use these alternatives: |
| 288 | + |
| 289 | +### Plain colors |
| 290 | + |
| 291 | +If the material defines plain colors, use the `<ambient>`, `<specular>`, |
| 292 | +`<emissive>` and `<diffuse>` tags as needed. |
| 293 | + |
| 294 | +For example, this material from |
| 295 | +[gazebo.material](https://github.com/osrf/gazebo/blob/gazebo11/media/materials/scripts/gazebo.material): |
| 296 | + |
| 297 | +``` |
| 298 | + <material> |
| 299 | + <script> |
| 300 | + <uri>file://media/materials/scripts/gazebo.material</uri> |
| 301 | + <name>Gazebo/Red</name> |
| 302 | + </script> |
| 303 | + </material> |
| 304 | +``` |
| 305 | + |
| 306 | +Can be changed to: |
| 307 | + |
| 308 | +``` |
| 309 | + <material> |
| 310 | + <ambient>1 0 0 1</ambient> |
| 311 | + <diffuse>1 0 0 1</diffuse> |
| 312 | + <specular>0.1 0.1 0.1 1</specular> |
| 313 | + </material> |
| 314 | +
|
| 315 | +``` |
| 316 | + |
| 317 | +### Textures |
| 318 | + |
| 319 | +If an Ogre material script is being used to define a texture, there are a |
| 320 | +couple alternatives. |
| 321 | + |
| 322 | +If using mesh files, the texture can be embedded into it. The advantage is that |
| 323 | +this works for both simulators. Some examples: |
| 324 | + |
| 325 | +* [OBJ + MTL](https://app.ignitionrobotics.org/OpenRobotics/fuel/models/DeskChair) |
| 326 | +* [COLLADA](https://app.ignitionrobotics.org/OpenRobotics/fuel/models/Lamp%20Post) |
| 327 | + |
| 328 | +For primitive shapes or even meshes, you can pass the texture as the albedo map. If you |
| 329 | +want the model to be compatible with both Classic and Ignition, you can specify both |
| 330 | +the script and the albedo map. |
| 331 | + |
| 332 | +``` |
| 333 | + <material> |
| 334 | + <pbr> |
| 335 | + <metal> |
| 336 | + <albedo_map>texture.png</albedo_map> |
| 337 | + </metal> |
| 338 | + </pbr> |
| 339 | + </material> |
| 340 | +``` |
| 341 | + |
0 commit comments