Detailed use of ROS1 rosbag, and use python to merge bag packages

When using ros, rosbag is often used to record or playback algorithms, which is a very useful tool.

List of rosbag commands

Order effect
record Record a package and specify a topic
info Summarize the details of a package
play Play back one or more packages, and you can specify a topic
check Determine if a pack is playable on the current system, or if it can be migrated
fix Fix a package so that it can be played on the current system
filter Convert package content via python script
compress Archive
decompress Unzip the package
reindex Reindex one or more broken packages

The record command uses

  • record <topic-names># Specify one or more topics to record
$ rosbag record body_status gnss_imu
  • record -a, --all# Record all topics
$ rosbag record -a
  • record -e, --regex# Record topics that match regular expressions
$ rosbag record -e "/(.*)_log/point"
  • rocord -p, -publish# (Melodic new feature) When starting to record a package, publish a topic="begin_write"
$ rosbag record -p
  • record -x, --exclude# Exclude topics that match regular expressions when recording
$ rosbag record -e "/(.*)_log/point" -x "(.*)/point"
  • record -q, --quiet# Suppress the log output of the specified topic when recording
$ rosbag record -q /body_status
  • record -d, --duration# Specify the maximum time for topic recording
$ rosbag record -d 30 /body_status
$ rosbag record -d 3m /body_status
$ rosbag record -d 3h /body_status
  • record -o, --output-prefix# Add a prefix before the output package name
$ rosbag record -o output /topic_name /topic_name2 
  • record -O, --output-name# Specify the output package name
$ rosbag record -O output.bag /topic_name /topic_name2 
  • record --split# Split packet recording every set time or size
$ rosbag record --split --size=1024 /topic_name
$ rosbag record --split --duration=30 /topic_name
$ rosbag record --split --duration=5m /topic_name
$ rosbag record --split --duration=2h /topic_name
  • record --max-splits# (Kinetic new feature) the maximum number of split packets
$ rosbag record --split --max-splits 3 --duration=30 /topic_name
  • record -b, --buffsize# Use internal buffer (default: 256MB, 0 for infinite)
$ rosbag record -b 1024 /topic_name
  • record --chunksize# Open up a buffer, more advanced than buffsize (default: 768KB, infinite is 0)
$ rosbag record --chunksize=1024 /topic_name
  • record -l, --limit# Only record the specified number of messages in the topic
$ rosbag record -l 1000 /topic_name
  • record --node# Record all messages subscribed by the specified node
$ rosbag record --node=/node
  • record -j, --bz2# Set the recording to be compressed in bz2 format
$ rosbag record -j /topic_name
  • record --lz4# Set the recording to be compressed in lz4 format
$ rosbag record --lz4 /topic_name

The info command uses

  • info <bag-files># View details of one or more packages
$ rosbag info test.bag
  • info -y, --yaml# Output details of one or more packages in yaml format
$ rosbag info -y test.bag
  • info -k, --key# View the output in yaml format, the data corresponding to the key value in the package
$ rosbag info -y -k topics test.bag

The play command uses

  • play <bag_name># Play one or more packets
$ rosbag play test.bag
  • play -p, --prefix# Prefix all output topics
$ rosbag play -p test test.bag
  • play -q, --quiet# suppress console output
$ rosbag play -q test.bag
  • play -i, --immediate# Play package does not wait
$ rosbag play -i test.bag
  • play --pause# Pause when starting to play a package
$ rosbag play --pause test.bag
  • play --queue# Play with the set queue size when playing the package, the default value is 100
$ rosbag play --queue=1000 test.bag
  • play --clock# Automatically publish a clocktopic
$ rosbag play --clock test.bag
  • play --hz# Publish the clock topic at the specified Hz
$ rosbag play --hz=1 --clock test.bag
  • play -d, --delay# Specify the time to delay playback
$ rosbag -d 5 test.bag
  • play -r, --rate# Specify playback speed
$ rosbag -r 10 test.bag
  • play -s, --start# Specify the start playback time
$ rosbag play -s 5 test.bag 
  • play -u,--duration# Set playback time
$ rosbag play -u 240 test.bag
  • play --skip-empty # Set the time to skip data without messages
$ rosbag play --skip-empty=1 test.bag 
  • play -l, --loop# Loop
$ rosbag play -l test.bag
  • play -k, --keep-alive# Keep active while playing
$ rosbag play -k test.bag
  • play --try-future-version# You can open the bag even if you don't know the version number
$ rosbag play --try-future-version test.bag
  • play --topics # Specify the corresponding topics to play
$ rosbag play test.bag --topics /topic1 /topic2
  • play --pause-topics# When playing back data, pause the specified topics
$ rosbag play test.bag --topics /topic1 /topic2 --pause-topics
  • play --bags # Specify multiple bags for playback
$ rosbag play --bags=test.bag 
  • play --wait-for-subscribers# Wait for each topic to have at least one subscriber before publishing
  • play --rate-control-topic=# Watch a given topic, if the last posting time exceeds <Rate Control Max Delay>, wait for that topic to post again before continuing playback
  • play --rate-control-max-delay=# Maximum time difference from <rate control topic> before pausing

The check command uses

  • check <file># Determine if a package is playable on the current system.
