-
Notifications
You must be signed in to change notification settings - Fork 321
rosbag2_py reader and writer #308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 52 commits
f5de2f8
2eb3e22
66dbd3c
acabf6a
e571154
6deb1da
68b6b46
a0ce1d8
b144bc3
31f245e
54799a9
c99d7f4
f8c4391
e9da5f6
d63eece
2aff04b
668a988
8b3f3d7
5767a61
58b24c5
2da411b
7eed626
e9c9262
449a939
562d2dd
d261c63
ab426d9
133e1a4
edcf24a
ec64c99
08db02f
089306a
1798096
363059b
9394844
41973ea
54f6722
b845790
be62274
295ee66
825250c
8f62f46
ff11f99
d86ebf4
9ee167e
76e3850
ab16d49
ebf3a01
a6774c7
020caa8
0e551ff
c9cd71e
0603d27
ddbbdf7
31a2551
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| cmake_minimum_required(VERSION 3.5) | ||
| project(rosbag2_py) | ||
|
|
||
| # Default to C99 | ||
| if(NOT CMAKE_C_STANDARD) | ||
| set(CMAKE_C_STANDARD 99) | ||
| endif() | ||
|
|
||
| # Default to C++14 | ||
| if(NOT CMAKE_CXX_STANDARD) | ||
| set(CMAKE_CXX_STANDARD 14) | ||
| endif() | ||
|
|
||
| if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||
| add_compile_options(-Wall -Wextra -Wpedantic -Werror) | ||
| endif() | ||
|
|
||
| find_package(ament_cmake REQUIRED) | ||
| find_package(ament_cmake_ros REQUIRED) | ||
| find_package(pybind11 REQUIRED) | ||
| find_package(python_cmake_module REQUIRED) | ||
| find_package(rosbag2_compression REQUIRED) | ||
| find_package(rosbag2_cpp REQUIRED) | ||
| find_package(rosbag2_storage REQUIRED) | ||
|
|
||
| ament_python_install_package(${PROJECT_NAME}) | ||
|
|
||
| pybind11_add_module(_reader SHARED | ||
| src/rosbag2_py/_reader.cpp | ||
| ) | ||
| ament_target_dependencies(_reader PUBLIC | ||
| "rosbag2_compression" | ||
| "rosbag2_cpp" | ||
| ) | ||
|
|
||
| pybind11_add_module(_storage SHARED | ||
| src/rosbag2_py/_storage.cpp | ||
| ) | ||
| ament_target_dependencies(_storage PUBLIC | ||
| "rosbag2_cpp" | ||
| "rosbag2_storage" | ||
| ) | ||
|
|
||
| pybind11_add_module(_writer SHARED | ||
| src/rosbag2_py/_writer.cpp | ||
| ) | ||
| ament_target_dependencies(_writer PUBLIC | ||
| "rosbag2_compression" | ||
|
mabelzhang marked this conversation as resolved.
|
||
| "rosbag2_cpp" | ||
| ) | ||
|
|
||
| # Install cython modules as sub-modules of the project | ||
| install( | ||
| TARGETS | ||
| _reader | ||
| _storage | ||
| _writer | ||
| DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}" | ||
| ) | ||
|
|
||
| if(BUILD_TESTING) | ||
| find_package(ament_lint_auto REQUIRED) | ||
| ament_lint_auto_find_test_dependencies() | ||
| find_package(ament_cmake_pytest REQUIRED) | ||
|
|
||
| set(_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}") | ||
| if(WIN32 AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") | ||
| set(_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE_DEBUG}") | ||
| endif() | ||
| set(pythonpath "${CMAKE_CURRENT_BINARY_DIR}/rosbag2_py;${CMAKE_CURRENT_SOURCE_DIR}") | ||
| if(NOT WIN32) | ||
| string(REPLACE ";" ":" pythonpath "${pythonpath}") | ||
| endif() | ||
|
mabelzhang marked this conversation as resolved.
|
||
| ament_add_pytest_test(test_sequential_reader_py "test/test_sequential_reader.py" | ||
| PYTHON_EXECUTABLE "${_PYTHON_EXECUTABLE}" | ||
| APPEND_ENV "PYTHONPATH=${pythonpath}" | ||
| APPEND_LIBRARY_DIRS "${_append_library_dirs}" | ||
| WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/resources" | ||
| ) | ||
| ament_add_pytest_test(test_sequential_writer_py "test/test_sequential_writer.py" | ||
| PYTHON_EXECUTABLE "${_PYTHON_EXECUTABLE}" | ||
| APPEND_ENV "PYTHONPATH=${pythonpath}" | ||
| APPEND_LIBRARY_DIRS "${_append_library_dirs}" | ||
| WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/resources" | ||
| ) | ||
| endif() | ||
|
|
||
| ament_package() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| <?xml version="1.0"?> | ||
| <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> | ||
| <package format="3"> | ||
| <name>rosbag2_py</name> | ||
| <version>0.2.4</version> | ||
| <description>Python API for rosbag2</description> | ||
| <maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer> | ||
|
piraka9011 marked this conversation as resolved.
|
||
| <maintainer email="ros-tooling@googlegroups.com">ROS Tooling Working Group</maintainer> | ||
| <license>Apache License 2.0</license> | ||
|
|
||
|
jacobperron marked this conversation as resolved.
|
||
| <buildtool_depend>ament_cmake_ros</buildtool_depend> | ||
|
|
||
| <depend>pybind11_vendor</depend> | ||
|
jacobperron marked this conversation as resolved.
|
||
| <depend>python_cmake_module</depend> | ||
| <depend>rosbag2_compression</depend> | ||
| <depend>rosbag2_cpp</depend> | ||
| <depend>rosbag2_storage</depend> | ||
|
|
||
| <exec_depend>rpyutils</exec_depend> | ||
|
|
||
| <test_depend>ament_lint_auto</test_depend> | ||
| <test_depend>ament_lint_common</test_depend> | ||
| <test_depend>python3-pytest</test_depend> | ||
| <test_depend>rcl_interfaces</test_depend> | ||
| <test_depend>rclpy</test_depend> | ||
| <test_depend>rosbag2_converter_default_plugins</test_depend> | ||
| <test_depend>rosbag2_storage_default_plugins</test_depend> | ||
| <test_depend>rosbag2_storage</test_depend> | ||
| <test_depend>rosidl_runtime_py</test_depend> | ||
| <test_depend>rpyutils</test_depend> | ||
| <test_depend>std_msgs</test_depend> | ||
|
|
||
| <export> | ||
| <build_type>ament_cmake</build_type> | ||
| </export> | ||
| </package> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| rosbag2_bagfile_information: | ||
| version: 4 | ||
| storage_identifier: sqlite3 | ||
| relative_file_paths: | ||
| - talker.db3 | ||
| duration: | ||
| nanoseconds: 4531096768 | ||
| starting_time: | ||
| nanoseconds_since_epoch: 1585866235112411371 | ||
| message_count: 20 | ||
| topics_with_message_count: | ||
| - topic_metadata: | ||
| name: /topic | ||
| type: std_msgs/msg/String | ||
| serialization_format: cdr | ||
| offered_qos_profiles: "- history: 3\n depth: 0\n reliability: 1\n durability: 2\n deadline:\n sec: 2147483647\n nsec: 4294967295\n lifespan:\n sec: 2147483647\n nsec: 4294967295\n liveliness: 1\n liveliness_lease_duration:\n sec: 2147483647\n nsec: 4294967295\n avoid_ros_namespace_conventions: false" | ||
| message_count: 10 | ||
| - topic_metadata: | ||
| name: /rosout | ||
| type: rcl_interfaces/msg/Log | ||
| serialization_format: cdr | ||
| offered_qos_profiles: "- history: 3\n depth: 0\n reliability: 1\n durability: 1\n deadline:\n sec: 2147483647\n nsec: 4294967295\n lifespan:\n sec: 10\n nsec: 0\n liveliness: 1\n liveliness_lease_duration:\n sec: 2147483647\n nsec: 4294967295\n avoid_ros_namespace_conventions: false" | ||
| message_count: 10 | ||
| - topic_metadata: | ||
| name: /parameter_events | ||
| type: rcl_interfaces/msg/ParameterEvent | ||
| serialization_format: cdr | ||
| offered_qos_profiles: "- history: 3\n depth: 0\n reliability: 1\n durability: 2\n deadline:\n sec: 2147483647\n nsec: 4294967295\n lifespan:\n sec: 2147483647\n nsec: 4294967295\n liveliness: 1\n liveliness_lease_duration:\n sec: 2147483647\n nsec: 4294967295\n avoid_ros_namespace_conventions: false" | ||
| message_count: 0 | ||
| compression_format: "" | ||
| compression_mode: "" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # Copyright 2020 Open Source Robotics Foundation, Inc. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| from rpyutils import add_dll_directories_from_env | ||
|
|
||
| # Since Python 3.8, on Windows we should ensure DLL directories are explicitly added | ||
| # to the search path. | ||
| # See https://docs.python.org/3/whatsnew/3.8.html#bpo-36085-whatsnew | ||
| with add_dll_directories_from_env('PATH'): | ||
| from rosbag2_py._reader import \ | ||
| SequentialCompressionReader, \ | ||
| SequentialReader | ||
| from rosbag2_py._storage import \ | ||
| ConverterOptions, \ | ||
| StorageFilter, \ | ||
| StorageOptions, \ | ||
| TopicMetadata | ||
| from rosbag2_py._writer import \ | ||
| SequentialCompressionWriter, \ | ||
| SequentialWriter | ||
|
|
||
| __all__ = [ | ||
| 'ConverterOptions', | ||
| 'SequentialCompressionReader', | ||
| 'SequentialCompressionWriter', | ||
| 'SequentialReader', | ||
| 'SequentialWriter', | ||
| 'StorageFilter', | ||
| 'StorageOptions', | ||
| 'TopicMetadata', | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| // Copyright 2020 Open Source Robotics Foundation, Inc. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| #include <pybind11/pybind11.h> | ||
| #include <pybind11/stl.h> | ||
|
|
||
| #include <memory> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "rosbag2_compression/sequential_compression_reader.hpp" | ||
| #include "rosbag2_cpp/converter_options.hpp" | ||
| #include "rosbag2_cpp/readers/sequential_reader.hpp" | ||
| #include "rosbag2_cpp/reader.hpp" | ||
| #include "rosbag2_cpp/storage_options.hpp" | ||
| #include "rosbag2_storage/storage_filter.hpp" | ||
| #include "rosbag2_storage/topic_metadata.hpp" | ||
|
|
||
| namespace rosbag2_py | ||
| { | ||
|
|
||
| template<typename T> | ||
| class Reader | ||
| { | ||
| public: | ||
| Reader() | ||
| : reader_(std::make_unique<rosbag2_cpp::Reader>(std::make_unique<T>())) | ||
| { | ||
| } | ||
|
|
||
| void open( | ||
| rosbag2_cpp::StorageOptions & storage_options, | ||
| rosbag2_cpp::ConverterOptions & converter_options) | ||
| { | ||
| reader_->open(storage_options, converter_options); | ||
| } | ||
|
|
||
| bool has_next() | ||
| { | ||
| return reader_->has_next(); | ||
| } | ||
|
|
||
| /// Return a tuple containing the topic name, the serialized ROS message, and | ||
| /// the timestamp. | ||
| pybind11::tuple read_next() | ||
| { | ||
| const auto next = reader_->read_next(); | ||
| rcutils_uint8_array_t rcutils_data = *next->serialized_data.get(); | ||
| std::string serialized_data(rcutils_data.buffer, | ||
| rcutils_data.buffer + rcutils_data.buffer_length); | ||
| return pybind11::make_tuple( | ||
| next->topic_name, pybind11::bytes(serialized_data), next->time_stamp); | ||
| } | ||
|
|
||
| /// Return a mapping from topic name to topic type. | ||
| std::vector<rosbag2_storage::TopicMetadata> get_all_topics_and_types() | ||
| { | ||
| return reader_->get_all_topics_and_types(); | ||
| } | ||
|
|
||
| void set_filter(const rosbag2_storage::StorageFilter & storage_filter) | ||
| { | ||
| return reader_->set_filter(storage_filter); | ||
| } | ||
|
|
||
| void reset_filter() | ||
| { | ||
| reader_->reset_filter(); | ||
| } | ||
|
|
||
| protected: | ||
| std::unique_ptr<rosbag2_cpp::Reader> reader_; | ||
| }; | ||
| } // namespace rosbag2_py | ||
|
|
||
| PYBIND11_MODULE(_reader, m) { | ||
| m.doc() = "Python wrapper of the rosbag2_cpp reader API"; | ||
|
|
||
| pybind11::class_<rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>>( | ||
| m, "SequentialReader") | ||
| .def(pybind11::init()) | ||
| .def("open", &rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>::open) | ||
| .def("read_next", &rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>::read_next) | ||
| .def("has_next", &rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>::has_next) | ||
| .def( | ||
| "get_all_topics_and_types", | ||
| &rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>::get_all_topics_and_types) | ||
| .def("set_filter", &rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>::set_filter) | ||
| .def("reset_filter", &rosbag2_py::Reader<rosbag2_cpp::readers::SequentialReader>::reset_filter); | ||
|
|
||
| pybind11::class_<rosbag2_py::Reader<rosbag2_compression::SequentialCompressionReader>>( | ||
| m, "SequentialCompressionReader") | ||
| .def(pybind11::init()) | ||
| .def("open", &rosbag2_py::Reader<rosbag2_compression::SequentialCompressionReader>::open) | ||
| .def( | ||
| "read_next", &rosbag2_py::Reader<rosbag2_compression::SequentialCompressionReader>::read_next) | ||
| .def("has_next", &rosbag2_py::Reader<rosbag2_compression::SequentialCompressionReader>::has_next) | ||
| .def( | ||
| "get_all_topics_and_types", | ||
| &rosbag2_py::Reader< | ||
| rosbag2_compression::SequentialCompressionReader | ||
| >::get_all_topics_and_types) | ||
| .def( | ||
| "set_filter", | ||
| &rosbag2_py::Reader<rosbag2_compression::SequentialCompressionReader>::set_filter) | ||
| .def( | ||
| "reset_filter", | ||
| &rosbag2_py::Reader<rosbag2_compression::SequentialCompressionReader>::reset_filter); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // Copyright 2020 Open Source Robotics Foundation, Inc. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| #include <pybind11/pybind11.h> | ||
| #include <pybind11/stl.h> | ||
|
|
||
| #include "rosbag2_cpp/converter_options.hpp" | ||
| #include "rosbag2_cpp/storage_options.hpp" | ||
| #include "rosbag2_storage/storage_filter.hpp" | ||
| #include "rosbag2_storage/topic_metadata.hpp" | ||
|
|
||
| PYBIND11_MODULE(_storage, m) { | ||
| m.doc() = "Python wrapper of the rosbag2 utilities API"; | ||
|
|
||
| pybind11::class_<rosbag2_cpp::ConverterOptions>(m, "ConverterOptions") | ||
| .def(pybind11::init()) | ||
| .def_readwrite( | ||
| "input_serialization_format", | ||
| &rosbag2_cpp::ConverterOptions::input_serialization_format) | ||
| .def_readwrite( | ||
| "output_serialization_format", | ||
| &rosbag2_cpp::ConverterOptions::output_serialization_format); | ||
|
|
||
| pybind11::class_<rosbag2_cpp::StorageOptions>(m, "StorageOptions") | ||
| .def(pybind11::init()) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we able to bind this constructor to a "brace initializer" (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#brace-initialization)? If not, can we define factory functions here in the python wrapper? I'd like for the py-side objects to be single-call constructable: e.g. instead of the API would be better if we can This comment/question applies to all the POD structs exposed in this PR (ConverterOptions, StorageOptions, StorageFilter, TopicMetadata i think is all of them)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried out the brace initialization and found that it doesn't let us have keyword arguments. Some of the structs have default values like 0, and currently with the pybind brace initialization alone, I have to initialize it like this, which is kind of dumb: The three 0s are max_bagfile_size, max_bagfile_duration, max_cache_size, which are by default 0s in C++. With the argument types specified in I think the keyword arguments might do what we want: https://pybind11.readthedocs.io/en/stable/advanced/functions.html#accepting-args-and-kwargs
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can do "named arguments" with defaults like the following? This may need us to define constructors or factory functions, which is maybe not ideal. If it gets too difficult, maybe we do end up keeping it as a "default then set" struct - I don't love it as an API but it may be more maintainable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw: It is sufficient to pass converter options without anything set: storage_options = rosbag2.StorageOptions()
storage_options.uri = uri
storage_options.storage_id = 'sqlite3'
reader.open(storage_options, rosbag2.ConverterOptions())
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @emersonknapp Nice find! That's a lot simpler than the |
||
| .def_readwrite("uri", &rosbag2_cpp::StorageOptions::uri) | ||
| .def_readwrite("storage_id", &rosbag2_cpp::StorageOptions::storage_id) | ||
| .def_readwrite( | ||
| "max_bagfile_size", | ||
| &rosbag2_cpp::StorageOptions::max_bagfile_size); | ||
|
|
||
| pybind11::class_<rosbag2_storage::StorageFilter>(m, "StorageFilter") | ||
| .def(pybind11::init()) | ||
| .def_readwrite("topics", &rosbag2_storage::StorageFilter::topics); | ||
|
|
||
| pybind11::class_<rosbag2_storage::TopicMetadata>(m, "TopicMetadata") | ||
| .def(pybind11::init()) | ||
| .def_readwrite("name", &rosbag2_storage::TopicMetadata::name) | ||
| .def_readwrite("type", &rosbag2_storage::TopicMetadata::type) | ||
| .def_readwrite( | ||
| "serialization_format", | ||
| &rosbag2_storage::TopicMetadata::serialization_format) | ||
| .def("equals", &rosbag2_storage::TopicMetadata::operator==); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.