Python bindings for Gazebo/Ignition

Hey folks, so python bindings for Gazebo are something I’ve considered for a long time now. Usually this comes up in the context of I have a ros python node that I want to interact with gazebo transport, but just recently I had another case where I have python scripts that I want to spin up and manage many instances of gazebo simulations and having bindings would be much better than using the subprocess module. A third possible motivation would be making it easier to teach people how to use the gazebo APIs.

I’ve been using pybind11 recently for some of my own C++ code and it’s quite simple to use.

I’m wondering if there are enough use cases or general interest in this? Has this been discussed at all within Open Robotics?

1 Like

A ruby interface using swig was added to ignition-math:

I think we could add a python interface in a similar way?

This is something we are interested in but haven’t been actively pursuing at the moment.

I don’t have any experience with tools that do it automatically (swig?) but I wouldn’t be surprised if they existed for python too. My approach has been to expose whatever I need to expose by hand. OMPL I believe generates all the bindings automatically so that could be a thing to look at.

I know Nate really likes Ruby, but I’ve always felt it was a weird choice since I’ve never heard of it used for anything in robotics. Do you know of anyone outside of open robotics using the Ruby bindings or expressing interest in them?

I believe swig supports python too, so I think the same approach that we’ve used for ruby could work for python too.

I am looking forward to having official ignition bindings, it would be really a great addition. Using external processes with transport is a sound solution, but many application might be limited if they have to rely to socket-based connections.

I have recently worked towards this direction for a project I’m developing and I can share my experience. Swig is one of the only mature solution that provide multiple languages support, and it was the natural choice despite I only currently need Python. I didn’t face many issues in the process, but instead of binding directly the Ignition Gazebo public APIs, I wrapped the simulator in a C++ wrapper, and then exposed the wrapper to Python with Swig. In this way I could configure the simulator in C++ using its native language and then expose to Python only a very high-level interface. This choice was also related to the fact that Ignition uses heavily C++17 and there is no support of this standard in Swig (e.g. std::optional, widely used in ignition robotics). I don’t think is very demanding developing new typemaps for the missing features, but it goes beyond the scope of my work for the time being.

If you want to have a look to the development status and have an example from where to start, have a look to robotology/gym-ignition, and particularly GazeboWrapper.

I’m not sure if it’s the thing you need, but I’m maintaining a small library for my project here: https://github.com/ci-group/pygazebo/tree/py2to3 (py2to3 branch)

it’s a library to communicate with gazebo via protobuf messages. It’s rough and I would like to improve it, but it works.

One of the main use cases I have is running a number of gazebo instances, and so I would actually want the ability to start gzserver/gzclient executables, manage them, etc… so just a messaing API would not quite do it for that scenario. But still a useful thing to have. Like Diego said, making bindings for ignition/gazebo would be the more complete solution.

Another project that might be quite interesting as a Swig alternative is Microsoft/xlang (FAQ). I do not have direct experience with it nor I saw in the past any real example, but it definitely worth a look.

Considering classic gazebo and ignition transport, I remember I read that the developers of gym-gazebo2 (paper) claim they have network segmentation to allow multiple simulator instances. I do not know exactly how port names are affected by it, but @portaloffreedom library might be useful in this setup if it can interface smoothly with it.

1 - I confirm that I’m actually running multiple instances gazebo at the same time, being able to communicate to them from the same python script at the same time.
2 - I just update the library to use python3 and asyncio, for clearer and more modern code. https://github.com/ci-group/pygazebo (master branch)

@portaloffreedom Nice work. Bwt for readers not very familiar with Gazebo I would like to point out that your library will not work (yet?) with Ignition Gazebo as the OP was asking.

For a very simple example on Ignition Gazebo you can refer to joint_controller.sdf.

I’m looking into using pybind11_protobuf to allow native Python bindings generated from the ign-msgs protobufs to be used with pybind11 extensions to ign-transport. The aim is to have the core ignition::transort::Node features available in Python (i.e. publish and subscribe to topics).

Progress so far is available here: GitHub - srmainwaring/python-ignition: Python bindings for `ign-msgs` and `ign-transport`. The Python / C++ interop is working for a selection of ign-msgs and there’s a mocked-up sketch of the extension for ign-transport. At present it is all built with Bazel as that’s the build system available for pybind11_protobuf, but the intention would be to port it all over to cmake when it’s working.

Next steps are to get a Bazel build of the ignition libraries using ign-bazel and wire up the interface to the actual libraries. Getting the subscriptions to work correctly will be the challenging part of the project, and any thoughts / help on that welcomed.

2 Likes

A follow-up on Python bindings for ign-msgs and ign-transport using pybind11.

There is an experimental version tested on macOS integrated with the main branches of ign-msgs and ign-transport. There are both Bazel and CMake builds available - I’d recommend the CMake build as it generates bindings for all messages and there is an odd issue with some message types not latching in the subscribe callback in the Bazel build.

The bindings let you write this type of thing in Python:

import time
import typing

from ignition.msgs.stringmsg_pb2 import StringMsg

from ignition_transport import SubscribeOptions
from ignition_transport import Node

def cb(msg: StringMsg) -> None:
    print("Msg: [{}] from Python".format(msg.data))

def main():
    # create a transport node
    node = Node()
    topic = "/foo"
    msg_type_name = StringMsg.DESCRIPTOR.full_name
    sub_options = SubscribeOptions()

    # subscribe to a topic by registering a callback
    if node.subscribe(topic, cb, msg_type_name, sub_options):
        print("Subscribing to type {} on topic [{}]".format(
            msg_type_name, topic))
    else:
        print("Error subscribing to topic [{}]".format(topic))
        return

    # wait for shutdown
    try:
      while True:
        time.sleep(0.001)
    except KeyboardInterrupt:
      pass

if __name__ == "__main__":
    main()

So far only the publish and subscribe interfaces of ignition::transport::Node are exposed, but it should be straightforward to add the service interface if required.

1 Like