Skip to content

Commit

Permalink
pydrake.systems: Add initial bindings and examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
EricCousineau-TRI committed Dec 20, 2017
1 parent c5bca1f commit 798474c
Show file tree
Hide file tree
Showing 16 changed files with 895 additions and 13 deletions.
7 changes: 4 additions & 3 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,10 @@ github_archive(

github_archive(
name = "pybind11",
repository = "RobotLocomotion/pybind11",
commit = "ffcf754ae9e766632610975d22372a86a7b63014",
sha256 = "7cd6f4efb02bf9ae17eeb2afba68023af913e61ae76e8b4254203d0eec019525", # noqa
# TODO(eric.cousineau): Merge this with RobotLocomotion.
repository = "EricCousineau-TRI/pybind11",
commit = "f87b3961002639b0bf2855d2e36e3ebaa71fac66",
sha256 = "f5e6d570de625d1f8ccaa0df21f8fd4cfcf0a07d459ea6460622afe4345de0af", # 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.
158 changes: 158 additions & 0 deletions bindings/pydrake/systems/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# -*- 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__",
]))

drake_py_library(
name = "module_py",
srcs = ["__init__.py"],
deps = [
"//drake/bindings/pydrake:common_py",
# TODO(eric.cousineau): This does NOT include direct dependencies to
# submodule. This is to preserve C++-like namespaces.
],
)

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",
srcs = ["test/general_test.py"],
deps = [
":analysis_py",
":framework_py",
":primitives_py",
],
)

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",
srcs = ["test/lifetime_test.py"],
deps = [
":analysis_py",
":framework_py",
":lifetime_test_util",
":primitives_py",
],
)

drake_py_test(
name = "custom_test",
size = "small",
srcs = ["test/custom_test.py"],
deps = [
":analysis_py",
":framework_py",
":primitives_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
25 changes: 25 additions & 0 deletions bindings/pydrake/systems/analysis_py.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#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_mutable_context", &Simulator<T>::get_mutable_context, py_iref);
}
37 changes: 37 additions & 0 deletions bindings/pydrake/systems/drawing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# @file
# 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):
# @see Ioannis's follow-up comment.
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 798474c

Please sign in to comment.