跳到正文

Wiki

回溯rosbag2

約 9 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

1.概述

方式1一邊採集資料,一邊生成地圖資訊。

方式2是將採集資料和生成地圖資訊分割開來了,方式2做到了解耦合,所以更靈活一些。用同一套資料,可能用不同的演算法處理,總之,非常靈活。

留存的過程咱們也可以叫做序列化。(轉化為磁碟檔案)

留存一般叫錄製(序列化)。

讀取一般叫回放(反序列化)。

留存時也可以將檔案進行分卷,也就是每個檔案最大能佔多大的大小,如果超過該大小,就新建一個檔案繼續留存。(類似於壓縮檔案的分卷)

這樣的話,存的資料太大,我們一次性開啟太慢,就可以分段開啟。

需要依賴於rosbag2_cpp或者rosbag2_py

然後還要依賴於geometry_msgs,這個是因為我們要序列化的資料是這個包下的速度指令。

ros2 pkg create cpp02_rosbag --build-type ament_cmake --dependencies rclcpp rosbag2_cpp geometry_msgs --node-name cpp01_writer

2.rosbag2的命令工具

一般ROSBAG2的使用有命令列工具和編碼兩種使用方式,命令列工具功能比較齊全,夠用。

檢視幫助文件ros2 bag -h

主要有6個指令。

可以看record的詳細用法。

record是用來將訊息序列化的。(錄製)

play是用來反序列化訊息的。(回放)

info是用來輸出bag檔案的相關資訊的。比如有多少條訊息,錄製起始時間和終止時間以及持續時間。

reindex是重建bag檔案,可以修改bag源資料檔案。

list是輸出rosbag2中可用的外掛(高階應用)。

convert我們可以用這個給bag檔案修改副檔名,也可以把多個bag檔案合併成一個檔案。

開啟小烏龜節點與鍵盤控制小烏龜節點。

我們用鍵盤控制小烏龜,然後把速度指令通過rosbag2給序列化。

然後我們關掉兩個節點,再重啟小烏龜節點,然後這次不通過鍵盤控制,而是通過play bag檔案讓小烏龜運動。

record指令後面要跟一個話題組成的列表,但是在咱們下面的操作中,只用到了一個話題。

然後再用output,把序列化後的檔案寫出到一個磁碟目錄中去。

cd進想儲存bag的目錄,然輸入record指令,後面跟話題名稱,然後-o +bag檔名,這裡也可以不重新命名bag檔案,這樣會用預設的名字,預設的名稱是年月日命名的。

這樣就已經開始錄製了。

按Ctrl + C進行結束,結束有個提示,說正在將訊息寫入bag,需要一段時間。

這個yaml檔案是源資料檔案。

db3是SQLite資料庫,這個是移動端(比如手機)常用的資料庫。

這個資料庫就儲存了錄製的資料。

3.rosbag2 C++案例分析及框架搭建

add_executable(demo01_writer src/demo01_writer.cpp)
ament_target_dependencies(
  demo01_writer
  "rclcpp"
  "rosbag2_cpp"
  "geometry_msgs"
)

add_executable(demo02_reader src/demo02_reader.cpp)
ament_target_dependencies(
  demo02_reader
  "rclcpp"
  "rosbag2_cpp"
  "geometry_msgs"
)

install(TARGETS 
  demo01_writer
  demo02_reader
  DESTINATION lib/${PROJECT_NAME})

4.rosbag2 C++ 錄製資料

/* 
  需求:录制 turtle_teleop_key 节点发布的速度指令。
  步骤:
    1.包含头文件;
    2.初始化 ROS 客户端;
    3.定义节点类;
      3-1.创建写出对象指针;
      3-2.设置写出的目标文件;
      3-3.写出消息。
    4.调用 spin 函数,并传入对象指针;
    5.释放资源。

 */
// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "rosbag2_cpp/writer.hpp"
#include "geometry_msgs/msg/twist.hpp"

using std::placeholders::_1;

