-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7590 from EricCousineau-TRI/feature/py_systems_pr1
Add preliminary Python bindings and examples for systems framework.
- Loading branch information
Showing
18 changed files
with
972 additions
and
12 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
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 @@ | ||
# Blank Python module. |
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,167 @@ | ||
# -*- python -*- | ||
|
||
load("@drake//tools/install:install.bzl", "install") | ||
load("//tools/lint:lint.bzl", "add_lint_tests") | ||
load( | ||
"//tools/skylark:pybind.bzl", | ||
"drake_pybind_library", | ||
"get_drake_pybind_installs", | ||
"get_pybind_library_dest", | ||
) | ||
load( | ||
"//tools/skylark:drake_py.bzl", | ||
"drake_py_binary", | ||
"drake_py_library", | ||
"drake_py_test", | ||
) | ||
load("//tools/skylark:6996.bzl", "adjust_labels_for_drake_hoist") | ||
|
||
package(default_visibility = adjust_labels_for_drake_hoist([ | ||
"//drake/bindings/pydrake:__subpackages__", | ||
])) | ||
|
||
# @note Symbols are NOT imported directly into | ||
# `__init__.py` to simplify dependency management, meaning that | ||
# classes are organized by their directory structure rather than | ||
# by C++ namespace. If you want all symbols, use `all.py`. | ||
drake_py_library( | ||
name = "module_py", | ||
srcs = ["__init__.py"], | ||
deps = [ | ||
"//drake/bindings/pydrake:common_py", | ||
], | ||
) | ||
|
||
drake_pybind_library( | ||
name = "framework_py", | ||
cc_so_name = "framework", | ||
cc_srcs = ["framework_py.cc"], | ||
py_deps = [ | ||
":module_py", | ||
], | ||
) | ||
|
||
drake_pybind_library( | ||
name = "primitives_py", | ||
cc_so_name = "primitives", | ||
cc_srcs = ["primitives_py.cc"], | ||
py_deps = [ | ||
":framework_py", | ||
":module_py", | ||
], | ||
) | ||
|
||
drake_pybind_library( | ||
name = "analysis_py", | ||
cc_so_name = "analysis", | ||
cc_srcs = ["analysis_py.cc"], | ||
py_deps = [ | ||
":framework_py", | ||
":module_py", | ||
], | ||
) | ||
|
||
drake_py_library( | ||
name = "drawing_py", | ||
srcs = ["drawing.py"], | ||
deps = [":module_py"], | ||
# TODO(eric.cousineau): Expose information to allow `imports = ...` to be | ||
# defined, rather than rely on `module_py`. | ||
) | ||
|
||
drake_py_library( | ||
name = "all_py", | ||
deps = [ | ||
":analysis_py", | ||
":drawing_py", | ||
":framework_py", | ||
":primitives_py", | ||
], | ||
) | ||
|
||
PYBIND_LIBRARIES = [ | ||
":analysis_py", | ||
":framework_py", | ||
":primitives_py", | ||
] | ||
|
||
PY_LIBRARIES = [ | ||
":all_py", | ||
":drawing_py", | ||
":module_py", | ||
] | ||
|
||
drake_py_library( | ||
name = "systems", | ||
deps = PYBIND_LIBRARIES + PY_LIBRARIES, | ||
) | ||
|
||
install( | ||
name = "install", | ||
targets = PY_LIBRARIES, | ||
py_dest = get_pybind_library_dest(), | ||
deps = get_drake_pybind_installs(PYBIND_LIBRARIES), | ||
) | ||
|
||
drake_py_test( | ||
name = "general_test", | ||
size = "small", | ||
deps = [ | ||
":analysis_py", | ||
":framework_py", | ||
":primitives_py", | ||
], | ||
) | ||
|
||
# TODO(eric.cousineau): Convert this to a workflow test once `pydot` is added | ||
# to `install_prereqs.sh`. | ||
drake_py_binary( | ||
name = "graphviz_example", | ||
srcs = ["test/graphviz_example.py"], | ||
deps = [ | ||
":drawing_py", | ||
":framework_py", | ||
":primitives_py", | ||
], | ||
) | ||
|
||
drake_pybind_library( | ||
name = "lifetime_test_util", | ||
testonly = 1, | ||
add_install = False, | ||
cc_so_name = "test/lifetime_test_util", | ||
cc_srcs = ["test/lifetime_test_util_py.cc"], | ||
py_deps = [ | ||
":primitives_py", | ||
], | ||
) | ||
|
||
drake_py_test( | ||
name = "lifetime_test", | ||
deps = [ | ||
":analysis_py", | ||
":framework_py", | ||
":lifetime_test_util", | ||
":primitives_py", | ||
], | ||
) | ||
|
||
drake_py_test( | ||
name = "custom_test", | ||
size = "small", | ||
deps = [ | ||
":analysis_py", | ||
":framework_py", | ||
":primitives_py", | ||
], | ||
) | ||
|
||
drake_py_test( | ||
name = "vector_test", | ||
size = "small", | ||
deps = [ | ||
":framework_py", | ||
], | ||
) | ||
|
||
add_lint_tests() |
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 @@ | ||
# Blank Python module. |
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,8 @@ | ||
from .analysis import * | ||
from .framework import * | ||
from .primitives import * | ||
|
||
try: | ||
from .drawing import * | ||
except ImportError: | ||
pass |
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,26 @@ | ||
#include <pybind11/pybind11.h> | ||
|
||
#include "drake/systems/analysis/simulator.h" | ||
|
||
namespace py = pybind11; | ||
|
||
using std::unique_ptr; | ||
|
||
PYBIND11_MODULE(analysis, m) { | ||
// NOLINTNEXTLINE(build/namespaces): Emulate placement in namespace. | ||
using namespace drake::systems; | ||
|
||
auto py_iref = py::return_value_policy::reference_internal; | ||
|
||
m.doc() = "Bindings for the analysis portion of the Systems framework."; | ||
|
||
using T = double; | ||
|
||
py::class_<Simulator<T>>(m, "Simulator") | ||
.def(py::init<const System<T>&>()) | ||
.def(py::init<const System<T>&, unique_ptr<Context<T>>>()) | ||
.def("Initialize", &Simulator<T>::Initialize) | ||
.def("StepTo", &Simulator<T>::StepTo) | ||
.def("get_context", &Simulator<T>::get_context, py_iref) | ||
.def("get_mutable_context", &Simulator<T>::get_mutable_context, py_iref); | ||
} |
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,40 @@ | ||
""" | ||
Provides general visualization utilities. This is NOT related to `rendering`. | ||
@note This is an optional module, dependent on `pydot` and `matplotlib` being | ||
installed. | ||
""" | ||
|
||
from StringIO import StringIO | ||
|
||
import matplotlib.image as mpimg | ||
import matplotlib.pyplot as plt | ||
import pydot | ||
|
||
|
||
# TODO(eric.cousineau): Move `plot_graphviz` to something more accessible to | ||
# `call_python_client`. | ||
|
||
|
||
def plot_graphviz(dot_text): | ||
"""Renders a DOT graph in matplotlib.""" | ||
# @ref https://stackoverflow.com/a/18522941/7829525 | ||
# Tried (reason ignored): pydotplus (`pydot` works), networkx | ||
# (`read_dot` does not work robustly?), pygraphviz (coupled with | ||
# `networkx`). | ||
g = pydot.graph_from_dot_data(dot_text) | ||
if isinstance(g, list): | ||
# Per Ioannis's follow-up comment in the above link, in pydot >= 1.2.3 | ||
# `graph_from_dot_data` returns a list of graphs. | ||
# Handle this case for now. | ||
assert len(g) == 1 | ||
g = g[0] | ||
s = StringIO() | ||
g.write_png(s) | ||
s.seek(0) | ||
plt.axis('off') | ||
return plt.imshow(plt.imread(s), aspect="equal") | ||
|
||
|
||
def plot_system_graphviz(system): | ||
"""Renders a System's Graphviz representation in `matplotlib`. """ | ||
return plot_graphviz(system.GetGraphvizString()) |
Oops, something went wrong.