Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
24 changes: 24 additions & 0 deletions rclpy/rclpy/impl/_rclpy_pybind11.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ class Client(Destroyable, Generic[SrvRequestT, SrvResponseT]):
def get_logger_name(self) -> str:
"""Get the name of the logger associated with the node of the client."""

def set_on_new_response_callback(self, callback: Callable[[int], None]) -> None:
"""Set the on new response callback function for the client."""

def clear_on_new_response_callback(self) -> None:
"""Clear the on new response callback function for the client."""


class Context(Destroyable):

Expand Down Expand Up @@ -286,6 +292,12 @@ class Service(Destroyable, Generic[SrvRequestT, SrvResponseT]):
def get_logger_name(self) -> str:
"""Get the name of the logger associated with the node of the service."""

def set_on_new_request_callback(self, callback: Callable[[int], None]) -> None:
"""Set the on new request callback function for the service."""

def clear_on_new_request_callback(self) -> None:
"""Clear the on new request callback function for the service."""


class TypeDescriptionService(Destroyable):

Expand Down Expand Up @@ -578,6 +590,12 @@ class Timer(Destroyable):
def is_timer_canceled(self) -> bool:
"""Check if a timer is canceled."""

def set_on_reset_callback(self, callback: Callable[[int], None]) -> None:
"""Set the on reset callback function for the timer."""

def clear_on_reset_callback(self) -> None:
"""Clear the on reset callback function for the timer."""


class Subscription(Destroyable, Generic[MsgT]):

Expand All @@ -600,6 +618,12 @@ class Subscription(Destroyable, Generic[MsgT]):
def get_publisher_count(self) -> int:
"""Count the publishers from a subscription."""

def set_on_new_message_callback(self, callback: Callable[[int], None]) -> None:
"""Set the on new message callback function for the subscription."""

def clear_on_new_message_callback(self) -> None:
"""Clear the on new message callback function for the subscription."""


class rcl_time_point_t:

Expand Down
48 changes: 47 additions & 1 deletion rclpy/src/rclpy/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,27 @@

#include <memory>
#include <string>
#include <utility>

#include "client.hpp"
#include "clock.hpp"
#include "exceptions.hpp"
#include "node.hpp"
#include "python_allocator.hpp"
#include "utils.hpp"
#include "events_executor/rcl_support.hpp"

namespace rclpy
{
using events_executor::RclEventCallbackTrampoline;

void
Client::destroy()
{
try {
clear_on_new_response_callback();
} catch (RCLError) {
}
rcl_client_.reset();
node_.destroy();
}
Expand Down Expand Up @@ -181,6 +188,41 @@ Client::get_logger_name() const
return node_logger_name;
}

void
Client::set_callback(
rcl_event_callback_t callback,
const void * user_data)
{
rcl_ret_t ret = rcl_client_set_on_new_response_callback(
rcl_client_.get(),
callback,
user_data);

if (RCL_RET_OK != ret) {
throw RCLError(std::string("Failed to set the on new response callback for client: ") +
rcl_get_error_string().str);
}
}

void
Client::set_on_new_response_callback(std::function<void(size_t)> callback)
{
clear_on_new_response_callback();
on_new_response_callback_ = std::move(callback);
set_callback(
RclEventCallbackTrampoline,
static_cast<const void *>(&on_new_response_callback_));
}

void
Client::clear_on_new_response_callback()
{
if (on_new_response_callback_) {
set_callback(nullptr, nullptr);
on_new_response_callback_ = nullptr;
}
}

void
define_client(py::object module)
{
Expand Down Expand Up @@ -208,6 +250,10 @@ define_client(py::object module)
"Configure whether introspection is enabled")
.def(
"get_logger_name", &Client::get_logger_name,
"Get the name of the logger associated with the node of the client.");
"Get the name of the logger associated with the node of the client.")
.def(
"set_on_new_response_callback", &Client::set_on_new_response_callback,
py::arg("callback"))
.def("clear_on_new_response_callback", &Client::clear_on_new_response_callback);
}
} // namespace rclpy
11 changes: 11 additions & 0 deletions rclpy/src/rclpy/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define RCLPY__CLIENT_HPP_

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>

#include <rcl/client.h>
#include <rcl/service_introspection.h>
Expand Down Expand Up @@ -120,10 +121,20 @@ class Client : public Destroyable, public std::enable_shared_from_this<Client>
const char *
get_logger_name() const;

void
set_on_new_response_callback(std::function<void(size_t)> callback);

void
clear_on_new_response_callback();

private:
Node node_;
std::function<void(size_t)> on_new_response_callback_{nullptr};
std::shared_ptr<rcl_client_t> rcl_client_;
rosidl_service_type_support_t * srv_type_;

void
set_callback(rcl_event_callback_t callback, const void * user_data);
};

/// Define a pybind11 wrapper for an rclpy::Client
Expand Down
8 changes: 7 additions & 1 deletion rclpy/src/rclpy/events_executor/rcl_support.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ namespace events_executor
extern "C" void RclEventCallbackTrampoline(const void * user_data, size_t number_of_events)
{
const auto cb = reinterpret_cast<const std::function<void(size_t)> *>(user_data);
(*cb)(number_of_events);
try {
(*cb)(number_of_events);
} catch (const std::exception & e) {
// Catch and print any exception to avoid propagation to c code
std::fprintf(stderr, "%s\n", e.what());
std::terminate();
}
}