$ rosbag check test.bag
  • check -g, --genrules# Generate a migration rule file named RULEFILE
$ rosbag check -g diagnostics.bmr test.bag
  • check -a, --append# Append to the end of the existing data migration rules file after loading.
$ rosbag check -a -g diagnostics.bmr test.bag
  • check -n, --noplugins# Do not load the rules file
$ rosbag check -n test.bag

The fix directive uses

  • fix <in-bag> <out-bag> [rules.bmr]# Fix packets using rules file
$ rosbag fix old.bag repaired.bag myrules.bmr
  • fix -n, --noplugins# Fix packets without rules files
$ rosbag fix -n old.bag repaired.bag

The filter directive uses

  • filter <in-bag> <out-bag> <expression># Transform the data file using the given Python expression.
$ rosbag filter my.bag only-tf.bag "topic == '/tf'"

The compress command uses

  • compress <bag-files># Use BZ2 format to compress the package
$ rosbag compress *.bag
  • compress --output-dir=DIR# Specify the path output file
$ rosbag compress *.bag --output-dir=compressed
  • compress -f, --force# force overwrite if package already exists
$ rosbag compress -f *.bag
  • compress -q, --quiet# Suppress non-critical information
$ rosbag compress -q *.bag
  • compress -j, --bz2# Use bz2 format to compress the package
$ rosbag compress -j *.bag
  • compress --lz4# Use the lz4 format to compress the package
$ rosbag compress --lz4 *.bag

The decompress command uses

  • decompress <bag-files># Unzip the package
$ rosbag decompress *.bag
  • decompress --output-dir=DIR# Specify the path to decompress
$ rosbag decompress --output-dir=uncompressed *.bag
  • decompress -f, --force# force overwrite if package already exists
$ rosbag decompress -f *.bag
  • decompress -q, --quiet# Suppress non-critical information
$ rosbag decompress -q *.bag

The reindex command uses

  • reindex <bag-files># fix bad packages
$ rosbag reindex *.bag
  • reindex --output-dir=DIR# specify the path
$ rosbag reindex --output-dir=reindexed *.bag
  • reindex -f, --force# force overwrite if package already exists
$ rosbag reindex -f *.bag
  • reindex -q, --quiet# Suppress non-critical information
$ rosbag reindex -q *.bag

2. Use Python to merge package code

#! /usr/bin/env python3
import os
import time
import argparse
from rosbag import Bag, Compression

def parse_compression(compression):
    if compression == "none" or compression == "NONE":
        compression = Compression.NONE
    elif compression == "bz2":
        compression = Compression.BZ2
    elif compression == "lz4":
        compression = Compression.LZ4
    return compression

def get_files_list(arg_input, arg_select):
    files = None
    if " " in arg_input:
        files = arg_input.split(" ")
    elif "," in arg_input:
        files = arg_input.split(",")
    elif os.path.exists(args.input) or "*" in args.input:
        rfind_index = arg_input.rfind("/")
        dir_path = arg_input[:rfind_index]
        files = os.listdir(dir_path)
        files.sort() # 名称排序
        files = [dir_path + "/" + file for file in files]
    
    if arg_select:
        files = select_bags(files)
    
    print("bags list:")
    for i in range(len(files)):
        print(str(i) + "." + files[i])

    return files

def select_bags(files):
    for i in range(len(files)):
        print(str(i) + "." + files[i])
    print("Please input bag numbers to merge. split by , or space", end=":")
    s_b = input()
    s_b_list = []
    if "," in s_b:
        s_b_list = s_b.split(",")
    elif " " in s_b:
        s_b_list = s_b.split(" ")
    files = [files[int(x)] for x in s_b_list]
    return files


def show_process_bar(total, i, start):
    a = "*" * i
    b = "." * (total - i)
    c = (i / total) * 100
    dur = time.perf_counter() - start
    print("\r{:^3.0f}%[{}->{}]{:.2f}s".format(c,a,b,dur), end="")

def merge_bags(args):
    print("start merge bags.")
    compression = parse_compression(args.compression)
    print(f"bag's compression mode is {compression}.")
    files = get_files_list(args.input, args.select)
    with Bag(args.output, "w",  compression=compression) as o:
        start = time.perf_counter()
        for i in range(len(files)):
            show_process_bar(len(files), i+1, start)
            with Bag(files[i], "r") as ib:
                for topic, msg, t in ib:
                    o.write(topic, msg, t)
            show_process_bar(len(files), i+1, start)
            

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Merge one or more bag files to one file.")
    parser.add_argument("-o", "--output", help="Output bag's file path.",
                        default="output.bag", required=True)

    parser.add_argument("-i", "--input", help="Input files bags name or path, split by , .",
                        required=True)
    
    parser.add_argument("-c", "--compression", help="Compress the bag by bz2 or lz4",
                        default="lz4", choices=["none", "lz4", "bz2"])
    
    parser.add_argument("-s", "--select", help="Select bags to merge.",
                        default=False)

    parser.add_argument("-v", "--verbose", help="Show the verbose msg.")

    args = parser.parse_args()
    merge_bags(args)        


Reference:

http://wiki.ros.org/rosbag/Commandline

Guess you like

Origin blog.csdn.net/xiaokai1999/article/details/130504577