Add 'rosbags/' from commit 'c80625df279c154c6ec069cbac30faa319755e47'
git-subtree-dir: rosbags git-subtree-mainline:48df1fbdf4git-subtree-split:c80625df27
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
rosbags.convert
|
||||
===============
|
||||
|
||||
.. automodule:: rosbags.convert
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
rosbags.highlevel
|
||||
=================
|
||||
|
||||
.. automodule:: rosbags.highlevel
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
rosbags.rosbag1
|
||||
===============
|
||||
|
||||
.. automodule:: rosbags.rosbag1
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
rosbags.rosbag2
|
||||
===============
|
||||
|
||||
.. automodule:: rosbags.rosbag2
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,13 @@
|
||||
Rosbags namespace
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
rosbags.convert
|
||||
rosbags.highlevel
|
||||
rosbags.rosbag1
|
||||
rosbags.rosbag2
|
||||
rosbags.serde
|
||||
rosbags.typesys
|
||||
rosbags.typesys.types
|
||||
@@ -0,0 +1,6 @@
|
||||
rosbags.serde
|
||||
=============
|
||||
|
||||
.. automodule:: rosbags.serde
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
rosbags.typesys
|
||||
===============
|
||||
|
||||
.. automodule:: rosbags.typesys
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
rosbags.typesys.types
|
||||
=====================
|
||||
|
||||
.. automodule:: rosbags.typesys.types
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1 @@
|
||||
.. include:: ../CHANGES.rst
|
||||
@@ -0,0 +1,34 @@
|
||||
# Copyright 2020-2023 Ternaris.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Sphinx config."""
|
||||
|
||||
import typing
|
||||
|
||||
# https://github.com/sphinx-doc/sphinx/issues/9243
|
||||
import sphinx.builders.html as _1
|
||||
import sphinx.builders.latex as _2
|
||||
import sphinx.builders.texinfo as _3
|
||||
import sphinx.builders.text as _4
|
||||
import sphinx.ext.autodoc as _5
|
||||
|
||||
__all__ = ['_1', '_2', '_3', '_4', '_5']
|
||||
|
||||
# pylint: disable=invalid-name,redefined-builtin
|
||||
|
||||
typing.TYPE_CHECKING = True
|
||||
|
||||
project = 'Rosbags'
|
||||
copyright = '2020-2023, Ternaris'
|
||||
author = 'Ternaris'
|
||||
|
||||
autoapi_python_use_implicit_namespaces = True
|
||||
autodoc_typehints = 'description'
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.napoleon',
|
||||
'sphinx_autodoc_typehints',
|
||||
'sphinx_rtd_theme',
|
||||
]
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
@@ -0,0 +1,44 @@
|
||||
"""Example: Edit timestamps."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
from rosbags.interfaces import ConnectionExtRosbag2
|
||||
from rosbags.rosbag2 import Reader, Writer
|
||||
from rosbags.serde import deserialize_cdr, serialize_cdr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def offset_timestamps(src: Path, dst: Path, offset: int) -> None:
|
||||
"""Offset timestamps.
|
||||
|
||||
Args:
|
||||
src: Source path.
|
||||
dst: Destination path.
|
||||
offset: Amount of nanoseconds to offset timestamps.
|
||||
|
||||
"""
|
||||
with Reader(src) as reader, Writer(dst) as writer:
|
||||
conn_map = {}
|
||||
for conn in reader.connections:
|
||||
ext = cast(ConnectionExtRosbag2, conn.ext)
|
||||
conn_map[conn.id] = writer.add_connection(
|
||||
conn.topic,
|
||||
conn.msgtype,
|
||||
ext.serialization_format,
|
||||
ext.offered_qos_profiles,
|
||||
)
|
||||
|
||||
for conn, timestamp, data in reader.messages():
|
||||
# Adjust header timestamps, too
|
||||
msg = deserialize_cdr(data, conn.msgtype)
|
||||
if head := getattr(msg, 'header', None):
|
||||
headstamp = head.stamp.sec * 10**9 + head.stamp.nanosec + offset
|
||||
head.stamp.sec = headstamp // 10**9
|
||||
head.stamp.nanosec = headstamp % 10**9
|
||||
data = serialize_cdr(msg, conn.msgtype)
|
||||
|
||||
writer.write(conn_map[conn.id], timestamp + offset, data)
|
||||
@@ -0,0 +1,38 @@
|
||||
"""Example: Remove topic."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
from rosbags.interfaces import ConnectionExtRosbag2
|
||||
from rosbags.rosbag2 import Reader, Writer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def remove_topic(src: Path, dst: Path, topic: str) -> None:
|
||||
"""Remove topic from rosbag2.
|
||||
|
||||
Args:
|
||||
src: Source path.
|
||||
dst: Destination path.
|
||||
topic: Name of topic to remove.
|
||||
|
||||
"""
|
||||
with Reader(src) as reader, Writer(dst) as writer:
|
||||
conn_map = {}
|
||||
for conn in reader.connections:
|
||||
if conn.topic == topic:
|
||||
continue
|
||||
ext = cast(ConnectionExtRosbag2, conn.ext)
|
||||
conn_map[conn.id] = writer.add_connection(
|
||||
conn.topic,
|
||||
conn.msgtype,
|
||||
ext.serialization_format,
|
||||
ext.offered_qos_profiles,
|
||||
)
|
||||
|
||||
rconns = [reader.connections[x] for x in conn_map]
|
||||
for conn, timestamp, data in reader.messages(connections=rconns):
|
||||
writer.write(conn_map[conn.id], timestamp, data)
|
||||
@@ -0,0 +1,16 @@
|
||||
Edit rosbags
|
||||
============
|
||||
|
||||
Rosbags does not support opening files in read-write mode, but implicitly enforces copy-on-write semantics. Apart from the mapping of reader to writer connections the process is fairly straightforward.
|
||||
|
||||
|
||||
Remove topic
|
||||
------------
|
||||
|
||||
.. literalinclude:: ./edit_rosbags_remove_topic.py
|
||||
|
||||
|
||||
Edit timestamps
|
||||
---------------
|
||||
|
||||
.. literalinclude:: ./edit_rosbags_edit_timestamps.py
|
||||
@@ -0,0 +1,22 @@
|
||||
Register custom message types
|
||||
=============================
|
||||
|
||||
Out of the box rosbags only supports the message types that ship with a default ROS2 distribution. If you want to (de)serialize custom messages you need to add them to the type system manually.
|
||||
|
||||
|
||||
From rosbag1
|
||||
------------
|
||||
|
||||
.. literalinclude:: ./register_types_rosbag1.py
|
||||
|
||||
|
||||
From definition string
|
||||
----------------------
|
||||
|
||||
.. literalinclude:: ./register_types_string.py
|
||||
|
||||
|
||||
From multiple files
|
||||
-------------------
|
||||
|
||||
.. literalinclude:: ./register_types_files.py
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Example: Register types from msg files."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from rosbags.typesys import get_types_from_msg, register_types
|
||||
|
||||
|
||||
def guess_msgtype(path: Path) -> str:
|
||||
"""Guess message type name from path."""
|
||||
name = path.relative_to(path.parents[2]).with_suffix('')
|
||||
if 'msg' not in name.parts:
|
||||
name = name.parent / 'msg' / name.name
|
||||
return str(name)
|
||||
|
||||
|
||||
add_types = {}
|
||||
|
||||
for pathstr in [
|
||||
'/path/to/custom_msgs/msg/Speed.msg',
|
||||
'/path/to/custom_msgs/msg/Accel.msg',
|
||||
]:
|
||||
msgpath = Path(pathstr)
|
||||
msgdef = msgpath.read_text(encoding='utf-8')
|
||||
add_types.update(get_types_from_msg(msgdef, guess_msgtype(msgpath)))
|
||||
|
||||
register_types(add_types)
|
||||
|
||||
# Type import works only after the register_types call,
|
||||
# the classname is derived from the msgtype names above.
|
||||
|
||||
# pylint: disable=no-name-in-module,wrong-import-position
|
||||
from rosbags.typesys.types import custom_msgs__msg__Accel as Accel # type: ignore # noqa
|
||||
from rosbags.typesys.types import custom_msgs__msg__Speed as Speed # type: ignore # noqa
|
||||
|
||||
# pylint: enable=no-name-in-module,wrong-import-position
|
||||
@@ -0,0 +1,29 @@
|
||||
"""Example: Register rosbag1 types."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from rosbags.rosbag1 import Reader
|
||||
from rosbags.typesys import get_types_from_msg, register_types
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def process_bag(src: Path) -> None:
|
||||
"""Register contained messages types before processing bag.
|
||||
|
||||
Args:
|
||||
src: Bag to process.
|
||||
|
||||
"""
|
||||
with Reader(src) as reader:
|
||||
typs = {}
|
||||
for conn in reader.connections:
|
||||
typs.update(get_types_from_msg(conn.msgdef, conn.msgtype))
|
||||
register_types(typs)
|
||||
|
||||
# Now all message types used in the bag are registered
|
||||
# for conn, timestamp, data in reader.messages():
|
||||
# ...
|
||||
@@ -0,0 +1,25 @@
|
||||
"""Example: Register type from definition string."""
|
||||
|
||||
from rosbags.serde import serialize_cdr
|
||||
from rosbags.typesys import get_types_from_msg, register_types
|
||||
|
||||
# Your custom message definition
|
||||
STRIDX_MSG = """
|
||||
string string
|
||||
uint32 index
|
||||
"""
|
||||
|
||||
register_types(get_types_from_msg(STRIDX_MSG, 'custom_msgs/msg/StrIdx'))
|
||||
|
||||
# Type import works only after the register_types call,
|
||||
# the classname is derived from the msgtype name above
|
||||
|
||||
# pylint: disable=no-name-in-module,wrong-import-position
|
||||
from rosbags.typesys.types import custom_msgs__msg__StrIdx as StrIdx # type: ignore # noqa
|
||||
|
||||
# pylint: enable=no-name-in-module,wrong-import-position
|
||||
|
||||
message = StrIdx(string='foo', index=42)
|
||||
|
||||
# Rawdata that can be passed to rosbag2.Writer.write
|
||||
rawdata = serialize_cdr(message, message.__msgtype__)
|
||||
@@ -0,0 +1,16 @@
|
||||
Save images as rosbag
|
||||
=====================
|
||||
|
||||
The following examples show how to create new ROS bags from images.
|
||||
|
||||
|
||||
Save rosbag1
|
||||
------------
|
||||
|
||||
.. literalinclude:: ./save_images_rosbag1.py
|
||||
|
||||
|
||||
Save rosbag2
|
||||
------------
|
||||
|
||||
.. literalinclude:: ./save_images_rosbag2.py
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Example: Save images as rosbag1."""
|
||||
|
||||
import numpy
|
||||
|
||||
from rosbags.rosbag1 import Writer
|
||||
from rosbags.serde import serialize_ros1
|
||||
from rosbags.typesys.types import builtin_interfaces__msg__Time as Time
|
||||
from rosbags.typesys.types import sensor_msgs__msg__CompressedImage as CompressedImage
|
||||
from rosbags.typesys.types import std_msgs__msg__Header as Header
|
||||
|
||||
TOPIC = '/camera'
|
||||
FRAMEID = 'map'
|
||||
|
||||
# Contains filenames and their timestamps
|
||||
IMAGES = [
|
||||
('homer.jpg', 42),
|
||||
('marge.jpg', 43),
|
||||
]
|
||||
|
||||
|
||||
def save_images() -> None:
|
||||
"""Iterate over IMAGES and save to output bag."""
|
||||
with Writer('output.bag') as writer:
|
||||
conn = writer.add_connection(TOPIC, CompressedImage.__msgtype__)
|
||||
|
||||
for path, timestamp in IMAGES:
|
||||
message = CompressedImage(
|
||||
Header(
|
||||
stamp=Time(
|
||||
sec=int(timestamp // 10**9),
|
||||
nanosec=int(timestamp % 10**9),
|
||||
),
|
||||
frame_id=FRAMEID,
|
||||
),
|
||||
format='jpeg', # could also be 'png'
|
||||
data=numpy.fromfile(path, dtype=numpy.uint8),
|
||||
)
|
||||
|
||||
writer.write(
|
||||
conn,
|
||||
timestamp,
|
||||
serialize_ros1(message, CompressedImage.__msgtype__),
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Save multiple images in rosbag2."""
|
||||
|
||||
import numpy
|
||||
|
||||
from rosbags.rosbag2 import Writer
|
||||
from rosbags.serde import serialize_cdr
|
||||
from rosbags.typesys.types import builtin_interfaces__msg__Time as Time
|
||||
from rosbags.typesys.types import sensor_msgs__msg__CompressedImage as CompressedImage
|
||||
from rosbags.typesys.types import std_msgs__msg__Header as Header
|
||||
|
||||
TOPIC = '/camera'
|
||||
FRAMEID = 'map'
|
||||
|
||||
# Contains filenames and their timestamps
|
||||
IMAGES = [
|
||||
('homer.jpg', 42),
|
||||
('marge.jpg', 43),
|
||||
]
|
||||
|
||||
|
||||
def save_images() -> None:
|
||||
"""Iterate over IMAGES and save to output bag."""
|
||||
with Writer('output') as writer:
|
||||
conn = writer.add_connection(TOPIC, CompressedImage.__msgtype__, 'cdr', '')
|
||||
|
||||
for path, timestamp in IMAGES:
|
||||
message = CompressedImage(
|
||||
Header(
|
||||
stamp=Time(
|
||||
sec=int(timestamp // 10**9),
|
||||
nanosec=int(timestamp % 10**9),
|
||||
),
|
||||
frame_id=FRAMEID,
|
||||
),
|
||||
format='jpeg', # could also be 'png'
|
||||
data=numpy.fromfile(path, dtype=numpy.uint8),
|
||||
)
|
||||
|
||||
writer.write(
|
||||
conn,
|
||||
timestamp,
|
||||
serialize_cdr(message, message.__msgtype__),
|
||||
)
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Example: Message instance conversion."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import numpy
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
NATIVE_CLASSES: dict[str, Any] = {}
|
||||
|
||||
|
||||
def to_native(msg: Any) -> Any: # noqa: ANN401
|
||||
"""Convert rosbags message to native message.
|
||||
|
||||
Args:
|
||||
msg: Rosbags message.
|
||||
|
||||
Returns:
|
||||
Native message.
|
||||
|
||||
"""
|
||||
msgtype: str = msg.__msgtype__
|
||||
if msgtype not in NATIVE_CLASSES:
|
||||
pkg, name = msgtype.rsplit('/', 1)
|
||||
NATIVE_CLASSES[msgtype] = getattr(importlib.import_module(pkg.replace('/', '.')), name)
|
||||
|
||||
fields = {}
|
||||
for name, field in msg.__dataclass_fields__.items():
|
||||
if 'ClassVar' in field.type:
|
||||
continue
|
||||
value = getattr(msg, name)
|
||||
if '__msg__' in field.type:
|
||||
value = to_native(value)
|
||||
elif isinstance(value, numpy.ndarray):
|
||||
value = value.tolist()
|
||||
fields[name] = value
|
||||
|
||||
return NATIVE_CLASSES[msgtype](**fields)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from rosbags.typesys.types import (
|
||||
builtin_interfaces__msg__Time,
|
||||
sensor_msgs__msg__Image,
|
||||
std_msgs__msg__Header,
|
||||
)
|
||||
|
||||
image = sensor_msgs__msg__Image(
|
||||
std_msgs__msg__Header(
|
||||
builtin_interfaces__msg__Time(42, 666),
|
||||
'/frame',
|
||||
),
|
||||
4,
|
||||
4,
|
||||
'rgb8',
|
||||
False,
|
||||
4 * 3,
|
||||
numpy.zeros(4 * 4 * 3, dtype=numpy.uint8),
|
||||
)
|
||||
|
||||
native_image = to_native(image)
|
||||
# native_image can now be passed to the ROS stack
|
||||
@@ -0,0 +1,10 @@
|
||||
Use with native stack
|
||||
=====================
|
||||
|
||||
Messages read with rosbags are simple dataclasses that mimic the native ROS2 interface. If you want to pass those messages to the native ROS2 stack, you need to convert them into native objects first.
|
||||
|
||||
|
||||
Message instance conversion
|
||||
---------------------------
|
||||
|
||||
.. literalinclude:: ./use_with_native.py
|
||||
@@ -0,0 +1,48 @@
|
||||
.. include:: ../README.rst
|
||||
:end-before: Documentation
|
||||
|
||||
.. include:: ../README.rst
|
||||
:start-after: .. end documentation
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Documentation
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
topics/highlevel
|
||||
topics/typesys
|
||||
topics/serde
|
||||
topics/rosbag2
|
||||
topics/rosbag1
|
||||
topics/convert
|
||||
|
||||
.. toctree::
|
||||
:caption: Usage examples
|
||||
:maxdepth: 0
|
||||
:hidden:
|
||||
:glob:
|
||||
|
||||
examples/*
|
||||
|
||||
.. toctree::
|
||||
:caption: API
|
||||
:glob:
|
||||
:hidden:
|
||||
|
||||
api/rosbags
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Changes
|
||||
:hidden:
|
||||
|
||||
changes
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Links
|
||||
:hidden:
|
||||
|
||||
Source Code <https://gitlab.com/ternaris/rosbags>
|
||||
Issues <https://gitlab.com/ternaris/rosbags/issues>
|
||||
@@ -0,0 +1,36 @@
|
||||
Convert rosbag versions
|
||||
=======================
|
||||
|
||||
The :py:mod:`rosbags.convert` package includes a CLI tool to convert legacy rosbag1 files to rosbag2 and vice versa.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Reasonably fast, as it converts raw ROS1 messages to raw CDR messages without going though deserialization and serialization
|
||||
- Tries to match ROS1 message type names to registered ROS2 types
|
||||
- Automatically registers unknown message types present in the legacy rosbag file for the conversion
|
||||
- Handles differences of ``std_msgs/msg/Header`` between both ROS versions
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
- Refuses to convert unindexed rosbag1 files, please reindex files before conversion
|
||||
- Currently does not handle split bags
|
||||
- Only ROS2 default message types are supported when converting rosbag2 to rosbag1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# Convert "foo.bag", result will be "foo/"
|
||||
$ rosbags-convert foo.bag
|
||||
|
||||
# Convert "bar", result will be "bar.bag"
|
||||
$ rosbags-convert bar
|
||||
|
||||
# Convert "foo.bag", save the result as "bar"
|
||||
$ rosbags-convert foo.bag --dst /path/to/bar
|
||||
|
||||
# Convert "bar", save the result as "foo.bag"
|
||||
$ rosbags-convert bar --dst /path/to/foo.bag
|
||||
@@ -0,0 +1,22 @@
|
||||
Highlevel APIs
|
||||
==============
|
||||
The :py:mod:`rosbags.highlevel` package provides classes that abstract the complexity of ROS types, serialization and message access into single easy-to-use interfaces.
|
||||
|
||||
All in one reader
|
||||
-----------------
|
||||
Instances of the :py:class:`AnyReader <rosbags.highlevel.AnyReader>` class give unified access to ROS1 and ROS2 bag files. If a bag file includes message definitions the reader auto-registers all messages into a blank type store, otherwise it falls back to the default type store. It also exposes appropriate deserialization methods on the reader instance itself.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from rosbags.highlevel import AnyReader
|
||||
|
||||
# create reader instance and open for reading
|
||||
with AnyReader([Path('/home/ros/rosbag_2020_03_24')]) as reader:
|
||||
connections = [x for x in reader.connections if x.topic == '/imu_raw/Imu']
|
||||
for connection, timestamp, rawdata in reader.messages(connections=connections):
|
||||
msg = reader.deserialize(rawdata, connection.msgtype)
|
||||
print(msg.header.frame_id)
|
||||
|
||||
AnyReader takes a list of ``pathlib.Path`` instances as arguments. It can take either one ROS2 bag file or one or more ROS1 bag files belonging to a split bag. The reader will replay ROS1 split bags in correct timestamp order.
|
||||
@@ -0,0 +1,54 @@
|
||||
Rosbag1
|
||||
=======
|
||||
|
||||
The :py:mod:`rosbags.rosbag1` package provides fast read-only access to raw messages stored in the legacy bag format. The rosbag1 support is built for a ROS2 world and some APIs and values perform normalizations to mimic ROS2 behavior and make messages originating from rosbag1 and rosbag2 behave identically. Most notably message types are internally renamed to match their ROS2 counterparts.
|
||||
|
||||
Writing rosbag1
|
||||
---------------
|
||||
Instances of the :py:class:`Writer <rosbags.rosbag1.Writer>` class can create and write to new rosbag1 files. It is usually used as a context manager. Before the first message of a topic can be written, its topic must first be added to the bag. The following example shows the typical usage pattern:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.rosbag1 import Writer
|
||||
from rosbags.serde import cdr_to_ros1, serialize_cdr
|
||||
from rosbags.typesys.types import std_msgs__msg__String as String
|
||||
|
||||
# create writer instance and open for writing
|
||||
with Writer('/home/ros/rosbag_2020_03_24.bag') as writer:
|
||||
# add new connection
|
||||
topic = '/chatter'
|
||||
msgtype = String.__msgtype__
|
||||
connection = writer.add_connection(topic, msgtype, latching=True)
|
||||
|
||||
# serialize and write message
|
||||
message = String('hello world')
|
||||
timestamp = 42
|
||||
writer.write(connection, timestamp, cdr_to_ros1(serialize_cdr(message, msgtype), msgtype))
|
||||
|
||||
Reading rosbag1
|
||||
---------------
|
||||
Instances of the :py:class:`Reader <rosbags.rosbag2.Reader>` class are typically used as context managers and provide access to bag metadata and contents after the bag has been opened. The following example shows the typical usage pattern:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.rosbag1 import Reader
|
||||
from rosbags.serde import deserialize_cdr, ros1_to_cdr
|
||||
|
||||
|
||||
# create reader instance
|
||||
with Reader('/home/ros/rosbag_2020_03_24.bag') as reader:
|
||||
# topic and msgtype information is available on .connections list
|
||||
for connection in reader.connections:
|
||||
print(connection.topic, connection.msgtype)
|
||||
|
||||
# iterate over messages
|
||||
for connection, timestamp, rawdata in reader.messages():
|
||||
if connection.topic == '/imu_raw/Imu':
|
||||
msg = deserialize_cdr(ros1_to_cdr(rawdata, connection.msgtype), connection.msgtype)
|
||||
print(msg.header.frame_id)
|
||||
|
||||
# messages() accepts connection filters
|
||||
connections = [x for x in reader.connections if x.topic == '/imu_raw/Imu']
|
||||
for connection, timestamp, rawdata in reader.messages(connections=connections):
|
||||
msg = deserialize_cdr(ros1_to_cdr(rawdata, connection.msgtype), connection.msgtype)
|
||||
print(msg.header.frame_id)
|
||||
@@ -0,0 +1,70 @@
|
||||
Rosbag2
|
||||
=======
|
||||
The :py:mod:`rosbags.rosbag2` package provides a conformant implementation of rosbag2. It provides read-write access to raw message data saved inside rosbag2 containers, and supports all features present in the C++ reference implementation.
|
||||
|
||||
Supported Versions
|
||||
------------------
|
||||
All versions up to the current (ROS2 Humble) version 6 are supported.
|
||||
|
||||
Supported Features
|
||||
------------------
|
||||
Rosbag2 is a flexible format that supports plugging different serialization methods, compression formats, and storage containers together. The rosbag2 C++ reference implementation is build around plugins that provide serialization, compression, and storage. This project implements all rosbag2 core plugins that are distributed with the C++ reference implementation.
|
||||
|
||||
:Serializers:
|
||||
- cdr (without wstring)
|
||||
|
||||
:Compressors:
|
||||
- zstd
|
||||
|
||||
:Storages:
|
||||
- sqlite3
|
||||
- mcap
|
||||
|
||||
Writing rosbag2
|
||||
---------------
|
||||
Instances of the :py:class:`Writer <rosbags.rosbag2.Writer>` class can create and write to new rosbag2 files. It is usually used as a context manager. Before the first message of a topic can be written, its topic must first be added to the bag. The following example shows the typical usage pattern:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.rosbag2 import Writer
|
||||
from rosbags.serde import serialize_cdr
|
||||
from rosbags.typesys.types import std_msgs__msg__String as String
|
||||
|
||||
# create writer instance and open for writing
|
||||
with Writer('/home/ros/rosbag_2020_03_24') as writer:
|
||||
# add new connection
|
||||
topic = '/chatter'
|
||||
msgtype = String.__msgtype__
|
||||
connection = writer.add_connection(topic, msgtype, 'cdr', '')
|
||||
|
||||
# serialize and write message
|
||||
timestamp = 42
|
||||
message = String('hello world')
|
||||
writer.write(connection, timestamp, serialize_cdr(message, msgtype))
|
||||
|
||||
Reading rosbag2
|
||||
---------------
|
||||
Instances of the :py:class:`Reader <rosbags.rosbag2.Reader>` class are used to read rosbag2 metadata and its contents. Most of the metadata is available on Reader instances right away, messages can only be accessed after the bag has been opened. To this end it is recommended to use the Reader as a context manager. The following example shows the typical usage pattern:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.rosbag2 import Reader
|
||||
from rosbags.serde import deserialize_cdr
|
||||
|
||||
# create reader instance and open for reading
|
||||
with Reader('/home/ros/rosbag_2020_03_24') as reader:
|
||||
# topic and msgtype information is available on .connections list
|
||||
for connection in reader.connections:
|
||||
print(connection.topic, connection.msgtype)
|
||||
|
||||
# iterate over messages
|
||||
for connection, timestamp, rawdata in reader.messages():
|
||||
if connection.topic == '/imu_raw/Imu':
|
||||
msg = deserialize_cdr(rawdata, connection.msgtype)
|
||||
print(msg.header.frame_id)
|
||||
|
||||
# messages() accepts connection filters
|
||||
connections = [x for x in reader.connections if x.topic == '/imu_raw/Imu']
|
||||
for connection, timestamp, rawdata in reader.messages(connections=connections):
|
||||
msg = deserialize_cdr(rawdata, connection.msgtype)
|
||||
print(msg.header.frame_id)
|
||||
@@ -0,0 +1,49 @@
|
||||
Serialization and deserialization
|
||||
=================================
|
||||
|
||||
The serialization and deserialization system :py:mod:`rosbags.serde` supports multiple raw message formats. For each format it provides a pair of functions, one for serialization and one for deserialization. In addition to the data to process each function usually only requires the message type name.
|
||||
|
||||
Deserialization
|
||||
---------------
|
||||
|
||||
Deserialize a CDR bytes object using :py:func:`deserialize_cdr() <rosbags.serde.deserialize_cdr>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.serde import deserialize_cdr
|
||||
|
||||
# rawdata is of type bytes and contains serialized message
|
||||
msg = deserialize_cdr(rawdata, 'geometry_msgs/msg/Quaternion')
|
||||
|
||||
Deserialize a ROS1 bytes object using :py:func:`deserialize_ros1() <rosbags.serde.deserialize_ros1>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.serde import deserialize_ros1
|
||||
|
||||
# rawdata is of type bytes and contains serialized message
|
||||
msg = deserialize_ros1(rawdata, 'geometry_msgs/msg/Quaternion')
|
||||
|
||||
|
||||
Serialization
|
||||
---------------
|
||||
|
||||
Serialize a message with CDR using :py:func:`serialize_cdr() <rosbags.serde.serialize_cdr>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.serde import serialize_cdr
|
||||
|
||||
# serialize message with system endianess
|
||||
serialized = serialize_cdr(msg, 'geometry_msgs/msg/Quaternion')
|
||||
|
||||
# serialize message with explicit endianess
|
||||
serialized = serialize_cdr(msg, 'geometry_msgs/msg/Quaternion', little_endian=False)
|
||||
|
||||
Serialize a message with ROS1 using :py:func:`serialize_ros1() <rosbags.serde.serialize_ros1>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rosbags.serde import serialize_ros1
|
||||
|
||||
serialized = serialize_ros1(msg, 'geometry_msgs/msg/Quaternion')
|
||||
@@ -0,0 +1,194 @@
|
||||
builtin_interfaces
|
||||
******************
|
||||
- :py:class:`Duration <rosbags.typesys.types.builtin_interfaces__msg__Duration>`
|
||||
- :py:class:`Time <rosbags.typesys.types.builtin_interfaces__msg__Time>`
|
||||
|
||||
diagnostic_msgs
|
||||
***************
|
||||
- :py:class:`DiagnosticArray <rosbags.typesys.types.diagnostic_msgs__msg__DiagnosticArray>`
|
||||
- :py:class:`DiagnosticStatus <rosbags.typesys.types.diagnostic_msgs__msg__DiagnosticStatus>`
|
||||
- :py:class:`KeyValue <rosbags.typesys.types.diagnostic_msgs__msg__KeyValue>`
|
||||
|
||||
geometry_msgs
|
||||
*************
|
||||
- :py:class:`Accel <rosbags.typesys.types.geometry_msgs__msg__Accel>`
|
||||
- :py:class:`AccelStamped <rosbags.typesys.types.geometry_msgs__msg__AccelStamped>`
|
||||
- :py:class:`AccelWithCovariance <rosbags.typesys.types.geometry_msgs__msg__AccelWithCovariance>`
|
||||
- :py:class:`AccelWithCovarianceStamped <rosbags.typesys.types.geometry_msgs__msg__AccelWithCovarianceStamped>`
|
||||
- :py:class:`Inertia <rosbags.typesys.types.geometry_msgs__msg__Inertia>`
|
||||
- :py:class:`InertiaStamped <rosbags.typesys.types.geometry_msgs__msg__InertiaStamped>`
|
||||
- :py:class:`Point <rosbags.typesys.types.geometry_msgs__msg__Point>`
|
||||
- :py:class:`Point32 <rosbags.typesys.types.geometry_msgs__msg__Point32>`
|
||||
- :py:class:`PointStamped <rosbags.typesys.types.geometry_msgs__msg__PointStamped>`
|
||||
- :py:class:`Polygon <rosbags.typesys.types.geometry_msgs__msg__Polygon>`
|
||||
- :py:class:`PolygonStamped <rosbags.typesys.types.geometry_msgs__msg__PolygonStamped>`
|
||||
- :py:class:`Pose <rosbags.typesys.types.geometry_msgs__msg__Pose>`
|
||||
- :py:class:`Pose2D <rosbags.typesys.types.geometry_msgs__msg__Pose2D>`
|
||||
- :py:class:`PoseArray <rosbags.typesys.types.geometry_msgs__msg__PoseArray>`
|
||||
- :py:class:`PoseStamped <rosbags.typesys.types.geometry_msgs__msg__PoseStamped>`
|
||||
- :py:class:`PoseWithCovariance <rosbags.typesys.types.geometry_msgs__msg__PoseWithCovariance>`
|
||||
- :py:class:`PoseWithCovarianceStamped <rosbags.typesys.types.geometry_msgs__msg__PoseWithCovarianceStamped>`
|
||||
- :py:class:`Quaternion <rosbags.typesys.types.geometry_msgs__msg__Quaternion>`
|
||||
- :py:class:`QuaternionStamped <rosbags.typesys.types.geometry_msgs__msg__QuaternionStamped>`
|
||||
- :py:class:`Transform <rosbags.typesys.types.geometry_msgs__msg__Transform>`
|
||||
- :py:class:`TransformStamped <rosbags.typesys.types.geometry_msgs__msg__TransformStamped>`
|
||||
- :py:class:`Twist <rosbags.typesys.types.geometry_msgs__msg__Twist>`
|
||||
- :py:class:`TwistStamped <rosbags.typesys.types.geometry_msgs__msg__TwistStamped>`
|
||||
- :py:class:`TwistWithCovariance <rosbags.typesys.types.geometry_msgs__msg__TwistWithCovariance>`
|
||||
- :py:class:`TwistWithCovarianceStamped <rosbags.typesys.types.geometry_msgs__msg__TwistWithCovarianceStamped>`
|
||||
- :py:class:`Vector3 <rosbags.typesys.types.geometry_msgs__msg__Vector3>`
|
||||
- :py:class:`Vector3Stamped <rosbags.typesys.types.geometry_msgs__msg__Vector3Stamped>`
|
||||
- :py:class:`Wrench <rosbags.typesys.types.geometry_msgs__msg__Wrench>`
|
||||
- :py:class:`WrenchStamped <rosbags.typesys.types.geometry_msgs__msg__WrenchStamped>`
|
||||
|
||||
libstatistics_collector
|
||||
***********************
|
||||
- :py:class:`DummyMessage <rosbags.typesys.types.libstatistics_collector__msg__DummyMessage>`
|
||||
|
||||
lifecycle_msgs
|
||||
**************
|
||||
- :py:class:`State <rosbags.typesys.types.lifecycle_msgs__msg__State>`
|
||||
- :py:class:`Transition <rosbags.typesys.types.lifecycle_msgs__msg__Transition>`
|
||||
- :py:class:`TransitionDescription <rosbags.typesys.types.lifecycle_msgs__msg__TransitionDescription>`
|
||||
- :py:class:`TransitionEvent <rosbags.typesys.types.lifecycle_msgs__msg__TransitionEvent>`
|
||||
|
||||
nav_msgs
|
||||
********
|
||||
- :py:class:`GridCells <rosbags.typesys.types.nav_msgs__msg__GridCells>`
|
||||
- :py:class:`MapMetaData <rosbags.typesys.types.nav_msgs__msg__MapMetaData>`
|
||||
- :py:class:`OccupancyGrid <rosbags.typesys.types.nav_msgs__msg__OccupancyGrid>`
|
||||
- :py:class:`Odometry <rosbags.typesys.types.nav_msgs__msg__Odometry>`
|
||||
- :py:class:`Path <rosbags.typesys.types.nav_msgs__msg__Path>`
|
||||
|
||||
rcl_interfaces
|
||||
**************
|
||||
- :py:class:`FloatingPointRange <rosbags.typesys.types.rcl_interfaces__msg__FloatingPointRange>`
|
||||
- :py:class:`IntegerRange <rosbags.typesys.types.rcl_interfaces__msg__IntegerRange>`
|
||||
- :py:class:`ListParametersResult <rosbags.typesys.types.rcl_interfaces__msg__ListParametersResult>`
|
||||
- :py:class:`Log <rosbags.typesys.types.rcl_interfaces__msg__Log>`
|
||||
- :py:class:`Parameter <rosbags.typesys.types.rcl_interfaces__msg__Parameter>`
|
||||
- :py:class:`ParameterDescriptor <rosbags.typesys.types.rcl_interfaces__msg__ParameterDescriptor>`
|
||||
- :py:class:`ParameterEvent <rosbags.typesys.types.rcl_interfaces__msg__ParameterEvent>`
|
||||
- :py:class:`ParameterEventDescriptors <rosbags.typesys.types.rcl_interfaces__msg__ParameterEventDescriptors>`
|
||||
- :py:class:`ParameterType <rosbags.typesys.types.rcl_interfaces__msg__ParameterType>`
|
||||
- :py:class:`ParameterValue <rosbags.typesys.types.rcl_interfaces__msg__ParameterValue>`
|
||||
- :py:class:`SetParametersResult <rosbags.typesys.types.rcl_interfaces__msg__SetParametersResult>`
|
||||
|
||||
rmw_dds_common
|
||||
**************
|
||||
- :py:class:`Gid <rosbags.typesys.types.rmw_dds_common__msg__Gid>`
|
||||
- :py:class:`NodeEntitiesInfo <rosbags.typesys.types.rmw_dds_common__msg__NodeEntitiesInfo>`
|
||||
- :py:class:`ParticipantEntitiesInfo <rosbags.typesys.types.rmw_dds_common__msg__ParticipantEntitiesInfo>`
|
||||
|
||||
rosgraph_msgs
|
||||
*************
|
||||
- :py:class:`Clock <rosbags.typesys.types.rosgraph_msgs__msg__Clock>`
|
||||
|
||||
sensor_msgs
|
||||
***********
|
||||
- :py:class:`BatteryState <rosbags.typesys.types.sensor_msgs__msg__BatteryState>`
|
||||
- :py:class:`CameraInfo <rosbags.typesys.types.sensor_msgs__msg__CameraInfo>`
|
||||
- :py:class:`ChannelFloat32 <rosbags.typesys.types.sensor_msgs__msg__ChannelFloat32>`
|
||||
- :py:class:`CompressedImage <rosbags.typesys.types.sensor_msgs__msg__CompressedImage>`
|
||||
- :py:class:`FluidPressure <rosbags.typesys.types.sensor_msgs__msg__FluidPressure>`
|
||||
- :py:class:`Illuminance <rosbags.typesys.types.sensor_msgs__msg__Illuminance>`
|
||||
- :py:class:`Image <rosbags.typesys.types.sensor_msgs__msg__Image>`
|
||||
- :py:class:`Imu <rosbags.typesys.types.sensor_msgs__msg__Imu>`
|
||||
- :py:class:`JointState <rosbags.typesys.types.sensor_msgs__msg__JointState>`
|
||||
- :py:class:`Joy <rosbags.typesys.types.sensor_msgs__msg__Joy>`
|
||||
- :py:class:`JoyFeedback <rosbags.typesys.types.sensor_msgs__msg__JoyFeedback>`
|
||||
- :py:class:`JoyFeedbackArray <rosbags.typesys.types.sensor_msgs__msg__JoyFeedbackArray>`
|
||||
- :py:class:`LaserEcho <rosbags.typesys.types.sensor_msgs__msg__LaserEcho>`
|
||||
- :py:class:`LaserScan <rosbags.typesys.types.sensor_msgs__msg__LaserScan>`
|
||||
- :py:class:`MagneticField <rosbags.typesys.types.sensor_msgs__msg__MagneticField>`
|
||||
- :py:class:`MultiDOFJointState <rosbags.typesys.types.sensor_msgs__msg__MultiDOFJointState>`
|
||||
- :py:class:`MultiEchoLaserScan <rosbags.typesys.types.sensor_msgs__msg__MultiEchoLaserScan>`
|
||||
- :py:class:`NavSatFix <rosbags.typesys.types.sensor_msgs__msg__NavSatFix>`
|
||||
- :py:class:`NavSatStatus <rosbags.typesys.types.sensor_msgs__msg__NavSatStatus>`
|
||||
- :py:class:`PointCloud <rosbags.typesys.types.sensor_msgs__msg__PointCloud>`
|
||||
- :py:class:`PointCloud2 <rosbags.typesys.types.sensor_msgs__msg__PointCloud2>`
|
||||
- :py:class:`PointField <rosbags.typesys.types.sensor_msgs__msg__PointField>`
|
||||
- :py:class:`Range <rosbags.typesys.types.sensor_msgs__msg__Range>`
|
||||
- :py:class:`RegionOfInterest <rosbags.typesys.types.sensor_msgs__msg__RegionOfInterest>`
|
||||
- :py:class:`RelativeHumidity <rosbags.typesys.types.sensor_msgs__msg__RelativeHumidity>`
|
||||
- :py:class:`Temperature <rosbags.typesys.types.sensor_msgs__msg__Temperature>`
|
||||
- :py:class:`TimeReference <rosbags.typesys.types.sensor_msgs__msg__TimeReference>`
|
||||
|
||||
shape_msgs
|
||||
**********
|
||||
- :py:class:`Mesh <rosbags.typesys.types.shape_msgs__msg__Mesh>`
|
||||
- :py:class:`MeshTriangle <rosbags.typesys.types.shape_msgs__msg__MeshTriangle>`
|
||||
- :py:class:`Plane <rosbags.typesys.types.shape_msgs__msg__Plane>`
|
||||
- :py:class:`SolidPrimitive <rosbags.typesys.types.shape_msgs__msg__SolidPrimitive>`
|
||||
|
||||
statistics_msgs
|
||||
***************
|
||||
- :py:class:`MetricsMessage <rosbags.typesys.types.statistics_msgs__msg__MetricsMessage>`
|
||||
- :py:class:`StatisticDataPoint <rosbags.typesys.types.statistics_msgs__msg__StatisticDataPoint>`
|
||||
- :py:class:`StatisticDataType <rosbags.typesys.types.statistics_msgs__msg__StatisticDataType>`
|
||||
|
||||
std_msgs
|
||||
********
|
||||
- :py:class:`Bool <rosbags.typesys.types.std_msgs__msg__Bool>`
|
||||
- :py:class:`Byte <rosbags.typesys.types.std_msgs__msg__Byte>`
|
||||
- :py:class:`ByteMultiArray <rosbags.typesys.types.std_msgs__msg__ByteMultiArray>`
|
||||
- :py:class:`Char <rosbags.typesys.types.std_msgs__msg__Char>`
|
||||
- :py:class:`ColorRGBA <rosbags.typesys.types.std_msgs__msg__ColorRGBA>`
|
||||
- :py:class:`Empty <rosbags.typesys.types.std_msgs__msg__Empty>`
|
||||
- :py:class:`Float32 <rosbags.typesys.types.std_msgs__msg__Float32>`
|
||||
- :py:class:`Float32MultiArray <rosbags.typesys.types.std_msgs__msg__Float32MultiArray>`
|
||||
- :py:class:`Float64 <rosbags.typesys.types.std_msgs__msg__Float64>`
|
||||
- :py:class:`Float64MultiArray <rosbags.typesys.types.std_msgs__msg__Float64MultiArray>`
|
||||
- :py:class:`Header <rosbags.typesys.types.std_msgs__msg__Header>`
|
||||
- :py:class:`Int16 <rosbags.typesys.types.std_msgs__msg__Int16>`
|
||||
- :py:class:`Int16MultiArray <rosbags.typesys.types.std_msgs__msg__Int16MultiArray>`
|
||||
- :py:class:`Int32 <rosbags.typesys.types.std_msgs__msg__Int32>`
|
||||
- :py:class:`Int32MultiArray <rosbags.typesys.types.std_msgs__msg__Int32MultiArray>`
|
||||
- :py:class:`Int64 <rosbags.typesys.types.std_msgs__msg__Int64>`
|
||||
- :py:class:`Int64MultiArray <rosbags.typesys.types.std_msgs__msg__Int64MultiArray>`
|
||||
- :py:class:`Int8 <rosbags.typesys.types.std_msgs__msg__Int8>`
|
||||
- :py:class:`Int8MultiArray <rosbags.typesys.types.std_msgs__msg__Int8MultiArray>`
|
||||
- :py:class:`MultiArrayDimension <rosbags.typesys.types.std_msgs__msg__MultiArrayDimension>`
|
||||
- :py:class:`MultiArrayLayout <rosbags.typesys.types.std_msgs__msg__MultiArrayLayout>`
|
||||
- :py:class:`String <rosbags.typesys.types.std_msgs__msg__String>`
|
||||
- :py:class:`UInt16 <rosbags.typesys.types.std_msgs__msg__UInt16>`
|
||||
- :py:class:`UInt16MultiArray <rosbags.typesys.types.std_msgs__msg__UInt16MultiArray>`
|
||||
- :py:class:`UInt32 <rosbags.typesys.types.std_msgs__msg__UInt32>`
|
||||
- :py:class:`UInt32MultiArray <rosbags.typesys.types.std_msgs__msg__UInt32MultiArray>`
|
||||
- :py:class:`UInt64 <rosbags.typesys.types.std_msgs__msg__UInt64>`
|
||||
- :py:class:`UInt64MultiArray <rosbags.typesys.types.std_msgs__msg__UInt64MultiArray>`
|
||||
- :py:class:`UInt8 <rosbags.typesys.types.std_msgs__msg__UInt8>`
|
||||
- :py:class:`UInt8MultiArray <rosbags.typesys.types.std_msgs__msg__UInt8MultiArray>`
|
||||
|
||||
stereo_msgs
|
||||
***********
|
||||
- :py:class:`DisparityImage <rosbags.typesys.types.stereo_msgs__msg__DisparityImage>`
|
||||
|
||||
tf2_msgs
|
||||
********
|
||||
- :py:class:`TF2Error <rosbags.typesys.types.tf2_msgs__msg__TF2Error>`
|
||||
- :py:class:`TFMessage <rosbags.typesys.types.tf2_msgs__msg__TFMessage>`
|
||||
|
||||
trajectory_msgs
|
||||
***************
|
||||
- :py:class:`JointTrajectory <rosbags.typesys.types.trajectory_msgs__msg__JointTrajectory>`
|
||||
- :py:class:`JointTrajectoryPoint <rosbags.typesys.types.trajectory_msgs__msg__JointTrajectoryPoint>`
|
||||
- :py:class:`MultiDOFJointTrajectory <rosbags.typesys.types.trajectory_msgs__msg__MultiDOFJointTrajectory>`
|
||||
- :py:class:`MultiDOFJointTrajectoryPoint <rosbags.typesys.types.trajectory_msgs__msg__MultiDOFJointTrajectoryPoint>`
|
||||
|
||||
unique_identifier_msgs
|
||||
**********************
|
||||
- :py:class:`UUID <rosbags.typesys.types.unique_identifier_msgs__msg__UUID>`
|
||||
|
||||
visualization_msgs
|
||||
******************
|
||||
- :py:class:`ImageMarker <rosbags.typesys.types.visualization_msgs__msg__ImageMarker>`
|
||||
- :py:class:`InteractiveMarker <rosbags.typesys.types.visualization_msgs__msg__InteractiveMarker>`
|
||||
- :py:class:`InteractiveMarkerControl <rosbags.typesys.types.visualization_msgs__msg__InteractiveMarkerControl>`
|
||||
- :py:class:`InteractiveMarkerFeedback <rosbags.typesys.types.visualization_msgs__msg__InteractiveMarkerFeedback>`
|
||||
- :py:class:`InteractiveMarkerInit <rosbags.typesys.types.visualization_msgs__msg__InteractiveMarkerInit>`
|
||||
- :py:class:`InteractiveMarkerPose <rosbags.typesys.types.visualization_msgs__msg__InteractiveMarkerPose>`
|
||||
- :py:class:`InteractiveMarkerUpdate <rosbags.typesys.types.visualization_msgs__msg__InteractiveMarkerUpdate>`
|
||||
- :py:class:`Marker <rosbags.typesys.types.visualization_msgs__msg__Marker>`
|
||||
- :py:class:`MarkerArray <rosbags.typesys.types.visualization_msgs__msg__MarkerArray>`
|
||||
- :py:class:`MenuEntry <rosbags.typesys.types.visualization_msgs__msg__MenuEntry>`
|
||||
@@ -0,0 +1,44 @@
|
||||
Type system
|
||||
===========
|
||||
|
||||
Rosbags ships its own pure python typesystem :py:mod:`rosbags.typesys`. It uses parse trees to represent message definitions internally. It ships its own ``.idl`` and ``.msg`` definition parser to convert message definition files into the internal format.
|
||||
|
||||
Out of the box it supports the message types defined by the standard ROS2 distribution. Message types can be parsed and added on the fly during runtime without an additional build step.
|
||||
|
||||
Message instances
|
||||
-----------------
|
||||
The type system generates a dataclass for each message type. These dataclasses give direct read write access to all mutable fields of a message. Fields should be mutated with care as no type checking is applied during runtime.
|
||||
|
||||
.. note::
|
||||
|
||||
Limitation: While the type system parses message definitions with array bounds and/or default values, neither bounds nor default values are enforced or assigned to message instances.
|
||||
|
||||
Included message types
|
||||
----------------------
|
||||
|
||||
.. include:: ./typesys-types.rst
|
||||
|
||||
Extending the type system
|
||||
-------------------------
|
||||
Adding custom message types consists of two steps. First, message definitions are converted into parse trees using :py:func:`get_types_from_idl() <rosbags.typesys.get_types_from_idl>` or :py:func:`get_types_from_msg() <rosbags.typesys.get_types_from_msg>`, and second the types are registered in the type system via :py:func:`register_types() <rosbags.typesys.register_types>`. The following example shows how to add messages type definitions from ``.msg`` and ``.idl`` files:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from rosbags.typesys import get_types_from_idl, get_types_from_msg, register_types
|
||||
|
||||
idl_text = Path('foo_msgs/msg/Foo.idl').read_text()
|
||||
msg_text = Path('bar_msgs/msg/Bar.msg').read_text()
|
||||
|
||||
# plain dictionary to hold message definitions
|
||||
add_types = {}
|
||||
|
||||
# add all definitions from one idl file
|
||||
add_types.update(get_types_from_idl(idl_text))
|
||||
|
||||
# add definition from one msg file
|
||||
add_types.update(get_types_from_msg(msg_text, 'bar_msgs/msg/Bar'))
|
||||
|
||||
# make types available to rosbags serializers/deserializers
|
||||
register_types(add_types)
|
||||
Reference in New Issue
Block a user