Skip to content

Commit d78593a

Browse files
Add Python bindings for human state-related data structures (#379)
Co-authored-by: Silvio Traversaro <silvio@traversaro.it>
1 parent 8909f4b commit d78593a

File tree

11 files changed

+323
-0
lines changed

11 files changed

+323
-0
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ find_package(YCM REQUIRED)
3636
# Import cmake utilities
3737
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
3838
include(AddWarningsConfigurationToTarget)
39+
include(AddHDEPythonModule)
3940

4041
# To build shared libraries in Windows, we set CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS to TRUE
4142
# See https://cmake.org/cmake/help/v3.4/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.html
@@ -51,6 +52,9 @@ endif()
5152

5253
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
5354

55+
# Flag to enable python bindings
56+
option(HDE_COMPILE_PYTHON_BINDINGS "Flag that enables building the bindings" OFF)
57+
5458
# Plugins are force to be Shared/Dynamic Library
5559
set(YARP_FORCE_DYNAMIC_PLUGINS ON)
5660

@@ -86,6 +90,7 @@ add_subdirectory(modules)
8690
add_subdirectory(servers)
8791
add_subdirectory(clients)
8892
add_subdirectory(publishers)
93+
add_subdirectory(bindings)
8994
add_subdirectory(HumanDynamicsEstimationLibrary)
9095

9196
include(InstallBasicPackageFiles)

bindings/CMakeLists.txt

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
if(HDE_COMPILE_PYTHON_BINDINGS)
5+
6+
find_package(Python3 3.6 COMPONENTS Interpreter Development REQUIRED)
7+
8+
find_package(pybind11 2.4.3 CONFIG REQUIRED)
9+
10+
set(NEW_LINE "\n")
11+
12+
option(HDE_DETECT_ACTIVE_PYTHON_SITEPACKAGES
13+
"Do you want HDE to detect and use the active site-package directory? (it could be a system dir)"
14+
FALSE)
15+
16+
# Install the resulting Python package for the active interpreter
17+
if(NOT DEFINED HDE_PYTHON_INSTALL_DIR)
18+
if(HDE_DETECT_ACTIVE_PYTHON_SITEPACKAGES)
19+
set(HDE_PYTHON_INSTALL_DIR ${Python3_SITELIB})
20+
else()
21+
execute_process(COMMAND ${Python3_EXECUTABLE} -c "from distutils import sysconfig; print(sysconfig.get_python_lib(1,0,prefix=''))"
22+
OUTPUT_VARIABLE _PYTHON_INSTDIR)
23+
string(STRIP ${_PYTHON_INSTDIR} _PYTHON_INSTDIR_CLEAN)
24+
set(HDE_PYTHON_INSTALL_DIR ${_PYTHON_INSTDIR_CLEAN})
25+
endif()
26+
endif()
27+
set(PYTHON_INSTDIR ${HDE_PYTHON_INSTALL_DIR}/hde)
28+
29+
# Folder of the Python package within the build tree.
30+
# It is used for the Python tests.
31+
set(HDE_PYTHON_PACKAGE "${CMAKE_BINARY_DIR}/hde")
32+
33+
# Add the bindings directory
34+
add_subdirectory(python)
35+
36+
# Create the __init__.py file
37+
file(GENERATE
38+
OUTPUT "${HDE_PYTHON_PACKAGE}/__init__.py"
39+
CONTENT "from .bindings import *${NEW_LINE}")
40+
41+
# Install the __init__.py file
42+
install(FILES "${HDE_PYTHON_PACKAGE}/__init__.py"
43+
DESTINATION ${PYTHON_INSTDIR})
44+
45+
# Install pip metadata files to ensure that HDE installed via CMake is listed by pip list
46+
# See https://packaging.python.org/specifications/recording-installed-packages/
47+
# and https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata
48+
option(HDE_PYTHON_PIP_METADATA_INSTALL "Use CMake to install Python pip metadata. Set to off if some other tool already installs it." ON)
49+
mark_as_advanced(HDE_PYTHON_PIP_METADATA_INSTALL)
50+
set(HDE_PYTHON_PIP_METADATA_INSTALLER "cmake" CACHE STRING "Specify the string to identify the pip Installer. Default: cmake, change this if you are using another tool.")
51+
mark_as_advanced(HDE_PYTHON_PIP_METADATA_INSTALLER)
52+
if(HDE_PYTHON_PIP_METADATA_INSTALL)
53+
get_filename_component(PYTHON_METADATA_PARENT_DIR ${PYTHON_INSTDIR} DIRECTORY)
54+
if(WIN32)
55+
set(NEW_LINE "\n\r")
56+
else()
57+
set(NEW_LINE "\n")
58+
endif()
59+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/METADATA "")
60+
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/METADATA "Metadata-Version: 2.1${NEW_LINE}")
61+
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/METADATA "Name: hde${NEW_LINE}")
62+
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/METADATA "Version: ${hde_VERSION}${NEW_LINE}")
63+
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/INSTALLER "${HDE_PYTHON_PIP_METADATA_INSTALLER}${NEW_LINE}")
64+
install(
65+
FILES "${CMAKE_CURRENT_BINARY_DIR}/METADATA" "${CMAKE_CURRENT_BINARY_DIR}/INSTALLER"
66+
DESTINATION ${PYTHON_METADATA_PARENT_DIR}/hde-${hde_VERSION}.dist-info)
67+
endif()
68+
69+
endif()

