ROS(Robot Operating System)是一个用于机器人开发的开源软件框架,其中涉及到了一些与时间相关的概念和工具,如时间戳、计时器等。本文将主要介绍ROS中时间戳的概念和应用,并提供一个Python代码案例演示如何处理ROS时间戳。

ROS时间戳的概念

在ROS中,时间戳(timestamp)是用来表示某个事件发生时间的一种方式。时间戳通常由两部分组成:一个整数表示自某个特定时间点(如1970年1月1日00:00:00 UTC)到事件发生时的秒数(即“秒级时间戳”),以及一个整数表示事件发生时相对于秒级时间戳的纳秒数(即“纳秒偏移量”)。

在ROS中,时间戳通常用一种特定的数据结构rospy.Time来表示。这个数据结构包含两个成员变量secsnsecs,分别对应秒级时间戳和纳秒偏移量。例如,下面的代码创建了一个时间戳表示2022年3月1日12:34:56.789000000这个时刻:

import rospy t = rospy.Time.from_sec(1646145296.789)

其中from_sec方法将秒级时间戳作为参数,返回一个rospy.Time对象。

除了rospy.Time,在ROS中还有另外一个时间戳类型std_msgs/Header,该类型包含一个stamp成员变量,是一个rospy.Time对象,表示消息的时间戳信息。例如,下面是一个带有时间戳的消息:

 

header:

 seq: 1

 stamp:

  { secs: 1646145296,

   nsecs: 789000000 }

 frame_id: "world"

ROS时间戳的应用

在ROS中,时间戳被广泛应用于消息传输、数据记录、控制等方面。其中,一些重要的应用包括:

消息传输

ROS中的消息通常包含一个时间戳stamp,用来表示消息的发送时间。这个时间戳在一些应用中非常重要,例如在多机器人协同、多传感器融合等场景下,需要保证各个消息之间的时间同步,才能正确地进行数据融合和处理。

数据记录

在ROS中,数据记录是一项重要的功能。数据记录器(rosbag)可以记录ROS系统中所有的消息和服务调用,并将它们保存到磁盘上,以供后续的数据处理和分析。在数据记录过程中,时间戳是一个非常重要的信息,可以用来对消息进行排序、匹配、过滤等操作。

时间同步

我们在ROS中使用的时间戳有两种,一种是ROS的系统时间戳(ROS time), 另一种是外部硬件设备的时间戳(例如相机、激光雷达等),也称为硬件时间戳(hardware time)。

ROS时间戳是一个浮点数,以秒为单位,从1970年1月1日00:00:00 UTC开始计算,可以通过rospy.Time.now()获取。ROS时间戳在整个ROS系统中是全局唯一的,也就是说,当ROS系统中的节点(node)需要在时间上进行同步时,ROS时间戳可以作为一个标准,各个节点可以基于它来同步。

硬件时间戳则是由外部设备提供的,它可以是相对时间戳(相对于设备启动时间或者某个固定时间点的时间差),也可以是绝对时间戳(相对于某个固定的时间点的时间)。由于外部设备和ROS系统是

不同的系统,它们的时钟可能会有差异,因此需要进行时间戳转换,将硬件时间戳转换成ROS时间戳,或将ROS时间戳转换成硬件时间戳,以便进行时间同步和数据融合等操作。

在ROS中,时间戳的表示方式有两种:secs和nsecs。其中,secs表示自1970年1月1日00:00:00 UTC开始经过的秒数,是一个32位整数;nsecs表示自1970年1月1日00:00:00 UTC开始经过的纳秒数,是一个32位整数。ROS时间戳可以通过secs和nsecs组合而成。

下面是一个Python代码示例,演示如何将ROS时间戳转换为Python中的datetime对象:

import rospy
from datetime import datetime

# 获取ROS时间戳
ros_time = rospy.Time.now()

# 将ROS时间戳转换为datetime对象
secs = ros_time.secs
nsecs = ros_time.nsecs
time_in_nanoseconds = secs * 1e9 + nsecs
datetime_obj = datetime.utcfromtimestamp(time_in_nanoseconds / 1e9)

# 打印datetime对象
print(datetime_obj)

ROS消息中的meta字段里的时间戳:

header: 
  seq: 86694
  stamp: 
    secs: 1673860445
    nsecs: 720726000
  frame_id: "car"
meta: 
  algorithm_name: "vision_perception"
  instance_name: "vision_perception_around_view"
  sensor_timestamp_us: 1673860445491191
  pipeline_start_timestamp_us: 1673860445624726
  pipeline_finish_timestamp_us: 1673860445719726
  relevant_frames: 
    - 
      timestamp_us: 1673860445491191
      sequence: 13501
      camera_source: 
        value: 0
      camera_model: 
        value: 2
    - 
      timestamp_us: 1673860445491191
      sequence: 13501
      camera_source: 
        value: 1
      camera_model: 
        value: 2
    - 

在这个ROS消息中,meta字段包含了一些额外的元数据信息,其中包括三个时间戳:

  • sensor_timestamp_us:传感器时间戳,单位为微秒。它表示数据采集的实际时间。
  • pipeline_start_timestamp_us:数据处理管道开始处理的时间戳,单位为微秒。
  • pipeline_finish_timestamp_us:数据处理管道处理完成的时间戳,单位为微秒。

这三个时间戳可以用来评估数据处理管道的性能,例如计算延迟等指标。同时,还可以使用这些时间戳来进行数据同步,例如将传感器数据同步到机器人的其他传感器或执行器。

需要注意的是,这三个时间戳的精度可能会因为硬件、操作系统或其他因素而不同,因此需要进行时间戳转换和校准,以确保数据的准确性和可靠性。

除了这三个时间戳之外,ROS消息中的relevant_frames字段中还包含了一些与时间相关的信息,例如timestamp_us字段表示相关帧的时间戳,sequence表示相关帧的序列号等等。这些信息可以帮助我们对数据进行更加精细的处理和分析。

stamp 和 meta

stamp: 
  secs: 1673860445
  nsecs: 720726000

这个时间戳表示 ROS 消息的创建时间。与此相比,meta 部分中的 timestamp_us 字段用于记录与这个消息相关的其他时间戳,例如传感器采集时间戳、处理流程开始/结束时间戳、相关帧的时间戳等。

因此,如果要在 meta 部分中找到与 stamp 字段对应的时间戳,应该寻找最接近 stamp 时间戳的 timestamp_us 值。在这个例子中,sensor_timestamp_us 字段的值是 1673860445491191,与 stamp 时间戳的值 1673860445.720726000 相差不到 1 毫秒,因此它可能是与 stamp 对应的时间戳。但是需要注意的是,实际上这个时间戳可能对应于消息的创建时间,也可能对应于消息中包含的某个帧的时间戳,具体要看这个消息的含义和上下文。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