Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: python bindings for image_transport and publish #323

Merged
merged 27 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c4d8434
feat: python bindings for image_transport and publish
tfoldi Sep 23, 2024
ac72a10
style: reformat code
tfoldi Sep 24, 2024
4f95097
style: missing headers, copyright year
tfoldi Sep 24, 2024
ff4ffd7
build: add tests
tfoldi Sep 24, 2024
8a4250c
build: remove pluginlib (not used)
tfoldi Sep 24, 2024
898d875
style: reformat with rolling ament config
tfoldi Sep 24, 2024
4ceb2ec
WIP: before moving spin to custom class
tfoldi Sep 26, 2024
591c0fe
doc: fix repository and bugtracker url
tfoldi Sep 26, 2024
2eddcbf
feat: camera_info and subscriber support
tfoldi Sep 26, 2024
4ba43b5
Merge branch 'feat_image_transport_py' of https://github.com/tfoldi/i…
tfoldi Sep 26, 2024
1d331ab
doc: create initial version of the README.md file
tfoldi Sep 26, 2024
74e32f1
doc: move README.md to the right location
tfoldi Sep 26, 2024
f3ece7d
feat: add image_transport parameter
tfoldi Sep 26, 2024
98042aa
doc: complete documentation
tfoldi Sep 27, 2024
1cc8b23
style: remove too long line
tfoldi Sep 27, 2024
03b8e9a
style: reformat
tfoldi Sep 27, 2024
d2983f8
style: fix documentation formating
tfoldi Sep 27, 2024
6b615d2
fix: CameraSubscriber class name
tfoldi Oct 1, 2024
0f0f3c7
build: move pybind11 to build only dep
tfoldi Oct 2, 2024
9246ea6
chore: implement review suggestions
tfoldi Oct 4, 2024
e6428ae
build: add <2.9 pybind11 compatibility
tfoldi Oct 8, 2024
6b802dd
Merge branch 'feat_image_transport_py' of https://github.com/tfoldi/i…
tfoldi Oct 8, 2024
e6e71f0
build: add <2.9 pybind11 compatibility
tfoldi Oct 8, 2024
2424f26
build: add <2.9 pybind11 compatibility
tfoldi Oct 8, 2024
817ed6c
build: ament_cppcheck(LANGUAGE "c++") after ament_lint_auto_find_test…
tfoldi Oct 8, 2024
7c1ea65
build: cpp check after test dependencies
tfoldi Oct 8, 2024
bf4eae9
build: skip cppcheck on Windows
tfoldi Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()

tfoldi marked this conversation as resolved.
Show resolved Hide resolved
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
tfoldi marked this conversation as resolved.
Show resolved Hide resolved

## 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