Skip to content

Commit

Permalink
Add preliminary binding example for systems framework.
Browse files Browse the repository at this point in the history
  • Loading branch information
EricCousineau-TRI committed Dec 13, 2017
1 parent c8a6b51 commit 005e836
Show file tree
Hide file tree
Showing 11 changed files with 533 additions and 13 deletions.
7 changes: 4 additions & 3 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,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 = "b7e92676552dc73613c8e18624091fa9ffd4fa54",
sha256 = "464d35d81c680ea251f3c09d6f1f2fef34e9696c49865a6cea193d6a0de9caf9", # 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,
)

drake_py_test(
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
115 changes: 115 additions & 0 deletions bindings/pydrake/systems/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# -*- 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`.
)

PYBIND_LIBRARIES = [
":analysis_py",
":framework_py",
":primitives_py",
]

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

drake_py_binary(
name = "system_graphviz_example",
srcs = ["test/system_graphviz_example.py"],
deps = [
":analysis_py",
":drawing_py",
":framework_py",
":primitives_py",
],
)

add_lint_tests()
23 changes: 23 additions & 0 deletions bindings/pydrake/systems/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import absolute_import, print_function

# TODO(eric.cousineau): Should we attempt to modularize this dependency graph?
# How about separating this setup (development) from a more pure approach
# (deployment)?

try:
from .analysis import *
except ImportError as e:
print(e)
pass

try:
from .framework import *
except ImportError as e:
print(e)
pass

try:
from .primitives import *
except ImportError as e:
print(e)
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);
}
33 changes: 33 additions & 0 deletions bindings/pydrake/systems/drawing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# @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)
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 005e836

Please sign in to comment.