Document the `offered_qos_profiles` argument of `TopicMetadata`
asymingt opened this issue · 3 comments
Description
Right now it's not clear how to use the offered_qos_profiles
argument of TopicMetadata
in the rosbag2_py
API. By looking at the source code I have worked out that it's stringified YAML but I can't work out the exact syntax. Looking at the QoS overrides syntax, I would assume that it's something like this:
import rosbag2_py
offered_qos_profiles = """
- reliability : reliable
durability: volatile
history: keep_last
depth: 100
"""
topic_metadata = rosbag2_py.TopicMetadata(
name="/clock",
type="rosgraph_msgs/msg/Clock",
offered_qos_profiles=offered_qos_profiles,
serialization_format="cdr")
Or possibly something like this:
import yaml
import rosbag2_py
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSDurabilityPolicy, QoSHistoryPolicy
offered_qos_profiles = yaml.dump([{
"reliability" : int(QoSReliabilityPolicy.RELIABLE),
"durability": int(QoSDurabilityPolicy.VOLATILE),
"history": int(QoSHistoryPolicy.KEEP_LAST),
"depth": 100}], default_flow_style=True)
topic_metadata = rosbag2_py.TopicMetadata(
name="/clock",
type="rosgraph_msgs/msg/Clock",
offered_qos_profiles=offered_qos_profiles,
serialization_format="cdr")
In both cases there is no runtime error and the bag superficially looks good:
$ ros2 bag info preprocess.bag
Files: preprocess.bag_0.mcap
Bag size: 2.4 MiB
Storage id: mcap
Duration: 4290.0s
Start: Oct 12 2015 12:00:00.0 (1444651200.0)
End: Oct 12 2015 13:11:30.0 (1444655490.0)
Messages: 42901
Topic information: Topic: /clock | Type: rosgraph_msgs/msg/Clock | Count: 42901 | Serialization Format: cdr
The trouble is when you try and play it, then you get this error:
$ ros2 bag bag play preprocess.bag
[INFO] [1689265071.129672762] [rosbag2_player]: Set rate to 1
invalid node; this may result from using a map iterator as a sequence iterator, or vice-versa
I have confirmed that removing offered_qos_profiles=offered_qos_profiles
from the TopicMetadata
constructor removed warning at the cost of losing QoS information.
Related Issues
None
Completion Criteria
Need to have: A section in the root README that provides a short guide on how to get the QoS syntax correct to ensure that the offered profiles are parseable at runtime.
Nice to have: at bag generation time, issue a warning or error if the profiles are not readable when you call writer.create_topic(topic_metadata)
.
Implementation Notes / Suggestions
I'd be happy to implement this feature if you show me one example of how to get this working. I still am unable to the the offered QoS profiles stringified YAML syntax correct.
Testing Notes / Suggestions
A test showing that an unparseable offered_qos_profiles
value results in a warning or error being thrown when writer.create_topic(topic_metadata)
is called.
I was able to work out the serialization scheme by poking around an existing working bag, and I found this:
>>> bag_file = os.path.join(get_package_prefix('my_test'), 'bags', 'example.bag')
>>> storage_options, converter_options = get_rosbag_options(bag_file, 'sqlite3')
>>> reader = rosbag2_py.SequentialReader()
>>> reader.open(storage_options, converter_options)
[INFO] [1689268155.189086900] [rosbag2_storage]: Opened database for READ_ONLY.
>>> tm = reader.get_all_topics_and_types()
>>> tm[0]
>>> tm[0].offered_qos_profiles
'- history: 3\n depth: 0\n reliability: 1\n durability: 2\n deadline:\n sec: 9223372036\n nsec: 854775807\n lifespan:\n sec: 9223372036\n nsec: 854775807\n liveliness: 1\n liveliness_lease_duration:\n sec: 9223372036\n nsec: 854775807\n avoid_ros_namespace_conventions: false'
Looking deeper, it seems like something of this form should work:
qos_profile = QoSProfile(depth=10,
reliability=QoSReliabilityPolicy.RELIABLE,
durability=QoSDurabilityPolicy.TRANSIENT_LOCAL)
qos_profile_dict = yaml.dump([qos_profile.get_c_qos_profile().to_dict()])
... but it doesn't quite handle the Duration
types correctly and you get this:
TypeError: cannot pickle 'rclpy._rclpy_pybind11.rcl_duration_t' object
Offered QoS profiles is, agreed, a pretty awkward part of this data structure. It was implemented that way as a workaround for some circular dependencies, long ago. It could use some rework - I even opened #1197 but there just hasn't been time to finish it.
The source for how the YAML is serialized/deserialized is in https://github.com/ros2/rosbag2/blob/rolling/rosbag2_transport/src/rosbag2_transport/qos.cpp - hopefully that can give some more insight into the structure. Any PR to the README would be welcome for review.
@asymingt We recently made structural changes and cleanup in the scope of the #1476 and now we are using std::vector<rclcpp::QoS> offered_qos_profiles;
in the TopicMetadata
instead of the previous serialized version of qos_profiles.
Now it is pretty clear and obvious what parameters should correspond to what value in this data structure since now it is a rclcpp::QoS
structure and pretty much corresponds to the dedicated section in the readme file Overriding QoS Profiles
- Closing this issue as done in the scope of the #1476.
Feel free to reopen if you think more changes are needed.