def get_action_clients_and_servers(*, node, action_name): action_clients = [] action_servers = [] expanded_name = expand_topic_name(action_name, node.get_name(), node.get_namespace()) validate_full_topic_name(expanded_name) node_names_and_ns = node.get_node_names_and_namespaces() for node_name, node_ns in node_names_and_ns: # Construct fully qualified name node_fqn = '/'.join(node_ns) + node_name # Get any action clients associated with the node client_names_and_types = rclpy.action.get_action_client_names_and_types_by_node( node, node_name, node_ns, ) for client_name, client_types in client_names_and_types: if client_name == expanded_name: action_clients.append((node_fqn, client_types)) # Get any action servers associated with the node server_names_and_types = rclpy.action.get_action_server_names_and_types_by_node( node, node_name, node_ns, ) for server_name, server_types in server_names_and_types: if server_name == expanded_name: action_servers.append((node_fqn, server_types)) return (action_clients, action_servers)
def subscriber(node: Node, topic_name: str, message_type: MsgType, callback: Callable[[MsgType], Any], qos_profile: QoSProfile) -> Optional[str]: """Initialize a node with a single subscription and spin.""" if message_type is None: topic_names_and_types = get_topic_names_and_types( node=node, include_hidden_topics=True) try: expanded_name = expand_topic_name(topic_name, node.get_name(), node.get_namespace()) except ValueError as e: raise RuntimeError(e) try: validate_full_topic_name(expanded_name) except rclpy.exceptions.InvalidTopicNameException as e: raise RuntimeError(e) for n, t in topic_names_and_types: if n == expanded_name: if len(t) > 1: raise RuntimeError( "Cannot echo topic '%s', as it contains more than one type: [%s]" % (topic_name, ', '.join(t))) message_type = t[0] break else: raise RuntimeError( 'Could not determine the type for the passed topic') msg_module = get_message(message_type) node.create_subscription(msg_module, topic_name, callback, qos_profile) rclpy.spin(node)
def _get_msg_class(node, topic, include_hidden_topics): """ Get message module based on topic name. :param topic: topic name, ``list`` of ``str`` """ topic_names_and_types = get_topic_names_and_types( node=node, include_hidden_topics=include_hidden_topics) try: expanded_name = expand_topic_name(topic, node.get_name(), node.get_namespace()) except ValueError as e: raise RuntimeError(e) try: validate_full_topic_name(expanded_name) except rclpy.exceptions.InvalidTopicNameException as e: raise RuntimeError(e) for n, t in topic_names_and_types: if n == expanded_name: if len(t) > 1: raise RuntimeError( "Cannot echo topic '%s', as it contains more than one type: [%s]" % (topic, ', '.join(t))) message_type = t[0] break else: # Could not determine the type for the passed topic return None return import_message_type(topic, message_type)
def subscriber(node, topic_name, message_type, callback): if message_type is None: topic_names_and_types = get_topic_names_and_types( node=node, include_hidden_topics=True) try: expanded_name = expand_topic_name(topic_name, node.get_name(), node.get_namespace()) except ValueError as e: raise RuntimeError(e) try: validate_full_topic_name(expanded_name) except rclpy.exceptions.InvalidTopicNameException as e: raise RuntimeError(e) for n, t in topic_names_and_types: if n == expanded_name: if len(t) > 1: raise RuntimeError( "Cannot echo topic '%s', as it contains more than one type: [%s]" % (topic_name, ', '.join(t))) message_type = t[0] break else: raise RuntimeError( 'Could not determine the type for the passed topic') msg_module = import_message_type(topic_name, message_type) node.create_subscription(msg_module, topic_name, callback, qos_profile_sensor_data) while rclpy.ok(): rclpy.spin_once(node)
def test_validate_full_topic_name_failures_services(self): # service name may not contain '?' with self.assertRaisesRegex(InvalidServiceNameException, 'must not contain characters'): validate_full_topic_name('/invalid_service?', is_service=True) # service name must start with / with self.assertRaisesRegex(InvalidServiceNameException, 'must be absolute'): validate_full_topic_name('invalid_service', is_service=True)
def test_validate_full_topic_name_failures(self): # topic name may not contain '?' with self.assertRaisesRegex(InvalidTopicNameException, 'must not contain characters'): validate_full_topic_name('/invalid_topic?') # topic name must start with / with self.assertRaisesRegex(InvalidTopicNameException, 'must be absolute'): validate_full_topic_name('invalid_topic')
def _validate_topic_or_service_name(self, topic_or_service_name, *, is_service=False): name = self.get_name() namespace = self.get_namespace() validate_node_name(name) validate_namespace(namespace) validate_topic_name(topic_or_service_name, is_service=is_service) expanded_topic_or_service_name = expand_topic_name(topic_or_service_name, name, namespace) validate_full_topic_name(expanded_topic_or_service_name, is_service=is_service)
def test_validate_full_topic_name(self): tests = [ '/chatter', '/node_name/chatter', '/ns/node_name/chatter', ] for topic in tests: # Will raise if invalid validate_full_topic_name(topic)
def subscriber(node, topic_name, message_type, callback): if message_type is None: topic_names_and_types = get_topic_names_and_types(node=node) try: expanded_name = expand_topic_name(topic_name, node.get_name(), node.get_namespace()) except ValueError as e: raise RuntimeError(e) try: validate_full_topic_name(expanded_name) except rclpy.exceptions.InvalidTopicNameException as e: raise RuntimeError(e) for n, t in topic_names_and_types: if n == expanded_name: if len(t) > 1: raise RuntimeError( "Cannot echo topic '%s', as it contains more than one type: [%s]" % (topic_name, ', '.join(t))) message_type = t[0] break else: raise RuntimeError( 'Could not determine the type for the passed topic') # TODO(dirk-thomas) this logic should come from a rosidl related package try: package_name, message_name = message_type.split('/', 2) if not package_name or not message_name: raise ValueError() except ValueError: raise RuntimeError('The passed message type is invalid') module = importlib.import_module(package_name + '.msg') msg_module = getattr(module, message_name) node.create_subscription(msg_module, topic_name, callback, qos_profile=qos_profile_sensor_data) while rclpy.ok(): rclpy.spin_once(node)
def _get_msg_class(node, topic): """ Get message module based on topic name. :param topic: topic name, ``list`` of ``str`` """ topic_names_and_types = get_topic_names_and_types(node=node) try: expanded_name = expand_topic_name(topic, node.get_name(), node.get_namespace()) except ValueError as e: raise RuntimeError(e) try: validate_full_topic_name(expanded_name) except rclpy.exceptions.InvalidTopicNameException as e: raise RuntimeError(e) for n, t in topic_names_and_types: if n == expanded_name: if len(t) > 1: raise RuntimeError( "Cannot echo topic '%s', as it contains more than one type: [%s]" % (topic, ', '.join(t))) message_type = t[0] break else: # Could not determine the type for the passed topic return None # TODO(dirk-thomas) this logic should come from a rosidl related package try: package_name, message_name = message_type.split('/', 2) if not package_name or not message_name: raise ValueError() except ValueError: raise RuntimeError('The passed message type is invalid') module = importlib.import_module(package_name + '.msg') return getattr(module, message_name)