RclCallbackManager::RclCallbackManager(EventsQueue * events_queue)
Expand Down
48 changes: 47 additions & 1 deletion rclpy/src/rclpy/service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,26 @@

#include <memory>
#include <string>
#include <utility>

#include "clock.hpp"
#include "exceptions.hpp"
#include "node.hpp"
#include "service.hpp"
#include "utils.hpp"
#include "events_executor/rcl_support.hpp"

namespace rclpy
{
using events_executor::RclEventCallbackTrampoline;

void
Service::destroy()
{
try {
clear_on_new_request_callback();
} catch (RCLError) {
}
rcl_service_.reset();
node_.destroy();
}
Expand Down Expand Up @@ -184,6 +191,41 @@ Service::configure_introspection(
}
}

void
Service::set_callback(
rcl_event_callback_t callback,
const void * user_data)
{
rcl_ret_t ret = rcl_service_set_on_new_request_callback(
rcl_service_.get(),
callback,
user_data);

if (RCL_RET_OK != ret) {
throw RCLError(std::string("Failed to set the on new request callback for service: ") +
rcl_get_error_string().str);
}
}

void
Service::set_on_new_request_callback(std::function<void(size_t)> callback)
{
clear_on_new_request_callback();
on_new_request_callback_ = std::move(callback);
set_callback(
RclEventCallbackTrampoline,
static_cast<const void *>(&on_new_request_callback_));
}

void
Service::clear_on_new_request_callback()
{
if (on_new_request_callback_) {
set_callback(nullptr, nullptr);
on_new_request_callback_ = nullptr;
}
}

void
define_service(py::object module)
{
Expand Down Expand Up @@ -211,6 +253,10 @@ define_service(py::object module)
"Configure whether introspection is enabled")
.def(
"get_logger_name", &Service::get_logger_name,
"Get the name of the logger associated with the node of the service.");
"Get the name of the logger associated with the node of the service.")
.def(
"set_on_new_request_callback", &Service::set_on_new_request_callback,
py::arg("callback"))
.def("clear_on_new_request_callback", &Service::clear_on_new_request_callback);
}
} // namespace rclpy
11 changes: 11 additions & 0 deletions rclpy/src/rclpy/service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define RCLPY__SERVICE_HPP_

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>

#include <rcl/service.h>
#include <rcl/service_introspection.h>
Expand Down Expand Up @@ -125,10 +126,20 @@ class Service : public Destroyable, public std::enable_shared_from_this<Service>
void
destroy() override;

void
set_on_new_request_callback(std::function<void(size_t)> callback);

void
clear_on_new_request_callback();

private:
Node node_;
std::function<void(size_t)> on_new_request_callback_{nullptr};
std::shared_ptr<rcl_service_t> rcl_service_;
rosidl_service_type_support_t * srv_type_;

void
set_callback(rcl_event_callback_t callback, const void * user_data);
};

/// Define a pybind11 wrapper for an rclpy::Service
Expand Down
49 changes: 48 additions & 1 deletion rclpy/src/rclpy/subscription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,21 @@
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>

#include "exceptions.hpp"
#include "node.hpp"
#include "serialization.hpp"
#include "subscription.hpp"
#include "utils.hpp"
#include "events_executor/rcl_support.hpp"

using pybind11::literals::operator""_a;

namespace rclpy
{
using events_executor::RclEventCallbackTrampoline;

Subscription::Subscription(
Node & node, py::object pymsg_type, std::string topic,
py::object pyqos_profile)
Expand Down Expand Up @@ -87,6 +91,10 @@ Subscription::Subscription(

void Subscription::destroy()
{
try {
clear_on_new_message_callback();
} catch (RCLError) {
}
rcl_subscription_.reset();
node_.destroy();
}
Expand Down Expand Up @@ -194,6 +202,41 @@ Subscription::get_publisher_count() const
return count;
}

void
Subscription::set_callback(
rcl_event_callback_t callback,
const void * user_data)
{
rcl_ret_t ret = rcl_subscription_set_on_new_message_callback(
rcl_subscription_.get(),
callback,
user_data);

if (RCL_RET_OK != ret) {
throw RCLError(std::string("Failed to set the on new message callback for subscription: ") +
rcl_get_error_string().str);
}
}

void
Subscription::set_on_new_message_callback(std::function<void(size_t)> callback)
{
clear_on_new_message_callback();
on_new_message_callback_ = std::move(callback);
set_callback(
RclEventCallbackTrampoline,
static_cast<const void *>(&on_new_message_callback_));
}

void
Subscription::clear_on_new_message_callback()
{
if (on_new_message_callback_) {
set_callback(nullptr, nullptr);
on_new_message_callback_ = nullptr;
}
}

void
define_subscription(py::object module)
{
Expand All @@ -215,6 +258,10 @@ define_subscription(py::object module)
"Return the resolved topic name of a subscription.")
.def(
"get_publisher_count", &Subscription::get_publisher_count,
"Count the publishers from a subscription.");
"Count the publishers from a subscription.")
.def(
"set_on_new_message_callback", &Subscription::set_on_new_message_callback,
py::arg("callback"))
.def("clear_on_new_message_callback", &Subscription::clear_on_new_message_callback);
}
} // namespace rclpy
Loading