// 3.定义节点类;
class SimpleBagRecorder : public rclcpp::Node
{
public:
  SimpleBagRecorder()
  : Node("simple_bag_recorder")
  {
    // 3-1.创建写出对象指针;
    writer_ = std::make_unique<rosbag2_cpp::Writer>();
    // 3-2.设置写出的目标文件;(目录为ws目录)
    writer_->open("src/cpp02_rosbag/my_bag");
    subscription_ = create_subscription<geometry_msgs::msg::Twist>(
      "/turtle1/cmd_vel", 10, std::bind(&SimpleBagRecorder::topic_callback, this, _1));
  }

private:
  void topic_callback(std::shared_ptr<rclcpp::SerializedMessage> msg) const
  {
    rclcpp::Time time_stamp = this->now();
    // 3-3.写出消息。
    RCLCPP_INFO(this->get_logger(),"数据写出... ...");
    writer_->write(msg, "/turtle1/cmd_vel", "geometry_msgs/msg/Twist", time_stamp);
  }

  rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr subscription_;
  std::unique_ptr<rosbag2_cpp::Writer> writer_;
};

int main(int argc, char * argv[])
{
  // 2.初始化 ROS 客户端;
  rclcpp::init(argc, argv);
  // 4.调用 spin 函数,并传入对象指针;
  rclcpp::spin(std::make_shared<SimpleBagRecorder>());
  // 5.释放资源。
  rclcpp::shutdown();
  return 0;
}

這是一個相對目錄,目錄位置是工作空間目錄。

寫資料之前,要先建立一個訂閱方,訂閱方要建立一個回撥函式。

回撥函式入口引數,訊息型別用write函式的入口引數。

這裡要用斜槓代替冒號,因為入口是string型別。

建立烏龜節點。

啟動writer節點

執行小烏龜

執行一會兒後,關掉所有節點。

成功生成了檔案

驗證錄製檔案是否成功。

在驗證前,先建立一個烏龜節點,不用建立控制節點。

ros2 bag play src/cpp02_rosbag/my_bag

可以看到烏龜正常走了。回放成功!

如果已經生成了一遍my_bag,再想生成新的會顯示不能覆蓋。

解決方案,可以把my_bag設定為動態的,加個時間戳或者直接按功能命名。

5.rosbag2 C++ 讀取資料

/* 
  需求:读取 bag 文件数据。
  步骤:
    1.包含头文件;
    2.初始化 ROS 客户端;
    3.定义节点类;
      3-1.创建读取对象指针;
      3-2.设置读取的目标文件;
      3-3.读消息;
      3-4.关闭文件。
    4.调用 spin 函数,并传入对象指针;
    5.释放资源。

 */
 // 1.包含头文件;
 #include "rclcpp/rclcpp.hpp"
 #include "rosbag2_cpp/reader.hpp"
 #include "geometry_msgs/msg/twist.hpp"
 // 3.定义节点类;
class SimpleBagPlayer: public rclcpp::Node {
public:
    SimpleBagPlayer():Node("simple_bag_player"){
        // 3-1.创建读取对象指针;
        reader_ = std::make_unique<rosbag2_cpp::Reader>();
        // 3-2.设置读取的目标文件;
        reader_->open("src/cpp02_rosbag/my_bag");
        // 3-3.读消息;
        while (reader_->has_next())
        {
            auto twist = reader_->read_next<geometry_msgs::msg::Twist>();
            RCLCPP_INFO(this->get_logger(),"线速度:%.2f, 角速度: %.2f",twist.linear.x, twist.angular.z);
        }
        // 3-4.关闭文件。
        reader_->close();
    }
private:
    std::unique_ptr<rosbag2_cpp::Reader> reader_;

};

int main(int argc, char const *argv[]){
    // 2.初始化 ROS 客户端;
    rclcpp::init(argc,argv);
    // 4.调用 spin 函数,并传入对象指针;
    rclcpp::spin(std::make_shared<SimpleBagPlayer>());
    // 5.释放资源。
    rclcpp::shutdown();
    return 0;
}

編譯

這顯示能讀出來幾條資訊。能讀出來8條。

正好8條