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

refactor: sparate ros2 dependency in aimrt_py #117

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Next Next commit
feat: enhance aimrt_py with ROS2 support and modularize functionality
- Added support for ROS2 message types in aimrt_py, improving interoperability with ROS2 systems.
- Introduced new module aimrt_python_runtime_ros2 for ROS2-specific functionalities, including publishing, subscribing, and RPC handling.
- Updated existing files to integrate ROS2 capabilities, ensuring seamless interaction between ROS1 and ROS2 message types.
- Enhanced CMake configuration to conditionally include ROS2 components based on build settings.
- Improved code organization by separating ROS2-related functionalities into dedicated headers and source files for better maintainability.
  • Loading branch information
zhangyi1357 committed Dec 3, 2024
commit 45c87840508e5220e0db7f2db0e62b73fb7dbde9
28 changes: 16 additions & 12 deletions src/runtime/python_runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@ set(CUR_TARGET_NAME ${CUR_SUPERIOR_NAMESPACE_UNDERLINE}_${CUR_DIR})
set(CUR_TARGET_ALIAS_NAME ${CUR_SUPERIOR_NAMESPACE}::${CUR_DIR})

# Set file collection
file(GLOB_RECURSE src CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
file(GLOB_RECURSE src CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/python_runtime_main.cc)
file(GLOB_RECURSE py_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.py)
file(GLOB_RECURSE ros2_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ros2_type_support_utils.cc)

if(NOT AIMRT_BUILD_WITH_ROS2)
list(REMOVE_ITEM src ${ros2_files})
endif()
file(GLOB_RECURSE ros2_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ros2_type_support_utils.cc ${CMAKE_CURRENT_SOURCE_DIR}/python_runtime_ros2.cc)

# Add target
pybind11_add_module(${CUR_TARGET_NAME} SHARED)
Expand All @@ -33,13 +29,21 @@ target_link_libraries(
${CUR_TARGET_NAME}
PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,aimrt::runtime::core>)

# Link ros2 interface if building with ros2
if(AIMRT_BUILD_WITH_ROS2)
target_link_libraries(${CUR_TARGET_NAME} PRIVATE aimrt::interface::aimrt_module_ros2_interface)
target_compile_definitions(${CUR_TARGET_NAME} PRIVATE AIMRT_BUILD_WITH_ROS2)
endif()

# Set misc of target
set_target_properties(${CUR_TARGET_NAME} PROPERTIES OUTPUT_NAME "aimrt_python_runtime")

set_property(TARGET ${CUR_TARGET_NAME} PROPERTY PY_FILES ${py_files})

if(AIMRT_BUILD_WITH_ROS2)
pybind11_add_module(${CUR_TARGET_NAME}_ros2 SHARED)
add_library(${CUR_TARGET_ALIAS_NAME}_ros2 ALIAS ${CUR_TARGET_NAME}_ros2)

target_sources(${CUR_TARGET_NAME}_ros2 PRIVATE ${ros2_files})

target_link_libraries(
${CUR_TARGET_NAME}_ros2
PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,aimrt::runtime::core>
aimrt::interface::aimrt_module_ros2_interface)

set_target_properties(${CUR_TARGET_NAME}_ros2 PROPERTIES OUTPUT_NAME "aimrt_python_runtime_ros2")
endif()
1 change: 1 addition & 0 deletions src/runtime/python_runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
Publish, RegisterPublishType, Subscribe)
from .aimrt_py_log import *
from .aimrt_python_runtime import *
from .aimrt_python_runtime_ros2 import *
from .check_ros2_type import (check_is_valid_ros2_msg_type,
check_is_valid_srv_type)
12 changes: 6 additions & 6 deletions src/runtime/python_runtime/aimrt_py_chn.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import google.protobuf
import google.protobuf.message

from . import aimrt_python_runtime
from . import aimrt_python_runtime, aimrt_python_runtime_ros2
from .check_ros2_type import check_is_valid_ros2_msg_type

