-
Notifications
You must be signed in to change notification settings - Fork 275
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
Scripting interface to simulation workflow #789
Comments
I started a prototype of I converted some few method to make it work:
You can try it with the following Python script: from ignition_gazebo import ServerConfig, Server
from ignition_common import set_verbosity
import time
set_verbosity(4)
server_config = ServerConfig()
server_config.set_sdf_file('rolling_shapes.sdf')
server = Server(server_config)
print('Has entity ', server.has_entity('box', 0))
server.run(False, 10000, False)
while(server.is_running()):
time.sleep(0.1)
Incremental example 1But I was thinking about how to get some data from the simulation. I thought that I can subscribe to some ignition topic. Then I ported:
from ignition_gazebo import ServerConfig, Server
from ignition_common import set_verbosity
from ignition_transport import Node
from ignition_msgs import PoseV
import time
set_verbosity(4)
server_config = ServerConfig()
server_config.set_sdf_file('rolling_shapes.sdf')
server = Server(server_config)
print('Has entity ', server.has_entity('box', 0))
def square(msg):
msg.show()
node = Node()
node.subscribe('/world/shapes/pose/info', square)
server.run(False, 10000, False)
while(server.is_running()):
time.sleep(0.1) Incremental example 2Then I was thinking about to get values from the msgs in Python, not calling a method that prints everything. Here is where the magic start. I don't know if there is a simpler way to convert types between pybind11 and SWIG. from ignition_gazebo import ServerConfig, Server
from ignition.math import Vector3d
from ignition_msgs import PoseV
p = PoseV()
print(p.get_size())
print(p.get_names())
print(p.get_poses())
print(p.pose())
print(p.pose().x())
p.set_pose(Vector3d(0, 1, 2)) The two key methods are:
These thow functions are defined in Suggestions are welcome |
By the way this is branch https://github.com/ignitionrobotics/ign-gazebo/tree/ahcorde/pybind11 |
By the way, regarding the interoperation of Python bindings created by different systems a relevant discussion in Pinocchio is stack-of-tasks/pinocchio#1518 . There is a PR from @jmirabel in stack-of-tasks/pinocchio#1519 providing (as far as I understand) interoperability of pybind11 and boost-python, while in stack-of-tasks/pinocchio#1518 (comment) @jcarpent mention something related to SWIG and boost-python interoperability, that I guess was provided by this PR : https://github.com/stack-of-tasks/eigenpy/pull/219/files . FYI @GiulioRomualdi @S-Dafarra @prashanthr05 @diegoferigo as I think this discussion is similar to the one in ami-iit/bipedal-locomotion-framework#214 . |
While this is a pretty straightforward path to extract data from the simulation as first attempt, I would argue about its efficiency and precision. In your example, the
My suggestion for the first comment would be to run the server synchronously so that code that caller doesn't have to poll the simulation status. For the second, instead, you might want to exposing to some extent the ECM to Python. If the whole ECM is too much, access can be limited by only exposing the These two comments are also part of how the ScenarIO project is based. You can find the wrapper class of What's still challenging is how to expose sensors (robotology-legacy/gym-ignition#199), it's something not yet possible and I think it could become a bottleneck in the future, especially for all the visual data-rich sensors. Passing through the many copies using transport might not be efficient. In any case, exposing sensors is an even wider discussion, I just wanted to mention it here since it could affect design choices. |
Thank you for your feedback @diegoferigo and @traversaro, I has been prototyping more ideas here, in particular
SWIG Examplefrom ignition.gazebo import Console, ServerConfig, Server, HelperFixture, World, Callback, EntityComponentManager
from ignition.math import Vector3d
import time
Console.set_verbosity(4)
helper = HelperFixture('gravity.sdf')
post_iterations = 0
iterations = 0
pre_iterations = 0
class CallPostUpdate(Callback):
def __init__(self):
super(CallPostUpdate, self).__init__()
def call_update(self, _info, _ecm):
global post_iterations
post_iterations += 1
class CallUpdate(Callback):
def __init__(self):
super(CallUpdate, self).__init__()
def call_update_no_const(self, _info, _ecm):
global iterations
iterations += 1
class CallPreUpdate(Callback):
def __init__(self):
super(CallPreUpdate, self).__init__()
def call_update_no_const(self, _info, _ecm):
global pre_iterations
pre_iterations += 1
class CallConfigure(Callback):
def __init__(self):
super(CallConfigure, self).__init__()
def call_configure_callback(self, _entity, _ecm):
world = World(_entity)
gravity = world.gravity(_ecm)
modelEntity = world.model_by_name(_ecm, "falling")
print("modelEntity ", modelEntity)
# print("gravity ", gravity)
postupdate = CallPostUpdate()
update = CallUpdate()
preupdate = CallPreUpdate()
configure = CallConfigure()
helper.on_post_update(postupdate)
helper.on_update(update)
helper.on_pre_update(preupdate)
helper.on_configure(configure)
helper.finalize()
server = helper.server()
server.run(False, 1000, False)
while(server.running()):
time.sleep(0.1)
print("iterations ", iterations)
print("post_iterations ", post_iterations)
print("pre_iterations ", pre_iterations) Examplefrom ignition_gazebo import ServerConfig, Server, HelperFixture, World
from ignition_common import set_verbosity
from ignition_transport import Node
from ignition_msgs import PoseV
from ignition.math import Vector3d
import time
set_verbosity(4)
helper = HelperFixture('gravity.sdf')
post_iterations = 0
iterations = 0
pre_iterations = 0
def on_configure_cb(worldEntity, _ecm):
print("worldEntity ", worldEntity)
w = World(worldEntity)
# print("Gravety ", str(w.gravity()))
modelEntity = w.model_by_name(_ecm, "falling")
print("modelEntity ", modelEntity)
def on_post_udpate_cb(_info, _ecm):
global post_iterations
post_iterations += 1
# print(_info.sim_time)
def on_pre_udpate_cb(_info, _ecm):
global pre_iterations
pre_iterations += 1
# print(_info.sim_time)
def on_udpate_cb(_info, _ecm):
global iterations
iterations += 1
# print(_info.sim_time)
helper = helper.on_post_update(on_post_udpate_cb)
helper = helper.on_update(on_udpate_cb)
helper = helper.on_pre_update(on_pre_udpate_cb)
helper = helper.on_configure(on_configure_cb)
helper = helper.finalize()
server = helper.server()
server.run(False, 1000, False)
while(server.is_running()):
time.sleep(0.1)
print("iterations ", iterations)
print("post_iterations ", post_iterations)
print("pre_iterations ", pre_iterations) I have some blockers:
|
Ey @diegoferigo and @traversaro, I saw that you have read the last comment (because of the thumbs up). Do you have any idea about how to create SWIG object inside pybind11 ? or do you an an opinion about mixing these two libraries ? it's SWIG or pybin11 the way to go ?. We appreciate any feddback here. |
Hi @ahcorde, I was hoping someone to chime in, I have experience with both pybind11 and SWIG used independently, but I've never tried to make bound objects compatible from one system to the other. For what regards pybind11 vs SWIG, I can only repeat what I've already wrote in gazebosim/gz-math#210 (comment). In my experiments, I've only used SWIG within the same project. This means that I didn't have the chance to explore how Python objects from other projects can be passed as arguments. I guess that, under the assumption you control all the Staying instead in a pybind11 setup, the interoperability between different projects seems easier. We successfully managed to use the official In light of my gazebosim/gz-math#210 (comment), considering the stability of your APIs, the standard you're using in the public headers, the willing to make bindings coming from different projects interoperate, and -perhaps- easy numpy support, I think that the task would be easier with pybind11, but I also imagine that only supporting Python could be a blocker. |
I must confess that it was a "thumb up" for "great that someone is working on this", without reading in detail your comment, not sure if this violates any code of conduct or similar. : ) |
Can you make an example of what you would like to do? Anyhow, in general my general instinct is that mixing pybind11 and swig bindings is a bit of dangerous/effort intensive path.
Why we would need to create manually ign-math objects if all is handled by SWIG? If I remember correctly how these things works in SWIG, you should install the <>.i file of ign-math and then import it in the <>.i of ign-gazebo. For an example of such workflow, see https://github.com/casadi/casadi/tree/3.5.5/swig/extending_casadi and casadi/casadi#1559, in which casadi (a C++ project with SWIG bindings) is extended by another C++ project (in this case |
xref related issue: pybind/pybind11#1706 . |
@ahcorde thanks for posting your branch with the experimental pybind11 Python bindings, it's been very helpful. My immediate interest is to obtain bindings to the ignition-msgs and ignition-transport libraries so I can subscribe to ignition topics in Python for further processing. Have you looked into using https://github.com/pybind/pybind11_protobuf to manage the conversion between the Python bindings generated by |
Hi @srmainwaring , the scope of our current scripting efforts is limited to Thank you for pointing us at |
@chapulina thanks for the outline. As you're not planning to work on I've put together a project here https://github.com/srmainwaring/python-ignition which generates bindings for the messages I'm interested in and exposes a mock-up of ign-transport which is then exposed to Python with It's all built with Bazel as that is what the If there's any interest or overlap with your team's work - happy to collaborate, otherwise I'll post something on community if I manage to get it all working. |
That's great to hear, @srmainwaring ! We'd be willing to maintain and package the pybind11 interfaces within We'd need to get it to work with CMake though. Our Bazel support is experimental and meant to help downstream users who want to use it, but our official build tool is CMake. In any case, you should advertise your work to the community, no matter where it lands 😉 |
@chapulina that would be great thanks. The plan is to get it working with CMake but easiest path initially is using Bazel as some of the dependent libraries are missing CMake builds (namely pybind11_protobuf). In the meanwhile I'll track the Bazel version in this issue gazebosim/gz-bazel#40 (and the publishing bindings are working!!) |
The proof-of-concept has been merged, so I'm closing this issue. If bugs come up and more features are desired, please open new tickets for them. We'd love to hear what the community thinks of the proof-of-concept before adding more features to the current implementation. |
Desired behavior
Gazebo can be used as a library by other programs, like shown on the custom_server example. The Server C++ API can be used to initialize the simulation and step it using the
Run
function.It would be interesting to expose that functionality through a C API so that it can be eventually wrapped by other scripting languages like Python.
We already have a C API in ign.cc which is used by the command line tool, but we don't expose that to users or keep it stable.
The new C API should be able to do things like starting a server, loading an SDF file, stepping the simulation and retrieving data (entities and components) from it.
Alternatives considered
Instead of adding a C API, we could extend the C++ API to add the desired functionality, and that can be converted to scripting languages using SWIG like we're doing on ign-math.
Implementation suggestion
Before creating the API, it would be interesting to write a concise design doc into https://github.com/ignitionrobotics/design
Additional context
The
gym-ignition
project is using SWIG to wrap our C++ API, with some sugar on top 🍬The text was updated successfully, but these errors were encountered: