-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Hi,
I came across an issue of set_message_fields
not handling the Byte
type correctly. Please take a look at the cases below.
Cases
- Directly via ros2cli
$ ros2 topic pub --once /dummy_topic std_msgs/Byte '{data: "\x00"}'
Failed to populate field: Value '' is expected to be a dictionary but is a str
$ ros2 topic pub --once /dummy_topic std_msgs/Byte "{data: '\x00'}"
Failed to populate field: Value '\x00' is expected to be a dictionary but is a str
- Invoking
message_to_yaml
and thenset_message_fields
#!/usr/bin/python3
from rosidl_runtime_py import set_message_fields, message_to_yaml
import yaml
from std_msgs.msg import Byte
msg = Byte()
print(msg) # std_msgs.msg.Byte(data=b'\x00')
msg_yaml = message_to_yaml(msg)
print(msg_yaml) # data: "\0"
# mimic the behavior of ros2 topic pub
values_dictionary = yaml.safe_load(msg_yaml)
print(values_dictionary) # {'data': '\x00'}
set_message_fields(msg, values_dictionary) # fails
I end up getting the following error:
Traceback (most recent call last):
File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 55, in set_message_fields
value = field_type(field_value)
TypeError: string argument without an encoding
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 39, in set_message_fields
items = values.items()
AttributeError: 'str' object has no attribute 'items'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "p.py", line 8, in <module>
set_message_fields(msg, values_dictionary)
File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 58, in set_message_fields
set_message_fields(value, field_value)
File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 41, in set_message_fields
raise TypeError(
TypeError: Value '' is expected to be a dictionary but is a str
Reason
When message_to_yaml
processes a message and returns a YAML string, the byte string is no longer of type 'byte' because _convert_value
coverts the byte to a string. When this YAML string is loaded as a dictionary through yaml.safe_load(values)
and set_message_fields
is invoked with this dictionary, the data e.g., "\x00", is regarded as a string, while the type information claims it's a byte.
Thoughts / suggestions
I am aware that a byte-typed data can be published via the following command:
$ ros2 topic pub --once /dummy std_msgs/Byte "{data: {0}}"
However, as per the docstring, message_to_yaml
"Converts a ROS message to a YAML string", and ros2 topic pub
takes args as a YAML string (doc), an attempt to publish a byte message converted with message_to_yaml
should not fail.
In addition, ros2interface proto
, which relies on message_to_yaml
to show the prototype of a message, prints the following result, which can mislead the users into trying to publish a byte as advised and fail.
$ ros2 interface proto std_msgs/msg/Byte
"data: "\0"
"
$ ros2 topic pub --once /dummy std_msgs/Byte "{data: '\0'}"
Failed to populate field: Value '\0' is expected to be a dictionary but is a str
So, I think either
message_to_yaml
should return "data: {value}" if datatype is byte, orset_message_fields
should be modified to be able to tell a string from an escaped byte..
What do you think?
Thanks!