Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speak the Ignition discovery protocol #5

Open
FirefoxMetzger opened this issue Mar 24, 2021 · 2 comments
Open

Speak the Ignition discovery protocol #5

FirefoxMetzger opened this issue Mar 24, 2021 · 2 comments
Labels
ignition Issue related to ropy.ignition

Comments

@FirefoxMetzger
Copy link
Owner

Ignition uses ign-transport to communicate between different parts of the library, and we can introspect this communication using ropy.Subscriber.

Under the hood, this uses a mix of zmq and the ignition CLI (via subprocess) to make itself known to ignition and to start receiving messages. The main reason why this isn't implemented cleaner is that I didn't find documentation on how topic discovery works in ignition. However, there appears to be some documentation (living here) that describes how ignition passes messages around to discover topics.

A great addition would be to implement this discovery protocol here, so that we can cleanly interface with Ignition.

Possible related issue: gazebosim/gz-transport#225

@mjcarroll
Copy link

Great work on ropy so far!

One thought is that we could either expose a C API for doing a CPython-style wrapper. Alternatively, ROS2 has been moving forward with using pybind11 as a wrapper.

Adding a python api natively to transport could help reduce some wheel reinvention.

@FirefoxMetzger
Copy link
Owner Author

Great work on ropy so far!

Thanks! Glad to hear you like it 😄

Adding a python api natively to transport could help reduce some wheel reinvention.

I agree that it would be very nice to not have to reinvent the wheel unnecessarily. What I am less clear about is how to accomplish that. I seem to just see obstacles everywhere. Here are some thoughts:

  1. The current transport API only offers callback-based subscriptions, which voids any chance of determinism. This is fine for most cases, but if your aim is determinism and reproducible simulations then callbacks are a no-go. You need something like an await-able call to keep the simulation in sync and account for network/transport delays after each simulation step. ropy.ignition.Subscriber.recv(blocking=True) does just that. Here is a related comment and the comments above are partly on this topic. Unfortunately, this isn't possible via the current ign-transport API, but I guess it could be added? However, if you combine gym-ignition (to control the main loop) and ropy (for message passing) you can do just that.

On the topic of generated bindings (swig and to some extent pybind11) there are two drawbacks:

  1. If you use a wrapper you are missing out on all the language-specific features. For example, ropy.ignition.Subscriber implements a context manager, so you can use with ign.Subscriber(...) as topic: and have guaranteed cleanup. The same QoL applies to the interface in general. The generated API will always have a C++ feel with signatures that may be unintuitive in a language that isn't C++, cryptic error messages, and/or bad exception handling. gym-ignition (a really awesome library) is a good example here (uses swig bindings around a C++ API). You end up having to do something like assert model.to_gazebo().reset_base_world_linear_velocity(scenario_core.Array3d(velocity.tolist())) for something that should really be model.base_velocity = velocity (and fails with an Exception instead of True/False) in python.
  2. Another big point is documentation. If you come from python (in particular scipy/pydata), you are quite pampered on this point. Documentation is simply amazing. Lack of documentation aside (this could be fixed by simply writing it), documentation for C++ doesn't always translate well to the language of the wrapper. OpenCV is a nice example. The docs are primarily written for C++, and you have to infer the python syntax from it (though this improved in the recent past). Not exactly beginner-friendly.

Another option is to write a python wrapper by hand with meaningful signatures and docstrings, which then calls the C++ API under the hood. Many big python libraries do this (pytorch/torch, tensorflow, pyzmq, numpy, scipy) and this effectively deals with the two drawbacks of an automatically wrapped library. In general, this is a very nice approach and if Ignition goes down that road I'll probably end up helping out in some form. For ign-transport specifically, I think it may be easier to speak just speak the same protocol on the wire and use I/O as the natural boundary between languages. It just seems like less work given that we have pyzmq and betterproto which make communicating with Ignition quite pythonic already. For this to work, what is missing is node discovery, but that is mainly due to a lack of understanding on my part.

@FirefoxMetzger FirefoxMetzger added the ignition Issue related to ropy.ignition label Mar 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ignition Issue related to ropy.ignition
Projects
None yet
Development

No branches or pull requests

2 participants