🍀

ROS2 Foxyでrqt_bagを使えるようにする

25 min read

はじめに

ROSを開発するうえで便利なフレームワークとしてRQtと呼ばれるものがあります。
RQtはQtをベースとしたGUIフレームワークで、様々なツールやインターフェースをプラグインの形で実装しているのが特徴です。
詳細はROS2の公式ドキュメントを参考にしてください。

http://docs.ros.org/en/foxy/Concepts/About-RQt.html

ROS1[1]では、20以上のプラグインが作成され、これらはROS2へと移植されている段階です。
なので、ROS1のときに使えていたのに、ROS2ではまだ使えないプラグインもあったりします。

その内のひとつがrqt_bagになります。
rqt_bagはROS2 Foxyでは標準で使用できないツールになっています。

ROS1/ROS2にはrosbagと呼ばれる流れるトピックを保存する機能があるのですが、rqt_bagは保存したrosbagを可視化してどのトピックがいつ流れているのかを確認することができるツールになります。

ROS1のときのrqt_bagの使い方はこちらの記事が参考になります。

https://qiita.com/srs/items/f6e2c36996e34bcc4d73#概要

今回はこのrqt_bagをROS2 Foxyでも使えるようにしようという内容です。

必要なリポジトリのクローン

rqt_bagを使用するのに必要なリポジトリをGitHubからクローンしてきます。

必要なリポジトリは以下の5つです。

No. リポジトリ名 URL
1 rcl_interfaces https://github.com/ros2/rcl_interfaces
2 test_interface_files https://github.com/ros2/test_interface_files
3 pybind11_vendor https://github.com/ros2/pybind11_vendor
4 rosbag2 https://github.com/ros2/rosbag2
5 rqt_bag https://github.com/ros-visualization/rqt_bag

もともとインストールされているFoxyの環境はいじりたくないので、バグツール用にワークスペースを一つ作成し、そこに上記のリポジトリをクローンしていきます。

$ mkdir -p ~/bag_tool_ws/src
$ cd ~/bag_tool_ws/src
$ git clone https://github.com/ros2/rcl_interfaces.git -b foxy
$ git clone https://github.com/ros2/test_interface_files.git -b foxy
$ git clone https://github.com/ros2/pybind11_vendor.git -b foxy
$ git clone https://github.com/ros2/rosbag2.git -b emersonknapp/futurize-foxy
$ git clone https://github.com/ros-visualization/rqt_bag.git -b ros2

ポイントはrosbag2のリポジトリをクローンする際に、ブランチをemersonknapp/futurize-foxyにしている点です。
ただし、現在も開発中のブランチで後述するように一部ビルドが通らないなどの問題もありますので、自己責任で使用してください。
また、このemersonknapp/futurize-foxyは将来的にfoxy-futureブランチにマージされる予定です[2]。その際はfoxy-futureブランチを使用してください。

ビルドしてみる

必要なものは用意できたので、バグツール用のワークスペースごとビルドしてみましょう。

$ cd ~/bag_tool_ws
$ colcon build --symlink-install

あれ、ビルドが通らないだと。。。
以下のような、エラーが出力されるかと思います。

