Only released in EOL distros:  

As of ROS 1.3.0, rosbagmigration has been deprecated.

Please see rosbag/migration

Rule Files

Rule files define one or more Python classes which subclass rosbagmigration.MessageUpdateRule and override the appropriate fields and functions. Since they take a specific form, we use the extention .bmr (bag migration rule) in place of the typical .py extension.

The following fields must be overridden:

  • old_type: The full type of the old message.

  • old_full_text: The full message text.

    • If necessary, this can be generated from a message using: rosrun rosbagmigration savemsg.py msgname

  • new_type: The full type of the new message.

  • new_full_text: The full message text.

    • If necessary, this can be generated from a message using: rosrun rosbagmigration savemsg.py msgname

  • order: Every message with the same old_type must have a unique order number which constains the order in which they are chained together. Ordering is from lowest to highest order number.

  • migrated_types: A list of pairs of ("oldsubtype", "newsubtype") which can be used with the migrate helper function.

  • valid: This must be set to True manually to verify that a human has interacted with the rule file.

The following method must be overridden:

  • update(self, old_msg, new_msg): The instance of new_msg passed into this function should be populated from the old_msg.

The update function

For the most part just about all of the rule definition will be generated for you by rosbag check or makerule.py. The place where the most user intervention is necessary is the update function. The update function takes two inputs: old_msg, and new_msg. The intent is to fill in the fields of new_msg appropriately with a combination of default values or values moved over from old_msg.

There are a few important helper classes to make this substantially easier:

  • self.migrate(old_sub_msg, new_sub_msg) can be used to migrate a sub-message. This migration has the full power of the message migration system behind it and will make use of all available rules (including those defined later in the file).

  • self.get_new_class(type_name) returns a Python class corresponding to the name of the type passed to it. Important: only instantiate classes using this approach. Never use a message definition imported from a system package as it means the update rule will break in the future if the system definition of the message ever changes.

  • self.migrate_array(old_sub_msg_array, new_sub_msg_array, type_name) works to migrate an array instead of a sub-message. The extra argument, type_name, is necessary since in most cases; new_sub_msg_array is a empty. type_name will be internally passed through to get_new_class.

An example rule file for a message and its sub-message. Note: With the exception of changing the valid member to True, this entire file was generated by following the directions in Migrating Messages.

class update_mypkg_MyMsg_cdeceeac6a1a98788dbcb8bf5f31b49b(MessageUpdateRule):
        old_type = "mypkg/MyMsg"
        old_full_text = """
MySubMsg data

================================================================================
MSG: mypkg/MySubMsg
int32 field1
string field2
"""

        new_type = "mypkg/MyMsg"
        new_full_text = """
MySubMsg data
MySubMsg more_data

================================================================================
MSG: mypkg/MySubMsg
int32 field1
string field2
float64 another_field
"""

        order = 0
        migrated_types = [("MySubMsg","MySubMsg")]

        valid = True

        def update(self, old_msg, new_msg):
                self.migrate(old_msg.data, new_msg.data)
                #No matching field name in old message
                new_msg.more_data = self.get_new_class('MySubMsg')()

class update_mypkg_MySubMsg_4b12e5ff694b0e2a31b2ea9e0bd900f4(MessageUpdateRule):
        old_type = "mypkg/MySubMsg"
        old_full_text = """
int32 field1
string field2
"""

        new_type = "mypkg/MySubMsg"
        new_full_text = """
int32 field1
string field2
float64 another_field
"""

        order = 0
        migrated_types = []

        valid = True

        def update(self, old_msg, new_msg):
                new_msg.field1 = old_msg.field1
                new_msg.field2 = old_msg.field2
                #No matching field name in old message
                new_msg.another_field = 0.

Migrating Messages

Preferred Approach to Making Rules

Rather than generating rules from bag files after the fact, the preferred approach is to generate the necessary rules at the time that the message is migrated. There are 2 scripts for making this fairly easy to do. savemsg.py and makerule.py

savemsg.py allows you to save a full message definition in a temporary file so that when you modify it you can create a rule between the original and the new version.

makerule.py generates a migration rule between a saved instance of a message and a message currently defined in the system. It is functionally equivalent to creating a recording, except that the file format is human readable for convenience.

For example, in a tree at a revision that contains the old copy of your message:

$ roscd mypkg
$ rosmake mypkg
$ rosrun rosbagmigration savemsg.py mypkg/MyMsg > MyMsg.saved

Now, edit your Message, or change revisions to the revision containing the new copy of your message.

Make sure to rebuild in the tree with the new definition, and then you can generate a rule:

$ rosmake mypkg
$ rosrun rosbagmigration makerule.py MyMsg.saved myrule.bmr

If you have moved the message, it will prompt you for the new location.

Now you can edit the file myrule.bmr according to Rule Files.

Finally, if you want the rule to be permanently exported for people to use, add:

<depend package="rosbagmigration"/>
<export>
  <rosbagmigration rule_file="myrule.bmr"/>
</export>

to your manifest file. This will cause the rule file to be automatically get loaded whenever the message migrator is instantiated.

NOTE: in order for a plugin to be exported correctly, you must depend on the package the plugin is used for. In this case your package MUST have a dependency on rosbagmigration to export migration rules.

Alternative Approach to Making Rules

rosbag check can also be used to populate most of the rule templates for you so long as the type names still match.

To generate rules:

$ rosbag check in.bag -g myrules.bmr 

Note: Using this functionality is not generally advised for creating permanent rules to check into the system. Creating rules directly from arbitrarily old bag files is likely to skip intermediate changes and lead to ordering confusion. However, if a bag is missing rules, this is intended to be the quickest pathway to making it functional.

At this point, you will need to edit myrules.bmr by hand. See Rule Files for more info.

To make sure your rules are sufficient, you can now pass the rule file into rosbag check explicitly:

$ rosbag check in.bag myrules.bmr

Wiki: rosbagmigration (last edited 2010-10-14 23:09:04 by JeremyLeibs)