bindings/python/CMakeLists.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
add_subdirectory(msgs)
5+
6+
get_property(pybind_headers GLOBAL PROPERTY pybind_headers)
7+
get_property(pybind_sources GLOBAL PROPERTY pybind_sources)
8+
get_property(pybind_include_dirs GLOBAL PROPERTY pybind_include_dirs)
9+
get_property(pybind_link_libraries GLOBAL PROPERTY pybind_link_libraries)
10+
11+
pybind11_add_module(pybind11_hde MODULE
12+
hde.cpp
13+
${pybind_sources}
14+
${pybind_headers}
15+
)
16+
17+
target_include_directories(pybind11_hde PUBLIC "$<BUILD_INTERFACE:${pybind_include_dirs}>")
18+
19+
target_link_libraries(pybind11_hde PRIVATE
20+
${pybind_link_libraries})
21+
22+
# # The generated Python dynamic module must have the same name as the pybind11
23+
# # module, i.e. `bindings`.
24+
set_target_properties(pybind11_hde PROPERTIES
25+
LIBRARY_OUTPUT_DIRECTORY "${HDE_PYTHON_PACKAGE}"
26+
OUTPUT_NAME "bindings")
27+
28+
# Output package is:
29+
#
30+
# hde
31+
# |-- __init__.py (generated from main bindings CMake file)
32+
# `-- bindings.<cpython_extension>
33+
34+
install(TARGETS pybind11_hde DESTINATION ${PYTHON_INSTDIR})

