diff --git a/manifest.xml b/manifest.xml index 8d345ae..3032285 100644 --- a/manifest.xml +++ b/manifest.xml @@ -142,6 +142,17 @@ beginner + + python/tutorial_13.md + + How to use SDFormat Python bindings + + + python + + beginner + + custom_elements_attributes/proposal.md @@ -285,6 +296,7 @@ install quickstart convert_sdf_to_usd + python_bindings roadmap proposal_format diff --git a/python/tutorial_13.md b/python/tutorial_13.md new file mode 100644 index 0000000..7c5bf82 --- /dev/null +++ b/python/tutorial_13.md @@ -0,0 +1,185 @@ +# Python Get Started + +## Overview + +This tutorial describes how to get started using SDFormat library with Python. +This Python bindings are available from SDFormat13 (Gazebo Garden). + +**NOTE**: If you have compiled SDFormat from source, you should export your `PYTHONPATH`. + +```bash +export PYTHONPATH=$PYTHONPATH:/install/lib/python +``` + +## Tutorial + +We will run through an example that read a SDF file, modify the structure and +create a new file. Start by creating the following file SDF file `sphere.sdf` +using the editor of your choice: + +```xml + + + + + 0 1.5 0.5 0 0 0 + + + + 3 + 0 + 0 + 3 + 0 + 3 + + 3.0 + + + + + 0.5 + + + + + + + 0.5 + + + + 0 0 1 1 + 0 0 1 1 + 0 0 1 1 + + + + + + +``` + +Now let's create a bare-bones main Python file: + +```python +def main(): + pass + +if __name__ == "__main__": + main() +``` + +The easiest way to include SDFormat is through `import sdformat as sdf`. + +At this point your main file should look like + +```python +import sdformat as sdf + +def main(): + pass + +if __name__ == "__main__": + main() +``` + +Next step it's to read the file. The `load` method might throw an exception, +for this reason we will use `try/except` and if there is any exception we will +print the error in the terminal. + +```python +import sdformat as sdf +import sys + + +def main(): + input_file = 'sphere.sdf' + root = sdf.Root() + try: + root.load(input_file) + except sdf.SDFErrorsException as e: + print(e, file=sys.stderr) + +if __name__ == "__main__": + main() +``` + +We can iterate through the SDF file showing the name of the different elements: + +```python +def main(): + input_file = './sphere.sdf' + root = sdf.Root() + try: + root.load(input_file) + except sdf.SDFErrorsException as e: + print(e, file=sys.stderr) + + for world_index in range(root.world_count()): + world = root.world_by_index(world_index) + print(world.name()) + + for model_index in range(world.model_count()): + model = world.model_by_index(model_index) + print("\tModel: ", model.name()) + for link_index in range(model.link_count()): + link = model.link_by_index(link_index) + print("\t\tLink: ", link.name()) + for collision_index in range(link.collision_count()): + collision = link.collision_by_index(collision_index) + print("\t\t\tCollision: ", collision.name()) + for visual_index in range(link.collision_count()): + visual = link.visual_by_index(visual_index) + print("\t\t\tVisual: ", visual.name()) +``` + +Or you can create and add a new element to the SDF DOM, finally we will save it in a new file: + +```python +from ignition.math import Vector3d + +... + +def main(): + input_file = './sphere.sdf' + root = sdf.Root() + try: + root.load(input_file) + except sdf.SDFErrorsException as e: + print(e, file=sys.stderr) + + # Create a new model + world = root.world_by_index(0) + world.set_name('shapes') + + model = sdf.Model() + model.set_name('box') + + link = sdf.Link() + link.set_name('box_link') + + geometry = sdf.Geometry() + box = sdf.Box() + + box.set_size(Vector3d(1, 1, 1)) + geometry.set_box_shape(box) + geometry.set_type(sdf.GeometryType.BOX) + + collision = sdf.Collision() + collision.set_name('collision_box') + collision.set_geometry(geometry) + + visual = sdf.Visual() + visual.set_name('visual_box') + visual.set_geometry(geometry) + + link.add_visual(visual) + link.add_collision(collision) + model.add_link(link) + world.add_model(model) + + # finally we save the result in a new file + with open('new_sdf.sdf', "w") as f: + f.write(root.to_string()) +```