Skip to content

Commit

Permalink
Pybind11 manual bindings (#499)
Browse files Browse the repository at this point in the history
* Manual binding for minimal set of  aikido components

* Update readme

* Fix typo

* Add Skeleton, MetaSkeleton, WorldInteractiveMarkerViewer, TSRMarker, World, ConcreteManipulator, CollisionFree to pybind11

* update python binding install guide

* update pybinding for conda-managed python

* remove swp file

* Update README.md

* Skeleton code for aikidopy using pybind11 (#528)
  • Loading branch information
gilwoolee authored and brianhou committed Jul 21, 2019
1 parent de5ee11 commit 2c75322
Show file tree
Hide file tree
Showing 43 changed files with 676 additions and 367 deletions.
23 changes: 23 additions & 0 deletions .ci/install_linux_catkin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,26 @@ cp -r "${TRAVIS_BUILD_DIR}" src
if [ $BUILD_NAME = TRUSTY_FULL_DEBUG ]; then
sudo apt-get install -y clang-format-3.8
fi

if [ "$BUILD_AIKIDOPY" = "ON" ]; then
$SUDO apt-get -y install python3-dev python3-numpy
$SUDO apt-get -y install python3-pip -y
$SUDO pip3 install pytest -U

if [ $(lsb_release -sc) = "trusty" ] || [ $(lsb_release -sc) = "xenial" ] || [ $(lsb_release -sc) = "bionic" ]; then
git clone https://github.com/pybind/pybind11 -b 'v2.3.0' --single-branch --depth 1
cd pybind11
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DPYBIND11_TEST=OFF
make -j4
$SUDO make install
cd ../..
elif [ $(lsb_release -sc) = "cosmic" ] || [ $(lsb_release -sc) = "disco" ]; then
$SUDO apt-get -y install pybind11-dev python3 libpython3-dev python3-pytest \
python3-distutils
else
echo -e "$(lsb_release -sc) is not supported."
exit 1
fi
fi
7 changes: 7 additions & 0 deletions .ci/script_catkin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ if [ $BUILD_NAME = TRUSTY_FULL_DEBUG ]; then
./scripts/internal-run.sh catkin build --no-status --no-deps -p 1 -i --make-args check-format -- aikido
fi

# Build aikidopy and pytest
if [ $BUILD_AIKIDOPY = ON ]; then
./scripts/internal-run.sh catkin build --no-status --no-deps -p 1 -i --cmake-args -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DTREAT_WARNINGS_AS_ERRORS=OFF -DCODECOV=OFF --make-args aikidopy -- aikido
./scripts/internal-run.sh make -C build/aikido pytest
exit 0
fi

# Manually build Aikido's tests; they are not built automatically because it is not a Catkin package.
if [ $BUILD_NAME = TRUSTY_FULL_DEBUG ]; then
./scripts/internal-run.sh catkin build --no-status --no-deps -p 1 -i --cmake-args -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DTREAT_WARNINGS_AS_ERRORS=ON -DCODECOV=ON --make-args tests -- aikido
Expand Down
13 changes: 10 additions & 3 deletions .ci/script_cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ unset -f cd; # Disable rvm override of cd (see https://github.com/travis-ci/trav

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTREAT_WARNINGS_AS_ERRORS=ON ..
make -j4 tests
make test

if [ $BUILD_AIKIDOPY = ON ]; then
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTREAT_WARNINGS_AS_ERRORS=ON -DBUILD_AIKIDOPY=ON ..
make -j4 aikidopy
make pytest
else
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DTREAT_WARNINGS_AS_ERRORS=ON ..
make -j4 tests
make test
fi
27 changes: 27 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,25 @@ matrix:
- USE_CATKIN=OFF
services: docker

- os: linux
env:
- BUILD_NAME=BIONIC_CATKIN_FULL_RELEASE_AIKIDOPY
- DOCKER_FILE="ubuntu-bionic"
- BUILD_TYPE=Release
- CATKIN_CONFIG_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DTREAT_WARNINGS_AS_ERRORS=ON -DBUILD_AIKIDOPY=ON"
- USE_CATKIN=ON
- BUILD_AIKIDOPY=ON
services: docker

- os: linux
env:
- BUILD_NAME=BIONIC_CMAKE_RELEASE_AIKIDOPY
- DOCKER_FILE="ubuntu-bionic"
- BUILD_TYPE=Release
- USE_CATKIN=OFF
- BUILD_AIKIDOPY=ON
services: docker

- os: osx
osx_image: xcode11
compiler: clang
Expand Down Expand Up @@ -150,6 +169,14 @@ matrix:
- USE_CATKIN=ON
services: docker

- os: osx
osx_image: xcode11
compiler: clang
env:
- BUILD_NAME=XCODE11_CMAKE_RELEASE
- BUILD_TYPE=Release
- USE_CATKIN=OFF

before_install:
- if [ -n "$DOCKER_FILE" ]; then
docker build -t "$DOCKER_FILE" -f ".ci/docker/$DOCKER_FILE" .;
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ set(CONFIG_INSTALL_DIR "${LIBRARY_INSTALL_DIR}/${PROJECT_NAME}/cmake")
option(CODECOV "Enable codecov support" OFF)
option(DOWNLOAD_TAGFILES "Download Doxygen tagfiles for dependencies" OFF)
option(TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
option(BUILD_AIKIDOPY "Build aikidopy (the python binding)" OFF)

if(BUILD_AIKIDOPY)
set(BUILD_SHARED_LIBS OFF)
endif()

#==============================================================================
# codecov Setup
Expand Down Expand Up @@ -134,6 +139,8 @@ add_custom_target(headers SOURCES ${aikido_headers})

add_subdirectory("src")

add_subdirectory("python")

enable_testing()
add_subdirectory("tests" EXCLUDE_FROM_ALL)

Expand Down
7 changes: 7 additions & 0 deletions include/aikido/robot.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "robot/ConcreteManipulator.hpp"
#include "robot/ConcreteRobot.hpp"
#include "robot/GrabMetadata.hpp"
#include "robot/Hand.hpp"
#include "robot/Manipulator.hpp"
#include "robot/Robot.hpp"
#include "robot/util.hpp"
4 changes: 2 additions & 2 deletions include/aikido/rviz.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "rviz/BodyNodeMarker.hpp"
#include "rviz/FrameMarker.hpp"
#include "rviz/InteractiveMarkerViewer.hpp"
#include "rviz/pointers.hpp"
#include "rviz/ResourceServer.hpp"
#include "rviz/shape_conversions.hpp"
#include "rviz/ShapeFrameMarker.hpp"
#include "rviz/SkeletonMarker.hpp"
#include "rviz/SmartPointers.hpp"
#include "rviz/TSRMarker.hpp"
#include "rviz/WorldInteractiveMarkerViewer.hpp"
#include "rviz/shape_conversions.hpp"
4 changes: 4 additions & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(AIKIDOPY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/aikidopy")

add_subdirectory(aikidopy)
add_subdirectory(tests)
55 changes: 55 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# aikidopy

This folder contains manual bindings for aikidopy using pybind11. The installation guide have been tested on
- sudo apt installed Python 2.7 and Python 3.4.
- anaconda managed Python 3.6

0. If you use system installed Python, ensure you have `python2.7-dev` or `python3-dev` correspondingly. Run `$ sudo apt-get install python3-dev` to obtain it.


1. Install [pybind11](https://github.com/pybind/pybind11.git) **from source** following these [instructions](https://pybind11.readthedocs.io/en/master/basics.html#compiling-the-test-cases). (Need version >= 2.2.0).

```
$ git clone https://github.com/pybind/pybind11.git
$ cd pybind11
$ mkdir build
$ cd build
$ cmake ..
$ make -j 4
```

- For system managed python: `$ sudo make install`;
- For anaconda: `$ pip install -e .`.

You should be able to load `pybind11` in your python.

```
$ python
>>> import pybind11
```

2. Build aikido and source the setup file.
```
$ catkin build aikido
$ source workspace/devel/setup.bash
```

3. Create a folder `workspace/src/aikido/python/build` (instead of `workspace/src/aikido/build`). Build and install the python binding, passing the desired python version using `-DAIKIDOPY_PYTHON_VERSION`.

```
$ cd build
$ cmake .. -DAIKIDOPY_PYTHON_VERSION=2.7 # or 3.4, 3.6 etc
$ make -j
$ sudo make install
```

Read the output of `sudo make install` and ensure that `aikidopy.so` get installed in the python library path (i.e. `/usr/lib/python2.7/dist-packages/aikidopy.so` or `anaconda3/envs/YOUR_ENV/lib/python3.6/site-packages/aikidopy.so`).

4. Try loading.
```
$ python
>>> import aikidopy
```

## Tips
- If you have multiple python environment, ensure that `which python` and the python version you passed to cmake refers to the same python.
101 changes: 101 additions & 0 deletions python/aikidopy/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
cmake_minimum_required(VERSION 2.8.12)

if(NOT AIKIDOPY_PYTHON_VERSION)
set(AIKIDOPY_PYTHON_VERSION 3.4 CACHE STRING "Choose the target Python version (e.g., 3.4, 2.7)" FORCE)
endif()

find_package(PythonInterp ${AIKIDOPY_PYTHON_VERSION} REQUIRED)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c
"from distutils.sysconfig import get_python_lib;\
print(get_python_lib(plat_specific=True, prefix=''))"
OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT PythonInterp_FOUND)
message(STATUS "BUILD_PYTHON is ON, but failed to find PythonInterp. "
"Disabling aikidopy."
)
return()
endif()

find_package(PythonLibs ${AIKIDOPY_PYTHON_VERSION} QUIET)
if(NOT PythonLibs_FOUND)
message(STATUS "BUILD_AIKIDOPY is ON, but failed to find PythonLibs. "
"Disabling aikidopy."
)
return()
endif()

# Find pybind11
# Needs to set PYBIND11_PYTHON_VERSION before finding pybind11
set(PYBIND11_PYTHON_VERSION ${AIKIDOPY_PYTHON_VERSION})
find_package(pybind11 2.2.0 QUIET)
if(NOT pybind11_FOUND)
message(STATUS "BUILD_PYTHON is ON, but failed to find pybind11 >= "
"2.2.0. Disabling aikidopy."
)
return()
endif()

#================================================================================
# Dependencies
#

#================================================================================

file(GLOB_RECURSE aikidopy_headers "*.h" "*.hpp")
file(GLOB_RECURSE aikidopy_sources "*.cpp")

# Build a Python extension module:
# pybind11_add_module(<name> [MODULE | SHARED] [EXCLUDE_FROM_ALL]
# [NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...])
#
pybind11_add_module(aikidopy
MODULE
${aikidopy_headers}
${aikidopy_sources}
)

target_include_directories(aikidopy
SYSTEM PUBLIC
${PYTHON_INCLUDE_DIRS}
${pybind11_INCLUDE_DIRS}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)

target_link_libraries(aikidopy
PUBLIC
aikido_common
aikido_constraint
aikido_control
aikido_distance
aikido_io
aikido_planner
aikido_robot
aikido_statespace
aikido_trajectory
${PYTHON_LIBRARIES}
)
if(TARGET aikido_control_ros)
target_link_libraries(aikidopy PUBLIC aikido_control_ros)
endif()
if(TARGET aikido_perception)
target_link_libraries(aikidopy PUBLIC aikido_perception)
endif()
if(TARGET aikido_rviz)
target_link_libraries(aikidopy PUBLIC aikido_rviz)
endif()

set_target_properties(aikidopy
PROPERTIES
PREFIX ""
SUFFIX ".so" # python uses '.so' extension even on macOS
DEBUG_POSTFIX ""
)

install(TARGETS aikidopy
LIBRARY DESTINATION "${PYTHON_SITE_PACKAGES}"
)

clang_format_add_sources(${aikidopy_headers} ${aikidopy_sources})
37 changes: 37 additions & 0 deletions python/aikidopy/aikidopy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <pybind11/pybind11.h>

namespace py = pybind11;

namespace aikido {
namespace python {

void eigen_geometry(py::module& m);

void aikidopy_common(py::module& m);
void aikidopy_statespace(py::module& m);
void aikidopy_constraint(py::module& m);
void aikidopy_planner(py::module& m);
void aikidopy_robot(py::module& m);
#ifdef AIKIDO_HAS_RVIZ
void aikidopy_rviz(py::module& m);
#endif // AIKIDO_HAS_RVIZ

PYBIND11_MODULE(aikidopy, m)
{
py::module::import("numpy");

m.doc() = "aikidopy is a Python library for solving robotic motion planning "
"and decision making problems.";

aikidopy_common(m);
aikidopy_statespace(m);
aikidopy_constraint(m);
aikidopy_planner(m);
aikidopy_robot(m);
#ifdef AIKIDO_HAS_RVIZ
aikidopy_rviz(m);
#endif // AIKIDO_HAS_RVIZ
}

} // namespace python
} // namespace aikido
14 changes: 14 additions & 0 deletions python/aikidopy/common/module.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <pybind11/pybind11.h>

namespace py = pybind11;

namespace aikido {
namespace python {

void aikidopy_common(py::module& m)
{
auto sm = m.def_submodule("common");
}

} // namespace python
} // namespace aikido
16 changes: 16 additions & 0 deletions python/aikidopy/constraint/dart/CollisionFree.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <pybind11/pybind11.h>
#include <aikido/constraint.hpp>
#include <aikido/constraint/dart/CollisionFree.hpp>

namespace py = pybind11;

namespace aikido {
namespace python {

void CollisionFree(py::module& m)
{
py::class_<aikido::constraint::dart::CollisionFree, std::shared_ptr<aikido::constraint::dart::CollisionFree>>(m, "CollisionFree");
}

} // namespace python
} // namespace aikido
Loading

0 comments on commit 2c75322

Please sign in to comment.