rosbag.js

repository·main·Indexed 41 days ago

https://github.com/cruise-automation/rosbag.js

A Node.js and browser-compatible module for reading, parsing, and serializing ROS (Robot Operating System) binary bag files. Version 5.0.0 provides utilities to parse ROS message definitions into JavaScript objects, filter messages by topic or time range, and serialize objects back into binary buffers using the MessageWriter class.

Tokens
6.3K
Snippets
26
Records
34
Agent score
51%

What's inside rosbag.js

  1. Parse JSON fields in ROS messages using #pragma

    main

    If a ROS message definition contains a string field preceded by the #pragma rosbag_parse_json comment, rosbag will automatically parse that string field into a JavaScript object during the read operation.

    Example Message Definition:

    #pragma rosbag_parse_json
    string data

    In this case, the data field in the resulting JavaScript object will be a parsed JSON object rather than a string.

  2. Import rosbag in Node.js or the Browser

    main

    Depending on your environment and build system, you can import the module as follows:

    Node.js (CommonJS):

    const { open } = require('rosbag');

    Node.js/Browser (ESM):

    import { open } from 'rosbag';

    Direct Browser Script (No bundler): If you are not using a package manager or bundler, include the script directly in your HTML:

    <script src="node_modules/rosbag/dist/web/index.js"></script>
    <script>
      // use rosbag.open() here...
    </script>
  3. Quick start: Read messages from a rosbag

    main

    To read messages, use open() to create a Bag instance, then call bag.readMessages() with a callback function to process each record. The library automatically parses ROS message definitions into JavaScript objects.

    const { open } = require('rosbag');
    
    async function logMessagesFromFooBar() {
      // open a new bag at a given file location:
      const bag = await open('../path/to/ros.bag');
    
      // read all messages from both the '/foo' and '/bar' topics:
      await bag.readMessages({ topics: ['/foo', '/bar'] }, (result) => {
        // topic is the topic the data record was in
        console.log(result.topic);
    
        // message is the parsed payload
        console.log(result.message);
      });
    }
    
    logMessagesFromFooBar();
    const { open } = require('rosbag');
    
    async function logMessagesFromFooBar() {
      const bag = await open('../path/to/ros.bag');
    
      await bag.readMessages({ topics: ['/foo', '/bar'] }, (result) => {
        console.log(result.topic);
        console.log(result.message);
      });
    }
    
    logMessagesFromFooBar();
  4. Use the rosbag package entrypoint

    main

    The rosbag package provides tools for reading and writing ROS bag files. The primary entrypoint is the Bag class, which can be used to open bag files for reading or writing. The package also exports specialized utilities for message parsing, field extraction, and time manipulation.

    import Bag from 'rosbag';
    
    // Example usage pattern
    // const bag = await Bag.open('path/to/bagfile');
  5. Understand the OpenBag interface

    main

    An OpenBag is a specialized version of the Bag class that is guaranteed to have its metadata loaded. While a standard Bag instance might not have its properties initialized, an OpenBag provides:

    • header: The BagHeader containing metadata like connection and chunk counts.
    • connections: A record of Connection objects indexed by their connection ID.
    • chunkInfos: An array of ChunkInfo objects describing the physical layout of the bag.
    • startTime / endTime: The temporal bounds of the bag based on its chunks.
  6. Configure BagOptions for filtering and decompression

    main

    The BagOptions object allows you to optimize reading by filtering data before it is fully processed, which provides significant performance and memory gains.

    Available Options:

    • topics?: Array<string>: Filter to only read specific topics. Defaults to all topics.
    • startTime?: Time: Filter to only read records starting on or after this time.
    • endTime?: Time: Filter to only read records ending on or before this time.
    • decompress?: { bz2?: (buffer: Buffer, uncompressedByteLength: number) => Buffer, lz4?: (buffer: Buffer, uncompressedByteLength: number) => Buffer }: Callbacks to handle compressed bags. The callback receives the compressed buffer and the uncompressedByteLength.
    • noParse?: boolean: If true, skips the message parsing step (useful for raw data access).
    • freeze?: boolean: If true, deeply freezes parsed messages using Object.freeze() to prevent accidental mutation. Defaults to false.
    const bagOptions = {
      topics?: Array<string>,
      startTime?: Time,
      endTime?: Time,
      decompress?: {
        bz2?: (buffer: Buffer, uncompressedByteLength: number) => Buffer,
        lz4?: (buffer: Buffer, uncompressedByteLength: number) => Buffer,
      },
      noParse?: boolean,
      freeze?: boolean,
    }
  7. Understand the RosbagRecord data structure

    main

    The RosbagRecord class is the base abstraction for all parsed elements within a ROS bag file. It provides spatial information about where a specific record (like a header, chunk, or connection) is located within the file's buffer.

    Key properties include:

    • offset: The starting position of the record in the file.
    • dataOffset: The starting position of the actual data payload.
    • end: The end position of the data payload.
    • length: The total length of the data payload (end - offset).
    // Base class properties
    record.offset
    record.dataOffset
    record.end
    record.length
  8. Work with ROS Time and TimeUtil

    main

    ROS time uses nanosecond granularity. In JavaScript, a Time object consists of sec (seconds) and nsec (nanoseconds) fields.

    Use the TimeUtil interface for common time operations:

    • toDate(Time): Date: Converts a Time to a JS Date (Note: lossy, nanoseconds are lost).
    • fromDate(Date): Time: Creates a Time from a JS Date.
    • compare(left: Time, right: Time): number: Returns positive if left > right, negative if left < right, or 0 if equal. Useful for sorting.
    • isLessThan(left: Time, right: Time): boolean: Checks if left < right.
    • isGreaterThan(left: Time, right: Time): boolean: Checks if left > right.
    • areSame(left: Time, right: Time): boolean: Checks if times are equal.
    • add(left: Time, right: Time): Time: Returns the sum of two times.
    interface TimeUtil {
      toDate(Time): Date,
      fromDate(Date): Time,
      compare(left: Time, right: Time): number,
      isLessThan(left: Time, right: Time): boolean,
      isGreaterThan(left: Time, right: Time): boolean,
      areSame(left: Time, right: Time): boolean,
      add(left: Time, right: Time): Time,
    }
  9. Open a new rosbag reader with open()

    main

    The open function initializes a reader for a rosbag file.

    • In Node.js: Pass a string representing the full path to the file on disk.
    • In the Browser: Pass a File instance (e.g., from an <input type="file"> element).

    Returns a Promise<Bag> that resolves with a Bag instance or rejects if the file is invalid or cannot be opened.

    function open(fileOrPath: File | string) => Promise<Bag>
  10. Use the Bag instance to manage bag data

    main

    A Bag instance provides metadata about the bag and the primary method for reading data.

    Properties:

    • startTime: Time: The time of the earliest message.
    • endTime: Time: The time of the last message.
    • connections: { [number]: Connection }: A hash of connection records indexed by their ID.
    • chunkInfos: Array<ChunkInfo>: An array describing the chunks within the bag.

    Methods:

    • readMessages(options: BagOptions, cb: (result: ReadResult) => void) => Promise<void>: Consumes messages from the bag. The promise resolves when the entire read operation is complete. The callback cb is invoked for each ReadResult during the operation.
    class Bag {
      startTime: Time,
      endTime: Time,
      connections: { [number]: Connection },
      chunkInfos: Array<ChunkInfo>,
      readMessages(options: BagOptions, cb: (result: ReadResult) => void) => Promise<void>
    }
  11. Understand the ReadResult object

    main

    Each time the readMessages callback is triggered, it receives a ReadResult object containing the following fields:

    • topic: string: The topic name for the current record.
    • message: { [string]: any }: The parsed message contents. This is undefined if noParse: true was used in BagOptions.
    • timestamp: Time: The receive time of the message.
    • data: Array<int8>: The raw buffer data (Node.js Buffer in Node, ArrayBuffer in the browser).
    • chunkOffset: number: The current chunk index (useful for calculating read progress).
    • totalChunks: number: The total number of chunks to be consumed in the current operation.
    class ReadResult {
      topic: string,
      message: { [string]: any },
      timestamp: Time,
      data: Array<int8>,
      chunkOffset: number,
      totalChunks: number,
    }