bindings/python/hde.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
5+
#include <pybind11/pybind11.h>
6+
7+
#include <hde/bindings/msgs/Module.h>
8+
9+
// Create the Python module
10+
PYBIND11_MODULE(bindings, m)
11+
{
12+
namespace py = ::pybind11;
13+
14+
m.doc() = "Human dynamics estimation bindings";
15+
16+
py::module msgModule = m.def_submodule("msg");
17+
hde::bindings::msgs::CreateModule(msgModule);
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
4+
5+
set(H_PREFIX include/hde/bindings/msgs)
6+
7+
add_hde_python_module(
8+
NAME MsgsBindings
9+
SOURCES src/HumanState.cpp src/Module.cpp
10+
HEADERS ${H_PREFIX}/HumanState.h ${H_PREFIX}/BufferedPort.h ${H_PREFIX}/Module.h
11+
LINK_LIBRARIES HumanDynamicsEstimation::HumanStateMsg YARP::YARP_os)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
#ifndef HDE_BINDINGS_MSGS_BUFFERED_PORT_H
5+
#define HDE_BINDINGS_MSGS_BUFFERED_PORT_H
6+
7+
#include <string>
8+
9+
#include <pybind11/detail/common.h>
10+
#include <pybind11/pybind11.h>
11+
12+
#include <yarp/os/BufferedPort.h>
13+
14+
namespace hde {
15+
namespace bindings {
16+
namespace msgs {
17+
18+
template <typename T>
19+
void CreateBufferedPort(pybind11::module& module, const std::string& name)
20+
{
21+
namespace py = ::pybind11;
22+
py::class_<::yarp::os::BufferedPort<T>>(module, name.c_str())
23+
.def(py::init())
24+
.def("open",
25+
py::overload_cast<const std::string&>(&::yarp::os::BufferedPort<T>::open),
26+
py::arg("name"))
27+
.def("close", &::yarp::os::BufferedPort<T>::close)
28+
.def("isClosed", &::yarp::os::BufferedPort<T>::isClosed)
29+
.def("prepare",
30+
&::yarp::os::BufferedPort<T>::prepare,
31+
py::return_value_policy::reference_internal)
32+
.def("write",
33+
&::yarp::os::BufferedPort<T>::write,
34+
py::arg("forceStrict") = false)
35+
.def("read",
36+
&::yarp::os::BufferedPort<T>::read,
37+
py::arg("shouldWait") = true,
38+
py::return_value_policy::reference_internal);
39+
}
40+
} // namespace msgs
41+
} // namespace bindings
42+
} // namespace hde
43+
44+
#endif // HDE_BINDINGS_MSGS_BUFFERED_PORT_H
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
#ifndef HDE_BINDINGS_MSGS_HUMAN_STATE_H
5+
#define HDE_BINDINGS_MSGS_HUMAN_STATE_H
6+
7+
#include <pybind11/pybind11.h>
8+
9+
namespace hde {
10+
namespace bindings {
11+
namespace msgs {
12+
13+
void CreateHumanState(pybind11::module& module);
14+
15+
} // namespace msgs
16+
} // namespace bindings
17+
} // namespace hde
18+
19+
#endif // HDE_BINDINGS_MSGS_HUMAN_STATE_H
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
#ifndef HDE_BINDINGS_MSGS_MODULE_H
5+
#define HDE_BINDINGS_MSGS_MODULE_H
6+
7+
#include <pybind11/pybind11.h>
8+
9+
namespace hde {
10+
namespace bindings {
11+
namespace msgs {
12+
13+
void CreateModule(pybind11::module& module);
14+
15+
} // namespace msgs
16+
} // namespace bindings
17+
} // namespace hde
18+
19+
#endif // HDE_BINDINGS_MSGS_MODULE_H
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
#include <pybind11/pybind11.h>
5+
#include <pybind11/stl.h>
6+
7+
#include <string>
8+
#include <hde/msgs/HumanState.h>
9+
10+
#include <hde/bindings/msgs/BufferedPort.h>
11+
#include <hde/bindings/msgs/HumanState.h>
12+
13+
namespace hde {
14+
namespace bindings {
15+
namespace msgs {
16+
17+
void CreateHumanState(pybind11::module& module)
18+
{
19+
namespace py = ::pybind11;
20+
using namespace ::hde::msgs;
21+
22+
py::class_<HumanState>(module, "HumanState")
23+
.def(py::init())
24+
.def_readwrite("jointNames", &HumanState::jointNames)
25+
.def_readwrite("positions", &HumanState::positions)
26+
.def_readwrite("velocities", &HumanState::velocities)
27+
.def_readwrite("baseName", &HumanState::baseName)
28+
.def_readwrite("baseOriginWRTGlobal", &HumanState::baseOriginWRTGlobal)
29+
.def_readwrite("baseOrientationWRTGlobal", &HumanState::baseOrientationWRTGlobal)
30+
.def_readwrite("baseVelocityWRTGlobal", &HumanState::baseVelocityWRTGlobal)
31+
.def_readwrite("CoMPositionWRTGlobal", &HumanState::CoMPositionWRTGlobal)
32+
.def_readwrite("CoMVelocityWRTGlobal", &HumanState::CoMVelocityWRTGlobal);
33+
34+
CreateBufferedPort<HumanState>(module, "BufferedPortHumanState");
35+
}
36+
} // namespace msgs
37+
} // namespace bindings
38+
} // namespace hde
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-FileCopyrightText: Fondazione Istituto Italiano di Tecnologia (IIT)
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
#include <pybind11/pybind11.h>
5+
6+
#include <hde/bindings/msgs/HumanState.h>
7+
8+
namespace hde {
9+
namespace bindings {
10+
namespace msgs {
11+
12+
void CreateModule(pybind11::module& module)
13+
{
14+
module.doc() = "YarpUtilities module.";
15+
16+
CreateHumanState(module);
17+
}
18+
} // namespace msgs
19+
} // namespace bindings
20+
} // namespace hde

0 commit comments

Comments
 (0)