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

Add support for writing systems in Python #2081

Merged
merged 23 commits into from
Aug 31, 2023
Merged

Conversation

azeey
Copy link
Contributor

@azeey azeey commented Aug 17, 2023

🎉 New feature

Closes #790
Replaces #2045, which was automatically closed by Github when the branch it was targeting was deleted.

Summary

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.

I'd appreciate feedback on the convention/general interface between PythonSystemLoader and python systems.

TODO:

  • Add tests

Test it

Run examples/worlds/python_system_loader.sdf. See the file for instructions on environmental variables that need to be set.

Checklist

  • Signed all commits for DCO
  • Added tests
  • Added example and/or tutorial
  • Updated documentation (as needed)
  • Updated migration guide (as needed)
  • Consider updating Python bindings (if the library has them)
  • codecheck passed (See contributing)
  • All tests passed (See test coverage)
  • While waiting for a review on your PR, please help review another open pull request to support the maintainers

Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining Signed-off-by messages.

@azeey azeey requested a review from mjcarroll as a code owner August 17, 2023 23:22
@github-actions github-actions bot added the 🎵 harmonic Gazebo Harmonic label Aug 17, 2023
}
catch (const pybind11::error_already_set &_err)
{
gzerr << _err.what() << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the error message contain the name of the method and python module here? It would certainly help with tracking down errors, otherwise they will all have the same name, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should, but I'll double check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I threw an exception in the python file and this is what I got

[Err] [PythonSystemLoader.cc:174] NameError: name 'entity' is not defined

At:
  ~/ws/harmonic/src/gz-sim/python/test/plugins/test_model_system.py(51): pre_update

I think that's sufficient.

}

//////////////////////////////////////////////////
void PythonSystemLoader::PostUpdate(const UpdateInfo &_info,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we determine what happens when there are multiple python modules? Is that supported/unsupported?

Postupdate is the most interesting case because of parallel execution

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we're currently creating an instance of pybind11::scoped_interpreter in ServerPrivate and it seems to work fine with multiple python modules, since there's only one Server instance. However, if we want to have multiple Servers in the same process, this will not work. So maybe we need a Singleton for this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can generally assume that multiple Servers per process isn't likely at the moment. We may want to add a note somewhere in the event that someone attempts it, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the tests were failing because they initialized two Server instances. I fixed it by using pybind11::initialize_interpreter() instead of pybind11::scoped_interpreter so we can skip initialization of the interpreter is already initialized.

@mjcarroll
Copy link
Contributor

Hmm, approval is more of approval-of-approach. I think we still need a few tests here (which you have already noted)

@azeey azeey added the beta Targeting beta release of upcoming collection label Aug 21, 2023
Copy link
Contributor

@caguero caguero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works for me, this is very cool. I just left very minor comments.

I think the PythonSystemLoader is a good option. I was thinking if it would make sense to promote this upstream somehow but I didn't find a better approach than this one.

@azeey azeey requested a review from mabelzhang as a code owner August 24, 2023 19:33
azeey added 10 commits August 24, 2023 14:33
Signed-off-by: Addisu Z. Taddese <[email protected]>
This allows multiple PythonSystemLoaders to run albeit with a single
python interpreter.

Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
Copy link
Contributor Author

@azeey azeey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a couple of GIL issues that showed up when I started using gz-transport inside the python system. The fix requires releasing the GIL when we run PostUpdate threads and acquire the GIL from the threads each PostUpdate runs in. This also requires an update to gz-transport so that the GIL is acquired before calling subscription callbacks since that also happens from a different thread than the main thread that contains the Python interpreter.

}

//////////////////////////////////////////////////
void PythonSystemLoader::PostUpdate(const UpdateInfo &_info,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the tests were failing because they initialized two Server instances. I fixed it by using pybind11::initialize_interpreter() instead of pybind11::scoped_interpreter so we can skip initialization of the interpreter is already initialized.

Signed-off-by: Addisu Z. Taddese <[email protected]>
azeey added 2 commits August 24, 2023 18:26
Signed-off-by: Addisu Z. Taddese <[email protected]>
src/ServerPrivate.hh Outdated Show resolved Hide resolved
}

void PythonSystemLoader::Configure(
const Entity &_entity, const std::shared_ptr<const sdf::Element> &_sdf,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

include ENtity, sdf::Element, EntityComponentManager, EventManager, SystemLoader

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some were already there, added the rest in f30128f

CallPythonMethod(this->resetMethod, _info, &_ecm);
}

GZ_ADD_PLUGIN(PythonSystemLoader, System, ISystemConfigure, ISystemPreUpdate,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

include system.hh

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to if it's already in "PythonSystemLoader.hh"? Added anyway f30128f

test/integration/python_system_loader.cc Show resolved Hide resolved
common::joinPaths(std::string(PROJECT_SOURCE_PATH), "python",
"test", "plugins"));

sim::ServerConfig serverConfig;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

include: ServerConfig, gz/common/Filesystem.hh, components::Name, components::Model, sim::worldPose

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the headers were already there, added the rest in f30128f

test/integration/python_system_loader.cc Show resolved Hide resolved
Signed-off-by: Addisu Z. Taddese <[email protected]>
@azeey azeey self-assigned this Aug 25, 2023
tutorials/python_interfaces.md Outdated Show resolved Hide resolved
tutorials/python_interfaces.md Outdated Show resolved Hide resolved
azeey added 4 commits August 28, 2023 10:41
Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
Signed-off-by: Addisu Z. Taddese <[email protected]>
@codecov
Copy link

codecov bot commented Aug 28, 2023

Codecov Report

Merging #2081 (5d11d53) into main (5846393) will decrease coverage by 0.03%.
Report is 2 commits behind head on main.
The diff coverage is 68.03%.

❗ Current head 5d11d53 differs from pull request most recent head dfe27ab. Consider uploading reports for the commit dfe27ab to get more accurate results

@@            Coverage Diff             @@
##             main    #2081      +/-   ##
==========================================
- Coverage   65.32%   65.30%   -0.03%     
==========================================
  Files         321      322       +1     
  Lines       30303    30410     +107     
==========================================
+ Hits        19795    19858      +63     
- Misses      10508    10552      +44     
Files Changed Coverage Δ
include/gz/sim/EventManager.hh 75.75% <ø> (ø)
...systems/python_system_loader/PythonSystemLoader.cc 57.60% <57.60%> (ø)
src/Link.cc 98.31% <100.00%> (+0.05%) ⬆️
src/Server.cc 87.13% <100.00%> (+0.15%) ⬆️
src/SimulationRunner.cc 91.13% <100.00%> (-0.85%) ⬇️

... and 2 files with indirect coverage changes

@azeey azeey merged commit a84d66a into gazebosim:main Aug 31, 2023
3 checks passed
@azeey azeey deleted the python_systems branch August 31, 2023 03:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta Targeting beta release of upcoming collection 🎵 harmonic Gazebo Harmonic
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants