Skip to content

Commit

Permalink
Merge pull request #7590 from EricCousineau-TRI/feature/py_systems_pr1
Browse files Browse the repository at this point in the history
Add preliminary Python bindings and examples for systems framework.
  • Loading branch information
EricCousineau-TRI authored Dec 22, 2017
2 parents 13c40e5 + 39ed50e commit 942aac2
Show file tree
Hide file tree
Showing 18 changed files with 972 additions and 12 deletions.
4 changes: 2 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ github_archive(
github_archive(
name = "pybind11",
repository = "RobotLocomotion/pybind11",
commit = "ffcf754ae9e766632610975d22372a86a7b63014",
sha256 = "7cd6f4efb02bf9ae17eeb2afba68023af913e61ae76e8b4254203d0eec019525", # noqa
commit = "48999b69bde29cdf8d616d4fbd3d6ab1c561027d",
sha256 = "2ea18adfb608948cab1b5978081dc8c318ed47573ccd66f1603a37fbdbfc56da", # noqa
build_file = "tools/workspace/pybind11/pybind11.BUILD.bazel",
)

Expand Down
11 changes: 7 additions & 4 deletions bindings/pydrake/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,16 @@ PYBIND_LIBRARIES = adjust_labels_for_drake_hoist([
":rbtree_py",
":symbolic_py",
"//drake/bindings/pydrake/solvers",
"//drake/bindings/pydrake/systems",
])

PY_LIBRARIES = [
":util_py",
]

install(
name = "install",
targets = [
":util_py",
],
targets = PY_LIBRARIES,
py_dest = get_pybind_library_dest(),
visibility = ["//visibility:public"],
deps = get_drake_pybind_installs(PYBIND_LIBRARIES),
Expand All @@ -131,7 +134,7 @@ install(
drake_py_library(
name = "pydrake",
visibility = ["//visibility:public"],
deps = PYBIND_LIBRARIES,
deps = PYBIND_LIBRARIES + PY_LIBRARIES,
)

# Test ODR (One Definition Rule).
Expand Down
12 changes: 6 additions & 6 deletions bindings/pydrake/solvers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,18 @@ PYBIND_LIBRARIES = [
":mosek_py",
]

PY_LIBRARIES = [
":module_py",
]

drake_py_library(
name = "solvers",
deps = PYBIND_LIBRARIES + [
":module_py",
],
deps = PYBIND_LIBRARIES + PY_LIBRARIES,
)

install(
name = "install",
targets = [
":module_py",
],
targets = PY_LIBRARIES,
py_dest = get_pybind_library_dest(),
deps = get_drake_pybind_installs(PYBIND_LIBRARIES),
)
Expand Down
1 change: 1 addition & 0 deletions bindings/pydrake/solvers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Blank Python module.
167 changes: 167 additions & 0 deletions bindings/pydrake/systems/BUILD.bazel
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()
1 change: 1 addition & 0 deletions bindings/pydrake/systems/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Blank Python module.
8 changes: 8 additions & 0 deletions bindings/pydrake/systems/all.py
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
26 changes: 26 additions & 0 deletions bindings/pydrake/systems/analysis_py.cc
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);
}
40 changes: 40 additions & 0 deletions bindings/pydrake/systems/drawing.py
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())
Loading

0 comments on commit 942aac2

Please sign in to comment.