[Documentation] [TitleIndex] [WordIndex

Bagys and Map Bagys

ROSH provides libraries for two types of YAML-based message storage: bagys and map bagys. Regular bagys, just like ROS bags, store a sequence of messages. Map bagys are like Python dictionaries: they store a mapping between a key and a message.

Bagys

Bagys are like ROS bags, except they are based on a human-readable YAML format. They also have some other key differences:

  1. The message type is not stored in the bagy
  2. (Corollary) They can only store a single message type
  3. The do not record message receipt time

The format for bagys is identical to the output of rostopic echo and rosservice call. This means that the bagy equivalent of rosbag record is simply:

rostopic echo /my_topic > file.bagy

Similarly, the bagy format is is identical to the input of rostopic pub and rosservice call. That means that it is possible to echo a single bagy message into either of these tools. In the future, this will be improved upon.

Writing to a bagy

bagys have an API similar to files, i.e. open().

Using with statement

Explicit close()

Recording a bagy

If you don't want to write messages individually to a bagy, you can setup a bagy to record a single topic. You can call stop() and start() to pause/resume the recording.

WARNING: bagy recording within ROSH is not high performance.

b = Bagy('record.bagy', 'w')
b.record(topics.rosout_agg)
b.stop()
b.start()
b.close()

Reading from a bagy

There are a variety of ways of reading from a bagy, depending on your needs.

Read all messages into a list

Iterate over messages

Read messages one by one

Advanced: Homographs

It is possible to record a bagy with one message type and read it back as another provided that the type you are reading into has at least the fields present in the original type, and the fields are of compatible types. For example, geometry_msgs/Vector3 vs. geometry_msgs/Point have identical specifications.

There are several potential use cases for this:

You can also manually create "sparse" bagys, where you only store only a subset of the message's fields. When you load from the bagy, the rest of the fields will get default value assignments.

Recipe: Bagy-based Service

This creates the get_outlets service. In this particular case, our bagy contains a list of poses that we want to return.

with Bagy(findros('foo', 'outlet_poses.yaml'), srv.pr2_plugs_msgs.GetOutletsResponse) as b:
  resp = b.read()[0] # assume only one message in file
Service('get_outlets', srv.pr2_plugs_msgs.GetOutlets, lambda x: resp)
serve_forever()

Map Bagys

Map bagys are bagys that are indexed by keys. Whereas normal bagys are useful for storing a sequence of messages, map bagys are useful for storing a dictionary of messages.

Creating a map bagy

Map bagys have a file-like API, though there are various ways you can choose to write data to them.

Dictionary style

Explicit write()

Keyword style

Reading from a key bagy

Read entire bagy into dictionary

Iterator style (default iterator iterates over keys and msgs)

Dictionary style

Recipe: Map-Bagy-based Service

This creates a fictional get_outlet service. In this particular case, our bagy contains a list of poses that we want to return, indexed by name. Our fictional query has a single name field that specifies which outlet we want.

with MapBagy(findros('foo', 'outlet_db.yaml'), srv.pr2_plugs_msgs.GetOutletResponse) as b:
  responses = b.read()
Service('get_outlets', srv.pr2_plugs_msgs.GetOutlet, lambda x: responses[x.name])
serve_forever()

2023-10-28 12:59