エラー内容
--- stderr: rosbag2_transport
In file included from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:42,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/record_integration_fixture.hpp:31,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:24:
/home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/mock_sequential_reader.hpp:28:8: error: ‘void MockSequentialReader::open(const rosbag2_storage::StorageOptions&, const rosbag2_cpp::ConverterOptions&)’ marked ‘override’, but does not override
   28 |   void open(
      |        ^~~~
In file included from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:43,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/record_integration_fixture.hpp:31,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:24:
/home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/mock_sequential_writer.hpp:28:8: error: ‘void MockSequentialWriter::open(const rosbag2_storage::StorageOptions&, const rosbag2_cpp::ConverterOptions&)’ marked ‘override’, but does not override
   28 |   void open(
      |        ^~~~
In file included from /usr/include/c++/9/memory:80,
                 from /opt/ros/foxy/src/gmock_vendor/include/gmock/gmock-actions.h:45,
                 from /opt/ros/foxy/src/gmock_vendor/include/gmock/gmock.h:59,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:15:
/usr/include/c++/9/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = MockSequentialReader; _Args = {}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<MockSequentialReader, std::default_delete<MockSequentialReader> >]’:
/home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:62:90:   required from here
/usr/include/c++/9/bits/unique_ptr.h:857:30: error: invalid new-expression of abstract class type ‘MockSequentialReader’
  857 |     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:42,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/record_integration_fixture.hpp:31,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:24:
/home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/mock_sequential_reader.hpp:25:7: note:   because the following virtual functions are pure within ‘MockSequentialReader’:
   25 | class MockSequentialReader : public rosbag2_cpp::reader_interfaces::BaseReaderInterface
      |       ^~~~~~~~~~~~~~~~~~~~
In file included from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/mock_sequential_reader.hpp:23,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:42,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/record_integration_fixture.hpp:31,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:24:
/opt/ros/foxy/include/rosbag2_cpp/reader_interfaces/base_reader_interface.hpp:40:16: note: 	‘virtual void rosbag2_cpp::reader_interfaces::BaseReaderInterface::open(const rosbag2_cpp::StorageOptions&, const rosbag2_cpp::ConverterOptions&)’
   40 |   virtual void open(
      |                ^~~~
In file included from /usr/include/c++/9/memory:80,
                 from /opt/ros/foxy/src/gmock_vendor/include/gmock/gmock-actions.h:45,
                 from /opt/ros/foxy/src/gmock_vendor/include/gmock/gmock.h:59,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:15:
/usr/include/c++/9/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = MockSequentialWriter; _Args = {}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<MockSequentialWriter, std::default_delete<MockSequentialWriter> >]’:
/home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:63:90:   required from here
/usr/include/c++/9/bits/unique_ptr.h:857:30: error: invalid new-expression of abstract class type ‘MockSequentialWriter’
  857 |     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:43,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/record_integration_fixture.hpp:31,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:24:
/home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/mock_sequential_writer.hpp:25:7: note:   because the following virtual functions are pure within ‘MockSequentialWriter’:
   25 | class MockSequentialWriter : public rosbag2_cpp::writer_interfaces::BaseWriterInterface
      |       ^~~~~~~~~~~~~~~~~~~~
In file included from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/mock_sequential_writer.hpp:23,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/rosbag2_transport_test_fixture.hpp:43,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/record_integration_fixture.hpp:31,
                 from /home/ubuntu/shared_dir/ros2_bag_ws/src/rosbag2/rosbag2_transport/test/rosbag2_transport/test_record_regex.cpp:24:
/opt/ros/foxy/include/rosbag2_cpp/writer_interfaces/base_writer_interface.hpp:37:16: note: 	‘virtual void rosbag2_cpp::writer_interfaces::BaseWriterInterface::open(const rosbag2_cpp::StorageOptions&, const rosbag2_cpp::ConverterOptions&)’
   37 |   virtual void open(
      |                ^~~~
make[2]: *** [CMakeFiles/test_record_regex__rmw_fastrtps_cpp.dir/build.make:63: CMakeFiles/test_record_regex__rmw_fastrtps_cpp.dir/test/rosbag2_transport/test_record_regex.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:512: CMakeFiles/test_record_regex__rmw_fastrtps_cpp.dir/all] Error 2
make: *** [Makefile:141: all] Error 2
---
Failed   <<< rosbag2_transport [5.92s, exited with code 2]

どうもrosbag2_transportパッケージのビルドに失敗しているようです。
しかし、よく見るとビルドが失敗しているのはテストコードなので、テストコード通さなければいけるじゃん?という安直なノリでrosbag2_transportCMakeLists.txtからテストに該当する部分をコメントアウトしてしまいます。笑

変更前
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(rosbag2_transport)

# 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)
endif()

# Windows supplies macros for min and max by default. We should only use min and max from stl
if(WIN32)
  add_definitions(-DNOMINMAX)
endif()

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(rcl REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw REQUIRED)
find_package(rosbag2_compression REQUIRED)
find_package(rosbag2_cpp REQUIRED)
find_package(rosbag2_interfaces REQUIRED)
find_package(rosbag2_storage REQUIRED)
find_package(rmw_implementation_cmake REQUIRED)
find_package(shared_queues_vendor REQUIRED)
find_package(yaml_cpp_vendor REQUIRED)

add_library(${PROJECT_NAME} SHARED
  src/rosbag2_transport/player.cpp
  src/rosbag2_transport/qos.cpp
  src/rosbag2_transport/recorder.cpp
  src/rosbag2_transport/topic_filter.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
ament_target_dependencies(${PROJECT_NAME}
  rcl
  rclcpp
  rcutils
  rmw
  rosbag2_compression
  rosbag2_cpp
  rosbag2_interfaces
  rosbag2_storage
  shared_queues_vendor
  yaml_cpp_vendor
)

# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(${PROJECT_NAME} PRIVATE "ROSBAG2_TRANSPORT_BUILDING_LIBRARY")

install(
  DIRECTORY include/
  DESTINATION include
)
install(
  TARGETS ${PROJECT_NAME}
  EXPORT export_${PROJECT_NAME}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
)

ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(export_${PROJECT_NAME})
ament_export_dependencies(
  rosbag2_cpp
  rosbag2_compression
  rosbag2_interfaces
  shared_queues_vendor
  yaml_cpp_vendor)

function(create_tests_for_rmw_implementation)
  # disable the following tests for connext
  # due to slower discovery of nodes
  set(SKIP_TEST "")
  if(${rmw_implementation} MATCHES "rmw_connext(.*)")
    set(SKIP_TEST "SKIP_TEST")
  endif()

  rosbag2_transport_add_gmock(test_play
    src/rosbag2_transport/qos.cpp
    test/rosbag2_transport/test_play.cpp
    INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common
    ${SKIP_TEST})

  rosbag2_transport_add_gmock(test_play_loop
    test/rosbag2_transport/test_play_loop.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common
    ${SKIP_TEST})

  rosbag2_transport_add_gmock(test_play_publish_clock
    test/rosbag2_transport/test_play_publish_clock.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common
    ${SKIP_TEST})

  rosbag2_transport_add_gmock(test_play_timing
    test/rosbag2_transport/test_play_timing.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common)

  rosbag2_transport_add_gmock(test_play_services
    test/rosbag2_transport/test_play_services.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common)

  rosbag2_transport_add_gmock(test_play_topic_remap
    test/rosbag2_transport/test_play_topic_remap.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common
    ${SKIP_TEST})

  rosbag2_transport_add_gmock(test_play_next
      test/rosbag2_transport/test_play_next.cpp
      INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
      LINK_LIBS rosbag2_transport
      AMENT_DEPS test_msgs rosbag2_test_common)

  rosbag2_transport_add_gmock(test_qos
    src/rosbag2_transport/qos.cpp
    test/rosbag2_transport/test_qos.cpp
    INCLUDE_DIRS
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
    AMENT_DEPS rosbag2_test_common yaml_cpp_vendor)

  rosbag2_transport_add_gmock(test_record
    test/rosbag2_transport/test_record.cpp
    INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common
    ${SKIP_TEST})

  rosbag2_transport_add_gmock(test_record_all
    test/rosbag2_transport/test_record_all.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common)

  rosbag2_transport_add_gmock(test_record_all_no_discovery
    test/rosbag2_transport/test_record_all_no_discovery.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common)

  rosbag2_transport_add_gmock(test_record_regex
    test/rosbag2_transport/test_record_regex.cpp
    LINK_LIBS rosbag2_transport
    AMENT_DEPS test_msgs rosbag2_test_common
    ${SKIP_TEST})

  rosbag2_transport_add_gmock(test_topic_filter
    test/rosbag2_transport/test_topic_filter.cpp
    INCLUDE_DIRS
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
    LINK_LIBS rosbag2_transport)
endfunction()

if(BUILD_TESTING)
  find_package(ament_cmake_gmock REQUIRED)
  find_package(ament_index_cpp REQUIRED)
  find_package(ament_lint_auto REQUIRED)
  find_package(test_msgs REQUIRED)
  find_package(rosbag2_test_common REQUIRED)
  include(cmake/rosbag2_transport_add_gmock.cmake)
  ament_lint_auto_find_test_dependencies()
  call_for_each_rmw_implementation(create_tests_for_rmw_implementation)
endif()

ament_package()
変更後
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(rosbag2_transport)

# 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)
endif()

# Windows supplies macros for min and max by default. We should only use min and max from stl
if(WIN32)
  add_definitions(-DNOMINMAX)
endif()

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(rcl REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw REQUIRED)
find_package(rosbag2_compression REQUIRED)
find_package(rosbag2_cpp REQUIRED)
find_package(rosbag2_interfaces REQUIRED)
find_package(rosbag2_storage REQUIRED)
find_package(rmw_implementation_cmake REQUIRED)
find_package(shared_queues_vendor REQUIRED)
find_package(yaml_cpp_vendor REQUIRED)

add_library(${PROJECT_NAME} SHARED
  src/rosbag2_transport/player.cpp
  src/rosbag2_transport/qos.cpp
  src/rosbag2_transport/recorder.cpp
  src/rosbag2_transport/topic_filter.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
ament_target_dependencies(${PROJECT_NAME}
  rcl
  rclcpp
  rcutils
  rmw
  rosbag2_compression
  rosbag2_cpp
  rosbag2_interfaces
  rosbag2_storage
  shared_queues_vendor
  yaml_cpp_vendor
)

# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(${PROJECT_NAME} PRIVATE "ROSBAG2_TRANSPORT_BUILDING_LIBRARY")

install(
  DIRECTORY include/
  DESTINATION include
)
install(
  TARGETS ${PROJECT_NAME}
  EXPORT export_${PROJECT_NAME}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
)

ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(export_${PROJECT_NAME})
ament_export_dependencies(
  rosbag2_cpp
  rosbag2_compression
  rosbag2_interfaces
  shared_queues_vendor
  yaml_cpp_vendor)

# function(create_tests_for_rmw_implementation)
#   # disable the following tests for connext
#   # due to slower discovery of nodes
#   set(SKIP_TEST "")
#   if(${rmw_implementation} MATCHES "rmw_connext(.*)")
#     set(SKIP_TEST "SKIP_TEST")
#   endif()
# 
#   rosbag2_transport_add_gmock(test_play
#     src/rosbag2_transport/qos.cpp
#     test/rosbag2_transport/test_play.cpp
#     INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common
#     ${SKIP_TEST})
# 
#   rosbag2_transport_add_gmock(test_play_loop
#     test/rosbag2_transport/test_play_loop.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common
#     ${SKIP_TEST})
# 
#   rosbag2_transport_add_gmock(test_play_publish_clock
#     test/rosbag2_transport/test_play_publish_clock.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common
#     ${SKIP_TEST})
# 
#   rosbag2_transport_add_gmock(test_play_timing
#     test/rosbag2_transport/test_play_timing.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common)
# 
#   rosbag2_transport_add_gmock(test_play_services
#     test/rosbag2_transport/test_play_services.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common)
# 
#   rosbag2_transport_add_gmock(test_play_topic_remap
#     test/rosbag2_transport/test_play_topic_remap.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common
#     ${SKIP_TEST})
# 
#   rosbag2_transport_add_gmock(test_play_next
#       test/rosbag2_transport/test_play_next.cpp
#       INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
#       LINK_LIBS rosbag2_transport
#       AMENT_DEPS test_msgs rosbag2_test_common)
# 
#   rosbag2_transport_add_gmock(test_qos
#     src/rosbag2_transport/qos.cpp
#     test/rosbag2_transport/test_qos.cpp
#     INCLUDE_DIRS
#       $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
#       $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
#     AMENT_DEPS rosbag2_test_common yaml_cpp_vendor)
# 
#   rosbag2_transport_add_gmock(test_record
#     test/rosbag2_transport/test_record.cpp
#     INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common
#     ${SKIP_TEST})
# 
#   rosbag2_transport_add_gmock(test_record_all
#     test/rosbag2_transport/test_record_all.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common)
# 
#   rosbag2_transport_add_gmock(test_record_all_no_discovery
#     test/rosbag2_transport/test_record_all_no_discovery.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common)
# 
#   rosbag2_transport_add_gmock(test_record_regex
#     test/rosbag2_transport/test_record_regex.cpp
#     LINK_LIBS rosbag2_transport
#     AMENT_DEPS test_msgs rosbag2_test_common
#     ${SKIP_TEST})
# 
#   rosbag2_transport_add_gmock(test_topic_filter
#     test/rosbag2_transport/test_topic_filter.cpp
#     INCLUDE_DIRS
#       $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
#     LINK_LIBS rosbag2_transport)
# endfunction()
# 
# if(BUILD_TESTING)
#   find_package(ament_cmake_gmock REQUIRED)
#   find_package(ament_index_cpp REQUIRED)
#   find_package(ament_lint_auto REQUIRED)
#   find_package(test_msgs REQUIRED)
#   find_package(rosbag2_test_common REQUIRED)
#   include(cmake/rosbag2_transport_add_gmock.cmake)
#   ament_lint_auto_find_test_dependencies()
#   call_for_each_rmw_implementation(create_tests_for_rmw_implementation)
# endif()

ament_package()

やっていることは、function(create_tests_for_rmw_implementation)if(BUILD_TESTING)の中身をまるっとコメントアウトにしているだけです。
これでもう一度ビルドを実行すると....やったー!ビルド通りました。
あとは、使いたいときにワークスペースをsourceすれば大丈夫です。

$ source ~/bag_tool_ws/install/setup.bash

使ってみる

rqt_bagを起動するには以下のコマンドを実行します。

$ ros2 run rqt_bag rqt_bag

よし、画面が開いたぞ!だけど、何かおかしいような....

あれ、ボタンのアイコンが表示されていない。。。
いや、心の目で見れば大丈夫。そうか、左から二つ目がrosbagのフォルダを選択するボタンか。
クリックしてみよう。ダイアログが開いたな。

これで、予め保存しておいた、rosbagのフォルダを選択してみよう!

おおー、しっかり表示されてる!値も確認できるぞ!

ということで、使える(?)ようになりました。笑

補足ですが、ROS2でrosbagを保存するには

$ ros2 bag record {topic_name}

とすると、指定したトピックが流れるたびに、rosbagとして記録が残ります(もちろん、複数のトピックをまとめて保存することも可能です)。
最終的に、rosbagはトピックの基本的な情報をまとめたmetadata.yamlと実際に送信されたトピック内部のデータを保存したデータベース(*****.db3)とをまとめた一つのフォルダが生成されます。
rqt_bagでrosbagを表示する際にはmetadata.yamlとデータベースのどちらも必要になります。
上記でrosbagのフォルダを選択していましたが、フォルダ内に必要なファイルが揃っていないとうまくrosbagが表示されなかったりするので、ご注意ください。

まとめ

rqt_bagが重宝するのは、おそらくバグの解析が必要になったときだと思います。
大規模なプロジェクトになると、様々なトピックが送受信され、それぞれのトピックがいつ送信されたのか前後関係を把握するのが難しくなったりするので、こういったツールを使って可視化できるのはとても役に立ちます。
皆さんもぜひバグの解析にrqt_bagを使ってみてくださいね!

脚注
  1. ROS2と区別するために明示的に1をつけて「ROS1」と記載しています。 ↩︎

  2. https://github.com/ros2/rosbag2/pull/687 ↩︎

GitHubで編集を提案

Discussion

ログインするとコメントできます