-
Notifications
You must be signed in to change notification settings - Fork 275
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for writing systems in Python (#2081)
Creates a C++ system that is able to load a python module and pass along the System interface calls, such as Configure, PreUpdate, etc. The convention is pretty simple. The python module exposes a get_system function which returns an instance of a class that implements the desired System interface functions. --------- Signed-off-by: Addisu Z. Taddese <[email protected]>
- Loading branch information
Showing
23 changed files
with
964 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Copyright (C) 2023 Open Source Robotics Foundation | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?xml version="1.0" ?> | ||
<!-- | ||
Gazebo python system loader example | ||
Before running this, add `examples/scripts/python_api/systems` to your | ||
GZ_SIM_SYSTEM_PLUGIN_PATH | ||
``` | ||
export GZ_SIM_SYSTEM_PLUGIN_PATH=path_to_gazebo/examples/scripts/python_api/systems | ||
``` | ||
If you're building with Colcon, you'll also need to put `install/lib/python` in | ||
your PYTHONPATH | ||
``` | ||
export PYTHONPATH=path_to_colcon_workspace/install/lib/python:$PYTHONPATH | ||
``` | ||
--> | ||
<sdf version="1.6"> | ||
<world name="python_system"> | ||
|
||
|
||
<light type="directional" name="sun"> | ||
<cast_shadows>true</cast_shadows> | ||
<pose>0 0 10 0 0 0</pose> | ||
<diffuse>1 1 1 1</diffuse> | ||
<specular>0.5 0.5 0.5 1</specular> | ||
<attenuation> | ||
<range>1000</range> | ||
<constant>0.9</constant> | ||
<linear>0.01</linear> | ||
<quadratic>0.001</quadratic> | ||
</attenuation> | ||
<direction>-0.5 0.1 -0.9</direction> | ||
</light> | ||
|
||
<model name="ground_plane"> | ||
<static>true</static> | ||
<link name="link"> | ||
<collision name="collision"> | ||
<geometry> | ||
<plane> | ||
<normal>0 0 1</normal> | ||
<size>100 100</size> | ||
</plane> | ||
</geometry> | ||
</collision> | ||
<visual name="visual"> | ||
<geometry> | ||
<plane> | ||
<normal>0 0 1</normal> | ||
<size>100 100</size> | ||
</plane> | ||
</geometry> | ||
<material> | ||
<ambient>0.8 0.8 0.8 1</ambient> | ||
<diffuse>0.8 0.8 0.8 1</diffuse> | ||
<specular>0.8 0.8 0.8 1</specular> | ||
</material> | ||
</visual> | ||
</link> | ||
</model> | ||
|
||
<model name="box"> | ||
<pose>0 0 0.5 0 0 0</pose> | ||
<link name="box_link"> | ||
<inertial> | ||
<inertia> | ||
<ixx>0.16666</ixx> | ||
<ixy>0</ixy> | ||
<ixz>0</ixz> | ||
<iyy>0.16666</iyy> | ||
<iyz>0</iyz> | ||
<izz>0.16666</izz> | ||
</inertia> | ||
<mass>1.0</mass> | ||
</inertial> | ||
<collision name="box_collision"> | ||
<geometry> | ||
<box> | ||
<size>1 1 1</size> | ||
</box> | ||
</geometry> | ||
</collision> | ||
|
||
<visual name="box_visual"> | ||
<geometry> | ||
<box> | ||
<size>1 1 1</size> | ||
</box> | ||
</geometry> | ||
<material> | ||
<ambient>1 0 0 1</ambient> | ||
<diffuse>1 0 0 1</diffuse> | ||
<specular>1 0 0 1</specular> | ||
</material> | ||
</visual> | ||
</link> | ||
<plugin filename="gz-sim-python-system-loader-system" name="gz::sim::systems::PythonSystemLoader"> | ||
<module_name>test_system</module_name> | ||
<force>3000</force> | ||
</plugin> | ||
</model> | ||
|
||
</world> | ||
</sdf> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import sys | ||
import gz.msgs10 | ||
sys.modules["gz_test_deps.msgs"] = gz.msgs10 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from gz.transport13 import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# Copyright (C) 2023 Open Source Robotics Foundation | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import sys | ||
from os.path import dirname, realpath | ||
import threading | ||
|
||
# Add "../__file__" to sys.path to get gz_test_deps | ||
sys.path.append(dirname(dirname(realpath(__file__)))) | ||
|
||
from gz_test_deps.sim import Model | ||
from gz_test_deps.transport import Node | ||
from gz_test_deps.msgs.pose_pb2 import Pose | ||
from gz_test_deps.msgs.clock_pb2 import Clock | ||
|
||
|
||
# Test system to be used with test/integration/python_system_loader.cc | ||
class TestModelSystem(object): | ||
def __init__(self): | ||
self.node = Node() | ||
self.has_been_reset = False | ||
self.lock = threading.Lock() | ||
self.sim_time_from_clock = None | ||
|
||
def configure(self, entity, sdf, ecm, event_mgr): | ||
self.model = Model(entity) | ||
if not self.model.valid(ecm): | ||
raise RuntimeError(f"Model {entity} is invalid") | ||
|
||
self.target_pose = sdf.get_pose("target_pose") | ||
self.reset_pose = sdf.get_pose("reset_pose") | ||
self.pub = self.node.advertise(f"{self.model.name(ecm)}/pose", Pose) | ||
self.sub = self.node.subscribe(Clock, "/clock", self.clock_cb) | ||
|
||
def pre_update(self, info, ecm): | ||
if info.paused or self.has_been_reset: | ||
return | ||
|
||
self.model.set_world_pose_cmd(ecm, self.target_pose) | ||
|
||
def post_update(self, info, ecm): | ||
msg = Pose() | ||
msg.position.x = self.target_pose.x() | ||
msg.position.y = self.target_pose.y() | ||
msg.position.z = self.target_pose.z() | ||
with self.lock: | ||
if self.sim_time_from_clock is not None: | ||
stamp = msg.header.stamp | ||
stamp.sec = self.sim_time_from_clock.sec | ||
stamp.nsec = self.sim_time_from_clock.nsec | ||
self.pub.publish(msg) | ||
|
||
def reset(self, info, ecm): | ||
self.model.set_world_pose_cmd(ecm, self.reset_pose) | ||
self.has_been_reset = True | ||
|
||
def clock_cb(self, msg): | ||
with self.lock: | ||
self.sim_time_from_clock = msg.sim | ||
|
||
|
||
def get_system(): | ||
return TestModelSystem() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.