Skip to content

存储插件开发

存储插件为 Rosbag2 提供实际的底层存储格式。

插件可以实现以下 API 来提供存储插件,这些 API 在 rosbag2_storage::storage_interfaces 中定义:

  • ReadOnlyInterface —— 只负责文件的读取
  • ReadWriteInterface —— 既可以写新文件,也可以读现有文件。它是 ReadOnly 的超集

目标:创建一个名为 my_storage 的插件,位于包 rosbag2_storage_my_storage 中,由类 my_namespace::MyStorage 实现。

下面的代码片段展示了提供该插件所需的各个部分。

my_storage.cpp
#include "rosbag2_storage/storage_interfaces/read_write_interface.hpp"
namespace my_namespace {
class MyStorage : public rosbag2_storage::storage_interfaces::ReadWriteInterface
{
public:
MyStorage();
~MyStorage() override; // IMPORTANT: All cleanup must happen in the destructor, such as closing file handles or database connections
// ReadWriteInterface's virtual overrides here
};
// Implementations
} // namespace my_namespace
// The following block exposes our class to pluginlib so that it can be discovered at runtime.
#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(my_namespace::MyStorage,
rosbag2_storage::storage_interfaces::ReadWriteInterface)

接下来,我们的包必须提供一个名为 plugin_description.xml 的文件。 其内容如下:

<library path="rosbag2_storage_my_storage">
<class
name="my_storage"
type="MyStorage"
base_class_type="rosbag2_storage::storage_interfaces::ReadWriteInterface"
>
<description>Rosbag2 storage plugin providing the MyStorage file format.</description>
</class>
</library>

rosbag2_storage_my_storage 是 package.xml 中库的名称,而 my_storage 是 pluginlib 用来引用该插件的标识符。

最后,CMakeLists.txt 必须把我们的 plugin_description.xml 文件加入 ament index,以便在运行时被发现:

pluginlib_export_plugin_description_file(rosbag2_storage plugin_description.xml)

第一个参数 rosbag2_storage 表示我们向哪个库添加插件(对这种插件类型来说,它永远是 rosbag2_storage),第二个参数是插件描述文件的路径。

当编写只提供读取功能的插件时,改为让你的实现类继承 rosbag2_storage::storage_interfaces::ReadOnlyInterface。 这是唯一的功能性差异,它只需要接口覆盖的子集。

my_readonly_storage.cpp
#include "rosbag2_storage/storage_interfaces/read_only_interface.hpp"
namespace my_namespace {
class MyReadOnlyStorage : public rosbag2_storage::storage_interfaces::ReadOnlyInterface
{
public:
MyReadOnlyStorage();
~MyReadOnlyStorage() override; // IMPORTANT: All cleanup must happen in the destructor, such as closing file handles or database connections
// ReadOnlyInterface's virtual overrides here
};
// Implementations
} // namespace my_namespace
// The following block exposes our class to pluginlib so that it can be discovered at runtime.
#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(my_namespace::MyReadOnlyStorage,
rosbag2_storage::storage_interfaces::ReadOnlynterface)
plugin_description.xml
<library path="rosbag2_storage_my_storage">
<class
name="my_readonly_storage"
type="my_namespace::MyReadOnlyStorage"
base_class_type="rosbag2_storage::storage_interfaces::ReadOnlyInterface"
>
<description>Rosbag2 storage plugin providing read functionality for MyStorage file format.</description>
</class>
</library>

以及在 CMakeLists 中常见的 pluginlib 导出:

CMakeLists.txt
pluginlib_export_plugin_description_file(rosbag2_storage plugin_description.xml)

有些存储插件可能具有该格式特有的配置参数,你希望允许用户从命令行提供。 Rosbag2 提供了一个 CLI 参数 --storage-config-file,允许用户传入文件路径。 该文件可以包含任何内容,其格式由存储实现决定,文件路径会一路传递到插件,插件可以按需使用。 建议插件记录该文件的预期格式,以便用户编写格式良好的配置。

与写出文件相比,命令行参数可能是向用户暴露配置更方便的方式。 创建 ros2 bag 命令的 ros2bag 包为插件扩展 CLI 提供了一个入口点(entrypoint)。

包只需要向 ros2bag.storage_plugin_cli_extension 组暴露一个 Python setuptools 入口点,入口点的键为存储插件的名称。例如,下面是 rosbag2_storage_mcap 的 setup.cfg:

[options.entry_points]
ros2bag.storage_plugin_cli_extension =
mcap = ros2bag_mcap_cli

这在 ros2bag.storage_plugin_cli_extension 组中注册了一个名为 mcap 的插件的入口点,该插件由名为 ros2bag_mcap_cli 的 Python 模块实现。

暴露的入口点可以通过任何方式安装为 Python 模块,例如通过 ament_cmake_python 的 ament_python_install_package 宏,或者使用带 setup.py 的纯 Python ament_python 包。

该入口点可以提供的函数:

  • get_preset_profiles(): List[Tuple[str, str]] - 提供一个字符串对列表,包含用于写入存储文件的_预设配置(preset profiles)_的(名称,描述)。第一项将用作默认值。考虑把 ‘none’ 作为第一个配置。

注意:对于每个这样的列表,字符串字面量 ‘none’ 将用来表示该功能被禁用/未使用。

注意:任何入口点都可以省略任何扩展函数,对于每个省略的扩展点都会打印警告。当列表值函数未提供或返回 None 时,默认只提供 'none' 选项。