Skip to content

Commit

Permalink
feat: python bindings for image_transport and publish (#323)
Browse files Browse the repository at this point in the history
Co-authored-by: Alejandro Hernández Cordero <[email protected]>
  • Loading branch information
tfoldi and ahcorde authored Oct 9, 2024
1 parent 039810c commit c2952b0
Show file tree
Hide file tree
Showing 10 changed files with 867 additions and 4 deletions.
11 changes: 11 additions & 0 deletions image_transport/include/image_transport/image_transport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ class ImageTransport
IMAGE_TRANSPORT_PUBLIC
explicit ImageTransport(rclcpp::Node::SharedPtr node);

IMAGE_TRANSPORT_PUBLIC
ImageTransport(const ImageTransport & other);

IMAGE_TRANSPORT_PUBLIC
ImageTransport & operator=(const ImageTransport & other);

IMAGE_TRANSPORT_PUBLIC
~ImageTransport();

Expand Down Expand Up @@ -364,6 +370,11 @@ class ImageTransport
std::unique_ptr<Impl> impl_;
};

struct ImageTransport::Impl
{
rclcpp::Node::SharedPtr node_;
};

} // namespace image_transport

#endif // IMAGE_TRANSPORT__IMAGE_TRANSPORT_HPP_
6 changes: 2 additions & 4 deletions image_transport/src/image_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ std::vector<std::string> getLoadableTransports()
return loadableTransports;
}

struct ImageTransport::Impl
{
rclcpp::Node::SharedPtr node_;
};
ImageTransport::ImageTransport(const ImageTransport & other)
: impl_(std::make_unique<Impl>(*other.impl_)) {}

ImageTransport::ImageTransport(rclcpp::Node::SharedPtr node)
: impl_(std::make_unique<ImageTransport::Impl>())
Expand Down
3 changes: 3 additions & 0 deletions image_transport_py/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Changelog for package image_transport_py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
85 changes: 85 additions & 0 deletions image_transport_py/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
cmake_minimum_required(VERSION 3.20)
project(image_transport_py)

# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()

# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(image_transport REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)

# By default, without the settings below, find_package(Python3) will attempt
# to find the newest python version it can, and additionally will find the
# most specific version. For instance, on a system that has
# /usr/bin/python3.10, /usr/bin/python3.11, and /usr/bin/python3, it will find
# /usr/bin/python3.11, even if /usr/bin/python3 points to /usr/bin/python3.10.
# The behavior we want is to prefer the "system" installed version unless the
# user specifically tells us othewise through the Python3_EXECUTABLE hint.
# Setting CMP0094 to NEW means that the search will stop after the first
# python version is found. Setting Python3_FIND_UNVERSIONED_NAMES means that
# the search will prefer /usr/bin/python3 over /usr/bin/python3.11. And that
# latter functionality is only available in CMake 3.20 or later, so we need
# at least that version.
cmake_policy(SET CMP0094 NEW)
set(Python3_FIND_UNVERSIONED_NAMES FIRST)

# Find python before pybind11
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)

find_package(pybind11_vendor REQUIRED)
find_package(pybind11 REQUIRED)

ament_python_install_package(${PROJECT_NAME})

pybind11_add_module(_image_transport MODULE
src/image_transport_py/pybind_image_transport.cpp
)

target_include_directories(_image_transport PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")

target_link_libraries(_image_transport PUBLIC
image_transport::image_transport
rclcpp::rclcpp
${sensor_msgs_TARGETS}
)

# Install cython modules as sub-modules of the project
install(
TARGETS
_image_transport
DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}"
)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)

list(APPEND AMENT_LINT_AUTO_EXCLUDE
ament_cmake_cppcheck
)
ament_lint_auto_find_test_dependencies()

if(NOT WIN32)
ament_cppcheck(LANGUAGE "c++")
else()
message(STATUS "Skipping ament_cppcheck on Windows")
endif()
endif()

ament_package()
128 changes: 128 additions & 0 deletions image_transport_py/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# image_transport_py: Python Bindings for ROS 2 Image Transport

## Introduction

`image_transport_py` is a Python package that provides bindings for `image_transport`. It enables efficient publishing and subscribing of images in Python, leveraging various transport plugins (e.g., `raw`, `compressed`).
The package allows developers to handle image topics more efficiently and with less overhead than using standard ROS 2 topics.

## Usage

The detailed tutorial on `image_transport` and `image_transport_py` can be found at: https://github.com/ros-perception/image_transport_tutorials.

## Classes

### Publisher

A publisher for images.

#### Methods

- `get_topic()`

Returns the base image topic.

- `get_num_subscribers()`

Returns the number of subscribers this publisher is connected to.

- `shutdown()`

Unsubscribe the callback associated with this Publisher.

- `publish(img)`

Publish an image on the topics associated with this Publisher.

### CameraPublisher

A publisher for images with camera info.

#### Methods

- `get_topic()`

Returns the base (image) topic of this CameraPublisher.

- `get_num_subscribers()`

Returns the number of subscribers this camera publisher is connected to.

- `shutdown()`

Unsubscribe the callback associated with this CameraPublisher.

- `publish(img, info)`

Publish an image and camera info on the topics associated with this Publisher.

### ImageTransport

An object for image transport operations.

#### Constructor

- `__init__(node_name, image_transport="", launch_params_filepath="")`

Initialize an ImageTransport object with its node name, `image_transport` and launch params file path. If no `image_transport` specified, the default `raw` plugin will be initialized.

#### Methods

- `advertise(base_topic, queue_size, latch=False)`

Advertise an image topic.

- `advertise_camera(base_topic, queue_size, latch=False)`

Advertise an image topic with camera info.

- `subscribe(base_topic, queue_size, callback)`

Subscribe to an image topic.

- `subscribe_camera(base_topic, queue_size, callback)`

Subscribe to an image topic with camera info.

### Subscriber

A subscriber for images.

#### Methods

- `get_topic()`

Returns the base image topic.

- `get_num_publishers()`

Returns the number of publishers this subscriber is connected to.

- `get_transport()`

Returns the name of the transport being used.

- `shutdown()`

Unsubscribe the callback associated with this Subscriber.

### CameraSubscriber

A subscriber for images with camera info.

#### Methods

- `get_topic()`

Returns the base image topic.

- `get_num_publishers()`

Returns the number of publishers this subscriber is connected to.

- `get_transport()`

Returns the name of the transport being used.

- `shutdown()`

Unsubscribe the callback associated with this CameraSubscriber.
36 changes: 36 additions & 0 deletions image_transport_py/image_transport_py/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2024 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from rpyutils import add_dll_directories_from_env

# Since Python 3.8, on Windows we should ensure DLL directories are explicitly added
# to the search path.
# See https://docs.python.org/3/whatsnew/3.8.html#bpo-36085-whatsnew
with add_dll_directories_from_env('PATH'):
from image_transport_py._image_transport import (
ImageTransport,
Publisher,
Subscriber,
CameraPublisher,
CameraSubscriber,
)


__all__ = [
'ImageTransport',
'Publisher',
'Subscriber',
'CameraPublisher',
'CameraSubscriber',
]
Loading

0 comments on commit c2952b0

Please sign in to comment.