diff --git a/rclpy/CMakeLists.txt b/rclpy/CMakeLists.txt
index af1fc7f8f..4d24c9d27 100644
--- a/rclpy/CMakeLists.txt
+++ b/rclpy/CMakeLists.txt
@@ -38,10 +38,16 @@ find_package(rosidl_runtime_c REQUIRED)
cmake_policy(SET CMP0094 NEW)
set(Python3_FIND_UNVERSIONED_NAMES FIRST)
-# Find python before pybind11
+# Find python before nanobind
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
-find_package(pybind11 REQUIRED)
+# nanobind's CMake config requires the new-style FindPython module with the
+# Python::Module target defined. Reuse the interpreter found above so both
+# find_package calls agree on the same Python installation.
+set(Python_EXECUTABLE "${Python3_EXECUTABLE}")
+find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
+
+find_package(nanobind REQUIRED)
# enables using the Python extensions from the build space for testing
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_rclpy/__init__.py" "")
@@ -69,10 +75,10 @@ function(configure_build_install_location _library_name)
)
endfunction()
-# Split from main extension and converted to pybind11
-pybind11_add_module(_rclpy_pybind11
+# Split from main extension and converted to nanobind
+nanobind_add_module(_rclpy_nanobind
src/rclpy/_rclpy_logging.cpp
- src/rclpy/_rclpy_pybind11.cpp
+ src/rclpy/_rclpy_nanobind.cpp
src/rclpy/action_client.cpp
src/rclpy/action_goal_handle.cpp
src/rclpy/action_server.cpp
@@ -111,13 +117,13 @@ pybind11_add_module(_rclpy_pybind11
)
if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT APPLE)
- target_link_libraries(_rclpy_pybind11 PRIVATE atomic)
+ target_link_libraries(_rclpy_nanobind PRIVATE atomic)
endif()
-target_include_directories(_rclpy_pybind11 PRIVATE
+target_include_directories(_rclpy_nanobind PRIVATE
src/rclpy/
)
-target_link_libraries(_rclpy_pybind11 PRIVATE
+target_link_libraries(_rclpy_nanobind PRIVATE
ament_cmake_ros_core::ament_ros_cxx_standard
lifecycle_msgs::lifecycle_msgs__rosidl_generator_c
lifecycle_msgs::lifecycle_msgs__rosidl_typesupport_c
@@ -130,7 +136,23 @@ target_link_libraries(_rclpy_pybind11 PRIVATE
rcutils::rcutils
rosidl_runtime_c::rosidl_runtime_c
)
-configure_build_install_location(_rclpy_pybind11)
+configure_build_install_location(_rclpy_nanobind)
+
+# Generate the type stubs for the extension module into the source tree,
+# so that they stay committed alongside the bindings.
+nanobind_add_stub(_rclpy_nanobind_stub
+ MODULE _rclpy_nanobind
+ OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rclpy/impl/_rclpy_nanobind.pyi"
+ PYTHON_PATH "${CMAKE_CURRENT_BINARY_DIR}/test_rclpy"
+ PATTERN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/stubgen_pattern.pat"
+ DEPENDS _rclpy_nanobind "${CMAKE_CURRENT_SOURCE_DIR}/stubgen_pattern.pat"
+)
+nanobind_add_stub(_rclpy_nanobind_service_introspection_stub
+ MODULE _rclpy_nanobind.service_introspection
+ OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rclpy/impl/service_introspection.pyi"
+ PYTHON_PATH "${CMAKE_CURRENT_BINARY_DIR}/test_rclpy"
+ DEPENDS _rclpy_nanobind
+)
if(NOT WIN32)
ament_environment_hooks(
@@ -175,7 +197,7 @@ if(BUILD_TESTING)
target_include_directories(test_python_allocator PRIVATE src/rclpy)
target_link_libraries(test_python_allocator
ament_cmake_ros_core::ament_ros_cxx_standard
- pybind11::embed)
+ Python3::Python)
if(NOT _typesupport_impls STREQUAL "")
# Run each test in its own pytest invocation to isolate any global state in rclpy
diff --git a/rclpy/package.xml b/rclpy/package.xml
index 69f609908..9d2fba8f0 100644
--- a/rclpy/package.xml
+++ b/rclpy/package.xml
@@ -25,7 +25,7 @@
rcl_lifecycle
rcl_logging_interface
rcl_yaml_param_parser
- pybind11-dev
+ nanobind-dev
python3-dev
rcpputils
rcutils
diff --git a/rclpy/rclpy/duration.py b/rclpy/rclpy/duration.py
index 73edc78f5..711586d1f 100644
--- a/rclpy/rclpy/duration.py
+++ b/rclpy/rclpy/duration.py
@@ -32,7 +32,7 @@ def __init__(self, *, seconds: Union[int, float] = 0, nanoseconds: Union[int, fl
total_nanoseconds = int(seconds * S_TO_NS)
total_nanoseconds += int(nanoseconds)
if total_nanoseconds >= 2**63 or total_nanoseconds < -2**63:
- # pybind11 would raise TypeError, but we want OverflowError
+ # nanobind would raise TypeError, but we want OverflowError
raise OverflowError(
'Total nanoseconds value is too large to store in C duration.')
self._duration_handle = _rclpy.rcl_duration_t(total_nanoseconds)
diff --git a/rclpy/rclpy/experimental/events_executor.py b/rclpy/rclpy/experimental/events_executor.py
index c6807bf65..3bc68c009 100644
--- a/rclpy/rclpy/experimental/events_executor.py
+++ b/rclpy/rclpy/experimental/events_executor.py
@@ -29,15 +29,6 @@ def EventsExecutor(*, context: typing.Optional[rclpy.Context] = None) -> rclpy.e
# Python backtrace dumped with the crash.
faulthandler.enable()
- ex = typing.cast(rclpy.executors.Executor, _rclpy.EventsExecutor(context))
-
- # rclpy.Executor does this too. Note, the context itself is smart enough to check
- # for bound methods, and check whether the instances they're bound to still exist at
- # callback time, so we don't have to worry about tearing down this stale callback at
- # destruction time.
- # TODO(bmartin427) This should really be done inside of the EventsExecutor
- # implementation itself, but I'm unable to figure out a pybind11 incantation that
- # allows me to pass this bound method call from C++.
- context.on_shutdown(ex.wake)
-
- return ex
+ # Note the EventsExecutor implementation takes care of registering a wake-on-shutdown
+ # callback with the context.
+ return typing.cast(rclpy.executors.Executor, _rclpy.EventsExecutor(context))
diff --git a/rclpy/rclpy/impl/_rclpy_nanobind.pyi b/rclpy/rclpy/impl/_rclpy_nanobind.pyi
new file mode 100644
index 000000000..817072e6f
--- /dev/null
+++ b/rclpy/rclpy/impl/_rclpy_nanobind.pyi
@@ -0,0 +1,1069 @@
+"""ROS 2 Python client library."""
+
+from collections.abc import Callable, Sequence
+import enum
+from typing import Any, Generic, TypeVar, overload
+
+from action_msgs.msg import GoalInfo, GoalStatusArray
+from action_msgs.srv._cancel_goal import (
+ CancelGoal_Request,
+ CancelGoal_Response
+)
+from rclpy.subscription import MessageInfo
+from rclpy.subscription_content_filter_options import (
+ ContentFilterOptions
+)
+from rclpy.type_support import (
+ Action,
+ FeedbackMessage,
+ FeedbackT,
+ GetResultServiceRequest,
+ GetResultServiceResponse,
+ GoalT,
+ ImplT,
+ MsgT,
+ ResultT,
+ SendGoalServiceRequest,
+ SendGoalServiceResponse,
+ Srv,
+ SrvRequestT,
+ SrvResponseT
+)
+
+from . import service_introspection as service_introspection
+
+
+T = TypeVar("T")
+
+class Destroyable:
+ def __enter__(self) -> None: ...
+
+ def __exit__(self, arg0: object | None, arg1: object | None, arg2: object | None) -> None: ...
+
+ def destroy_when_not_in_use(self) -> None:
+ """
+ Forcefully destroy the rcl object as soon as it's not actively being used
+ """
+
+class ClockType(enum.IntEnum):
+ UNINITIALIZED = 0
+
+ ROS_TIME = 1
+
+ SYSTEM_TIME = 2
+
+ STEADY_TIME = 3
+
+class GoalEvent(enum.IntEnum):
+ EXECUTE = 0
+
+ CANCEL_GOAL = 1
+
+ SUCCEED = 2
+
+ ABORT = 3
+
+ CANCELED = 4
+
+RCL_DEFAULT_DOMAIN_ID: int = 18446744073709551615
+
+RMW_DURATION_INFINITE: int = 9223372036854775807
+
+RMW_QOS_DEADLINE_BEST_AVAILABLE: int = 9223372036854775806
+
+RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE: int = 9223372036854775806
+
+class ClockChange(enum.IntEnum):
+ ROS_TIME_NO_CHANGE = 1
+ """ROS time is active and will continue to be active"""
+
+ ROS_TIME_ACTIVATED = 2
+ """ROS time is being activated"""
+
+ ROS_TIME_DEACTIVATED = 3
+ """
+ ROS TIME is being deactivated, the clock will report system time after the jump
+ """
+
+ SYSTEM_TIME_NO_CHANGE = 4
+ """ROS time is inactive and the clock will keep reporting system time"""
+
+class QoSCompatibility(enum.IntEnum):
+ OK = 0
+
+ WARNING = 1
+
+ ERROR = 2
+
+class QoSCheckCompatibleResult:
+ """Result type for checking QoS compatibility with result"""
+
+ def __init__(self) -> None: ...
+
+ @property
+ def compatibility(self) -> QoSCompatibility: ...
+
+ @property
+ def reason(self) -> str: ...
+
+class RCUtilsError(RuntimeError):
+ pass
+
+class RMWError(RuntimeError):
+ pass
+
+class RCLError(RuntimeError):
+ pass
+
+class RCLInvalidROSArgsError(RCLError):
+ pass
+
+class UnknownROSArgsError(RuntimeError):
+ pass
+
+class NodeNameNonExistentError(RCLError):
+ pass
+
+class UnsupportedEventTypeError(RCLError):
+ pass
+
+class TimerCancelledError(RCLError):
+ pass
+
+class NotImplementedError(NotImplementedError):
+ pass
+
+class InvalidHandle(RuntimeError):
+ pass
+
+class Client(Destroyable, Generic[SrvRequestT, SrvResponseT]):
+ def __init__(self, node: Node, srv_type: type[Srv[SrvRequestT, SrvResponseT]], srv_name: str, pyqos_profile: rmw_qos_profile_t | None, /) -> None: ...
+
+ @property
+ def service_name(self) -> str:
+ """Get the name of the service"""
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def send_request(self, pyrequest: SrvRequestT, /) -> int:
+ """Send a request"""
+
+ def service_server_is_available(self) -> bool:
+ """Return true if the service server is available"""
+
+ def take_response(self, pyresponse_type: type[SrvResponseT], /) -> tuple[rmw_service_info_t, SrvResponseT] | tuple[None, None]:
+ """Take a received response from an earlier request"""
+
+ def configure_introspection(self, arg0: Clock, arg1: rmw_qos_profile_t | None, arg2: service_introspection.ServiceIntrospectionState) -> None:
+ """Configure whether introspection is enabled"""
+
+ 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: ...
+
+ def clear_on_new_response_callback(self) -> None: ...
+
+class Context(Destroyable):
+ def __init__(self, arg0: list, arg1: int, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def get_domain_id(self) -> int:
+ """Retrieves domain id from init_options of context."""
+
+ def ok(self) -> bool:
+ """Status of the the client library"""
+
+ def shutdown(self) -> None:
+ """Shutdown context"""
+
+class rcl_duration_t:
+ def __init__(self, arg: int, /) -> None: ...
+
+ @property
+ def nanoseconds(self) -> int: ...
+
+class Publisher(Destroyable, Generic[MsgT]):
+ def __init__(self, node: Node, msg_type: type[MsgT], topic: str, pyqos_profile: rmw_qos_profile_t | None, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def get_logger_name(self) -> str:
+ """Get the name of the logger associated with the node of the publisher"""
+
+ def get_subscription_count(self) -> int:
+ """Count subscribers from a publisher."""
+
+ def get_topic_name(self) -> str:
+ """Retrieve the topic name from a Publisher."""
+
+ def publish(self, msg: MsgT, /) -> None:
+ """Publish a message"""
+
+ def publish_raw(self, arg: bytes, /) -> None:
+ """Publish a serialized message."""
+
+ def wait_for_all_acked(self, arg: rcl_duration_t, /) -> bool:
+ """Wait until all published message data is acknowledged"""
+
+class Service(Destroyable, Generic[SrvRequestT, SrvResponseT]):
+ def __init__(self, node: Node, pysrv_type: type[Srv[SrvRequestT, SrvResponseT]], name: str, pyqos_profile: rmw_qos_profile_t | None, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ @property
+ def name(self) -> str:
+ """Get the name of the service"""
+
+ @property
+ def qos(self) -> dict:
+ """Get the qos profile of the service"""
+
+ def service_send_response(self, pyresponse: SrvResponseT, header: rmw_request_id_t, /) -> None:
+ """Send a response"""
+
+ def service_take_request(self, pyrequest_type: type[SrvRequestT], /) -> tuple[SrvRequestT, rmw_service_info_t] | tuple[None, None]:
+ """Take a request from a given service"""
+
+ def configure_introspection(self, arg0: Clock, arg1: rmw_qos_profile_t | None, arg2: service_introspection.ServiceIntrospectionState) -> None:
+ """Configure whether introspection is enabled"""
+
+ 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: ...
+
+ def clear_on_new_request_callback(self) -> None: ...
+
+class TypeDescriptionService(Destroyable):
+ def __init__(self, arg: Node, /) -> None: ...
+
+ @property
+ def impl(self) -> Service:
+ """Get the rcl service wrapper capsule."""
+
+ def handle_request(self, arg0: object, arg1: object, arg2: Node, /) -> object:
+ """Handle an incoming request by calling RCL implementation"""
+
+class rmw_service_info_t:
+ @property
+ def source_timestamp(self) -> int: ...
+
+ @property
+ def received_timestamp(self) -> int: ...
+
+ @property
+ def request_id(self) -> rmw_request_id_t: ...
+
+class rmw_request_id_t:
+ @property
+ def sequence_number(self) -> int: ...
+
+def rclpy_qos_check_compatible(arg0: rmw_qos_profile_t, arg1: rmw_qos_profile_t, /) -> QoSCheckCompatibleResult:
+ """Check if two QoS profiles are compatible."""
+
+class ActionClient(Destroyable, Generic[GoalT, ResultT, FeedbackT, ImplT]):
+ def __init__(self, node: Node, action_type: type[Action[GoalT, ResultT, FeedbackT, ImplT]], action_name: str, goal_service_qos_profile: rmw_qos_profile_t, result_service_qos_profile: rmw_qos_profile_t, cancel_service_qos_profile: rmw_qos_profile_t, feedback_sub_qos_profile: rmw_qos_profile_t, status_sub_qos_profile: rmw_qos_profile_t, enable_feedback_msg_optimization: bool = False) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def take_goal_response(self, pymsg_type: type[SendGoalServiceResponse], /) -> tuple[int, SendGoalServiceResponse] | tuple[None, None]:
+ """Take an action goal response."""
+
+ def send_result_request(self, pyrequest: GetResultServiceRequest, /) -> int:
+ """Send an action result request."""
+
+ def take_cancel_response(self, pymsg_type: type[CancelGoal_Response], /) -> tuple[int, CancelGoal_Response] | tuple[None, None]:
+ """Take an action cancel response."""
+
+ def take_feedback(self, pymsg_type: type[FeedbackMessage[FeedbackT]], /) -> FeedbackMessage[FeedbackT] | None:
+ """Take a feedback message from a given action client."""
+
+ def send_cancel_request(self, pyrequest: CancelGoal_Request, /) -> int:
+ """Send an action cancel request."""
+
+ def send_goal_request(self, pyrequest: SendGoalServiceRequest[GoalT], /) -> int:
+ """Send an action goal request."""
+
+ def take_result_response(self, pymsg_type: type[GetResultServiceResponse[ResultT]], /) -> tuple[int, GetResultServiceResponse[ResultT]] | tuple[None, None]:
+ """Take an action result response."""
+
+ def get_num_entities(self) -> tuple:
+ """Get the number of wait set entities that make up an action entity."""
+
+ def is_action_server_available(self) -> bool:
+ """Check if an action server is available for the given action client."""
+
+ def add_to_waitset(self, arg: WaitSet, /) -> None:
+ """Add an action entity to a wait set."""
+
+ def is_ready(self, arg: WaitSet, /) -> tuple:
+ """Check if an action entity has any ready wait set entities."""
+
+ def take_status(self, pymsg_type: type[GoalStatusArray], /) -> GoalStatusArray | None:
+ """Take an action status response."""
+
+ def configure_introspection(self, arg0: Clock, arg1: rmw_qos_profile_t | None, arg2: service_introspection.ServiceIntrospectionState) -> None:
+ """Configure whether internal client introspection is enabled"""
+
+ def configure_feedback_subscription_filter_add_goal_id(self, arg: bytes, /) -> bool:
+ """Configure feedback subscription content filter to add a goal ID."""
+
+ def configure_feedback_subscription_filter_remove_goal_id(self, arg: bytes, /) -> bool:
+ """Configure feedback subscription content filter to remove a goal ID."""
+
+class ActionGoalHandle(Destroyable):
+ def __init__(self, arg0: ActionServer, arg1: object, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def get_status(self) -> int:
+ """Get the status of a goal."""
+
+ def update_goal_state(self, arg: GoalEvent, /) -> None:
+ """Update a goal state."""
+
+ def is_active(self) -> bool:
+ """Check if a goal is active."""
+
+class ActionServer(Destroyable, Generic[GoalT, ResultT, FeedbackT, ImplT]):
+ def __init__(self, node: Node, rclpy_clock: Clock, pyaction_type: type[Action[GoalT, ResultT, FeedbackT, ImplT]], action_name: str, goal_service_qos: rmw_qos_profile_t, result_service_qos: rmw_qos_profile_t, cancel_service_qos: rmw_qos_profile_t, feedback_topic_qos: rmw_qos_profile_t, status_topic_qos: rmw_qos_profile_t, result_timeout: float, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def take_goal_request(self, pymsg_type: type[SendGoalServiceRequest[GoalT]], /) -> tuple[rmw_request_id_t, SendGoalServiceRequest[GoalT]] | tuple[None, None]:
+ """Take an action goal request."""
+
+ def send_goal_response(self, header: rmw_request_id_t, pyresponse: SendGoalServiceResponse, /) -> None:
+ """Send an action goal response."""
+
+ def send_result_response(self, header: rmw_request_id_t, pyresponse: GetResultServiceResponse[ResultT], /) -> None:
+ """Send an action result response."""
+
+ def take_cancel_request(self, pymsg_type: type[CancelGoal_Request], /) -> tuple[rmw_request_id_t, CancelGoal_Request] | tuple[None, None]:
+ """Take an action cancel request."""
+
+ def take_result_request(self, pymsg_type: type[GetResultServiceRequest], /) -> tuple[rmw_request_id_t, GetResultServiceRequest] | tuple[None, None]:
+ """Take an action result request."""
+
+ def send_cancel_response(self, header: rmw_request_id_t, pyresponse: CancelGoal_Response, /) -> None:
+ """Send an action cancel response."""
+
+ def publish_feedback(self, pymsg: FeedbackT, /) -> None:
+ """Publish a feedback message from a given action server."""
+
+ def publish_status(self) -> None:
+ """Publish a status message from a given action server."""
+
+ def notify_goal_done(self) -> None:
+ """Notify goal is done."""
+
+ def goal_exists(self, pygoal_info: GoalInfo, /) -> bool:
+ """Check is a goal exists in the server."""
+
+ def process_cancel_request(self, pycancel_request: CancelGoal_Request, pycancel_response_type: type[CancelGoal_Response], /) -> CancelGoal_Response:
+ """Process a cancel request"""
+
+ def expire_goals(self, max_num_goals: int, /) -> tuple[GoalInfo, ...]:
+ """Expired goals."""
+
+ def get_num_entities(self) -> tuple:
+ """Get the number of wait set entities that make up an action entity."""
+
+ def is_ready(self, arg: WaitSet, /) -> tuple:
+ """Check if an action entity has any ready wait set entities."""
+
+ def add_to_waitset(self, arg: WaitSet, /) -> None:
+ """Add an action entity to a wait set."""
+
+ def configure_introspection(self, arg0: Clock, arg1: rmw_qos_profile_t | None, arg2: service_introspection.ServiceIntrospectionState) -> None:
+ """Configure whether internal service introspection is enabled"""
+
+def rclpy_action_get_rmw_qos_profile(arg: str, /) -> dict:
+ """Get an action RMW QoS profile."""
+
+class GuardCondition(Destroyable):
+ def __init__(self, arg: Context, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def trigger_guard_condition(self) -> None:
+ """Trigger a general purpose guard condition"""
+
+class Timer(Destroyable):
+ def __init__(self, arg0: Clock, arg1: Context, arg2: int, arg3: bool, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def reset_timer(self) -> None:
+ """Reset a timer."""
+
+ def is_timer_ready(self) -> bool:
+ """Check if a timer as reached timeout."""
+
+ def call_timer(self) -> None:
+ """Call a timer and starts counting again."""
+
+ def call_timer_with_info(self) -> object:
+ """
+ Call a timer and starts counting again, retrieves actual and expected call time.
+ """
+
+ def change_timer_period(self, arg: int, /) -> None:
+ """Set the period of a timer."""
+
+ def time_until_next_call(self) -> int | None:
+ """Get the remaining time before timer is ready."""
+
+ def time_since_last_call(self) -> int:
+ """Get the elapsed time since last timer call."""
+
+ def get_timer_period(self) -> int:
+ """Get the period of a timer."""
+
+ def cancel_timer(self) -> None:
+ """Cancel a timer."""
+
+ def is_timer_canceled(self) -> bool:
+ """Check if a timer is canceled."""
+
+ def set_on_reset_callback(self, callback: Callable[[int], None]) -> None: ...
+
+ def clear_on_reset_callback(self) -> None: ...
+
+class Subscription(Destroyable, Generic[MsgT]):
+ def __init__(self, node: Node, msg_type: type[MsgT], topic: str, qos_profile: rmw_qos_profile_t | None, content_filter_options: ContentFilterOptions | None = None, acceptable_buffer_backends: str | None = None) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def take_message(self, pymsg_type: type[MsgT], raw: bool, /) -> tuple[MsgT | bytes, MessageInfo] | None:
+ """Take a message and its metadata from a subscription"""
+
+ def get_logger_name(self) -> str:
+ """
+ Get the name of the logger associated with the node of the subscription.
+ """
+
+ def get_topic_name(self) -> str:
+ """Return the resolved topic name of a subscription."""
+
+ def get_publisher_count(self) -> int:
+ """Count the publishers from a subscription."""
+
+ def set_on_new_message_callback(self, callback: Callable[[int], None]) -> None: ...
+
+ def clear_on_new_message_callback(self) -> None: ...
+
+ def is_cft_supported(self) -> bool:
+ """Check if subscription instance supports content filtering."""
+
+ def is_cft_enabled(self) -> bool:
+ """Check if content filtering is enabled for this subscription."""
+
+ def set_content_filter(self, arg0: str, arg1: Sequence[str], /) -> None:
+ """
+ Set the filter expression and expression parameters for the subscription.
+ """
+
+ def get_content_filter(self) -> ContentFilterOptions:
+ """
+ Get the filter expression and expression parameters for the subscription.
+ """
+
+class rcl_time_point_t:
+ def __init__(self, arg0: int, arg1: int, /) -> None: ...
+
+ @property
+ def nanoseconds(self) -> int: ...
+
+ @property
+ def clock_type(self) -> ClockType: ...
+
+class Clock(Destroyable):
+ def __init__(self, arg: int, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def get_now(self) -> rcl_time_point_t:
+ """Current value of the clock"""
+
+ def get_ros_time_override_is_enabled(self) -> bool:
+ """Returns if a clock using ROS time has the ROS time override enabled."""
+
+ def set_ros_time_override_is_enabled(self, arg: bool, /) -> None:
+ """Set if a clock using ROS time has the ROS time override enabled."""
+
+ def set_ros_time_override(self, arg: rcl_time_point_t, /) -> None:
+ """Set the ROS time override for a clock using ROS time."""
+
+ def add_clock_callback(self, arg0: object, arg1: bool, arg2: int, arg3: int, /) -> None:
+ """Add a time jump callback to a clock."""
+
+ def remove_clock_callback(self, arg: object, /) -> None:
+ """Remove a time jump callback from a clock."""
+
+class WaitSet(Destroyable):
+ def __init__(self, arg0: int, arg1: int, arg2: int, arg3: int, arg4: int, arg5: int, arg6: Context, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def clear_entities(self) -> None:
+ """Clear all the pointers in the wait set"""
+
+ def add_service(self, arg: Service, /) -> int:
+ """Add a service to the wait set structure"""
+
+ def add_subscription(self, arg: Subscription, /) -> int:
+ """Add a subscription to the wait set structure"""
+
+ def add_client(self, arg: Client, /) -> int:
+ """Add a client to the wait set structure"""
+
+ def add_guard_condition(self, arg: GuardCondition, /) -> int:
+ """Add a guard condition to the wait set structure"""
+
+ def add_timer(self, arg: Timer, /) -> int:
+ """Add a timer to the wait set structure"""
+
+ def add_event(self, arg: EventHandle, /) -> int:
+ """Add an event to the wait set structure"""
+
+ def is_ready(self, arg0: str, arg1: int, /) -> bool:
+ """Check if an entity in the wait set is ready by its index"""
+
+ def get_ready_entities(self, arg: str, /) -> list:
+ """Get list of entities ready by entity type"""
+
+ def wait(self, arg: int, /) -> None:
+ """Wait until timeout is reached or event happened"""
+
+def rclpy_expand_topic_name(arg0: str, arg1: str, arg2: str, /) -> str:
+ """Expand a topic name."""
+
+def rclpy_remap_topic_name(arg0: Node, arg1: str, /) -> str:
+ """Remap a topic name."""
+
+def rclpy_get_validation_error_for_topic_name(arg: str, /) -> object:
+ """
+ Get the error message and invalid index of a topic name or None if valid.
+ """
+
+def rclpy_get_validation_error_for_full_topic_name(arg: str, /) -> object:
+ """
+ Get the error message and invalid index of a full topic name or None if valid.
+ """
+
+def rclpy_get_validation_error_for_namespace(arg: str, /) -> object:
+ """
+ Get the error message and invalid index of a namespace or None if valid.
+ """
+
+def rclpy_get_validation_error_for_node_name(arg: str, /) -> object:
+ """
+ Get the error message and invalid index of a node name or None if valid.
+ """
+
+def rclpy_resolve_name(arg0: Node, arg1: str, arg2: bool, arg3: bool, /) -> str:
+ """Expand and remap a topic or service name."""
+
+def rclpy_get_topic_names_and_types(arg0: Node, arg1: bool, /) -> list:
+ """Get all topic names and types in the ROS graph."""
+
+def rclpy_get_publisher_names_and_types_by_node(arg0: Node, arg1: bool, arg2: str, arg3: str, /) -> list:
+ """Get topic names and types for which a remote node has publishers."""
+
+def rclpy_get_subscriber_names_and_types_by_node(arg0: Node, arg1: bool, arg2: str, arg3: str, /) -> list:
+ """Get topic names and types for which a remote node has subscribers."""
+
+def rclpy_get_publishers_info_by_topic(arg0: Node, arg1: str, arg2: bool, /) -> list:
+ """Get publishers info for a topic."""
+
+def rclpy_get_subscriptions_info_by_topic(arg0: Node, arg1: str, arg2: bool, /) -> list:
+ """Get subscriptions info for a topic."""
+
+def rclpy_get_clients_info_by_service(arg0: Node, arg1: str, arg2: bool, /) -> list:
+ """Get clients info for a service."""
+
+def rclpy_get_servers_info_by_service(arg0: Node, arg1: str, arg2: bool, /) -> list:
+ """Get servers info for a service."""
+
+def rclpy_get_service_names_and_types(arg: Node, /) -> list:
+ """Get all service names and types in the ROS graph."""
+
+def rclpy_get_service_names_and_types_by_node(arg0: Node, arg1: str, arg2: str, /) -> list:
+ """Get service names and types for which a remote node has servers."""
+
+def rclpy_get_client_names_and_types_by_node(arg0: Node, arg1: str, arg2: str, /) -> list:
+ """Get service names and types for which a remote node has clients."""
+
+def rclpy_get_action_client_names_and_types_by_node(arg0: Node, arg1: str, arg2: str, /) -> list:
+ """Get action client names and types by node."""
+
+def rclpy_get_action_server_names_and_types_by_node(arg0: Node, arg1: str, arg2: str, /) -> list:
+ """Get action server names and types by node."""
+
+def rclpy_get_action_names_and_types(arg: Node, /) -> list:
+ """Get all action names and types in the ROS graph."""
+
+def rclpy_get_action_clients_info_by_action(arg0: Node, arg1: str, /) -> list:
+ """Get action clients info for an action."""
+
+def rclpy_get_action_servers_info_by_action(arg0: Node, arg1: str, /) -> list:
+ """Get action servers info for an action."""
+
+def rclpy_serialize(arg0: object, arg1: object, /) -> bytes:
+ """Serialize a ROS message."""
+
+def rclpy_deserialize(arg0: bytes, arg1: object, /) -> object:
+ """Deserialize a ROS message."""
+
+class Node(Destroyable):
+ def __init__(self, arg0: str, arg1: str, arg2: Context, arg3: list | None, arg4: bool, arg5: bool, arg6: rmw_qos_profile_t | None) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def get_fully_qualified_name(self) -> str:
+ """Get the fully qualified name of the node."""
+
+ def logger_name(self) -> str:
+ """Get the name of the logger associated with a node."""
+
+ def get_node_name(self) -> str:
+ """Get the name of a node."""
+
+ def get_namespace(self) -> str:
+ """Get the namespace of a node."""
+
+ def get_count_publishers(self, arg: str, /) -> int:
+ """
+ Returns the count of all the publishers known for that topic in the entire ROS graph.
+ """
+
+ def get_count_subscribers(self, arg: str, /) -> int:
+ """
+ Returns the count of all the subscribers known for that topic in the entire ROS graph.
+ """
+
+ def get_count_clients(self, arg: str, /) -> int:
+ """
+ Returns the count of all the clients known for that service in the entire ROS graph.
+ """
+
+ def get_count_services(self, arg: str, /) -> int:
+ """
+ Returns the count of all the servers known for that service in the entire ROS graph.
+ """
+
+ def get_count_action_clients(self, arg: str, /) -> int:
+ """
+ Returns the count of all the action clients known for that action in the entire ROS graph.
+ """
+
+ def get_count_action_servers(self, arg: str, /) -> int:
+ """
+ Returns the count of all the action servers known for that action in the entire ROS graph.
+ """
+
+ def get_node_names_and_namespaces(self) -> list:
+ """Get the list of nodes discovered by the provided node"""
+
+ def get_node_names_and_namespaces_with_enclaves(self) -> list:
+ """
+ Get the list of nodes discovered by the provided node, with their respective enclaves.
+ """
+
+ def get_action_client_names_and_types_by_node(self, arg0: str, arg1: str, /) -> list:
+ """Get action client names and types by node."""
+
+ def get_action_server_names_and_types_by_node(self, arg0: str, arg1: str, /) -> list:
+ """Get action server names and types by node."""
+
+ def get_action_names_and_types(self) -> list:
+ """Get action names and types."""
+
+ def get_parameters(self, arg: object, /) -> dict:
+ """Get a list of parameters for the current node"""
+
+class EventHandle(Destroyable, Generic[T]):
+ @overload
+ def __init__(self, subscription: Subscription[Any], event_type: rcl_subscription_event_type_t, /) -> None: ...
+
+ @overload
+ def __init__(self, publisher: Publisher[Any], event_type: rcl_publisher_event_type_t, /) -> None: ...
+
+ @property
+ def pointer(self) -> int:
+ """Get the address of the entity as an integer"""
+
+ def take_event(self) -> T | None:
+ """Get pending data from a ready event"""
+
+class rcl_subscription_event_type_t(enum.IntEnum):
+ RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED = 0
+
+ RCL_SUBSCRIPTION_LIVELINESS_CHANGED = 1
+
+ RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS = 2
+
+ RCL_SUBSCRIPTION_MESSAGE_LOST = 3
+
+ RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE = 4
+
+ RCL_SUBSCRIPTION_MATCHED = 5
+
+class rcl_publisher_event_type_t(enum.IntEnum):
+ RCL_PUBLISHER_OFFERED_DEADLINE_MISSED = 0
+
+ RCL_PUBLISHER_LIVELINESS_LOST = 1
+
+ RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS = 2
+
+ RCL_PUBLISHER_INCOMPATIBLE_TYPE = 3
+
+ RCL_PUBLISHER_MATCHED = 4
+
+class rmw_requested_deadline_missed_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count(self) -> int: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+class rmw_liveliness_changed_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def alive_count(self) -> int: ...
+
+ @property
+ def not_alive_count(self) -> int: ...
+
+ @property
+ def alive_count_change(self) -> int: ...
+
+ @property
+ def not_alive_count_change(self) -> int: ...
+
+class rmw_message_lost_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count(self) -> int: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+class rmw_requested_qos_incompatible_event_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count(self) -> int: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+ @property
+ def last_policy_kind(self) -> rmw_qos_policy_kind_t: ...
+
+class rmw_offered_deadline_missed_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count(self) -> int: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+class rmw_liveliness_lost_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count(self) -> int: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+class rmw_matched_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count(self) -> int: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+ @property
+ def current_count(self) -> int: ...
+
+ @property
+ def current_count_change(self) -> int: ...
+
+class rmw_qos_policy_kind_t(enum.IntEnum):
+ RMW_QOS_POLICY_INVALID = 1
+
+ RMW_QOS_POLICY_DURABILITY = 2
+
+ RMW_QOS_POLICY_DEADLINE = 4
+
+ RMW_QOS_POLICY_LIVELINESS = 8
+
+ RMW_QOS_POLICY_RELIABILITY = 16
+
+ RMW_QOS_POLICY_HISTORY = 32
+
+ RMW_QOS_POLICY_LIFESPAN = 64
+
+ RMW_QOS_POLICY_DEPTH = 128
+
+ RMW_QOS_POLICY_LIVELINESS_LEASE_DURATION = 256
+
+ RMW_QOS_POLICY_AVOID_ROS_NAMESPACE_CONVENTIONS = 512
+
+class rmw_incompatible_type_status_t:
+ def __init__(self) -> None: ...
+
+ @property
+ def total_count_change(self) -> int: ...
+
+def publisher_event_type_is_supported(arg: rcl_publisher_event_type_t, /) -> bool:
+ """
+ Check if a publisher event type is supported by the active RMW implementation.
+ """
+
+def subscription_event_type_is_supported(arg: rcl_subscription_event_type_t, /) -> bool:
+ """
+ Check if a subscription event type is supported by the active RMW implementation.
+ """
+
+def rclpy_get_rmw_implementation_identifier() -> str:
+ """Retrieve the identifier for the active RMW implementation."""
+
+def rclpy_assert_liveliness(arg: Publisher, /) -> None:
+ """Assert the liveliness of an entity."""
+
+def rclpy_remove_ros_args(arg: list | None) -> list:
+ """Remove ROS-specific arguments from argument vector."""
+
+class rmw_qos_profile_t:
+ def __init__(self, arg0: int, arg1: int, arg2: int, arg3: int, arg4: rcl_duration_t, arg5: rcl_duration_t, arg6: int, arg7: rcl_duration_t, arg8: bool, /) -> None: ...
+
+ def to_dict(self) -> dict: ...
+
+ @staticmethod
+ def predefined(arg: str, /) -> rmw_qos_profile_t: ...
+
+def rclpy_logging_fini() -> None:
+ """Finalize RCL logging."""
+
+def rclpy_logging_configure(arg: Context, /) -> None:
+ """Initialize RCL logging."""
+
+class RCUTILS_LOG_SEVERITY(enum.IntEnum):
+ RCUTILS_LOG_SEVERITY_UNSET = 0
+
+ RCUTILS_LOG_SEVERITY_DEBUG = 10
+
+ RCUTILS_LOG_SEVERITY_INFO = 20
+
+ RCUTILS_LOG_SEVERITY_WARN = 30
+
+ RCUTILS_LOG_SEVERITY_ERROR = 40
+
+ RCUTILS_LOG_SEVERITY_FATAL = 50
+
+def rclpy_logging_get_separator_string() -> str: ...
+
+def rclpy_logging_initialize() -> None: ...
+
+def rclpy_logging_shutdown() -> None: ...
+
+def rclpy_logging_set_logger_level(name: str, level: int, detailed_error: bool = False) -> None: ...
+
+def rclpy_logging_get_logger_effective_level(arg: str, /) -> int: ...
+
+def rclpy_logging_logger_is_enabled_for(arg0: str, arg1: int, /) -> bool: ...
+
+def rclpy_logging_rcutils_log(arg0: int, arg1: str, arg2: str, arg3: str, arg4: str, arg5: int, /) -> None: ...
+
+def rclpy_logging_severity_level_from_string(arg: str, /) -> int: ...
+
+def rclpy_logging_get_logging_directory() -> str: ...
+
+def rclpy_logging_rosout_add_sublogger(arg0: str, arg1: str, /) -> bool: ...
+
+def rclpy_logging_rosout_remove_sublogger(arg0: str, arg1: str, /) -> None: ...
+
+def rclpy_logging_get_logger_level(arg: str, /) -> int: ...
+
+def register_sigint_guard_condition(arg: GuardCondition, /) -> None:
+ """Register a guard condition to be called on SIGINT."""
+
+def unregister_sigint_guard_condition(arg: GuardCondition, /) -> None:
+ """Stop triggering a guard condition when SIGINT occurs."""
+
+def install_signal_handlers(arg: SignalHandlerOptions, /) -> None:
+ """Install rclpy signal handlers."""
+
+def get_current_signal_handlers_options() -> SignalHandlerOptions:
+ """Get currently installed signal handler options."""
+
+def uninstall_signal_handlers() -> None:
+ """Uninstall rclpy signal handlers."""
+
+class SignalHandlerOptions(enum.IntEnum):
+ """Enum with values: `ALL`, `SIGINT`, `SIGTERM`, `NO`."""
+
+ ALL = 3
+
+ NO = 0
+
+ SIGINT = 1
+
+ SIGTERM = 2
+
+class ClockEvent:
+ def __init__(self) -> None: ...
+
+ def wait_until_steady(self, arg0: Clock, arg1: rcl_time_point_t, /) -> None:
+ """Wait for the event to be set (monotonic wait)"""
+
+ def wait_until_system(self, arg0: Clock, arg1: rcl_time_point_t, /) -> None:
+ """Wait for the event to be set (system timed wait)"""
+
+ def wait_until_ros(self, arg0: Clock, arg1: rcl_time_point_t, /) -> None:
+ """Wait for the event to be set (ROS timed wait)"""
+
+ def is_set(self) -> bool:
+ """Return True if the event is set, False otherwise."""
+
+ def set(self) -> None:
+ """Set the event, waking all those who wait on it."""
+
+ def clear(self) -> None:
+ """Unset the event."""
+
+class LifecycleStateMachine(Destroyable):
+ def __init__(self, arg0: Node, arg1: Clock, arg2: bool, /) -> None: ...
+
+ @property
+ def initialized(self) -> bool:
+ """Check if state machine is initialized."""
+
+ @property
+ def current_state(self) -> tuple:
+ """Get the current state machine state."""
+
+ @property
+ def available_states(self) -> list[tuple[int, str]]:
+ """Get the available states."""
+
+ @property
+ def available_transitions(self) -> list[tuple[int, str, int, str, int, str]]:
+ """Get the available transitions."""
+
+ @property
+ def transition_graph(self) -> list[tuple[int, str, int, str, int, str]]:
+ """Get the transition graph."""
+
+ def get_transition_by_label(self, arg: str, /) -> int:
+ """Get the transition id from a transition label."""
+
+ def trigger_transition_by_id(self, arg0: int, arg1: bool, /) -> None:
+ """Trigger a transition by transition id."""
+
+ def trigger_transition_by_label(self, arg0: str, arg1: bool, /) -> None:
+ """Trigger a transition by label."""
+
+ @property
+ def service_change_state(self) -> Service:
+ """Get the change state service."""
+
+ @property
+ def service_get_state(self) -> Service:
+ """Get the get state service."""
+
+ @property
+ def service_get_available_states(self) -> Service:
+ """Get the get available states service."""
+
+ @property
+ def service_get_available_transitions(self) -> Service:
+ """Get the get available transitions service."""
+
+ @property
+ def service_get_transition_graph(self) -> Service:
+ """Get the get transition graph service."""
+
+class TransitionCallbackReturnType(enum.IntEnum):
+ SUCCESS = 97
+ """Callback succeeded."""
+
+ FAILURE = 98
+ """Callback failed."""
+
+ ERROR = 99
+ """Callback had an error."""
+
+ def to_label(self) -> str:
+ """Convert the transition callback return code to a transition label"""
+
+class EventsExecutor:
+ def __init__(self, context: object) -> None: ...
+
+ @property
+ def context(self) -> object: ...
+
+ def create_task(self, callback: object, *args, **kwargs) -> object: ...
+
+ def create_future(self) -> object: ...
+
+ def shutdown(self, timeout_sec: float | None = None) -> bool: ...
+
+ def add_node(self, node: object) -> bool: ...
+
+ def remove_node(self, node: object) -> None: ...
+
+ def wake(self) -> None: ...
+
+ def get_nodes(self) -> list: ...
+
+ def spin(self) -> None: ...
+
+ def spin_once(self, timeout_sec: float | None = None) -> None: ...
+
+ def spin_until_future_complete(self, future: object, timeout_sec: float | None = None) -> None: ...
+
+ def spin_once_until_future_complete(self, future: object, timeout_sec: float | None = None) -> None: ...
+
+ def __enter__(self) -> EventsExecutor: ...
+
+ def __exit__(self, arg0: object | None, arg1: object | None, arg2: object | None) -> None: ...
diff --git a/rclpy/rclpy/impl/_rclpy_pybind11.pyi b/rclpy/rclpy/impl/_rclpy_pybind11.pyi
deleted file mode 100644
index 4bd8e913d..000000000
--- a/rclpy/rclpy/impl/_rclpy_pybind11.pyi
+++ /dev/null
@@ -1,1368 +0,0 @@
-# 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 __future__ import annotations
-
-import builtins
-from enum import IntEnum
-from types import TracebackType
-from typing import (Any, Callable, Coroutine, Final, Generic, Literal, Optional, overload,
- Sequence, TypeAlias, TypedDict, TypeVar)
-
-
-from action_msgs.msg import GoalInfo
-from action_msgs.msg._goal_status_array import GoalStatusArray
-from action_msgs.srv._cancel_goal import CancelGoal
-from rclpy.clock import JumpHandle
-from rclpy.context import Context as RCLPyContext
-from rclpy.duration import Duration
-from rclpy.impl import service_introspection as service_introspection
-from rclpy.node import Node as RCLPyNode
-from rclpy.parameter import Parameter
-from rclpy.subscription import MessageInfo
-from rclpy.subscription_content_filter_options import ContentFilterOptions
-from rclpy.task import Future
-from rclpy.task import Task
-from rclpy.type_support import Action
-from rclpy.type_support import Srv
-from rclpy.type_support import FeedbackMessage
-from rclpy.type_support import FeedbackT
-from rclpy.type_support import ImplT
-from rclpy.type_support import GetResultServiceRequest
-from rclpy.type_support import GetResultServiceResponse
-from rclpy.type_support import GoalT
-from rclpy.type_support import MsgT
-from rclpy.type_support import ResultT
-from rclpy.type_support import SendGoalServiceRequest
-from rclpy.type_support import SendGoalServiceResponse
-from rclpy.type_support import SrvRequestT
-from rclpy.type_support import SrvResponseT
-from type_description_interfaces.srv import GetTypeDescription
-
-T = TypeVar('T')
-
-# All things are defined in same order as defined in _rclpy_pybind11.cpp
-
-
-class Destroyable:
-
- def __enter__(self) -> None: ...
-
- def __exit__(self, exc_type: type[BaseException] | None,
- exc_val: BaseException | None, exctb: TracebackType | None) -> None: ...
-
- def destroy_when_not_in_use(self) -> None:
- """Destroy the rcl object as soon as it's not actively being used."""
-
-
-class ClockType(IntEnum):
- UNINITIALIZED = ...
- ROS_TIME = ...
- SYSTEM_TIME = ...
- STEADY_TIME = ...
-
-
-class GoalEvent(IntEnum):
- EXECUTE = ...
- CANCEL_GOAL = ...
- SUCCEED = ...
- ABORT = ...
- CANCELED = ...
-
-
-RCL_DEFAULT_DOMAIN_ID: Final[int] = ...
-RMW_DURATION_INFINITE: Final[int] = ...
-RMW_QOS_DEADLINE_BEST_AVAILABLE: Final[int] = ...
-RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE: Final[int] = ...
-
-
-class ClockChange(IntEnum):
- ROS_TIME_NO_CHANGE = ...
- """ROS time is active and will continue to be active"."""
- ROS_TIME_ACTIVATED = ...
- """ROS time is being activated."""
- ROS_TIME_DEACTIVATED = ...
- """ROS TIME is being deactivated, the clock will report system time after the jump."""
- SYSTEM_TIME_NO_CHANGE = ...
- """ROS time is inactive and the clock will keep reporting system time."""
-
-
-class QoSCompatibility(IntEnum):
- OK = ...
- WARNING = ...
- ERROR = ...
-
-
-class _rmw_qos_compatibility_type_e(IntEnum):
- RMW_QOS_COMPATIBILITY_OK = ...
- RMW_QOS_COMPATIBILITY_WARNING = ...
- RMW_QOS_COMPATIBILITY_ERROR = ...
-
-
-_rmw_qos_compatibility_type_t: TypeAlias = _rmw_qos_compatibility_type_e
-
-
-class QoSCheckCompatibleResult:
- """Result type for checking QoS compatibility with result."""
-
- def __init__(self) -> None: ...
-
- @property
- def compatibility(self) -> _rmw_qos_compatibility_type_t: ...
-
- @property
- def reason(self) -> str: ...
-
-
-class RCUtilsError(RuntimeError):
-
- def __init__(self, error_text: str) -> None: ...
-
-
-class RMWError(RuntimeError):
-
- def __init__(self, error_text: str) -> None: ...
-
-
-class RCLError(RuntimeError):
-
- def __init__(self, error_text: str) -> None: ...
-
-
-class RCLInvalidROSArgsError(RCLError):
- pass
-
-
-class UnknownROSArgsError(RuntimeError):
- pass
-
-
-class NodeNameNonExistentError(RCLError):
- pass
-
-
-class UnsupportedEventTypeError(RCLError):
- pass
-
-
-class TimerCancelledError(RCLError):
- pass
-
-
-class NotImplementedError(builtins.NotImplementedError): # noqa: A001
- pass
-
-
-class InvalidHandle(RuntimeError):
- pass
-
-
-# Service Introspection imported above
-
-
-class Client(Destroyable, Generic[SrvRequestT, SrvResponseT]):
-
- def __init__(self, node: Node, srv_type: type[Srv[SrvRequestT, SrvResponseT]],
- srv_name: str, pyqos_profile: rmw_qos_profile_t) -> None: ...
-
- @property
- def service_name(self) -> str:
- """Get the name of the service."""
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def send_request(self, pyrequest: SrvRequestT) -> int:
- """Send a request."""
-
- def service_server_is_available(self) -> bool:
- """Return true if the service server is available."""
-
- def take_response(
- self, pyresponse_type: type[SrvResponseT]
- ) -> tuple[rmw_service_info_t, SrvResponseT] | tuple[None, None]:
- """Take a received response from an earlier request."""
-
- def configure_introspection(
- self,
- clock: Clock,
- pyqos_service_event_pub: rmw_qos_profile_t,
- introspection_state: service_introspection.ServiceIntrospectionState
- ) -> None:
- """Configure whether introspection is enabled."""
-
- 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):
-
- def __init__(self, pyargs: list[str], domain_id: int) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def get_domain_id(self) -> int:
- """Retrieve domain id from init_options of context."""
-
- def ok(self) -> bool:
- """Status of the the client library."""
-
- def shutdown(self) -> None:
- """Shutdown context."""
-
-
-class rcl_duration_t:
-
- def __init__(self, nanoseconds: int) -> None: ...
-
- @property
- def nanoseconds(self) -> int: ...
-
-
-class Publisher(Destroyable, Generic[MsgT]):
-
- def __init__(self, arg0: Node, arg1: type[MsgT], arg2: str, arg3: rmw_qos_profile_t) -> None:
- """Create _rclpy.Publisher."""
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def get_logger_name(self) -> str:
- """Get the name of the logger associated with the node of the publisher."""
-
- def get_subscription_count(self) -> int:
- """Count subscribers from a publisher."""
-
- def get_topic_name(self) -> str:
- """Retrieve the topic name from a Publisher."""
-
- def publish(self, arg0: MsgT) -> None:
- """Publish a message."""
-
- def publish_raw(self, arg0: bytes) -> None:
- """Publish a serialized message."""
-
- def wait_for_all_acked(self, arg0: rcl_duration_t) -> bool:
- """Wait until all published message data is acknowledged."""
-
-
-class Service(Destroyable, Generic[SrvRequestT, SrvResponseT]):
-
- def __init__(self, node: Node, pysrv_type: type[Srv[SrvRequestT, SrvResponseT]],
- name: str, pyqos_profile: rmw_qos_profile_t) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- @property
- def name(self) -> str:
- """Get the name of the service."""
-
- @property
- def qos(self) -> _rmw_qos_profile_dict:
- """Get the qos profile of the service."""
-
- def service_send_response(self, pyresponse: SrvResponseT, header: rmw_request_id_t) -> None:
- """Send a response."""
-
- def service_take_request(
- self,
- pyrequest_type: type[SrvRequestT]
- ) -> tuple[SrvRequestT, rmw_service_info_t] | tuple[None, None]:
- """Take a request from a given service."""
-
- def configure_introspection(
- self, clock: Clock,
- pyqos_service_event_pub: rmw_qos_profile_t,
- introspection_state: service_introspection.ServiceIntrospectionState
- ) -> None:
- """Configure whether introspection is enabled."""
-
- 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):
-
- def __init__(self, handle: Node) -> None: ...
-
- @property
- def impl(self) -> Service[GetTypeDescription.Request, GetTypeDescription.Response]:
- """Get the rcl service wrapper capsule."""
-
- def handle_request(
- self, pyrequest: GetTypeDescription.Request,
- pyresponse_type: type[GetTypeDescription.Response],
- node: Node
- ) -> GetTypeDescription.Response:
- """Handle an incoming request by calling RCL implementation."""
-
-
-class rmw_service_info_t:
-
- @property
- def source_timestamp(self) -> int: ...
-
- @property
- def received_timestamp(self) -> int: ...
-
- @property
- def request_id(self) -> rmw_request_id_t: ...
-
-
-class rmw_request_id_t:
-
- @property
- def sequence_number(self) -> int: ...
-
-
-def rclpy_qos_check_compatible(publisher_qos_profile: rmw_qos_profile_t,
- subscription_qos_profile: rmw_qos_profile_t
- ) -> QoSCheckCompatibleResult:
- """Check if two QoS profiles are compatible."""
-
-
-class ActionClient(Generic[GoalT, ResultT, FeedbackT, ImplT], Destroyable):
-
- def __init__(
- self,
- node: Node,
- pyaction_type: type[Action[GoalT, ResultT, FeedbackT, ImplT]],
- action_name: str,
- goal_service_qos: rmw_qos_profile_t,
- result_service_qos: rmw_qos_profile_t,
- cancel_service_qos: rmw_qos_profile_t,
- feedback_service_qos: rmw_qos_profile_t,
- status_topic_qos: rmw_qos_profile_t,
- enable_feedback_msg_optimization: bool
- ) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def take_goal_response(self, pymsg_type: type[SendGoalServiceResponse]
- ) -> tuple[int, SendGoalServiceResponse] | tuple[None, None]:
- """Take an action goal response."""
-
- def send_result_request(self, pyrequest: GetResultServiceRequest) -> int:
- """Send an action result request."""
-
- def take_cancel_response(self, pymsg_type: type[CancelGoal.Response]
- ) -> tuple[int, CancelGoal.Response] | tuple[None, None]:
- """Take an action cancel response."""
-
- def take_feedback(self, pymsg_type: type[FeedbackMessage[FeedbackT]]
- ) -> FeedbackMessage[FeedbackT] | None:
- """Take a feedback message from a given action client."""
-
- def send_cancel_request(self, pyrequest: CancelGoal.Request) -> int:
- """Send an action cancel request."""
-
- def send_goal_request(self, pyrequest: SendGoalServiceRequest[GoalT]) -> int:
- """Send an action goal request."""
-
- def take_result_response(
- self,
- pymsg_type: type[GetResultServiceResponse[ResultT]]
- ) -> tuple[int, GetResultServiceResponse[ResultT]] | tuple[None, None]:
- """Take an action result response."""
-
- def get_num_entities(self) -> tuple[int, int, int, int, int]:
- """Get the number of wait set entities that make up an action entity."""
-
- def is_action_server_available(self) -> bool:
- """Check if an action server is available for the given action client."""
-
- def add_to_waitset(self, wait_set: WaitSet) -> None:
- """Add an action entity to a wait set."""
-
- def is_ready(self, wait_set: WaitSet) -> tuple[bool, bool, bool, bool, bool]:
- """Check if an action entity has any ready wait set entities."""
-
- def take_status(self, pymsg_type: type[GoalStatusArray]) -> GoalStatusArray | None:
- """Take an action status response."""
-
- def configure_introspection(
- self,
- clock: Clock,
- pyqos_service_event_pub: Optional[rmw_qos_profile_t],
- introspection_state: service_introspection.ServiceIntrospectionState
- ) -> None:
- """Configure whether internal client introspection is enabled."""
-
- def configure_feedback_subscription_filter_add_goal_id(self, goal_id: bytes) -> bool:
- """Configure feedback subscription content filter to add a goal ID."""
-
- def configure_feedback_subscription_filter_remove_goal_id(self, goal_id: bytes) -> bool:
- """Configure feedback subscription content filter to remove a goal ID."""
-
-class ActionGoalHandle(Destroyable):
-
- def __init__(self, action_server: ActionServer[Any, Any, Any, Any],
- pygoal_info_msg: GoalInfo) -> None:
- ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def get_status(self) -> GoalEvent:
- """Get the status of a goal."""
-
- def update_goal_state(self, event: GoalEvent) -> None:
- """Update a goal state."""
-
- def is_active(self) -> bool:
- """Check if a goal is active."""
-
-
-class ActionServer(Generic[GoalT, ResultT, FeedbackT, ImplT], Destroyable):
-
- def __init__(
- self,
- node: Node,
- rclpy_clock: Clock,
- pyaction_type: type[Action[GoalT, ResultT, FeedbackT, ImplT]],
- action_name: str,
- goal_service_qos: rmw_qos_profile_t,
- result_service_qos: rmw_qos_profile_t,
- cancel_service_qos: rmw_qos_profile_t,
- feedback_topic_qos: rmw_qos_profile_t,
- status_topic_qos: rmw_qos_profile_t,
- result_timeout: float
- ) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def take_goal_request(
- self,
- pymsg_type: type[SendGoalServiceRequest[GoalT]]
- ) -> tuple[rmw_request_id_t, SendGoalServiceRequest[GoalT]] | tuple[None, None]:
- """Take an action goal request."""
-
- def send_goal_response(
- self,
- header: rmw_request_id_t,
- pyresponse: SendGoalServiceResponse
- ) -> None:
- """Send an action goal response."""
-
- def send_result_response(
- self,
- header: rmw_request_id_t,
- pyresponse: GetResultServiceResponse[ResultT]
- ) -> None:
- """Send an action result response."""
-
- def take_cancel_request(
- self,
- pymsg_type: type[CancelGoal.Request]
- ) -> tuple[rmw_request_id_t, CancelGoal.Request] | tuple[None, None]:
- """Take an action cancel request."""
-
- def take_result_request(
- self,
- pymsg_type: type[GetResultServiceRequest]
- ) -> tuple[rmw_request_id_t, GetResultServiceRequest] | tuple[None, None]:
- """Take an action result request."""
-
- def send_cancel_response(
- self,
- header: rmw_request_id_t,
- pyresponse: CancelGoal.Response
- ) -> None:
- """Send an action cancel response."""
-
- def publish_feedback(
- self,
- pymsg: FeedbackT
- ) -> None:
- """Publish a feedback message from a given action server."""
-
- def publish_status(self) -> None:
- """Publish a status message from a given action server."""
-
- def notify_goal_done(self) -> None:
- """Notify goal is done."""
-
- def goal_exists(self, pygoal_info: GoalInfo) -> bool:
- """Check is a goal exists in the server."""
-
- def process_cancel_request(
- self,
- pycancel_request: CancelGoal.Request,
- pycancel_response_type: type[CancelGoal.Response]
- ) -> CancelGoal.Response:
- """Process a cancel request."""
-
- def expire_goals(self, max_num_goals: int) -> tuple[GoalInfo, ...]:
- """Expired goals."""
-
- def get_num_entities(self) -> tuple[int, int, int, int, int]:
- """Get the number of wait set entities that make up an action entity."""
-
- def is_ready(self, wait_set: WaitSet) -> tuple[bool, bool, bool, bool]:
- """Check if an action entity has any ready wait set entities."""
-
- def add_to_waitset(self, wait_set: WaitSet) -> None:
- """Add an action entity to a wait set."""
-
- def configure_introspection(
- self,
- clock: Clock,
- pyqos_service_pub: Optional[rmw_qos_profile_t],
- introspection_state: service_introspection.ServiceIntrospectionState
- ) -> None:
- """Configure whether internal service introspection is enabled."""
-
-
-def rclpy_action_get_rmw_qos_profile(rmw_profile: str) -> _rmw_qos_profile_dict:
- """Get an action RMW QoS profile."""
-
-
-class GuardCondition(Destroyable):
-
- def __init__(self, context: Context) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def trigger_guard_condition(self) -> None:
- """Trigger a general purpose guard condition."""
-
-
-class _TimeInfoDict(TypedDict):
- expected_call_time: int
- actual_call_time: int
-
-
-class Timer(Destroyable):
-
- def __init__(self, clock: Clock, context: Context, period_nsec: int,
- autostart: bool) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def reset_timer(self) -> None:
- """Reset a timer."""
-
- def is_timer_ready(self) -> bool:
- """Check if a timer as reached timeout."""
-
- def call_timer(self) -> None:
- """Call a timer and starts counting again."""
-
- def call_timer_with_info(self) -> _TimeInfoDict:
- """Call a timer and starts counting again, retrieves actual and expected call time."""
-
- def change_timer_period(self, period_nsec: int) -> None:
- """Set the period of a timer."""
-
- def time_until_next_call(self) -> int | None:
- """Get the remaining time before timer is ready."""
-
- def time_since_last_call(self) -> int:
- """Get the elapsed time since last timer call."""
-
- def get_timer_period(self) -> int:
- """Get the period of a timer."""
-
- def cancel_timer(self) -> None:
- """Cancel a timer."""
-
- 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]):
-
- def __init__(self, node: Node, pymsg_type: type[MsgT], topic: str,
- pyqos_profile: rmw_qos_profile_t,
- content_filter_options: Optional[ContentFilterOptions] = None) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- @overload
- def take_message(self, pymsg_type: type[MsgT], raw: Literal[True]) -> tuple[bytes, MessageInfo] | None: ...
-
- @overload
- def take_message(self, pymsg_type: type[MsgT], raw: Literal[False]) -> tuple[MsgT, MessageInfo] | None: ...
-
- @overload
- def take_message(self, pymsg_type: type[MsgT], raw: bool) -> tuple[MsgT | bytes, MessageInfo] | None:
- """Take a message and its metadata from a subscription."""
-
- def get_logger_name(self) -> str:
- """Get the name of the logger associated with the node of the subscription."""
-
- def get_topic_name(self) -> str:
- """Return the resolved topic name of a subscription."""
-
- 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."""
-
- def is_cft_supported(self) -> bool:
- """Check if content filtering is supported for this subscription."""
-
- def is_cft_enabled(self) -> bool:
- """Check if content filtering is enabled for this subscription."""
-
- def set_content_filter(self, filter_expression: str, expression_parameters: list[str]) -> None:
- """Set the filter expression and expression parameters for the subscription."""
-
- def get_content_filter(self) -> ContentFilterOptions:
- """Get the filter expression and expression parameters for the subscription."""
-
-
-class rcl_time_point_t:
-
- def __init__(self, nanoseconds: int, clock_type: int) -> None: ...
-
- @property
- def nanoseconds(self) -> int: ...
-
- @property
- def clock_type(self) -> ClockType: ...
-
-
-class Clock(Destroyable):
-
- def __init__(self, clock_type: int) -> None: ...
-
- def get_now(self) -> rcl_time_point_t:
- """Value of the clock."""
-
- def get_ros_time_override_is_enabled(self) -> bool:
- """Return if a clock using ROS time has the ROS time override enabled."""
-
- def set_ros_time_override_is_enabled(self, enabled: bool) -> None:
- """Set if a clock using ROS time has the ROS time override enabled."""
-
- def set_ros_time_override(self, time_point: rcl_time_point_t) -> None:
- """Set the ROS time override for a clock using ROS time."""
-
- def add_clock_callback(self, pyjump_handle: JumpHandle,
- on_clock_change: bool, min_forward: int,
- min_backward: int) -> None:
- """Add a time jump callback to a clock."""
-
- def remove_clock_callback(self, pyjump_handle: JumpHandle) -> None:
- """Remove a time jump callback from a clock."""
-
-
-_IsReadyValues = Literal['subscription', 'client', 'service', 'timer', 'guard_condition', 'event']
-_GetReadyEntityValues = Literal['subscription', 'client', 'service', 'timer', 'guard_condition']
-
-
-class WaitSet(Destroyable):
-
- def __init__(self, number_of_subscriptions: int, number_of_guard_conditions: int,
- number_of_timers: int, number_of_clients: int, number_of_services: int,
- number_of_events: int, context: Context) -> None:
- """Construct a WaitSet."""
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def clear_entities(self) -> None:
- """Clear all the pointers in the wait set."""
-
- def add_service(self, service: Service[Any, Any]) -> int:
- """Add a service to the wait set structure."""
-
- def add_subscription(self, subscription: Subscription[Any]) -> int:
- """Add a subscription to the wait set structure."""
-
- def add_client(self, client: Client[Any, Any]) -> int:
- """Add a client to the wait set structure."""
-
- def add_guard_condition(self, guard_condition: GuardCondition) -> int:
- """Add a guard condition to the wait set structure."""
-
- def add_timer(self, timer: Timer) -> int:
- """Add a timer to the wait set structure."""
-
- def add_event(self, event: EventHandle[Any]) -> int:
- """Add an event to the wait set structure."""
-
- def is_ready(self, entity_type: _IsReadyValues, index: int) -> bool:
- """Check if an entity in the wait set is ready by its index."""
-
- def get_ready_entities(self, entity_type: _GetReadyEntityValues) -> list[int]:
- """Get list of entities ready by entity type."""
-
- def wait(self, timeout: int) -> None:
- """Wait until timeout is reached or event happened."""
-
-
-def rclpy_expand_topic_name(topic: str, node_name: str, node_namespace: str) -> str:
- """Expand a topic name."""
-
-
-def rclpy_remap_topic_name(node: Node, topic_name: str) -> str:
- """Remap a topic name."""
-
-
-def rclpy_get_validation_error_for_topic_name(topic_name: str) -> tuple[str, int] | None:
- """Get the error message and invalid index of a topic name or None if valid."""
-
-
-def rclpy_get_validation_error_for_full_topic_name(topic_name: str) -> tuple[str, int] | None:
- """Get the error message and invalid index of a full topic name or None if valid."""
-
-
-def rclpy_get_validation_error_for_namespace(namespace_: str) -> tuple[str, int] | None:
- """Get the error message and invalid index of a namespace or None if valid."""
-
-
-def rclpy_get_validation_error_for_node_name(namespace_: str) -> tuple[str, int] | None:
- """Get the error message and invalid index of a node name or None if valid."""
-
-
-def rclpy_resolve_name(node: Node, topic_name: str, only_expand: bool, is_service: bool) -> str:
- """Expand and remap a topic or service name."""
-
-
-def rclpy_get_topic_names_and_types(node: Node, no_demangle: bool) -> list[tuple[str, list[str]]]:
- """Get all topic names and types in the ROS graph."""
-
-
-def rclpy_get_publisher_names_and_types_by_node(node: Node, no_demangle: bool, node_name: str,
- node_namespace: str
- ) -> list[tuple[str, list[str]]]:
- """Get topic names and types for which a remote node has publishers."""
-
-
-def rclpy_get_subscriber_names_and_types_by_node(node: Node, no_demangle: bool, node_name: str,
- node_namespace: str
- ) -> list[tuple[str, list[str]]]:
- """Get topic names and types for which a remote node has subscribers."""
-
-
-class _TypeHashDict(TypedDict):
- version: int
- value: bytes
-
-
-class _TopicEndpointInfoDict(TypedDict):
- node_name: str
- node_namespace: str
- topic_type: str
- topic_type_hash: _TypeHashDict
- endpoint_type: int
- endpoint_gid: list[int]
- qos_profile: _rmw_qos_profile_dict
-
-
-class _ServiceEndpointInfoDict(TypedDict):
- node_name: str
- node_namespace: str
- service_type: str
- service_type_hash: _TypeHashDict
- qos_profiles: list[_rmw_qos_profile_dict]
- endpoint_gids: list[list[int]]
- endpoint_type: int
- endpoint_count: int
-
-
-class _ActionEndpointInfoDict(TypedDict):
- goal_service_info: Optional[_ServiceEndpointInfoDict]
- cancel_service_info: Optional[_ServiceEndpointInfoDict]
- result_service_info: Optional[_ServiceEndpointInfoDict]
- feedback_topic_info: Optional[_TopicEndpointInfoDict]
- status_topic_info: Optional[_TopicEndpointInfoDict]
-
-
-def rclpy_get_publishers_info_by_topic(node: Node, topic_name: str, no_mangle: bool
- ) -> list[_TopicEndpointInfoDict]:
- """Get publishers info for a topic."""
-
-
-def rclpy_get_subscriptions_info_by_topic(node: Node, topic_name: str, no_mangle: bool
- ) -> list[_TopicEndpointInfoDict]:
- """Get subscriptions info for a topic."""
-
-
-def rclpy_get_clients_info_by_service(node: Node, service_name: str, no_mangle: bool
- ) -> list[_ServiceEndpointInfoDict]:
- """Get clients info for a service."""
-
-
-def rclpy_get_servers_info_by_service(node: Node, service_name: str, no_mangle: bool
- ) -> list[_ServiceEndpointInfoDict]:
- """Get servers info for a service."""
-
-
-def rclpy_get_service_names_and_types(node: Node) -> list[tuple[str, list[str]]]:
- """Get all service names and types in the ROS graph."""
-
-
-def rclpy_get_service_names_and_types_by_node(node: Node, node_name: str, node_namespace: str
- ) -> list[tuple[str, list[str]]]:
- """Get all service names and types in the ROS graph."""
-
-
-def rclpy_get_client_names_and_types_by_node(node: Node, node_name: str, node_namespace: str
- ) -> list[tuple[str, list[str]]]:
- """Get service names and types for which a remote node has servers."""
-
-
-def rclpy_get_action_client_names_and_types_by_node(node: Node, node_name: str,
- node_namespace: str
- ) -> list[tuple[str, list[str]]]:
- """Get action client names and types by node."""
-
-
-def rclpy_get_action_server_names_and_types_by_node(node: Node, node_name: str,
- node_namespace: str
- ) -> list[tuple[str, list[str]]]:
- """Get action server names and types by node."""
-
-
-def rclpy_get_action_names_and_types(node: Node) -> list[tuple[str, list[str]]]:
- """Get all action names and types in the ROS graph."""
-
-
-def rclpy_get_action_clients_info_by_action(node: Node, action_name: str
- ) -> list[_ActionEndpointInfoDict]:
- """Get action clients info for an action."""
-
-
-def rclpy_get_action_servers_info_by_action(node: Node, action_name: str
- ) -> list[_ActionEndpointInfoDict]:
- """Get action servers info for an action."""
-
-
-def rclpy_serialize(pymsg: MsgT, py_msg_type: type[MsgT]) -> bytes:
- """Serialize a ROS message."""
-
-
-def rclpy_deserialize(pybuffer: bytes, pymsg_type: type[MsgT]) -> MsgT:
- """Deserialize a ROS message."""
-
-
-class Node(Destroyable):
-
- def __init__(self, node_name: str, namespace_: str, context: Context,
- pycli_args: list[str] | None, use_global_arguments: bool,
- enable: bool, rosout_qos_profile: rmw_qos_profile_t) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def get_fully_qualified_name(self) -> str:
- """Get the fully qualified name of the node."""
-
- def logger_name(self) -> str:
- """Get the name of the logger associated with a node."""
-
- def get_node_name(self) -> str:
- """Get the name of a node."""
-
- def get_namespace(self) -> str:
- """Get the namespace of a node."""
-
- def get_count_publishers(self, topic_name: str) -> int:
- """Return the count of all the publishers known for that topic in the entire ROS graph."""
-
- def get_count_subscribers(self, topic_name: str) -> int:
- """Return the count of all the subscribers known for that topic in the entire ROS graph."""
-
- def get_count_clients(self, service_name: str) -> int:
- """Return the count of all the clients known for that service in the entire ROS graph."""
-
- def get_count_services(self, service_name: str) -> int:
- """Return the count of all the servers known for that service in the entire ROS graph."""
-
- def get_count_action_clients(self, action_name: str) -> int:
- """Return the count of the action clients known for that action in the entire ROS graph."""
-
- def get_count_action_servers(self, action_name: str) -> int:
- """Return the count of the action servers known for that action in the entire ROS graph."""
-
- def get_node_names_and_namespaces(self) -> list[tuple[str, str]]:
- """Get the list of nodes discovered by the provided node."""
-
- def get_node_names_and_namespaces_with_enclaves(self) -> list[tuple[str, str, str]]:
- """Get the list of nodes discovered by the provided node, with their enclaves."""
-
- def get_action_client_names_and_types_by_node(self, remote_node_name: str,
- remote_node_namespace: str) -> list[tuple[str,
- list[str]]]:
- """Get action client names and types by node."""
-
- def get_action_server_names_and_types_by_node(self, remote_node_name: str,
- remote_node_namespace: str) -> list[tuple[str,
- list[str]]]:
- """Get action server names and types by node."""
-
- def get_action_names_and_types(self) -> list[tuple[str, list[str]]]:
- """Get action names and types."""
-
- def get_parameters(self, pyparamter_cls: type[Parameter[Any]]) -> dict[str, Parameter[Any]]:
- """Get a list of parameters for the current node."""
-
-
-class _rmw_qos_incompatible_event_status_s:
- total_count: int
- total_count_change: int
- last_policy_kind: rmw_qos_policy_kind_t
-
-
-_rmw_qos_incompatible_event_status_t: TypeAlias = _rmw_qos_incompatible_event_status_s
-_rmw_offered_qos_incompatible_event_status_t: TypeAlias = _rmw_qos_incompatible_event_status_t
-
-
-class EventHandle(Destroyable, Generic[T]):
-
- @overload
- def __init__(
- self,
- subscription: Subscription[Any],
- event_type: rcl_subscription_event_type_t
- ) -> None: ...
-
- @overload
- def __init__(
- self,
- publisher: Publisher[Any],
- event_type: rcl_publisher_event_type_t
- ) -> None: ...
-
- @property
- def pointer(self) -> int:
- """Get the address of the entity as an integer."""
-
- def take_event(self) -> T | None:
- """Get pending data from a ready event."""
-
-
-class rcl_subscription_event_type_t(IntEnum):
- RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED = ...
- RCL_SUBSCRIPTION_LIVELINESS_CHANGED = ...
- RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS = ...
- RCL_SUBSCRIPTION_MESSAGE_LOST = ...
- RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE = ...
- RCL_SUBSCRIPTION_MATCHED = ...
-
-
-class rcl_publisher_event_type_t(IntEnum):
- RCL_PUBLISHER_OFFERED_DEADLINE_MISSED = ...
- RCL_PUBLISHER_LIVELINESS_LOST = ...
- RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS = ...
- RCL_PUBLISHER_INCOMPATIBLE_TYPE = ...
- RCL_PUBLISHER_MATCHED = ...
-
-
-class rmw_requested_deadline_missed_status_t:
-
- @property
- def total_count(self) -> int: ...
-
- @property
- def total_count_change(self) -> int: ...
-
-
-class rmw_liveliness_changed_status_t:
-
- @property
- def alive_count(self) -> int: ...
-
- @property
- def not_alive_count(self) -> int: ...
-
- @property
- def alive_count_change(self) -> int: ...
-
- @property
- def not_alive_count_change(self) -> int: ...
-
-
-class rmw_message_lost_status_t:
-
- @property
- def total_count(self) -> int: ...
-
- @property
- def total_count_change(self) -> int: ...
-
-
-class rmw_requested_qos_incompatible_event_status_t:
-
- @property
- def total_count(self) -> int: ...
-
- @property
- def total_count_change(self) -> int: ...
-
- @property
- def last_policy_kind(self) -> rmw_qos_policy_kind_t: ...
-
-
-class rmw_offered_deadline_missed_status_t:
-
- @property
- def total_count(self) -> int: ...
-
- @property
- def total_count_change(self) -> int: ...
-
-
-class rmw_liveliness_lost_status_t:
-
- @property
- def total_count(self) -> int: ...
-
- @property
- def total_count_change(self) -> int: ...
-
-
-class rmw_matched_status_t:
-
- @property
- def total_count(self) -> int: ...
-
- @property
- def total_count_change(self) -> int: ...
-
- @property
- def current_count(self) -> int: ...
-
- @property
- def current_count_change(self) -> int: ...
-
-
-class rmw_qos_policy_kind_t(IntEnum):
- RMW_QOS_POLICY_INVALID = ...
- RMW_QOS_POLICY_DURABILITY = ...
- RMW_QOS_POLICY_DEADLINE = ...
- RMW_QOS_POLICY_LIVELINESS = ...
- RMW_QOS_POLICY_RELIABILITY = ...
- RMW_QOS_POLICY_HISTORY = ...
- RMW_QOS_POLICY_LIFESPAN = ...
- RMW_QOS_POLICY_DEPTH = ...
- RMW_QOS_POLICY_LIVELINESS_LEASE_DURATION = ...
- RMW_QOS_POLICY_AVOID_ROS_NAMESPACE_CONVENTIONS = ...
-
-
-class rmw_incompatible_type_status_t:
-
- @property
- def total_count_change(self) -> int: ...
-
-
-def rclpy_get_rmw_implementation_identifier() -> str:
- """Retrieve the identifier for the active RMW implementation."""
-
-
-def rclpy_assert_liveliness(publisher: Publisher[Any]) -> None:
- """Assert the liveliness of an entity."""
-
-
-def rclpy_remove_ros_args(pycli_args: Sequence[str]) -> list[str]:
- """Remove ROS-specific arguments from argument vector."""
-
-
-_PredefinedQosProfileTNames = Literal['qos_profile_sensor_data', 'qos_profile_default',
- 'qos_profile_system_default', 'qos_profile_services_default',
- 'qos_profile_unknown', 'qos_profile_parameters',
- 'qos_profile_parameter_events', 'qos_profile_best_available',
- 'qos_profile_rosout_default']
-
-
-class _rmw_qos_profile_dict(TypedDict):
- depth: int
- history: int
- reliability: int
- durability: int
- lifespan: Duration
- deadline: Duration
- liveliness: int
- liveliness_lease_duration: Duration
- avoid_ros_namespace_conventions: bool
-
-
-class rmw_qos_profile_t:
-
- def __init__(
- self,
- qos_history: int,
- qos_depth: int,
- qos_reliability: int,
- qos_durability: int,
- pyqos_lifespan: rcl_duration_t,
- pyqos_deadline: rcl_duration_t,
- qos_liveliness: int,
- pyqos_liveliness_lease_duration: rcl_duration_t,
- avoid_ros_namespace_conventions: bool
- ) -> None: ...
-
- def to_dict(self) -> _rmw_qos_profile_dict: ...
-
- @staticmethod
- def predefined(qos_profile_name: _PredefinedQosProfileTNames) -> rmw_qos_profile_t: ...
-
-
-def rclpy_logging_fini() -> None:
- """Finalize RCL logging."""
-
-
-def rclpy_logging_configure(context: Context) -> None:
- """Initialize RCL logging."""
-
-
-class RCUTILS_LOG_SEVERITY(IntEnum):
- RCUTILS_LOG_SEVERITY_UNSET = ...
- RCUTILS_LOG_SEVERITY_DEBUG = ...
- RCUTILS_LOG_SEVERITY_INFO = ...
- RCUTILS_LOG_SEVERITY_WARN = ...
- RCUTILS_LOG_SEVERITY_ERROR = ...
- RCUTILS_LOG_SEVERITY_FATAL = ...
-
-
-def rclpy_logging_get_separator_string() -> str: ...
-
-
-def rclpy_logging_initialize() -> None: ...
-
-
-def rclpy_logging_shutdown() -> None: ...
-
-
-def rclpy_logging_set_logger_level(name: str, level: int,
- detailed_error: bool = False) -> None: ...
-
-
-def rclpy_logging_get_logger_effective_level(name: str) -> int: ...
-
-
-def rclpy_logging_logger_is_enabled_for(name: str, severity: int) -> bool: ...
-
-
-def rclpy_logging_rcutils_log(severity: int, name: str, message: str, function_name: str,
- file_name: str, line_number: int) -> None: ...
-
-
-def rclpy_logging_severity_level_from_string(log_level: str) -> int: ...
-
-
-def rclpy_logging_get_logging_directory() -> str: ...
-
-
-def rclpy_logging_rosout_add_sublogger(logger_name: str, sublogger_name: str) -> bool: ...
-
-
-def rclpy_logging_rosout_remove_sublogger(logger_name: str, sublogger_name: str) -> None: ...
-
-
-def rclpy_logging_get_logger_level(name: str) -> int: ...
-
-
-def register_sigint_guard_condition(guard_condition: GuardCondition) -> None:
- """Register a guard condition to be called on SIGINT."""
-
-
-def unregister_sigint_guard_condition(guard_condition: GuardCondition) -> None:
- """Stop triggering a guard condition when SIGINT occurs."""
-
-
-def install_signal_handlers(options: SignalHandlerOptions) -> None:
- """Install rclpy signal handlers."""
-
-
-def get_current_signal_handlers_options() -> SignalHandlerOptions:
- """Get currently installed signal handler options."""
-
-
-def uninstall_signal_handlers() -> None:
- """Uninstall rclpy signal handlers."""
-
-
-class SignalHandlerOptions(IntEnum):
- """Enum with values: `ALL`, `SIGINT`, `SIGTERM`, `NO`."""
-
- NO = ...
- SigInt = ...
- SigTerm = ...
- ALL = ...
-
-
-class ClockEvent:
-
- def __init__(self) -> None: ...
-
- def wait_until_steady(self, clock: Clock, until: rcl_time_point_t) -> None:
- """Wait for the event to be set (monotonic wait)."""
-
- def wait_until_system(self, clock: Clock, until: rcl_time_point_t) -> None:
- """Wait for the event to be set (system timed wait)."""
-
- def wait_until_ros(self, clock: Clock, until: rcl_time_point_t) -> None:
- """Wait for the event to be set (ROS timed wait)."""
-
- def is_set(self) -> bool:
- """Return True if the event is set, False otherwise."""
-
- def set(self) -> None: # noqa: A003
- """Set the event, waking all those who wait on it."""
-
- def clear(self) -> None:
- """Unset the event."""
-
-
-_LifecycleStateMachineState: TypeAlias = tuple[int, str]
-
-
-class LifecycleStateMachine(Destroyable):
-
- def __init__(self, node: Node, clock: Clock, enable_com_interface: bool) -> None: ...
-
- @property
- def initialized(self) -> bool:
- """Check if state machine is initialized."""
-
- @property
- def current_state(self) -> _LifecycleStateMachineState:
- """Get the current state machine state."""
-
- @property
- def available_states(self) -> list[_LifecycleStateMachineState]:
- """Get the available states."""
-
- @property
- def available_transitions(self) -> list[tuple[int, str, int, str, int, str]]:
- """Get the available transitions."""
-
- @property
- def transition_graph(self) -> list[tuple[int, str, int, str, int, str]]:
- """Get the transition graph."""
-
- def get_transition_by_label(self, label: str) -> int:
- """Get the transition id from a transition label."""
-
- def trigger_transition_by_id(self, transition_id: int, publish_update: bool) -> None:
- """Trigger a transition by transition id."""
-
- def trigger_transition_by_label(self, label: str, publish_update: bool) -> None:
- """Trigger a transition by label."""
-
- @property
- def service_change_state(self) -> Service[Any, Any]:
- """Get the change state service."""
-
- @property
- def service_get_state(self) -> Service[Any, Any]:
- """Get the get state service."""
-
- @property
- def service_get_available_states(self) -> Service[Any, Any]:
- """Get the get available states service."""
-
- @property
- def service_get_available_transitions(self) -> Service[Any, Any]:
- """Get the get available transitions service."""
-
- @property
- def service_get_transition_graph(self) -> Service[Any, Any]:
- """Get the get transition graph service."""
-
-
-class TransitionCallbackReturnType(IntEnum):
- SUCCESS = ...
- FAILURE = ...
- ERROR = ...
-
- def to_label(self) -> str:
- """Convert the transition callback return code to a transition label."""
-
-
-class EventsExecutor:
-
- def __init__(self, context: RCLPyContext): ...
-
- @property
- def context(self) -> RCLPyContext: ...
-
- @overload
- def create_task(self, callback: Callable[..., Coroutine[Any, Any, T]],
- *args: Any, **kwargs: Any
- ) -> Task[T]: ...
-
- @overload
- def create_task(self, callback: Callable[..., T], *args: Any, **kwargs: Any
- ) -> Task[T]: ...
-
- def shutdown(self, timeout_sec: Optional[float] = None) -> bool: ...
-
- def add_node(self, node: RCLPyNode) -> bool: ...
-
- def remove_node(self, node: RCLPyNode) -> None: ...
-
- def wake(self) -> None: ...
-
- def get_nodes(self) -> list[RCLPyNode]: ...
-
- def spin(self) -> None: ...
-
- def spin_once(self, timeout_sec: Optional[float] = None) -> None: ...
-
- def spin_until_future_complete(self, future: Future[Any],
- timeout_sec: Optional[float] = None) -> None: ...
-
- def spin_once_until_future_complete(self, future: Future[Any],
- timeout_sec: Optional[float] = None) -> None: ...
-
- def __enter__(self) -> EventsExecutor: ...
-
- def __exit__(self, exc_type: type[BaseException] | None,
- exc_val: BaseException | None, exctb: TracebackType | None) -> None: ...
diff --git a/rclpy/rclpy/impl/implementation_singleton.py b/rclpy/rclpy/impl/implementation_singleton.py
index 3e312280b..0f7e03b2f 100644
--- a/rclpy/rclpy/impl/implementation_singleton.py
+++ b/rclpy/rclpy/impl/implementation_singleton.py
@@ -30,4 +30,4 @@
package = 'rclpy'
-rclpy_implementation = import_c_library('._rclpy_pybind11', package)
+rclpy_implementation = import_c_library('._rclpy_nanobind', package)
diff --git a/rclpy/rclpy/impl/implementation_singleton.pyi b/rclpy/rclpy/impl/implementation_singleton.pyi
index a1e16bdf9..182c3495d 100644
--- a/rclpy/rclpy/impl/implementation_singleton.pyi
+++ b/rclpy/rclpy/impl/implementation_singleton.pyi
@@ -13,6 +13,6 @@
# limitations under the License.
-from rclpy.impl import _rclpy_pybind11
+from rclpy.impl import _rclpy_nanobind
-rclpy_implementation = _rclpy_pybind11
+rclpy_implementation = _rclpy_nanobind
diff --git a/rclpy/rclpy/impl/service_introspection.pyi b/rclpy/rclpy/impl/service_introspection.pyi
index 2f68be303..a7c5bcdea 100644
--- a/rclpy/rclpy/impl/service_introspection.pyi
+++ b/rclpy/rclpy/impl/service_introspection.pyi
@@ -1,7 +1,11 @@
-from enum import IntEnum
+"""utilities for introspecting services"""
+import enum
-class ServiceIntrospectionState(IntEnum):
- OFF = ...
- METADATA = ...
- CONTENTS = ...
+
+class ServiceIntrospectionState(enum.IntEnum):
+ OFF = 0
+
+ METADATA = 1
+
+ CONTENTS = 2
diff --git a/rclpy/rclpy/lifecycle/__init__.py b/rclpy/rclpy/lifecycle/__init__.py
index 64f168873..61201437b 100644
--- a/rclpy/rclpy/lifecycle/__init__.py
+++ b/rclpy/rclpy/lifecycle/__init__.py
@@ -30,7 +30,7 @@
State = LifecycleState
Publisher = LifecyclePublisher
-# enum defined in pybind11 plugin
+# enum defined in nanobind plugin
TransitionCallbackReturn = _rclpy.TransitionCallbackReturnType
diff --git a/rclpy/rclpy/time.py b/rclpy/rclpy/time.py
index 2ede55d5b..3531e9cda 100644
--- a/rclpy/rclpy/time.py
+++ b/rclpy/rclpy/time.py
@@ -51,7 +51,7 @@ def __init__(
total_nanoseconds = int(seconds * S_TO_NS)
total_nanoseconds += int(nanoseconds)
if total_nanoseconds >= 2**63:
- # pybind11 would raise TypeError, but we want OverflowError
+ # nanobind would raise TypeError, but we want OverflowError
raise OverflowError(
'Total nanoseconds value is too large to store in C time point.')
self._time_handle = _rclpy.rcl_time_point_t(total_nanoseconds, clock_type)
diff --git a/rclpy/src/rclpy/_rclpy_logging.cpp b/rclpy/src/rclpy/_rclpy_logging.cpp
index 6d0eb283c..fb7dd00c1 100644
--- a/rclpy/src/rclpy/_rclpy_logging.cpp
+++ b/rclpy/src/rclpy/_rclpy_logging.cpp
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
-namespace py = pybind11;
+namespace nb = nanobind;
+using nb::literals::operator""_a;
#include
#include
@@ -237,9 +239,9 @@ rclpy_logging_rosout_remove_sublogger(const char * logger_name, const char * sub
namespace rclpy
{
void
-define_logging_api(py::module m)
+define_logging_api(nb::module_ m)
{
- py::enum_(m, "RCUTILS_LOG_SEVERITY")
+ nb::enum_(m, "RCUTILS_LOG_SEVERITY", nb::is_arithmetic())
.value("RCUTILS_LOG_SEVERITY_UNSET", RCUTILS_LOG_SEVERITY_UNSET)
.value("RCUTILS_LOG_SEVERITY_DEBUG", RCUTILS_LOG_SEVERITY_DEBUG)
.value("RCUTILS_LOG_SEVERITY_INFO", RCUTILS_LOG_SEVERITY_INFO)
@@ -252,7 +254,7 @@ define_logging_api(py::module m)
m.def("rclpy_logging_shutdown", &rclpy_logging_shutdown);
m.def(
"rclpy_logging_set_logger_level", &rclpy_logging_set_logger_level,
- py::arg("name"), py::arg("level"), py::arg("detailed_error") = false);
+ "name"_a, "level"_a, "detailed_error"_a = false);
m.def("rclpy_logging_get_logger_effective_level", &rclpy_logging_get_logger_effective_level);
m.def("rclpy_logging_logger_is_enabled_for", &rclpy_logging_logger_is_enabled_for);
m.def("rclpy_logging_rcutils_log", &rclpy_logging_rcutils_log);
diff --git a/rclpy/src/rclpy/_rclpy_pybind11.cpp b/rclpy/src/rclpy/_rclpy_nanobind.cpp
similarity index 79%
rename from rclpy/src/rclpy/_rclpy_pybind11.cpp
rename to rclpy/src/rclpy/_rclpy_nanobind.cpp
index ce3dea8df..69d79e2c4 100644
--- a/rclpy/src/rclpy/_rclpy_pybind11.cpp
+++ b/rclpy/src/rclpy/_rclpy_nanobind.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
#include
#include
@@ -55,34 +56,45 @@
#include "utils.hpp"
#include "wait_set.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
-PYBIND11_MODULE(_rclpy_pybind11, m) {
+NB_MODULE(_rclpy_nanobind, m) {
m.doc() = "ROS 2 Python client library.";
+ // rclpy imports this extension as "rclpy._rclpy_nanobind", but the stub
+ // generator loads it as the top-level module "_rclpy_nanobind". Register the
+ // canonical name too, so that importing rclpy afterwards reuses this already
+ // initialized module instead of loading the extension a second time.
+ nb::module_::import_("sys").attr("modules")["rclpy._rclpy_nanobind"] = m;
+
+ // Type variable for the generic classes in the generated stubs.
+ // The other type variables from rclpy.type_support that nb::sig()
+ // strings reference are imported into the stub by stubgen_pattern.pat.
+ // ``T`` has no equivalent there, so it is declared as a module attribute.
+ m.attr("T") = nb::type_var("T");
+
rclpy::define_destroyable(m);
- py::enum_(m, "ClockType")
+ nb::enum_(m, "ClockType", nb::is_arithmetic())
.value("UNINITIALIZED", RCL_CLOCK_UNINITIALIZED)
.value("ROS_TIME", RCL_ROS_TIME)
.value("SYSTEM_TIME", RCL_SYSTEM_TIME)
.value("STEADY_TIME", RCL_STEADY_TIME);
- py::enum_(m, "GoalEvent")
+ nb::enum_(m, "GoalEvent", nb::is_arithmetic())
.value("EXECUTE", GOAL_EVENT_EXECUTE)
.value("CANCEL_GOAL", GOAL_EVENT_CANCEL_GOAL)
.value("SUCCEED", GOAL_EVENT_SUCCEED)
.value("ABORT", GOAL_EVENT_ABORT)
.value("CANCELED", GOAL_EVENT_CANCELED);
- m.attr("RCL_DEFAULT_DOMAIN_ID") = py::int_(RCL_DEFAULT_DOMAIN_ID);
- m.attr("RMW_DURATION_INFINITE") = py::int_(rmw_time_total_nsec(RMW_DURATION_INFINITE));
- m.attr("RMW_QOS_DEADLINE_BEST_AVAILABLE") = py::int_(
- rmw_time_total_nsec(RMW_QOS_DEADLINE_BEST_AVAILABLE));
- m.attr("RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE") = py::int_(
- rmw_time_total_nsec(RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE));
+ m.attr("RCL_DEFAULT_DOMAIN_ID") = RCL_DEFAULT_DOMAIN_ID;
+ m.attr("RMW_DURATION_INFINITE") = rmw_time_total_nsec(RMW_DURATION_INFINITE);
+ m.attr("RMW_QOS_DEADLINE_BEST_AVAILABLE") = rmw_time_total_nsec(RMW_QOS_DEADLINE_BEST_AVAILABLE);
+ m.attr("RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE") =
+ rmw_time_total_nsec(RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE);
- py::enum_(m, "ClockChange")
+ nb::enum_(m, "ClockChange", nb::is_arithmetic())
.value(
"ROS_TIME_NO_CHANGE", RCL_ROS_TIME_NO_CHANGE,
"ROS time is active and will continue to be active")
@@ -96,33 +108,33 @@ PYBIND11_MODULE(_rclpy_pybind11, m) {
"SYSTEM_TIME_NO_CHANGE", RCL_SYSTEM_TIME_NO_CHANGE,
"ROS time is inactive and the clock will keep reporting system time");
- py::enum_(m, "QoSCompatibility")
+ nb::enum_(m, "QoSCompatibility", nb::is_arithmetic())
.value("OK", RMW_QOS_COMPATIBILITY_OK)
.value("WARNING", RMW_QOS_COMPATIBILITY_WARNING)
.value("ERROR", RMW_QOS_COMPATIBILITY_ERROR);
- py::class_(
+ nb::class_(
m, "QoSCheckCompatibleResult",
"Result type for checking QoS compatibility with result")
- .def(py::init<>())
- .def_readonly("compatibility", &rclpy::QoSCheckCompatibleResult::compatibility)
- .def_readonly("reason", &rclpy::QoSCheckCompatibleResult::reason);
-
- py::register_exception(m, "RCUtilsError", PyExc_RuntimeError);
- py::register_exception(m, "RMWError", PyExc_RuntimeError);
- auto rclerror = py::register_exception(m, "RCLError", PyExc_RuntimeError);
- py::register_exception(
+ .def(nb::init<>())
+ .def_ro("compatibility", &rclpy::QoSCheckCompatibleResult::compatibility)
+ .def_ro("reason", &rclpy::QoSCheckCompatibleResult::reason);
+
+ nb::exception(m, "RCUtilsError", PyExc_RuntimeError);
+ nb::exception(m, "RMWError", PyExc_RuntimeError);
+ auto rclerror = nb::exception(m, "RCLError", PyExc_RuntimeError);
+ nb::exception(
m, "RCLInvalidROSArgsError", rclerror.ptr());
- py::register_exception(m, "UnknownROSArgsError", PyExc_RuntimeError);
- py::register_exception(
+ nb::exception(m, "UnknownROSArgsError", PyExc_RuntimeError);
+ nb::exception(
m, "NodeNameNonExistentError", rclerror.ptr());
- py::register_exception(
+ nb::exception(
m, "UnsupportedEventTypeError", rclerror.ptr());
- py::register_exception(
+ nb::exception(
m, "TimerCancelledError", rclerror.ptr());
- py::register_exception(
+ nb::exception(
m, "NotImplementedError", PyExc_NotImplementedError);
- py::register_exception(
+ nb::exception(
m, "InvalidHandle", PyExc_RuntimeError);
rclpy::define_service_introspection(m);
diff --git a/rclpy/src/rclpy/action_client.cpp b/rclpy/src/rclpy/action_client.cpp
index 056602755..44c639874 100644
--- a/rclpy/src/rclpy/action_client.cpp
+++ b/rclpy/src/rclpy/action_client.cpp
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
+#include
#include
#include
@@ -29,6 +31,8 @@
#include "node.hpp"
#include "utils.hpp"
+using nb::literals::operator""_a;
+
namespace rclpy
{
@@ -41,7 +45,7 @@ ActionClient::destroy()
ActionClient::ActionClient(
Node & node,
- py::object pyaction_type,
+ nb::object pyaction_type,
const char * action_name,
const rmw_qos_profile_t & goal_service_qos,
const rmw_qos_profile_t & result_service_qos,
@@ -55,7 +59,7 @@ ActionClient::ActionClient(
action_type_support_ =
static_cast(common_get_type_support(pyaction_type));
if (!action_type_support_) {
- throw py::error_already_set();
+ throw nb::python_error();
}
rcl_action_client_options_t action_client_ops = rcl_action_client_get_default_options();
@@ -92,13 +96,13 @@ ActionClient::ActionClient(
error_text += "' : ";
error_text += rcl_get_error_string().str;
rcl_reset_error();
- throw py::value_error(error_text);
+ throw nb::value_error(error_text.c_str());
}
if (RCL_RET_OK != ret) {
std::string error_text{"Failed to create action client: "};
error_text += rcl_get_error_string().str;
rcl_reset_error();
- throw py::value_error(error_text);
+ throw nb::value_error(error_text.c_str());
}
}
@@ -111,14 +115,14 @@ ActionClient::ActionClient(
int64_t sequence = header.sequence_number; \
/* Create the tuple to return */ \
if (RCL_RET_ACTION_CLIENT_TAKE_FAILED == ret || RCL_RET_ACTION_SERVER_TAKE_FAILED == ret) { \
- return py::make_tuple(py::none(), py::none()); \
+ return nb::make_tuple(nb::none(), nb::none()); \
} else if (RCL_RET_OK != ret) { \
throw rclpy::RCLError("Failed to take " #Type); \
} \
- return py::make_tuple(sequence, convert_to_py(taken_msg.get(), pymsg_type)); \
+ return nb::make_tuple(sequence, convert_to_py(taken_msg.get(), pymsg_type)); \
-py::tuple
-ActionClient::take_goal_response(py::object pymsg_type)
+nb::tuple
+ActionClient::take_goal_response(nb::object pymsg_type)
{
TAKE_SERVICE_RESPONSE(goal)
}
@@ -134,13 +138,13 @@ ActionClient::take_goal_response(py::object pymsg_type)
return sequence_number;
int64_t
-ActionClient::send_result_request(py::object pyrequest)
+ActionClient::send_result_request(nb::object pyrequest)
{
SEND_SERVICE_REQUEST(result);
}
-py::tuple
-ActionClient::take_cancel_response(py::object pymsg_type)
+nb::tuple
+ActionClient::take_cancel_response(nb::object pymsg_type)
{
TAKE_SERVICE_RESPONSE(cancel)
}
@@ -151,43 +155,43 @@ ActionClient::take_cancel_response(py::object pymsg_type)
if (RCL_RET_OK != ret) { \
if (RCL_RET_ACTION_CLIENT_TAKE_FAILED == ret) { \
/* if take failed, just do nothing */ \
- return py::none(); \
+ return nb::none(); \
} \
throw rclpy::RCLError("Failed to take " #Type " with an action client"); \
} \
return convert_to_py(taken_msg.get(), pymsg_type);
-py::object
-ActionClient::take_feedback(py::object pymsg_type)
+nb::object
+ActionClient::take_feedback(nb::object pymsg_type)
{
TAKE_MESSAGE(feedback)
}
-py::object
-ActionClient::take_status(py::object pymsg_type)
+nb::object
+ActionClient::take_status(nb::object pymsg_type)
{
TAKE_MESSAGE(status)
}
int64_t
-ActionClient::send_cancel_request(py::object pyrequest)
+ActionClient::send_cancel_request(nb::object pyrequest)
{
SEND_SERVICE_REQUEST(cancel)
}
int64_t
-ActionClient::send_goal_request(py::object pyrequest)
+ActionClient::send_goal_request(nb::object pyrequest)
{
SEND_SERVICE_REQUEST(goal)
}
-py::tuple
-ActionClient::take_result_response(py::object pymsg_type)
+nb::tuple
+ActionClient::take_result_response(nb::object pymsg_type)
{
TAKE_SERVICE_RESPONSE(result);
}
-py::tuple
+nb::tuple
ActionClient::get_num_entities()
{
size_t num_subscriptions = 0u;
@@ -209,7 +213,7 @@ ActionClient::get_num_entities()
throw rclpy::RCLError(error_text);
}
- return py::make_tuple(
+ return nb::make_tuple(
num_subscriptions, num_guard_conditions, num_timers,
num_clients, num_services);
}
@@ -237,7 +241,7 @@ ActionClient::add_to_waitset(WaitSet & wait_set)
}
}
-py::tuple
+nb::tuple
ActionClient::is_ready(WaitSet & wait_set)
{
bool is_feedback_ready = false;
@@ -257,24 +261,23 @@ ActionClient::is_ready(WaitSet & wait_set)
throw rclpy::RCLError("Failed to get number of ready entities for action client");
}
- py::tuple result_tuple(5);
- result_tuple[0] = py::bool_(is_feedback_ready);
- result_tuple[1] = py::bool_(is_status_ready);
- result_tuple[2] = py::bool_(is_goal_response_ready);
- result_tuple[3] = py::bool_(is_cancel_response_ready);
- result_tuple[4] = py::bool_(is_result_response_ready);
- return result_tuple;
+ return nb::make_tuple(
+ is_feedback_ready,
+ is_status_ready,
+ is_goal_response_ready,
+ is_cancel_response_ready,
+ is_result_response_ready);
}
void
ActionClient::configure_introspection(
- Clock & clock, py::object pyqos_service_event_pub,
+ Clock & clock, std::optional pyqos_service_event_pub,
rcl_service_introspection_state_t introspection_state)
{
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
- pub_opts.qos =
- pyqos_service_event_pub.is_none() ? rcl_publisher_get_default_options().qos :
- pyqos_service_event_pub.cast();
+ if (pyqos_service_event_pub) {
+ pub_opts.qos = *pyqos_service_event_pub;
+ }
rcl_ret_t ret = rcl_action_client_configure_action_introspection(
rcl_action_client_.get(), node_.rcl_ptr(), clock.rcl_ptr(),
@@ -286,7 +289,7 @@ ActionClient::configure_introspection(
}
bool
-ActionClient::configure_feedback_subscription_filter_add_goal_id(py::bytes goal_id)
+ActionClient::configure_feedback_subscription_filter_add_goal_id(nb::bytes goal_id)
{
std::lock_guard lock(configure_feedback_sub_content_filter_mutex_);
@@ -294,7 +297,7 @@ ActionClient::configure_feedback_subscription_filter_add_goal_id(py::bytes goal_
return false;
}
- std::string str_goal_id = static_cast(goal_id);
+ std::string str_goal_id(goal_id.c_str(), goal_id.size());
const uint8_t * goal_id_array = reinterpret_cast(str_goal_id.data());
rcl_ret_t ret = rcl_action_client_configure_feedback_subscription_filter_add_goal_id(
rcl_action_client_.get(), goal_id_array, str_goal_id.size());
@@ -312,7 +315,7 @@ ActionClient::configure_feedback_subscription_filter_add_goal_id(py::bytes goal_
}
bool
-ActionClient::configure_feedback_subscription_filter_remove_goal_id(py::bytes goal_id)
+ActionClient::configure_feedback_subscription_filter_remove_goal_id(nb::bytes goal_id)
{
std::lock_guard lock(configure_feedback_sub_content_filter_mutex_);
@@ -320,7 +323,7 @@ ActionClient::configure_feedback_subscription_filter_remove_goal_id(py::bytes go
return false;
}
- std::string str_goal_id = static_cast(goal_id);
+ std::string str_goal_id(goal_id.c_str(), goal_id.size());
const uint8_t * goal_id_array = reinterpret_cast(str_goal_id.data());
rcl_ret_t ret = rcl_action_client_configure_feedback_subscription_filter_remove_goal_id(
rcl_action_client_.get(), goal_id_array, str_goal_id.size());
@@ -338,48 +341,75 @@ ActionClient::configure_feedback_subscription_filter_remove_goal_id(py::bytes go
}
void
-define_action_client(py::object module)
+define_action_client(nb::object module)
{
- py::class_>(module, "ActionClient")
+ nb::class_(
+ module, "ActionClient", nb::is_generic(),
+ nb::sig("class ActionClient(Destroyable, typing.Generic[GoalT, ResultT, FeedbackT, ImplT])"))
.def(
- py::init(),
- py::arg("node"),
- py::arg("action_type"),
- py::arg("action_name"),
- py::arg("goal_service_qos_profile"),
- py::arg("result_service_qos_profile"),
- py::arg("cancel_service_qos_profile"),
- py::arg("feedback_sub_qos_profile"),
- py::arg("status_sub_qos_profile"),
- py::arg("enable_feedback_msg_optimization") = false)
- .def_property_readonly(
+ "node"_a,
+ "action_type"_a,
+ "action_name"_a,
+ "goal_service_qos_profile"_a,
+ "result_service_qos_profile"_a,
+ "cancel_service_qos_profile"_a,
+ "feedback_sub_qos_profile"_a,
+ "status_sub_qos_profile"_a,
+ "enable_feedback_msg_optimization"_a = false,
+ nb::sig(
+ "def __init__(self, node: Node, "
+ "action_type: type[Action[GoalT, ResultT, FeedbackT, ImplT]], "
+ "action_name: str, goal_service_qos_profile: rmw_qos_profile_t, "
+ "result_service_qos_profile: rmw_qos_profile_t, "
+ "cancel_service_qos_profile: rmw_qos_profile_t, "
+ "feedback_sub_qos_profile: rmw_qos_profile_t, "
+ "status_sub_qos_profile: rmw_qos_profile_t, "
+ "enable_feedback_msg_optimization: bool = False) -> None"))
+ .def_prop_ro(
"pointer", [](const ActionClient & action_client) {
return reinterpret_cast(action_client.rcl_ptr());
},
"Get the address of the entity as an integer")
.def(
"take_goal_response", &ActionClient::take_goal_response,
- "Take an action goal response.")
+ "Take an action goal response.",
+ nb::sig(
+ "def take_goal_response(self, pymsg_type: type[SendGoalServiceResponse], /)"
+ " -> tuple[int, SendGoalServiceResponse] | tuple[None, None]"))
.def(
"send_result_request", &ActionClient::send_result_request,
- "Send an action result request.")
+ "Send an action result request.",
+ nb::sig("def send_result_request(self, pyrequest: GetResultServiceRequest, /) -> int"))
.def(
"take_cancel_response", &ActionClient::take_cancel_response,
- "Take an action cancel response.")
+ "Take an action cancel response.",
+ nb::sig(
+ "def take_cancel_response(self, pymsg_type: type[CancelGoal_Response], /)"
+ " -> tuple[int, CancelGoal_Response] | tuple[None, None]"))
.def(
"take_feedback", &ActionClient::take_feedback,
- "Take a feedback message from a given action client.")
+ "Take a feedback message from a given action client.",
+ nb::sig(
+ "def take_feedback(self, pymsg_type: type[FeedbackMessage[FeedbackT]], /)"
+ " -> FeedbackMessage[FeedbackT] | None"))
.def(
"send_cancel_request", &ActionClient::send_cancel_request,
- "Send an action cancel request.")
+ "Send an action cancel request.",
+ nb::sig(
+ "def send_cancel_request(self, pyrequest: CancelGoal_Request, /) -> int"))
.def(
"send_goal_request", &ActionClient::send_goal_request,
- "Send an action goal request.")
+ "Send an action goal request.",
+ nb::sig("def send_goal_request(self, pyrequest: SendGoalServiceRequest[GoalT], /) -> int"))
.def(
"take_result_response", &ActionClient::take_result_response,
- "Take an action result response.")
+ "Take an action result response.",
+ nb::sig(
+ "def take_result_response(self, pymsg_type: type[GetResultServiceResponse[ResultT]], /)"
+ " -> tuple[int, GetResultServiceResponse[ResultT]] | tuple[None, None]"))
.def(
"get_num_entities", &ActionClient::get_num_entities,
"Get the number of wait set entities that make up an action entity.")
@@ -394,7 +424,9 @@ define_action_client(py::object module)
"Check if an action entity has any ready wait set entities.")
.def(
"take_status", &ActionClient::take_status,
- "Take an action status response.")
+ "Take an action status response.",
+ nb::sig(
+ "def take_status(self, pymsg_type: type[GoalStatusArray], /) -> GoalStatusArray | None"))
.def(
"configure_introspection", &ActionClient::configure_introspection,
"Configure whether internal client introspection is enabled")
diff --git a/rclpy/src/rclpy/action_client.hpp b/rclpy/src/rclpy/action_client.hpp
index 666f7c3ac..08fd5d64d 100644
--- a/rclpy/src/rclpy/action_client.hpp
+++ b/rclpy/src/rclpy/action_client.hpp
@@ -15,20 +15,23 @@
#ifndef RCLPY__ACTION_CLIENT_HPP_
#define RCLPY__ACTION_CLIENT_HPP_
-#include
+#include
+#include
+#include
#include
#include
#include
#include
+#include
#include
#include "destroyable.hpp"
#include "node.hpp"
#include "wait_set.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -70,7 +73,7 @@ class ActionClient : public Destroyable, public std::enable_shared_from_this pyqos_service_event_pub,
rcl_service_introspection_state_t introspection_state);
/// Configure content filter for feedback subscription with the given goal ID.
@@ -209,7 +212,7 @@ class ActionClient : public Destroyable, public std::enable_shared_from_this
+#include
+#include
#include
#include
@@ -26,12 +27,12 @@
#include "exceptions.hpp"
#include "utils.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
ActionGoalHandle::ActionGoalHandle(
- rclpy::ActionServer & action_server, py::object pygoal_info_msg)
+ rclpy::ActionServer & action_server, nb::object pygoal_info_msg)
: action_server_(action_server)
{
auto goal_info_msg = convert_from_py(pygoal_info_msg);
@@ -39,7 +40,7 @@ ActionGoalHandle::ActionGoalHandle(
static_cast(goal_info_msg.get());
if (!goal_info_msg) {
- throw py::error_already_set();
+ throw nb::python_error();
}
auto rcl_handle = rcl_action_accept_new_goal(
@@ -96,12 +97,12 @@ ActionGoalHandle::update_goal_state(rcl_action_goal_event_t event)
}
void
-define_action_goal_handle(py::module module)
+define_action_goal_handle(nb::module_ module)
{
- py::class_>(
+ nb::class_(
module, "ActionGoalHandle")
- .def(py::init())
- .def_property_readonly(
+ .def(nb::init())
+ .def_prop_ro(
"pointer", [](const ActionGoalHandle & handle) {
return reinterpret_cast(handle.rcl_ptr());
},
diff --git a/rclpy/src/rclpy/action_goal_handle.hpp b/rclpy/src/rclpy/action_goal_handle.hpp
index 7bca00f3c..d8b73fa43 100644
--- a/rclpy/src/rclpy/action_goal_handle.hpp
+++ b/rclpy/src/rclpy/action_goal_handle.hpp
@@ -15,7 +15,8 @@
#ifndef RCLPY__ACTION_GOAL_HANDLE_HPP_
#define RCLPY__ACTION_GOAL_HANDLE_HPP_
-#include
+#include
+#include
#include
#include
@@ -25,7 +26,7 @@
#include "action_server.hpp"
#include "destroyable.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -44,7 +45,7 @@ class ActionGoalHandle : public Destroyable, public std::enable_shared_from_this
* \param[in] pyaction_server handle to the action server that is accepting the goal
* \param[in] pygoal_info_msg a message containing info about the goal being accepted
*/
- ActionGoalHandle(rclpy::ActionServer & action_server, py::object pygoal_info_msg);
+ ActionGoalHandle(rclpy::ActionServer & action_server, nb::object pygoal_info_msg);
~ActionGoalHandle() = default;
@@ -77,12 +78,12 @@ class ActionGoalHandle : public Destroyable, public std::enable_shared_from_this
std::shared_ptr rcl_action_goal_handle_;
};
-/// Define a pybind11 wrapper for an rclpy::ActionGoalHandle
+/// Define a nanobind wrapper for an rclpy::ActionGoalHandle
/**
- * \param[in] module a pybind11 module to add the definition to
+ * \param[in] module a nanobind module to add the definition to
*/
void
-define_action_goal_handle(py::module module);
+define_action_goal_handle(nb::module_ module);
} // namespace rclpy
#endif // RCLPY__ACTION_GOAL_HANDLE_HPP_
diff --git a/rclpy/src/rclpy/action_server.cpp b/rclpy/src/rclpy/action_server.cpp
index 098f19f17..44173bba7 100644
--- a/rclpy/src/rclpy/action_server.cpp
+++ b/rclpy/src/rclpy/action_server.cpp
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
+#include
#include
#include
@@ -47,7 +49,7 @@ ActionServer::destroy()
ActionServer::ActionServer(
Node & node,
const rclpy::Clock & rclpy_clock,
- py::object pyaction_type,
+ nb::object pyaction_type,
const char * action_name,
const rmw_qos_profile_t & goal_service_qos,
const rmw_qos_profile_t & result_service_qos,
@@ -62,7 +64,7 @@ ActionServer::ActionServer(
action_type_support_ = static_cast(
common_get_type_support(pyaction_type));
if (!action_type_support_) {
- throw py::error_already_set();
+ throw nb::python_error();
}
rcl_action_server_options_t action_server_ops = rcl_action_server_get_default_options();
@@ -99,9 +101,9 @@ ActionServer::ActionServer(
std::string error_text{"Failed to create action server due to invalid topic name '"};
error_text += action_name;
error_text += "' : ";
- throw py::value_error(append_rcl_error(error_text));
+ throw nb::value_error(append_rcl_error(error_text).c_str());
} else if (RCL_RET_OK != ret) {
- throw py::value_error(append_rcl_error("Failed to create action server"));
+ throw nb::value_error(append_rcl_error("Failed to create action server").c_str());
}
}
@@ -113,20 +115,20 @@ ActionServer::ActionServer(
rcl_action_take_ ## Type ## _request(rcl_action_server_.get(), &header, taken_msg.get()); \
/* Create the tuple to return */ \
if (ret == RCL_RET_ACTION_CLIENT_TAKE_FAILED || ret == RCL_RET_ACTION_SERVER_TAKE_FAILED) { \
- return py::make_tuple(py::none(), py::none()); \
+ return nb::make_tuple(nb::none(), nb::none()); \
} else if (RCL_RET_OK != ret) { \
throw rclpy::RCLError("Failed to take " #Type); \
} \
- return py::make_tuple(header, convert_to_py(taken_msg.get(), pymsg_type)); \
+ return nb::make_tuple(header, convert_to_py(taken_msg.get(), pymsg_type)); \
-py::tuple
-ActionServer::take_goal_request(py::object pymsg_type)
+nb::tuple
+ActionServer::take_goal_request(nb::object pymsg_type)
{
TAKE_SERVICE_REQUEST(goal)
}
-py::tuple
-ActionServer::take_result_request(py::object pymsg_type)
+nb::tuple
+ActionServer::take_result_request(nb::object pymsg_type)
{
TAKE_SERVICE_REQUEST(result)
}
@@ -149,33 +151,33 @@ ActionServer::take_result_request(py::object pymsg_type)
void
ActionServer::send_goal_response(
- rmw_request_id_t * header, py::object pyresponse)
+ rmw_request_id_t * header, nb::object pyresponse)
{
SEND_SERVICE_RESPONSE(goal)
}
void
ActionServer::send_result_response(
- rmw_request_id_t * header, py::object pyresponse)
+ rmw_request_id_t * header, nb::object pyresponse)
{
SEND_SERVICE_RESPONSE(result)
}
-py::tuple
-ActionServer::take_cancel_request(py::object pymsg_type)
+nb::tuple
+ActionServer::take_cancel_request(nb::object pymsg_type)
{
TAKE_SERVICE_REQUEST(cancel)
}
void
ActionServer::send_cancel_response(
- rmw_request_id_t * header, py::object pyresponse)
+ rmw_request_id_t * header, nb::object pyresponse)
{
SEND_SERVICE_RESPONSE(cancel)
}
void
-ActionServer::publish_feedback(py::object pymsg)
+ActionServer::publish_feedback(nb::object pymsg)
{
auto ros_message = convert_from_py(pymsg);
rcl_ret_t ret = rcl_action_publish_feedback(rcl_action_server_.get(), ros_message.get());
@@ -224,14 +226,14 @@ ActionServer::notify_goal_done()
}
bool
-ActionServer::goal_exists(py::object pygoal_info)
+ActionServer::goal_exists(nb::object pygoal_info)
{
auto goal_info = convert_from_py(pygoal_info);
rcl_action_goal_info_t * goal_info_type = static_cast(goal_info.get());
return rcl_action_server_goal_exists(rcl_action_server_.get(), goal_info_type);
}
-py::tuple
+nb::tuple
ActionServer::get_num_entities()
{
size_t num_subscriptions = 0u;
@@ -252,16 +254,16 @@ ActionServer::get_num_entities()
throw rclpy::RCLError("Failed to get number of entities for 'rcl_action_server_t'");
}
- py::tuple result_tuple(5);
- result_tuple[0] = py::int_(num_subscriptions);
- result_tuple[1] = py::int_(num_guard_conditions);
- result_tuple[2] = py::int_(num_timers);
- result_tuple[3] = py::int_(num_clients);
- result_tuple[4] = py::int_(num_services);
+ nb::tuple result_tuple = nb::make_tuple(
+ num_subscriptions,
+ num_guard_conditions,
+ num_timers,
+ num_clients,
+ num_services);
return result_tuple;
}
-py::tuple
+nb::tuple
ActionServer::is_ready(WaitSet & wait_set)
{
bool is_goal_request_ready = false;
@@ -280,12 +282,11 @@ ActionServer::is_ready(WaitSet & wait_set)
throw rclpy::RCLError("Failed to get number of ready entities for action server");
}
- py::tuple result_tuple(4);
- result_tuple[0] = py::bool_(is_goal_request_ready);
- result_tuple[1] = py::bool_(is_cancel_request_ready);
- result_tuple[2] = py::bool_(is_result_request_ready);
- result_tuple[3] = py::bool_(is_goal_expired);
- return result_tuple;
+ return nb::make_tuple(
+ is_goal_request_ready,
+ is_cancel_request_ready,
+ is_result_request_ready,
+ is_goal_expired);
}
void
@@ -298,9 +299,9 @@ ActionServer::add_to_waitset(WaitSet & wait_set)
}
}
-py::object
+nb::object
ActionServer::process_cancel_request(
- py::object pycancel_request, py::object pycancel_response_type)
+ nb::object pycancel_request, nb::object pycancel_response_type)
{
auto cancel_request = convert_from_py(pycancel_request);
rcl_action_cancel_request_t * cancel_request_tmp = static_cast(
@@ -319,7 +320,7 @@ ActionServer::process_cancel_request(
throw std::runtime_error(error_text);
}
- py::object return_value = convert_to_py(&cancel_response.msg, pycancel_response_type);
+ nb::object return_value = convert_to_py(&cancel_response.msg, pycancel_response_type);
RCPPUTILS_SCOPE_EXIT(
{
ret = rcl_action_cancel_response_fini(&cancel_response);
@@ -335,7 +336,7 @@ ActionServer::process_cancel_request(
return return_value;
}
-py::tuple
+nb::tuple
ActionServer::expire_goals(int64_t max_num_goals)
{
auto expired_goals =
@@ -348,30 +349,29 @@ ActionServer::expire_goals(int64_t max_num_goals)
}
// Get Python GoalInfo type
- py::module pyaction_msgs_module = py::module::import("action_msgs.msg");
- py::object pygoal_info_class = pyaction_msgs_module.attr("GoalInfo");
- py::object pygoal_info_type = pygoal_info_class();
+ nb::module_ pyaction_msgs_module = nb::module_::import_("action_msgs.msg");
+ nb::object pygoal_info_class = pyaction_msgs_module.attr("GoalInfo");
+ nb::object pygoal_info_type = pygoal_info_class();
// Create a tuple of GoalInfo instances to return
- py::tuple result_tuple(num_expired);
-
+ nb::list expired_list;
for (size_t i = 0; i < num_expired; ++i) {
- result_tuple[i] =
- convert_to_py(&(expired_goals.get()[i]), pygoal_info_type);
+ expired_list.append(
+ convert_to_py(&(expired_goals.get()[i]), pygoal_info_type));
}
- return result_tuple;
+ return nb::tuple(expired_list);
}
void
ActionServer::configure_introspection(
- Clock & clock, py::object pyqos_service_event_pub,
+ Clock & clock, std::optional pyqos_service_event_pub,
rcl_service_introspection_state_t introspection_state)
{
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
- pub_opts.qos =
- pyqos_service_event_pub.is_none() ? rcl_publisher_get_default_options().qos :
- pyqos_service_event_pub.cast();
+ if (pyqos_service_event_pub) {
+ pub_opts.qos = *pyqos_service_event_pub;
+ }
rcl_ret_t ret = rcl_action_server_configure_action_introspection(
rcl_action_server_.get(), node_.rcl_ptr(), clock.rcl_ptr(),
@@ -383,39 +383,67 @@ ActionServer::configure_introspection(
}
void
-define_action_server(py::object module)
+define_action_server(nb::object module)
{
- py::class_>(module, "ActionServer")
+ nb::class_(
+ module, "ActionServer", nb::is_generic(),
+ nb::sig("class ActionServer(Destroyable, typing.Generic[GoalT, ResultT, FeedbackT, ImplT])"))
.def(
- py::init())
- .def_property_readonly(
+ const rmw_qos_profile_t &, const rmw_qos_profile_t &, double>(),
+ nb::sig(
+ "def __init__(self, node: Node, rclpy_clock: Clock, "
+ "pyaction_type: type[Action[GoalT, ResultT, FeedbackT, ImplT]], "
+ "action_name: str, goal_service_qos: rmw_qos_profile_t, "
+ "result_service_qos: rmw_qos_profile_t, cancel_service_qos: rmw_qos_profile_t, "
+ "feedback_topic_qos: rmw_qos_profile_t, status_topic_qos: rmw_qos_profile_t, "
+ "result_timeout: float, /) -> None"))
+ .def_prop_ro(
"pointer", [](const ActionServer & action_server) {
return reinterpret_cast(action_server.rcl_ptr());
},
"Get the address of the entity as an integer")
.def(
"take_goal_request", &ActionServer::take_goal_request,
- "Take an action goal request.")
+ "Take an action goal request.",
+ nb::sig(
+ "def take_goal_request(self, pymsg_type: type[SendGoalServiceRequest[GoalT]], /)"
+ " -> tuple[rmw_request_id_t, SendGoalServiceRequest[GoalT]] | tuple[None, None]"))
.def(
"send_goal_response", &ActionServer::send_goal_response,
- "Send an action goal response.")
+ "Send an action goal response.",
+ nb::sig(
+ "def send_goal_response(self, header: rmw_request_id_t, "
+ "pyresponse: SendGoalServiceResponse, /) -> None"))
.def(
"send_result_response", &ActionServer::send_result_response,
- "Send an action result response.")
+ "Send an action result response.",
+ nb::sig(
+ "def send_result_response(self, header: rmw_request_id_t, "
+ "pyresponse: GetResultServiceResponse[ResultT], /) -> None"))
.def(
"take_cancel_request", &ActionServer::take_cancel_request,
- "Take an action cancel request.")
+ "Take an action cancel request.",
+ nb::sig(
+ "def take_cancel_request(self, pymsg_type: type[CancelGoal_Request], /)"
+ " -> tuple[rmw_request_id_t, CancelGoal_Request] | tuple[None, None]"))
.def(
"take_result_request", &ActionServer::take_result_request,
- "Take an action result request.")
+ "Take an action result request.",
+ nb::sig(
+ "def take_result_request(self, pymsg_type: type[GetResultServiceRequest], /)"
+ " -> tuple[rmw_request_id_t, GetResultServiceRequest] | tuple[None, None]"))
.def(
"send_cancel_response", &ActionServer::send_cancel_response,
- "Send an action cancel response.")
+ "Send an action cancel response.",
+ nb::sig(
+ "def send_cancel_response(self, header: rmw_request_id_t, "
+ "pyresponse: CancelGoal_Response, /) -> None"))
.def(
"publish_feedback", &ActionServer::publish_feedback,
- "Publish a feedback message from a given action server.")
+ "Publish a feedback message from a given action server.",
+ nb::sig("def publish_feedback(self, pymsg: FeedbackT, /) -> None"))
.def(
"publish_status", &ActionServer::publish_status,
"Publish a status message from a given action server.")
@@ -424,13 +452,18 @@ define_action_server(py::object module)
"Notify goal is done.")
.def(
"goal_exists", &ActionServer::goal_exists,
- "Check is a goal exists in the server.")
+ "Check is a goal exists in the server.",
+ nb::sig("def goal_exists(self, pygoal_info: GoalInfo, /) -> bool"))
.def(
"process_cancel_request", &ActionServer::process_cancel_request,
- "Process a cancel request")
+ "Process a cancel request",
+ nb::sig(
+ "def process_cancel_request(self, pycancel_request: CancelGoal_Request, "
+ "pycancel_response_type: type[CancelGoal_Response], /) -> CancelGoal_Response"))
.def(
"expire_goals", &ActionServer::expire_goals,
- "Expired goals.")
+ "Expired goals.",
+ nb::sig("def expire_goals(self, max_num_goals: int, /) -> tuple[GoalInfo, ...]"))
.def(
"get_num_entities", &ActionServer::get_num_entities,
"Get the number of wait set entities that make up an action entity.")
diff --git a/rclpy/src/rclpy/action_server.hpp b/rclpy/src/rclpy/action_server.hpp
index 4aa96c1e0..1d4457b25 100644
--- a/rclpy/src/rclpy/action_server.hpp
+++ b/rclpy/src/rclpy/action_server.hpp
@@ -15,19 +15,22 @@
#ifndef RCLPY__ACTION_SERVER_HPP_
#define RCLPY__ACTION_SERVER_HPP_
-#include
+#include
+#include
+#include
#include
#include
#include
+#include
#include "clock.hpp"
#include "destroyable.hpp"
#include "node.hpp"
#include "wait_set.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -59,7 +62,7 @@ class ActionServer : public Destroyable, public std::enable_shared_from_this pyqos_service_event_pub,
rcl_service_introspection_state_t introspection_state);
/// Force an early destruction of this object
@@ -270,11 +273,11 @@ class ActionServer : public Destroyable, public std::enable_shared_from_this rcl_action_server_;
const rosidl_action_type_support_t * action_type_support_;
};
-/// Define a pybind11 wrapper for an rclpy::ActionServer
+/// Define a nanobind wrapper for an rclpy::ActionServer
/**
- * \param[in] module a pybind11 module to add the definition to
+ * \param[in] module a nanobind module to add the definition to
*/
-void define_action_server(py::object module);
+void define_action_server(nb::object module);
} // namespace rclpy
#endif // RCLPY__ACTION_SERVER_HPP_
diff --git a/rclpy/src/rclpy/client.cpp b/rclpy/src/rclpy/client.cpp
index 5ee4405ee..dab148466 100644
--- a/rclpy/src/rclpy/client.cpp
+++ b/rclpy/src/rclpy/client.cpp
@@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
-#include
+#include
+#include
+#include
+#include
#include
#include
@@ -34,6 +36,8 @@
#include "utils.hpp"
#include "events_executor/rcl_support.hpp"
+using nb::literals::operator""_a;
+
namespace rclpy
{
using events_executor::RclEventCallbackTrampoline;
@@ -50,18 +54,19 @@ Client::destroy()
}
Client::Client(
- Node & node, py::object pysrv_type, const std::string & service_name, py::object pyqos_profile)
+ Node & node, nb::object pysrv_type, const std::string & service_name,
+ std::optional pyqos_profile)
: node_(node)
{
srv_type_ = static_cast(common_get_type_support(pysrv_type));
if (nullptr == srv_type_) {
- throw py::error_already_set();
+ throw nb::python_error();
}
rcl_client_options_t client_ops = rcl_client_get_default_options();
- if (!pyqos_profile.is_none()) {
- client_ops.qos = pyqos_profile.cast();
+ if (pyqos_profile) {
+ client_ops.qos = *pyqos_profile;
}
// Create a client
@@ -88,18 +93,18 @@ Client::Client(
error_text += "': ";
error_text += rcl_get_error_string().str;
rcl_reset_error();
- throw py::value_error(error_text);
+ throw nb::value_error(error_text.c_str());
}
throw RCLError("failed to create client");
}
}
int64_t
-Client::send_request(py::object pyrequest)
+Client::send_request(nb::object pyrequest)
{
auto raw_ros_request = convert_from_py(pyrequest);
if (!raw_ros_request) {
- throw py::error_already_set();
+ throw nb::python_error();
}
int64_t sequence_number;
@@ -123,40 +128,34 @@ Client::service_server_is_available()
return is_ready;
}
-py::tuple
-Client::take_response(py::object pyresponse_type)
+nb::tuple
+Client::take_response(nb::object pyresponse_type)
{
auto taken_response = create_from_py(pyresponse_type);
rmw_service_info_t header;
- py::tuple result_tuple(2);
rcl_ret_t ret = rcl_take_response_with_info(
rcl_client_.get(), &header, taken_response.get());
if (ret == RCL_RET_CLIENT_TAKE_FAILED) {
- result_tuple[0] = py::none();
- result_tuple[1] = py::none();
- return result_tuple;
+ return nb::make_tuple(nb::none(), nb::none());
}
if (RCL_RET_OK != ret) {
throw RCLError("encountered error when taking client response");
}
- result_tuple[0] = header;
- result_tuple[1] = convert_to_py(taken_response.get(), pyresponse_type);
-
- return result_tuple;
+ return nb::make_tuple(header, convert_to_py(taken_response.get(), pyresponse_type));
}
void
Client::configure_introspection(
- Clock & clock, py::object pyqos_service_event_pub,
+ Clock & clock, std::optional pyqos_service_event_pub,
rcl_service_introspection_state_t introspection_state)
{
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
- pub_opts.qos =
- pyqos_service_event_pub.is_none() ? rcl_publisher_get_default_options().qos :
- pyqos_service_event_pub.cast();
+ if (pyqos_service_event_pub) {
+ pub_opts.qos = *pyqos_service_event_pub;
+ }
rcl_ret_t ret = rcl_client_configure_service_introspection(
rcl_client_.get(), node_.rcl_ptr(), clock.rcl_ptr(), srv_type_, pub_opts, introspection_state);
@@ -219,27 +218,37 @@ Client::clear_on_new_response_callback()
}
void
-define_client(py::object module)
+define_client(nb::object module)
{
- py::class_>(module, "Client")
- .def(py::init())
- .def_property_readonly(
+ nb::class_(
+ module, "Client", nb::is_generic(),
+ nb::sig("class Client(Destroyable, typing.Generic[SrvRequestT, SrvResponseT])"))
+ .def(
+ nb::init>(),
+ nb::sig(
+ "def __init__(self, node: Node, srv_type: type[Srv[SrvRequestT, SrvResponseT]], "
+ "srv_name: str, pyqos_profile: rmw_qos_profile_t | None, /) -> None"))
+ .def_prop_ro(
"service_name", &Client::get_service_name,
"Get the name of the service")
- .def_property_readonly(
+ .def_prop_ro(
"pointer", [](const Client & client) {
return reinterpret_cast(client.rcl_ptr());
},
"Get the address of the entity as an integer")
.def(
"send_request", &Client::send_request,
- "Send a request")
+ "Send a request",
+ nb::sig("def send_request(self, pyrequest: SrvRequestT, /) -> int"))
.def(
"service_server_is_available", &Client::service_server_is_available,
"Return true if the service server is available")
.def(
"take_response", &Client::take_response,
- "Take a received response from an earlier request")
+ "Take a received response from an earlier request",
+ nb::sig(
+ "def take_response(self, pyresponse_type: type[SrvResponseT], /)"
+ " -> tuple[rmw_service_info_t, SrvResponseT] | tuple[None, None]"))
.def(
"configure_introspection", &Client::configure_introspection,
"Configure whether introspection is enabled")
@@ -248,7 +257,7 @@ define_client(py::object module)
"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"))
+ "callback"_a)
.def("clear_on_new_response_callback", &Client::clear_on_new_response_callback);
}
} // namespace rclpy
diff --git a/rclpy/src/rclpy/client.hpp b/rclpy/src/rclpy/client.hpp
index f31e0acb7..699a155e4 100644
--- a/rclpy/src/rclpy/client.hpp
+++ b/rclpy/src/rclpy/client.hpp
@@ -15,7 +15,11 @@
#ifndef RCLPY__CLIENT_HPP_
#define RCLPY__CLIENT_HPP_
-#include
+#include
+#include
+#include
+#include
+#include
#include
#include
@@ -23,13 +27,14 @@
#include
#include
+#include
#include
#include "clock.hpp"
#include "destroyable.hpp"
#include "node.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -50,7 +55,9 @@ class Client : public Destroyable, public std::enable_shared_from_this
* \param[in] service_name The service name
* \param[in] pyqos QoSProfile python object for this client
*/
- Client(Node & node, py::object pysrv_type, const std::string & service_name, py::object pyqos);
+ Client(
+ Node & node, nb::object pysrv_type, const std::string & service_name,
+ std::optional pyqos);
~Client() = default;
@@ -63,7 +70,7 @@ class Client : public Destroyable, public std::enable_shared_from_this
* \return sequence_number Index of the sent request
*/
int64_t
- send_request(py::object pyrequest);
+ send_request(nb::object pyrequest);
/// Check if a service server is available
/**
@@ -81,8 +88,8 @@ class Client : public Destroyable, public std::enable_shared_from_this
* \param[in] pyresponse_type Instance of the message type to take
* \return 2-tuple sequence number and received response, or None if there is no response
*/
- py::tuple
- take_response(py::object pyresponse_type);
+ nb::tuple
+ take_response(nb::object pyresponse_type);
/// Get rcl_client_t pointer
rcl_client_t *
@@ -101,7 +108,7 @@ class Client : public Destroyable, public std::enable_shared_from_this
*/
void
configure_introspection(
- Clock & clock, py::object pyqos_service_event_pub,
+ Clock & clock, std::optional pyqos_service_event_pub,
rcl_service_introspection_state_t introspection_state);
/// Force an early destruction of this object
@@ -137,12 +144,12 @@ class Client : public Destroyable, public std::enable_shared_from_this
set_callback(rcl_event_callback_t callback, const void * user_data);
};
-/// Define a pybind11 wrapper for an rclpy::Client
+/// Define a nanobind wrapper for an rclpy::Client
/**
- * \param[in] module a pybind11 module to add the definition to
+ * \param[in] module a nanobind module to add the definition to
*/
void
-define_client(py::object module);
+define_client(nb::object module);
} // namespace rclpy
#endif // RCLPY__CLIENT_HPP_
diff --git a/rclpy/src/rclpy/clock.cpp b/rclpy/src/rclpy/clock.cpp
index 4479c2f9a..88c7ed7d0 100644
--- a/rclpy/src/rclpy/clock.cpp
+++ b/rclpy/src/rclpy/clock.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
#include
#include
@@ -23,7 +24,7 @@
#include "clock.hpp"
-using pybind11::literals::operator""_a;
+using nb::literals::operator""_a;
namespace rclpy
{
@@ -91,7 +92,7 @@ void Clock::set_ros_time_override_is_enabled(bool enabled)
}
if (PyErr_Occurred()) {
// Time jump callbacks raised
- throw py::error_already_set();
+ throw nb::python_error();
}
}
@@ -104,7 +105,7 @@ void Clock::set_ros_time_override(rcl_time_point_t time_point)
if (PyErr_Occurred()) {
// Time jump callbacks raised
- throw py::error_already_set();
+ throw nb::python_error();
}
}
@@ -120,29 +121,30 @@ _rclpy_on_time_jump(
return;
}
auto pyjump_handle_c = static_cast(user_data);
- auto pyjump_handle = py::reinterpret_borrow(pyjump_handle_c);
+ auto pyjump_handle = nb::borrow(pyjump_handle_c);
if (before_jump) {
// Call pre jump callback with no arguments
- py::object pre_callback = pyjump_handle.attr("_pre_callback");
+ nb::object pre_callback = pyjump_handle.attr("_pre_callback");
if (pre_callback.is_none()) {
return;
}
pre_callback();
} else {
// Call post jump callback with JumpInfo as an argument
- py::object post_callback = pyjump_handle.attr("_post_callback");
+ nb::object post_callback = pyjump_handle.attr("_post_callback");
if (post_callback.is_none()) {
return;
}
- py::object clock_change = py::cast(time_jump->clock_change);
+ nb::object clock_change = nb::cast(time_jump->clock_change);
+ nb::object pydict = nb::module_::import_("builtins").attr("dict");
post_callback(
- py::dict("clock_change"_a = clock_change, "delta"_a = time_jump->delta.nanoseconds));
+ pydict("clock_change"_a = clock_change, "delta"_a = time_jump->delta.nanoseconds));
}
}
void Clock::add_clock_callback(
- py::object pyjump_handle,
+ nb::object pyjump_handle,
bool on_clock_change,
int64_t min_forward,
int64_t min_backward)
@@ -159,7 +161,7 @@ void Clock::add_clock_callback(
}
}
-void Clock::remove_clock_callback(py::object pyjump_handle)
+void Clock::remove_clock_callback(nb::object pyjump_handle)
{
rcl_ret_t ret = rcl_clock_remove_jump_callback(
rcl_clock_.get(), _rclpy_on_time_jump, pyjump_handle.ptr());
@@ -168,11 +170,11 @@ void Clock::remove_clock_callback(py::object pyjump_handle)
}
}
-void define_clock(py::object module)
+void define_clock(nb::object module)
{
- py::class_>(module, "Clock")
- .def(py::init())
- .def_property_readonly(
+ nb::class_(module, "Clock")
+ .def(nb::init())
+ .def_prop_ro(
"pointer", [](const Clock & clock) {
return reinterpret_cast(clock.rcl_ptr());
},
diff --git a/rclpy/src/rclpy/clock.hpp b/rclpy/src/rclpy/clock.hpp
index 53d0e0f4c..c4ff0631b 100644
--- a/rclpy/src/rclpy/clock.hpp
+++ b/rclpy/src/rclpy/clock.hpp
@@ -15,7 +15,8 @@
#ifndef RCLPY__CLOCK_HPP_
#define RCLPY__CLOCK_HPP_
-#include
+#include
+#include
#include
@@ -25,7 +26,7 @@
#include "exceptions.hpp"
#include "utils.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -89,7 +90,7 @@ class Clock : public Destroyable, public std::enable_shared_from_this
*/
void
add_clock_callback(
- py::object pyjump_handle,
+ nb::object pyjump_handle,
bool on_clock_change,
int64_t min_forward,
int64_t min_backward);
@@ -101,7 +102,7 @@ class Clock : public Destroyable, public std::enable_shared_from_this
* \param[in] pyjump_handle Instance of rclpy.clock.JumpHandle
*/
void
- remove_clock_callback(py::object pyjump_handle);
+ remove_clock_callback(nb::object pyjump_handle);
/// Get rcl_clock_t pointer
rcl_clock_t * rcl_ptr() const
@@ -116,8 +117,8 @@ class Clock : public Destroyable, public std::enable_shared_from_this
std::shared_ptr rcl_clock_;
};
-/// Define a pybind11 wrapper for an rclpy::Clock
-void define_clock(py::object module);
+/// Define a nanobind wrapper for an rclpy::Clock
+void define_clock(nb::object module);
} // namespace rclpy
#endif // RCLPY__CLOCK_HPP_
diff --git a/rclpy/src/rclpy/clock_event.cpp b/rclpy/src/rclpy/clock_event.cpp
index 71056dee3..4231f2730 100644
--- a/rclpy/src/rclpy/clock_event.cpp
+++ b/rclpy/src/rclpy/clock_event.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
#include
#include
@@ -24,7 +25,7 @@
#include "clock_event.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -48,7 +49,7 @@ void ClockEvent::wait_until(std::shared_ptr clock, rcl_time_point_t until
std::chrono::nanoseconds(delta_t.nanoseconds));
// Could be a long wait, release the gil
- py::gil_scoped_release release;
+ nb::gil_scoped_release release;
std::unique_lock lock(mutex_);
cv_.wait_until(lock, chrono_until, [this]() {return state_;});
}
@@ -58,7 +59,7 @@ void ClockEvent::wait_until_ros(std::shared_ptr clock, rcl_time_point_t u
// Check if ROS time is enabled in C++ to avoid TOCTTOU with TimeSource by holding GIL
if (clock->get_ros_time_override_is_enabled()) {
// Could be a long wait, release the gil
- py::gil_scoped_release release;
+ nb::gil_scoped_release release;
std::unique_lock lock(mutex_);
// Caller must have setup a time jump callback to wake this event
cv_.wait(lock, [this]() {return state_;});
@@ -92,10 +93,10 @@ void ClockEvent::clear()
cv_.notify_all();
}
-void define_clock_event(py::object module)
+void define_clock_event(nb::object module)
{
- py::class_(module, "ClockEvent")
- .def(py::init())
+ nb::class_(module, "ClockEvent")
+ .def(nb::init<>())
.def(
"wait_until_steady", &ClockEvent::wait_until,
"Wait for the event to be set (monotonic wait)")
diff --git a/rclpy/src/rclpy/clock_event.hpp b/rclpy/src/rclpy/clock_event.hpp
index d567fd933..7fc79c56e 100644
--- a/rclpy/src/rclpy/clock_event.hpp
+++ b/rclpy/src/rclpy/clock_event.hpp
@@ -15,7 +15,8 @@
#ifndef RCLPY__CLOCK_EVENT_HPP_
#define RCLPY__CLOCK_EVENT_HPP_
-#include
+#include
+#include
#include
@@ -25,7 +26,7 @@
#include "clock.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -62,8 +63,8 @@ class ClockEvent
std::condition_variable cv_;
};
-/// Define a pybind11 wrapper for an rclpy::ClockEvent
-void define_clock_event(py::object module);
+/// Define a nanobind wrapper for an rclpy::ClockEvent
+void define_clock_event(nb::object module);
} // namespace rclpy
#endif // RCLPY__CLOCK_EVENT_HPP_
diff --git a/rclpy/src/rclpy/context.cpp b/rclpy/src/rclpy/context.cpp
index e6b7166fc..320f46a0e 100644
--- a/rclpy/src/rclpy/context.cpp
+++ b/rclpy/src/rclpy/context.cpp
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
+#include
#include
#include
@@ -52,7 +54,7 @@ void shutdown_contexts()
g_contexts.clear();
}
-Context::Context(py::list pyargs, size_t domain_id)
+Context::Context(nb::list pyargs, size_t domain_id)
{
rcl_context_ = std::shared_ptr(
new rcl_context_t,
@@ -94,7 +96,7 @@ Context::Context(py::list pyargs, size_t domain_id)
// CPython owns const char * memory - no need to free it
arg_c_values[i] = PyUnicode_AsUTF8(pyargs[i].ptr());
if (!arg_c_values[i]) {
- throw py::error_already_set();
+ throw nb::python_error();
}
}
@@ -165,11 +167,11 @@ Context::shutdown()
}
}
-void define_context(py::object module)
+void define_context(nb::object module)
{
- py::class_>(module, "Context")
- .def(py::init())
- .def_property_readonly(
+ nb::class_(module, "Context")
+ .def(nb::init())
+ .def_prop_ro(
"pointer", [](const Context & context) {
return reinterpret_cast(context.rcl_ptr());
},
diff --git a/rclpy/src/rclpy/context.hpp b/rclpy/src/rclpy/context.hpp
index 30259e3e4..5710eb567 100644
--- a/rclpy/src/rclpy/context.hpp
+++ b/rclpy/src/rclpy/context.hpp
@@ -15,7 +15,8 @@
#ifndef RCLPY__CONTEXT_HPP_
#define RCLPY__CONTEXT_HPP_
-#include
+#include
+#include
#include
#include
@@ -26,7 +27,7 @@
#include "destroyable.hpp"
#include "exceptions.hpp"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -70,7 +71,7 @@ class Context : public Destroyable, public std::enable_shared_from_this
* \param[in] pyargs List of command line arguments
* \param[in] domain_id domain id to be set in this context
*/
- Context(py::list pyargs, size_t domain_id);
+ Context(nb::list pyargs, size_t domain_id);
/// Retrieves domain id from init_options of context
/**
@@ -104,8 +105,8 @@ class Context : public Destroyable, public std::enable_shared_from_this
bool already_shutdown_{false};
};
-/// Define a pybind11 wrapper for an rclpy::Context
-void define_context(py::object module);
+/// Define a nanobind wrapper for an rclpy::Context
+void define_context(nb::object module);
} // namespace rclpy
#endif // RCLPY__CONTEXT_HPP_
diff --git a/rclpy/src/rclpy/destroyable.cpp b/rclpy/src/rclpy/destroyable.cpp
index c981ac791..45e186654 100644
--- a/rclpy/src/rclpy/destroyable.cpp
+++ b/rclpy/src/rclpy/destroyable.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
#include
#include
@@ -40,7 +41,7 @@ Destroyable::enter()
}
void
-Destroyable::exit(py::object, py::object, py::object)
+Destroyable::exit(nb::object, nb::object, nb::object)
{
if (0u == use_count) {
throw std::runtime_error("Internal error: Destroyable use_count would be negative");
@@ -55,7 +56,7 @@ Destroyable::exit(py::object, py::object, py::object)
void
Destroyable::destroy()
{
- // Normally would be pure virtual, but then pybind11 can't create bindings for this class
+ // Normally would be pure virtual, but then nanobind can't create bindings for this class
throw NotImplementedError("Internal error: Destroyable subclass didn't override destroy()");
}
@@ -73,11 +74,11 @@ Destroyable::destroy_when_not_in_use()
}
void
-define_destroyable(py::object module)
+define_destroyable(nb::object module)
{
- py::class_>(module, "Destroyable")
+ nb::class_(module, "Destroyable")
.def("__enter__", &Destroyable::enter)
- .def("__exit__", &Destroyable::exit)
+ .def("__exit__", &Destroyable::exit, nb::arg().none(), nb::arg().none(), nb::arg().none())
.def(
"destroy_when_not_in_use", &Destroyable::destroy_when_not_in_use,
"Forcefully destroy the rcl object as soon as it's not actively being used");
diff --git a/rclpy/src/rclpy/destroyable.hpp b/rclpy/src/rclpy/destroyable.hpp
index 92d6b0ad3..830a43af9 100644
--- a/rclpy/src/rclpy/destroyable.hpp
+++ b/rclpy/src/rclpy/destroyable.hpp
@@ -15,9 +15,9 @@
#ifndef RCLPY__DESTROYABLE_HPP_
#define RCLPY__DESTROYABLE_HPP_
-#include
+#include
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
@@ -37,7 +37,7 @@ class Destroyable
/// Context manager __exit__ - unblock destruction
void
- exit(py::object pytype, py::object pyvalue, py::object pytraceback);
+ exit(nb::object pytype, nb::object pyvalue, nb::object pytraceback);
/// Signal that the object should be destroyed as soon as it's not in use
void
@@ -56,11 +56,11 @@ class Destroyable
bool please_destroy_ = false;
};
-/// Define a pybind11 wrapper for an rclpy::Destroyable
+/// Define a nanobind wrapper for an rclpy::Destroyable
/**
- * \param[in] module a pybind11 module to add the definition to
+ * \param[in] module a nanobind module to add the definition to
*/
-void define_destroyable(py::object module);
+void define_destroyable(nb::object module);
} // namespace rclpy
#endif // RCLPY__DESTROYABLE_HPP_
diff --git a/rclpy/src/rclpy/duration.cpp b/rclpy/src/rclpy/duration.cpp
index 6554c42e8..8f4760be4 100644
--- a/rclpy/src/rclpy/duration.cpp
+++ b/rclpy/src/rclpy/duration.cpp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
#include
@@ -28,10 +28,10 @@ create_duration(int64_t nanoseconds)
return duration;
}
void
-define_duration(py::object module)
+define_duration(nb::object module)
{
- py::class_(module, "rcl_duration_t")
- .def(py::init<>(&create_duration))
- .def_readonly("nanoseconds", &rcl_duration_t::nanoseconds);
+ nb::class_(module, "rcl_duration_t")
+ .def(nb::new_(&create_duration))
+ .def_ro("nanoseconds", &rcl_duration_t::nanoseconds);
}
} // namespace rclpy
diff --git a/rclpy/src/rclpy/duration.hpp b/rclpy/src/rclpy/duration.hpp
index a22855698..9f419ed75 100644
--- a/rclpy/src/rclpy/duration.hpp
+++ b/rclpy/src/rclpy/duration.hpp
@@ -15,17 +15,17 @@
#ifndef RCLPY__DURATION_HPP_
#define RCLPY__DURATION_HPP_
-#include
+#include
-namespace py = pybind11;
+namespace nb = nanobind;
namespace rclpy
{
-/// Define a pybind11 wrapper for an rcl_duration_t
+/// Define a nanobind wrapper for an rcl_duration_t
/**
- * \param[in] module a pybind11 module to add the definition to
+ * \param[in] module a nanobind module to add the definition to
*/
-void define_duration(py::object module);
+void define_duration(nb::object module);
} // namespace rclpy
#endif // RCLPY__DURATION_HPP_
diff --git a/rclpy/src/rclpy/event_handle.cpp b/rclpy/src/rclpy/event_handle.cpp
index 78dc3ec96..9cb3544a8 100644
--- a/rclpy/src/rclpy/event_handle.cpp
+++ b/rclpy/src/rclpy/event_handle.cpp
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include
+#include
+#include
#include
#include
@@ -114,7 +115,7 @@ typedef union event_callback_data {
rmw_incompatible_type_status_t incompatible_type;
} event_callback_data_t;
-py::object
+nb::object
EventHandle::take_event()
{
event_callback_data_t data;
@@ -124,7 +125,7 @@ EventHandle::take_event()
throw std::bad_alloc();
}
if (RCL_RET_EVENT_TAKE_FAILED == ret) {
- return py::none();
+ return nb::none();
}
if (RCL_RET_OK != ret) {
throw RCLError("failed to take event");
@@ -133,30 +134,30 @@ EventHandle::take_event()
if (auto sub_type = std::get_if(&event_type_)) {
switch (*sub_type) {
case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED:
- return py::cast(data.requested_deadline_missed);
+ return nb::cast(data.requested_deadline_missed);
case RCL_SUBSCRIPTION_LIVELINESS_CHANGED:
- return py::cast(data.liveliness_changed);
+ return nb::cast(data.liveliness_changed);
case RCL_SUBSCRIPTION_MESSAGE_LOST:
- return py::cast(data.message_lost);
+ return nb::cast(data.message_lost);
case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS:
- return py::cast(data.requested_incompatible_qos);
+ return nb::cast(data.requested_incompatible_qos);
case RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE:
- return py::cast(data.incompatible_type);
+ return nb::cast(data.incompatible_type);
case RCL_SUBSCRIPTION_MATCHED:
- return py::cast(data.subscription_matched);
+ return nb::cast(data.subscription_matched);
}
} else if (auto pub_type = std::get_if(&event_type_)) {
switch (*pub_type) {
case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED:
- return py::cast(data.offered_deadline_missed);
+ return nb::cast(data.offered_deadline_missed);
case RCL_PUBLISHER_LIVELINESS_LOST:
- return py::cast(data.liveliness_lost);
+ return nb::cast(data.liveliness_lost);
case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS:
- return py::cast(data.offered_incompatible_qos);
+ return nb::cast(data.offered_incompatible_qos);
case RCL_PUBLISHER_INCOMPATIBLE_TYPE:
- return py::cast(data.incompatible_type);
+ return nb::cast(data.incompatible_type);
case RCL_PUBLISHER_MATCHED:
- return py::cast(data.publisher_matched);
+ return nb::cast(data.publisher_matched);
}
}
throw std::runtime_error("cannot take event that is neither a publisher or a subscription event");
@@ -175,21 +176,33 @@ subscription_event_type_is_supported(rcl_subscription_event_type_t event_type)
}
void
-define_event_handle(py::module module)
+define_event_handle(nb::module_ module)
{
- py::class_>(module, "EventHandle")
- .def(py::init())
- .def(py::init())
- .def_property_readonly(
+ nb::class_(
+ module, "EventHandle", nb::is_generic(),
+ nb::sig("class EventHandle(Destroyable, typing.Generic[T])"))
+ .def(
+ nb::init(),
+ nb::sig(
+ "def __init__(self, subscription: Subscription[typing.Any], "
+ "event_type: rcl_subscription_event_type_t, /) -> None"))
+ .def(
+ nb::init(),
+ nb::sig(
+ "def __init__(self, publisher: Publisher[typing.Any], "
+ "event_type: rcl_publisher_event_type_t, /) -> None"))
+ .def_prop_ro(
"pointer", [](const EventHandle & event) {
return reinterpret_cast(event.rcl_ptr());
},
"Get the address of the entity as an integer")
.def(
"take_event", &EventHandle::take_event,
- "Get pending data from a ready event");
+ "Get pending data from a ready event",
+ nb::sig("def take_event(self) -> T | None"));
- py::enum_(module, "rcl_subscription_event_type_t")
+ nb::enum_(
+ module, "rcl_subscription_event_type_t", nb::is_arithmetic())
.value("RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED", RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED)
.value("RCL_SUBSCRIPTION_LIVELINESS_CHANGED", RCL_SUBSCRIPTION_LIVELINESS_CHANGED)
.value("RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS", RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS)
@@ -197,58 +210,59 @@ define_event_handle(py::module module)
.value("RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE", RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE)
.value("RCL_SUBSCRIPTION_MATCHED", RCL_SUBSCRIPTION_MATCHED);
- py::enum_(module, "rcl_publisher_event_type_t")
+ nb::enum_(
+ module, "rcl_publisher_event_type_t", nb::is_arithmetic())
.value("RCL_PUBLISHER_OFFERED_DEADLINE_MISSED", RCL_PUBLISHER_OFFERED_DEADLINE_MISSED)
.value("RCL_PUBLISHER_LIVELINESS_LOST", RCL_PUBLISHER_LIVELINESS_LOST)
.value("RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS", RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS)
.value("RCL_PUBLISHER_INCOMPATIBLE_TYPE", RCL_PUBLISHER_INCOMPATIBLE_TYPE)
.value("RCL_PUBLISHER_MATCHED", RCL_PUBLISHER_MATCHED);
- py::class_(
+ nb::class_(
module, "rmw_requested_deadline_missed_status_t")
- .def(py::init<>())
- .def_readonly("total_count", &rmw_requested_deadline_missed_status_t::total_count)
- .def_readonly("total_count_change", &rmw_requested_deadline_missed_status_t::total_count_change);
+ .def(nb::init<>())
+ .def_ro("total_count", &rmw_requested_deadline_missed_status_t::total_count)
+ .def_ro("total_count_change", &rmw_requested_deadline_missed_status_t::total_count_change);
- py::class_(module, "rmw_liveliness_changed_status_t")
- .def(py::init<>())
- .def_readonly("alive_count", &rmw_liveliness_changed_status_t::alive_count)
- .def_readonly("not_alive_count", &rmw_liveliness_changed_status_t::not_alive_count)
- .def_readonly("alive_count_change", &rmw_liveliness_changed_status_t::alive_count_change)
- .def_readonly("not_alive_count_change", &rmw_liveliness_changed_status_t::not_alive_count_change);
+ nb::class_(module, "rmw_liveliness_changed_status_t")
+ .def(nb::init<>())
+ .def_ro("alive_count", &rmw_liveliness_changed_status_t::alive_count)
+ .def_ro("not_alive_count", &rmw_liveliness_changed_status_t::not_alive_count)
+ .def_ro("alive_count_change", &rmw_liveliness_changed_status_t::alive_count_change)
+ .def_ro("not_alive_count_change", &rmw_liveliness_changed_status_t::not_alive_count_change);
- py::class_(module, "rmw_message_lost_status_t")
- .def(py::init<>())
- .def_readonly("total_count", &rmw_message_lost_status_t::total_count)
- .def_readonly("total_count_change", &rmw_message_lost_status_t::total_count_change);
+ nb::class_(module, "rmw_message_lost_status_t")
+ .def(nb::init<>())
+ .def_ro("total_count", &rmw_message_lost_status_t::total_count)
+ .def_ro("total_count_change", &rmw_message_lost_status_t::total_count_change);
- py::class_(
+ nb::class_(
module, "rmw_requested_qos_incompatible_event_status_t")
- .def(py::init<>())
- .def_readonly("total_count", &rmw_requested_qos_incompatible_event_status_t::total_count)
- .def_readonly(
+ .def(nb::init<>())
+ .def_ro("total_count", &rmw_requested_qos_incompatible_event_status_t::total_count)
+ .def_ro(
"total_count_change", &rmw_requested_qos_incompatible_event_status_t::total_count_change)
- .def_readonly(
+ .def_ro(
"last_policy_kind", &rmw_requested_qos_incompatible_event_status_t::last_policy_kind);
- py::class_(module, "rmw_offered_deadline_missed_status_t")
- .def(py::init<>())
- .def_readonly("total_count", &rmw_offered_deadline_missed_status_t::total_count)
- .def_readonly("total_count_change", &rmw_offered_deadline_missed_status_t::total_count_change);
+ nb::class_(module, "rmw_offered_deadline_missed_status_t")
+ .def(nb::init<>())
+ .def_ro("total_count", &rmw_offered_deadline_missed_status_t::total_count)
+ .def_ro("total_count_change", &rmw_offered_deadline_missed_status_t::total_count_change);
- py::class_(module, "rmw_liveliness_lost_status_t")
- .def(py::init<>())
- .def_readonly("total_count", &rmw_liveliness_lost_status_t::total_count)
- .def_readonly("total_count_change", &rmw_liveliness_lost_status_t::total_count_change);
+ nb::class_(module, "rmw_liveliness_lost_status_t")
+ .def(nb::init<>())
+ .def_ro("total_count", &rmw_liveliness_lost_status_t::total_count)
+ .def_ro("total_count_change", &rmw_liveliness_lost_status_t::total_count_change);
- py::class_(module, "rmw_matched_status_t")
- .def(py::init<>())
- .def_readonly("total_count", &rmw_matched_status_t::total_count)
- .def_readonly("total_count_change", &rmw_matched_status_t::total_count_change)
- .def_readonly("current_count", &rmw_matched_status_t::current_count)
- .def_readonly("current_count_change", &rmw_matched_status_t::current_count_change);
+ nb::class_