Ros2MsgType = TypeVar("Ros2MsgType")
Expand Down Expand Up @@ -81,10 +81,10 @@ def RegisterPublishType(publisher: aimrt_python_runtime.PublisherRef,
py_pb_ts.SetSerializationTypesSupportedList(["pb", "json"])
return publisher.PbRegisterPublishType(py_pb_ts)
elif check_is_valid_ros2_msg_type(msg_type):
py_ros2_ts = aimrt_python_runtime.PyRos2TypeSupport(msg_type)
py_ros2_ts = aimrt_python_runtime_ros2.PyRos2TypeSupport(msg_type)
py_ros2_ts.SetTypeName(GetRos2MessageTypeName(msg_type))
py_ros2_ts.SetSerializationTypesSupportedList(["ros2"])
return publisher.Ros2RegisterPublishType(py_ros2_ts)
return aimrt_python_runtime_ros2.Ros2RegisterPublishType(publisher, py_ros2_ts)
else:
raise TypeError(f"Invalid message type: {type(msg_type)}")

Expand Down Expand Up @@ -141,7 +141,7 @@ def Publish(publisher: aimrt_python_runtime.PublisherRef, second, third=None):
publisher.PbPublishWithCtx(GetPbMessageTypeName(msg.__class__), ctx_ref, serialized_msg)
elif message_type == "ros2":
ctx_ref = _CreateContextRef(ctx_or_type, default_serialization_type="ros2")
publisher.Ros2PublishWithCtx(GetRos2MessageTypeName(msg.__class__), ctx_ref, msg)
aimrt_python_runtime_ros2.Ros2PublishWithCtx(publisher, GetRos2MessageTypeName(msg.__class__), ctx_ref, msg)


def Subscribe(subscriber: aimrt_python_runtime.SubscriberRef,
Expand Down Expand Up @@ -187,7 +187,7 @@ def handle_callback(ctx_ref: aimrt_python_runtime.ContextRef, msg_buf: bytes):
subscriber.PbSubscribeWithCtx(py_pb_ts, handle_callback)

elif check_is_valid_ros2_msg_type(msg_type):
py_ros2_ts = aimrt_python_runtime.PyRos2TypeSupport(msg_type)
py_ros2_ts = aimrt_python_runtime_ros2.PyRos2TypeSupport(msg_type)
py_ros2_ts.SetTypeName(GetRos2MessageTypeName(msg_type))
py_ros2_ts.SetSerializationTypesSupportedList(["ros2"])

Expand All @@ -200,7 +200,7 @@ def ros2_callback_wrapper(ctx_ref: aimrt_python_runtime.ContextRef, msg):
except Exception as e:
print(f"AimRT channel handle get exception, {e}", file=sys.stderr)

subscriber.Ros2SubscribeWithCtx(py_ros2_ts, msg_type, ros2_callback_wrapper)
aimrt_python_runtime_ros2.Ros2SubscribeWithCtx(subscriber, py_ros2_ts, msg_type, ros2_callback_wrapper)

else:
raise TypeError(f"Invalid message type: {type(msg_type)}, expected Protobuf or ROS2 message type")
93 changes: 7 additions & 86 deletions src/runtime/python_runtime/export_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@

#include "python_runtime/export_pb_type_support.h"

#ifdef AIMRT_BUILD_WITH_ROS2
#include "python_runtime/export_ros2_type_support.h"
#include "python_runtime/ros2_type_support_utils.h"
#endif

namespace aimrt::runtime::python_runtime {

inline void ExportContext(const pybind11::object& m) {
Expand Down Expand Up @@ -104,76 +99,6 @@ inline bool PbSubscribeWithCtx(
});
}

#ifdef AIMRT_BUILD_WITH_ROS2

inline bool Ros2RegisterPublishType(
aimrt::channel::PublisherRef& publisher_ref,
const std::shared_ptr<const PyRos2TypeSupport>& py_ros2_type_support) {
static std::vector<std::shared_ptr<const PyRos2TypeSupport>> py_ros2_ts_vec;
py_ros2_ts_vec.emplace_back(py_ros2_type_support);

return publisher_ref.RegisterPublishType(py_ros2_type_support->NativeHandle());
}

inline void Ros2PublishWithCtx(
aimrt::channel::PublisherRef& publisher_ref,
std::string_view msg_type,
const aimrt::channel::ContextRef& ctx_ref,
pybind11::object msg_obj) {
auto msg_ptr = convert_from_py(msg_obj);
if (!msg_ptr) {
throw py::error_already_set();
}

publisher_ref.Publish(msg_type, ctx_ref, static_cast<const void*>(msg_ptr.get()));
}

inline bool Ros2SubscribeWithCtx(
aimrt::channel::SubscriberRef& subscriber_ref,
const std::shared_ptr<const PyRos2TypeSupport>& py_ros2_type_support,
pybind11::object pyclass,
std::function<void(aimrt::channel::ContextRef, pybind11::object)>&& callback) {
static std::vector<std::shared_ptr<const PyRos2TypeSupport>> py_ros2_ts_vec;
py_ros2_ts_vec.emplace_back(py_ros2_type_support);

pybind11::gil_scoped_acquire acquire;

pybind11::object pymetaclass = pyclass.attr("__class__");
auto* capsule_ptr = static_cast<void*>(pymetaclass.attr("_CONVERT_TO_PY").cast<py::capsule>());
typedef PyObject* convert_to_py_function(void*);
auto convert = reinterpret_cast<convert_to_py_function*>(capsule_ptr);
if (!convert) {
throw py::error_already_set();
}

pybind11::gil_scoped_release release;

return subscriber_ref.Subscribe(
py_ros2_type_support->NativeHandle(),
[callback = std::move(callback), convert](
const aimrt_channel_context_base_t* ctx_ptr,
const void* msg_ptr,
aimrt_function_base_t* release_callback_base) {
aimrt::channel::SubscriberReleaseCallback release_callback(release_callback_base);

pybind11::gil_scoped_acquire acquire;

auto msg_obj = pybind11::reinterpret_steal<pybind11::object>(convert(const_cast<void*>(msg_ptr)));
if (!msg_obj) {
throw py::error_already_set();
}

auto ctx_ref = aimrt::channel::ContextRef(ctx_ptr);
callback(ctx_ref, msg_obj);

pybind11::gil_scoped_release release;

release_callback();
});
}

#endif

inline void ExportPublisherRef(pybind11::object m) {
using aimrt::channel::PublisherRef;

Expand All @@ -183,12 +108,7 @@ inline void ExportPublisherRef(pybind11::object m) {
.def("GetTopic", &PublisherRef::GetTopic)
.def("MergeSubscribeContextToPublishContext", &PublisherRef::MergeSubscribeContextToPublishContext)
.def("PbPublishWithCtx", &PbPublishWithCtx)
.def("PbRegisterPublishType", &PbRegisterPublishType)
#ifdef AIMRT_BUILD_WITH_ROS2
.def("Ros2PublishWithCtx", &Ros2PublishWithCtx)
.def("Ros2RegisterPublishType", &Ros2RegisterPublishType)
#endif
;
.def("PbRegisterPublishType", &PbRegisterPublishType);
}

inline void ExportSubscriberRef(pybind11::object m) {
Expand All @@ -198,11 +118,7 @@ inline void ExportSubscriberRef(pybind11::object m) {
.def(pybind11::init<>())
.def("__bool__", &SubscriberRef::operator bool)
.def("GetTopic", &SubscriberRef::GetTopic)
.def("PbSubscribeWithCtx", &PbSubscribeWithCtx)
#ifdef AIMRT_BUILD_WITH_ROS2
.def("Ros2SubscribeWithCtx", &Ros2SubscribeWithCtx)
#endif
;
.def("PbSubscribeWithCtx", &PbSubscribeWithCtx);
}

inline void ExportChannelHandleRef(pybind11::object m) {
Expand All @@ -215,4 +131,9 @@ inline void ExportChannelHandleRef(pybind11::object m) {
.def("GetSubscriber", &ChannelHandleRef::GetSubscriber)
.def("MergeSubscribeContextToPublishContext", &ChannelHandleRef::MergeSubscribeContextToPublishContext);
}

#ifdef AIMRT_BUILD_WITH_ROS2

#endif // AIMRT_BUILD_WITH_ROS2

} // namespace aimrt::runtime::python_runtime
93 changes: 93 additions & 0 deletions src/runtime/python_runtime/export_ros2_channel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) 2024 The AimRT Authors.
// AimRT is licensed under Mulan PSL v2.

#pragma once

#include <pybind11/pybind11.h>

#include <pybind11/functional.h> // IWYU pragma: keep
#include <pybind11/stl.h> // IWYU pragma: keep

#include "aimrt_module_cpp_interface/channel/channel_context.h"
#include "aimrt_module_cpp_interface/channel/channel_handle.h"

#include "python_runtime/export_ros2_type_support.h"

namespace aimrt::runtime::python_runtime {

inline bool Ros2RegisterPublishType(
aimrt::channel::PublisherRef& publisher_ref,
const std::shared_ptr<const PyRos2TypeSupport>& py_ros2_type_support) {
static std::vector<std::shared_ptr<const PyRos2TypeSupport>> py_ros2_ts_vec;
py_ros2_ts_vec.emplace_back(py_ros2_type_support);

return publisher_ref.RegisterPublishType(py_ros2_type_support->NativeHandle());
}

inline void Ros2PublishWithCtx(
aimrt::channel::PublisherRef& publisher_ref,
std::string_view msg_type,
const aimrt::channel::ContextRef& ctx_ref,
pybind11::object msg_obj) {
auto msg_ptr = convert_from_py(msg_obj);
if (!msg_ptr) {
throw py::error_already_set();
}

publisher_ref.Publish(msg_type, ctx_ref, static_cast<const void*>(msg_ptr.get()));
}

inline bool Ros2SubscribeWithCtx(
aimrt::channel::SubscriberRef& subscriber_ref,
const std::shared_ptr<const PyRos2TypeSupport>& py_ros2_type_support,
pybind11::object pyclass,
std::function<void(aimrt::channel::ContextRef, pybind11::object)>&& callback) {
static std::vector<std::shared_ptr<const PyRos2TypeSupport>> py_ros2_ts_vec;
py_ros2_ts_vec.emplace_back(py_ros2_type_support);

pybind11::gil_scoped_acquire acquire;

pybind11::object pymetaclass = pyclass.attr("__class__");
auto* capsule_ptr = static_cast<void*>(pymetaclass.attr("_CONVERT_TO_PY").cast<py::capsule>());
typedef PyObject* convert_to_py_function(void*);
auto convert = reinterpret_cast<convert_to_py_function*>(capsule_ptr);
if (!convert) {
throw py::error_already_set();
}

pybind11::gil_scoped_release release;

return subscriber_ref.Subscribe(
py_ros2_type_support->NativeHandle(),
[callback = std::move(callback), convert](
const aimrt_channel_context_base_t* ctx_ptr,
const void* msg_ptr,
aimrt_function_base_t* release_callback_base) {
aimrt::channel::SubscriberReleaseCallback release_callback(release_callback_base);

pybind11::gil_scoped_acquire acquire;

auto msg_obj = pybind11::reinterpret_steal<pybind11::object>(convert(const_cast<void*>(msg_ptr)));
if (!msg_obj) {
throw py::error_already_set();
}

auto ctx_ref = aimrt::channel::ContextRef(ctx_ptr);
callback(ctx_ref, msg_obj);

pybind11::gil_scoped_release release;

release_callback();
});
}

inline void ExportRos2PublisherFunc(pybind11::module& m) {
m.def("Ros2PublishWithCtx", &Ros2PublishWithCtx);
m.def("Ros2RegisterPublishType", &Ros2RegisterPublishType);
}

inline void ExportRos2SubscribeFunc(pybind11::module& m) {
m.def("Ros2SubscribeWithCtx", &Ros2SubscribeWithCtx);
}

} // namespace aimrt::runtime::python_runtime
Loading