diff --git a/rclpy/rclpy/__init__.py b/rclpy/rclpy/__init__.py index 39d589e7a..abdd91e8d 100644 --- a/rclpy/rclpy/__init__.py +++ b/rclpy/rclpy/__init__.py @@ -49,7 +49,7 @@ from rclpy.context import Context from rclpy.parameter import Parameter -from rclpy.qos import qos_profile_system_default +from rclpy.qos import qos_profile_rosout_default from rclpy.qos import QoSProfile from rclpy.signals import install_signal_handlers from rclpy.signals import SignalHandlerOptions @@ -217,7 +217,7 @@ def create_node( namespace: Optional[str] = None, use_global_arguments: bool = True, enable_rosout: bool = True, - rosout_qos_profile: Optional[Union[QoSProfile, int]] = qos_profile_system_default, + rosout_qos_profile: Optional[Union[QoSProfile, int]] = qos_profile_rosout_default, start_parameter_services: bool = True, parameter_overrides: Optional[List[Parameter]] = None, allow_undeclared_parameters: bool = False, diff --git a/rclpy/rclpy/impl/_rclpy_pybind11.pyi b/rclpy/rclpy/impl/_rclpy_pybind11.pyi index f348b2519..6d4a0ca9b 100644 --- a/rclpy/rclpy/impl/_rclpy_pybind11.pyi +++ b/rclpy/rclpy/impl/_rclpy_pybind11.pyi @@ -430,7 +430,8 @@ class Timer(Destroyable): 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_parameter_events', 'qos_profile_best_available', + 'qos_profile_rosout_default'] class rmw_qos_profile_dict(TypedDict): diff --git a/rclpy/rclpy/node.py b/rclpy/rclpy/node.py index e66e82ae9..403525acc 100644 --- a/rclpy/rclpy/node.py +++ b/rclpy/rclpy/node.py @@ -74,7 +74,7 @@ from rclpy.publisher import Publisher from rclpy.qos import qos_profile_parameter_events from rclpy.qos import qos_profile_services_default -from rclpy.qos import qos_profile_system_default +from rclpy.qos import qos_profile_rosout_default from rclpy.qos import QoSProfile from rclpy.qos_overriding_options import _declare_qos_parameters from rclpy.qos_overriding_options import QoSOverridingOptions @@ -140,7 +140,7 @@ def __init__( namespace: Optional[str] = None, use_global_arguments: bool = True, enable_rosout: bool = True, - rosout_qos_profile: Optional[Union[QoSProfile, int]] = qos_profile_system_default, + rosout_qos_profile: Optional[Union[QoSProfile, int]] = qos_profile_rosout_default, start_parameter_services: bool = True, parameter_overrides: Optional[List[Parameter[Any]]] = None, allow_undeclared_parameters: bool = False, diff --git a/rclpy/rclpy/qos.py b/rclpy/rclpy/qos.py index 4c9dc0745..d80f3d162 100644 --- a/rclpy/rclpy/qos.py +++ b/rclpy/rclpy/qos.py @@ -479,13 +479,15 @@ class LivelinessPolicy(QoSPolicyEnum): #: can occur due to races with discovery. qos_profile_best_available = QoSProfile(**_rclpy.rmw_qos_profile_t.predefined( 'qos_profile_best_available').to_dict()) - # Separate rcl_action profile defined at # ros2/rcl : rcl/rcl_action/include/rcl_action/default_qos.h # #: For actions, using reliable reliability, transient-local durability. qos_profile_action_status_default = QoSProfile(**_rclpy.rclpy_action_get_rmw_qos_profile( 'rcl_action_qos_profile_status_default')) +#: The default qos profile setting for topic /rosout publisher. +qos_profile_rosout_default = QoSProfile(**_rclpy.rmw_qos_profile_t.predefined( + 'qos_profile_rosout_default').to_dict()) class QoSPresetProfiles(Enum): @@ -498,6 +500,7 @@ class QoSPresetProfiles(Enum): PARAMETER_EVENTS = qos_profile_parameter_events ACTION_STATUS_DEFAULT = qos_profile_action_status_default BEST_AVAILABLE = qos_profile_best_available + ROSOUT_DEFAULT = qos_profile_rosout_default """Noted that the following are duplicated from QoSPolicyEnum. diff --git a/rclpy/src/rclpy/qos.cpp b/rclpy/src/rclpy/qos.cpp index 324b78013..76778a4d6 100644 --- a/rclpy/src/rclpy/qos.cpp +++ b/rclpy/src/rclpy/qos.cpp @@ -152,6 +152,9 @@ predefined_qos_profile_from_name(const char * qos_profile_name) if (0 == strcmp(qos_profile_name, "qos_profile_best_available")) { return rmw_qos_profile_best_available; } + if (0 == strcmp(qos_profile_name, "qos_profile_rosout_default")) { + return rmw_qos_profile_rosout_default; + } std::string error_text = "Requested unknown rmw_qos_profile: "; error_text += qos_profile_name; diff --git a/rclpy/test/test_create_node.py b/rclpy/test/test_create_node.py index e9fd80a10..308d1f186 100644 --- a/rclpy/test/test_create_node.py +++ b/rclpy/test/test_create_node.py @@ -16,11 +16,15 @@ import rclpy +from rclpy.duration import Duration from rclpy.exceptions import InvalidNamespaceException from rclpy.exceptions import InvalidNodeNameException from rclpy.parameter import Parameter -from rclpy.qos import qos_profile_sensor_data - +from rclpy.qos import QoSDurabilityPolicy +from rclpy.qos import QoSHistoryPolicy +from rclpy.qos import QoSLivelinessPolicy +from rclpy.qos import QoSProfile +from rclpy.qos import QoSReliabilityPolicy class TestCreateNode(unittest.TestCase): @@ -33,6 +37,34 @@ def setUpClass(cls): def tearDownClass(cls): rclpy.shutdown(context=cls.context) + def assert_qos_equal(self, expected_qos_profile, actual_qos_profile, *, is_publisher): + # Depth and history are skipped because they are not retrieved. + self.assertEqual( + expected_qos_profile.durability, + actual_qos_profile.durability, + 'Durability is unequal') + self.assertEqual( + expected_qos_profile.reliability, + actual_qos_profile.reliability, + 'Reliability is unequal') + if is_publisher: + self.assertEqual( + expected_qos_profile.lifespan, + actual_qos_profile.lifespan, + 'lifespan is unequal') + self.assertEqual( + expected_qos_profile.deadline, + actual_qos_profile.deadline, + 'Deadline is unequal') + self.assertEqual( + expected_qos_profile.liveliness, + actual_qos_profile.liveliness, + 'liveliness is unequal') + self.assertEqual( + expected_qos_profile.liveliness_lease_duration, + actual_qos_profile.liveliness_lease_duration, + 'liveliness_lease_duration is unequal') + def test_create_node(self) -> None: node_name = 'create_node_test' rclpy.create_node(node_name, context=self.context).destroy_node() @@ -88,22 +120,33 @@ def test_create_node_disable_rosout(self): namespace = '/ns' node = rclpy.create_node( node_name, namespace=namespace, context=self.context, enable_rosout=False) + # topic /rosout publisher should not exist + self.assertFalse(node.get_publishers_info_by_topic('/rosout')) node.destroy_node() def test_create_node_rosout_qos_profile(self): - node_name = 'create_node_test_rosout_rosout_qos_profile' - namespace = '/ns' - node = rclpy.create_node( - node_name, namespace=namespace, context=self.context, enable_rosout=True, - rosout_qos_profile=qos_profile_sensor_data) - node.destroy_node() - - def test_create_node_rosout_qos_depth(self): - node_name = 'create_node_test_rosout_rosout_qos_depth' + test_qos_profile = QoSProfile( + depth=10, + history=QoSHistoryPolicy.KEEP_ALL, + deadline=Duration(seconds=1, nanoseconds=12345), + lifespan=Duration(seconds=20, nanoseconds=9887665), + reliability=QoSReliabilityPolicy.BEST_EFFORT, + durability=QoSDurabilityPolicy.TRANSIENT_LOCAL, + liveliness_lease_duration=Duration(seconds=5, nanoseconds=23456), + liveliness=QoSLivelinessPolicy.MANUAL_BY_TOPIC) + node_name = 'create_node_test_rosout_qos_profile' namespace = '/ns' node = rclpy.create_node( node_name, namespace=namespace, context=self.context, enable_rosout=True, - rosout_qos_profile=10) + rosout_qos_profile=test_qos_profile) + publisher_list = node.get_publishers_info_by_topic('/rosout') + # only test node /rosout topic publisher should exist + self.assertEqual(1, len(publisher_list)) + self.assertEqual(node.get_name(), publisher_list[0].node_name) + self.assertEqual(node.get_namespace(), publisher_list[0].node_namespace) + actual_qos_profile = publisher_list[0].qos_profile + # QoS should match except depth and history cz that are not retrieved from rmw. + self.assert_qos_equal(test_qos_profile, actual_qos_profile, is_publisher=True) node.destroy_node()