-
Notifications
You must be signed in to change notification settings - Fork 166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ros2 node get_type_description initial implementation #846
base: rolling
Are you sure you want to change the base?
Add ros2 node get_type_description initial implementation #846
Conversation
@clalancette could I get a reviewer assignment for this? (or @audrow @gbiggs friendly ping) |
Signed-off-by: Emerson Knapp <[email protected]>
adba69e
to
1703c0b
Compare
Signed-off-by: Emerson Knapp <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be nice to have test for topic.
if ns != 'msg': | ||
raise RuntimeError( | ||
f'Currently cannot auto-discover hashes for "{ns}", only "msg". ' | ||
'Please provide type_hash value to command.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of curiosity, how user can get type_hash for srv
or action
? that would be helpful to add here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately it is not exposed to user anywhere except in the source code
ros2/rmw#356 might help a little, but it's not the whole story. I think we need to change the signatures of Node::get_[service|topic]_names_and_types
, or provide a new alternative API something like
struct InterfaceType {
std::string name;
rosidl_type_hash_t hash;
};
std::vector<std::string, std::vector<InterfaceType>> get_topic_names_and_types;
|
||
rclpy.init() | ||
node = rclpy.create_node(f'{NODE_NAME_PREFIX}_td_requester_{os.getpid()}') | ||
cli = node.create_client(GetTypeDescription, '/talker/get_type_description') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cli = node.create_client(GetTypeDescription, '/talker/get_type_description') | |
cli = node.create_client(GetTypeDescription, service_name) |
if not cli.wait_for_service(timeout_sec=5.0): | ||
raise RuntimeError(f'Service {service_name} not found') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about waiting until service is ready, unless user sends the signal to stop? i would have timeout option instead of static timeout that user cannot even see how long it waits.
if not cli.wait_for_service(timeout_sec=5.0): | |
raise RuntimeError(f'Service {service_name} not found') | |
cli.wait_for_service() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emersonknapp In general looks good to me.
I only have a few minor concerns, especially about formatting output
formatting with
- capacity 255
could be a bit confusing especially if the afterward will be printed out the default value. It is gonna look like FIELD_TYPE_INT8_ARRAY - capacity 25 = 0
I agree that if we had ros2/rmw#356 implemented it would significantly simplify the search for hashes.
I also thinking about why we require to provide a hash when doing a service request for get_type_description
?
What if make the hash field optional and the service will return a list of types with hashes?
It will be a client-side responsibility to verify hashes and determine which type is really interesting.
IMO this way everybody's life would be much easier 😃
Update: @emersonknapp it would be nice to have some tests.
from type_description_interfaces.srv import GetTypeDescription | ||
|
||
|
||
def print_field_type(ft): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name print_field_type
is a bit misleading since it doesn't print anything.
IMO it would be more appropriate to rename it to the get_field_type_str
or something similar.
if ft.string_capacity: | ||
type_str += f' - string_capacity {ft.string_capacity}' | ||
if ft.capacity: | ||
type_str += f' - capacity {ft.capacity}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ft.string_capacity: | |
type_str += f' - string_capacity {ft.string_capacity}' | |
if ft.capacity: | |
type_str += f' - capacity {ft.capacity}' | |
if ft.string_capacity: | |
type_str += f' string_capacity({ft.string_capacity})' | |
if ft.capacity: | |
type_str += f' capacity({ft.capacity})' |
IMO formatting with - capacity 255
could be a bit confusing especially if afterward will be printed out the dafult value. It is gonna look like FIELD_TYPE_INT8_ARRAY - capacity 25 = 0
if field.default_value: | ||
field_string += f' = {field.default_value}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if field.default_value: | |
field_string += f' = {field.default_value}' | |
if field.default_value: | |
field_string += f' default({field.default_value})' |
print() | ||
print('Referenced Type Descriptions:') | ||
for rtd in td.referenced_type_descriptions: | ||
print_individual_type_description(rtd, indent=2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Printing 'Referenced Type Descriptions:'
make sense only if td.referenced_type_descriptions
is not empty
|
||
|
||
def discover_hash_for_type(node, remote_node_name, type_name): | ||
# TODO(emersonknapp) get hashes from names_and_types when that is implemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a reference to the tracking issue ros2/rmw#356 in the TODO comment.
Replaces #817
Implements a first pass at
ros2 node get_type_description
. It does its best to autofill the type hash so the user doesn't have to, but given the limitations of the current API this is only possible formsg
on pub/sub topics, not for srv/action. For those, the hash must be provided manually by the user, though it is not discoverable via any existing API.Sample output:
I think we should move forward with putting this in, as it covers the majority use case. Further discussion follows:
names_and_types
, then use that to go toget_x_info_by_topic
in order to getTopicEndpointInfo
to find the hash. Extendnames_and_types
to contain type hashes rmw#356 would make this part easier and support srv/actionGetTypeDescription
should allow for either (but not both) to be empty in the request, so that the requesting client doesn't necessarily even need to know both pieces of information. From a user point of view, it seems very natural to say "you node, give me your description for mypackage/msg/Foo". It also seems like it could come up, though less commonly, to request "you node, what is the type that has hash RIHS01_e28ce254ca8abc06abf92773b74602cdbf116ed34fbaf294fb9f81da9f318eac". The current underlying implementation inrcl
assumes the hash is the more important piece of information, using it as the key to its cache, but this usage reveals that it's probably more likely we wish to fetch this information by typename, using the hash as a potential validation. HOWEVER - all that aside, with Extendnames_and_types
to contain type hashes rmw#356 the "discovery" would be much simpler and so alleviate some of my concern with this point.