diff --git a/src/systems/python_system_loader/PythonSystemLoader.hh b/src/systems/python_system_loader/PythonSystemLoader.hh index eeb3b99b1fc..710589e064c 100644 --- a/src/systems/python_system_loader/PythonSystemLoader.hh +++ b/src/systems/python_system_loader/PythonSystemLoader.hh @@ -40,12 +40,28 @@ namespace systems /// The convention for a system written in Python supported by the /// `PythonSystemLoader` is that it's a Python module providing a `get_system` /// function which itself returns an instance of a class that implements the -/// various interfaces in gz::sim::System. +/// various interfaces in gz::sim::System. The spelling of the interfaces +/// conforms to Python code style guides, so the following name mapping applies +/// +/// * `configure` : Corresponds to System::ISystemConfigure::Configure +/// * `pre_update` : Corresponds to System::ISystemPreUpdate::PreUpdate +/// * `update` : Corresponds to System::ISystemUpdate::Update +/// * `post_update` : Corresponds to System::ISystemPostUpdate::PostUpdate +/// * `reset` : Corresponds to System::ISystemReset::Reset +/// +/// It is not necessary to implement all the interfaces. PythonSystemLoader will +/// check if the corresponding method is implemented in the Python system and +/// skip it if it's not found. +/// /// See examples/scripts/python_api/systems/test_system.py for an example /// /// ## Parameters -/// : Name of python module to be loaded. The search path includes -/// `GZ_SIM_SYSTEM_PLUGIN_PATH` as well as `PYTHONPATH`. +/// * : Name of python module to be loaded. The search path +/// includes `GZ_SIM_SYSTEM_PLUGIN_PATH` as well as +/// `PYTHONPATH`. +/// +/// The contents of the tag will be available in the configure method +/// of the Python system // TODO(azeey) Add ParameterConfigure class GZ_SIM_PYTHON_SYSTEM_LOADER_SYSTEM_HIDDEN PythonSystemLoader final : public System, diff --git a/tutorials/python_interfaces.md b/tutorials/python_interfaces.md index 8671966b0ce..b9f509ba9bf 100644 --- a/tutorials/python_interfaces.md +++ b/tutorials/python_interfaces.md @@ -81,3 +81,66 @@ iterations 1000 post_iterations 1000 pre_iterations 1000 ``` + +# Gazebo Systems written in Python + +Gazebo also provides a way to write systems in Python. This is done using the +`gz::sim::systems::PythonSystemLoader` system which loads a given python module +specified by its `` parameter. The search path for the module +includes `GZ_SIM_SYSTEM_PLUGIN_PATH` as well as `PYTHONPATH`. The module is +expected to provide a function called `get_system` that returns an instance of +a class that implements the various interfaces in `gz::sim::System`. + +Example python system: + + + +```python + +from gz.math7 import Vector3d +from gz.sim8 import Model, Link +import random + + +class TestSystem(object): + def __init__(self): + self.id = random.randint(1, 100) + + def configure(self, entity, sdf, ecm, event_mgr): + self.model = Model(entity) + self.link = Link(self.model.canonical_link(ecm)) + print("Configured on", entity) + print("sdf name:", sdf.get_name()) + self.force = sdf.get_double("force") + print(f"Applying {self.force} N on link {self.link.name(ecm)}") + + def pre_update(self, info, ecm): + if info.paused: + return + + if info.iterations % 3000 == 0: + print(f"{self.id} {info.real_time} pre_update") + + self.link.add_world_force( + ecm, Vector3d(0, 0, self.force), + Vector3d(random.random(), random.random(), 0)) + + +def get_system(): + return TestSystem() +``` + +The system can be added to SDFormat model or world with: + +```xml + + + test_system + 100 + + +``` + +asuming the name of the module is `test_system` and the directory containing +the module has been added to `GZ_SIM_SYSTEM_PLUGIN_PATH`,