ROS-rosbag
机器人传感器获取到的信息,有时我们可能需要时时处理,有时可能只是采集数据,事后分析,比如:
机器人导航实现中,可能需要绘制导航所需的全局地图,地图绘制实现,有两种方式,方式1:可以控制机器人运动,将机器人传感器感知到的数据时时处理,生成地图信息。方式2:同样是控制机器人运动,将机器人传感器感知到的数据留存,事后,再重新读取数据,生成地图信息。两种方式比较,显然方式2使用上更为灵活方便。
在ROS中关于数据的留存以及读取实现,提供了专门的工具: rosbag。
 ROS Bag通常用于以下场景:
- 离线数据处理:在无法连接实时ROS系统时,可以使用ROS Bag记录消息,然后在离线状态下进行数据处理和算法开发。
- 数据集收集:ROS Bag可以用于收集数据集,以用于机器学习和深度学习等应用。
- 调试和测试:ROS Bag可以用于调试和测试ROS节点和程序的行为。
概念
 是用于录制和回放 ROS 主题的一个工具集。
作用
 实现了数据的复用,方便调试、测试。
本质
 rosbag本质也是ros的节点,当录制时,rosbag是一个订阅节点,可以订阅话题消息并将订阅到的数据写入磁盘文件;当重放时,rosbag是一个发布节点,可以读取磁盘文件,发布文件中的话题消息。
需求
 ROS 内置的乌龟案例并操作,操作过程中使用 rosbag 录制,录制结束后,实现重放
一、命令行
实现
 1.准备
 创建目录保存录制的文件
mkdir ./xxx
cd xxx
2.开始录制
rosbag record -a -O 目标文件
- -a表示所有话题,-o表示输出
- 操作小乌龟一段时间,结束录制使用 ctrl + c,在创建的目录中会生成bag文件。
  
3.查看文件
rosbag info 文件名

 4.回放文件
rosbag play 文件名
重启乌龟节点,会发现,乌龟按照录制时的轨迹运动。
如果想改变消息的发布速率,可以用下面的命令,-r 后面的数字对应播放速率。
rosbag play -r 2 文件名
如果希望 rosbag 循环播放,可以用命令
rosbag play -l  文件名  # -l== --loop
如果只播放感兴趣的 topic ,则用命令
rosbag play <bagfile> --topic /topic1
上述播放命令执行期间,空格键可以暂停播放。
二、编码
方案A:C++实现
 1.写 bag
#include "ros/ros.h"
#include "rosbag/bag.h"
#include "std_msgs/String.h"
int main(int argc, char *argv[])
{
    ros::init(argc,argv,"bag_write");
    ros::NodeHandle nh;
    //创建bag对象
    rosbag::Bag bag;
    //打开
    bag.open("/home/rosdemo/demo/test.bag",rosbag::BagMode::Write);
    //写
    std_msgs::String msg;
    msg.data = "hello world";
    bag.write("/chatter",ros::Time::now(),msg);
    bag.write("/chatter",ros::Time::now(),msg);
    bag.write("/chatter",ros::Time::now(),msg);
    bag.write("/chatter",ros::Time::now(),msg);
    //关闭
    bag.close();
    return 0;
}

2.读bag
/*  
    读取 bag 文件:
*/
#include "ros/ros.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "std_msgs/String.h"
#include "std_msgs/Int32.h"
int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"bag_read");
    ros::NodeHandle nh;
    //创建 bag 对象
    rosbag::Bag bag;
    //打开 bag 文件
    bag.open("/home/rosdemo/demo/test.bag",rosbag::BagMode::Read);
    //读数据
    for (rosbag::MessageInstance const m : rosbag::View(bag))
    {
        std_msgs::String::ConstPtr p = m.instantiate<std_msgs::String>();
        if(p != nullptr){
            ROS_INFO("读取的数据:%s",p->data.c_str());
        }
    }
    //关闭文件流
    bag.close();
    return 0;
}
- ros中的bag包是按逐帧序列存储的,解析的时候创建View类可以逐帧把数据读取出来
  
- rosbag::View是ROS Bag文件中的一组消息的视图,它提供了一些方便的方法来遍历和访问这些消息。
rosbag::View实际上是一个包含rosbag::Connection对象的集合,每个对象代表一个主题。rosbag::Connection对象包含一组时间戳和消息,表示该主题的所有消息。您可以使用以下方法来访问这些消息:
- begin():返回指向第一条消息的迭代器。
- end():返回指向最后一条消息后面的位置的迭代器。
- rbegin():返回指向最后一条消息的迭代器。
- rend():返回指向第一条消息前面的位置的迭代器。
- size():返回视图中消息的数量。
在使用rosbag::View遍历Bag文件中的所有消息时,每个迭代器会返回一个rosbag::MessageInstance对象。这个对象包含了消息的时间戳、消息类型和消息数据等信息。您可以使用以下方法来访问这些信息:
- getTime():返回消息的时间戳。
- getTopic():返回消息所属的主题名称。
- getDataType():返回消息的数据类型。
- instantiate():将消息实例化为指定的数据类型。如果无法实例化,则返回空指针。
方案B:Python实现
1.写 bag
#! /usr/bin/env python
import rospy
import rosbag
from std_msgs.msg import String
if __name__ == "__main__":
    #初始化节点 
    rospy.init_node("w_bag_p")
    # 创建 rosbag 对象
    bag = rosbag.Bag("/home/rosdemo/demo/test.bag",'w')
    # 写数据
    s = String()
    s.data= "hahahaha"
    bag.write("chatter",s)
    bag.write("chatter",s)
    bag.write("chatter",s)
    # 关闭流
    bag.close()
2.读bag
#! /usr/bin/env python
import rospy
import rosbag
from std_msgs.msg import String
if __name__ == "__main__":
    #初始化节点 
    rospy.init_node("w_bag_p")
    # 创建 rosbag 对象
    bag = rosbag.Bag("/home/rosdemo/demo/test.bag",'r')
    # 读数据
    bagMessage = bag.read_messages("chatter")
    for topic,msg,t in bagMessage:
        rospy.loginfo("%s,%s,%s",topic,msg,t)
    # 关闭流
    bag.close()
参考:
 [1]Autolabor-ROS机器人入门课程《ROS理论与实践》季基础教程
 [2]【Autolabor初级教程】ROS机器人入门
 [3]胡春旭.ROS机器人开发实践[M].机械工业出版社,2018.
 [4]http://t.csdnimg.cn/6U3gV
 [5]https://blog.csdn.net/weixin_40582034/article/details/129040895
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!