ros时间戳机制剖析

事起

我发现ros在进行算法测试时经常会用到时间戳进行同步等操作,那么就需要数据的时间戳和我要使用的时间戳应该是在同一个尺度下的(比如都使用录制bag包当时的数据),ros中正好有这样的管理过程,之前没有注意里面具体的机制,这里详细的说明一下情况是怎么样的.

ROS1 时间系统详解

1. ROS时间系统概述

ROS (Robot Operating System) 提供了一套完整的时间管理系统,用于处理机器人系统中的时间同步问题。ROS时间系统的核心特点包括:

  • 统一时间基准:所有节点共享同一个时间基准
  • 仿真时间支持:支持仿真环境下的时间控制
  • 时间同步机制:通过clock话题实现时间同步
  • 灵活的时间模式:支持真实时间和仿真时间切换

1.1 时间类型

ROS中主要有两种时间类型:

  1. Wall Time(墙钟时间):系统真实时间,不受ROS参数影响(主要通过import time然后通过time.time()获取墙钟时间即可)
  2. ROS Time:ROS管理的时间,可以是真实时间或仿真时间

2. rospy.time 工作原理

2.1 基本概念

rospy.Time 是ROS Python API中的时间类,提供了时间相关的所有功能:

import rospy
from rospy import Time, Duration
import time

rospy.init_node('time_comparison_node')

# 获取当前ROS时间
current_time = rospy.Time.now()
# wall time 
time_wall = time.time()

# 创建特定时间戳
specific_time = rospy.Time(secs=1234567890, nsecs=123456789)

# 时间运算
time_diff = current_time - specific_time
future_time = current_time + rospy.Duration(10)  # 10秒后

print(f"当前ROS时间: {current_time.to_sec():.3f}")
print(f"当前墙钟时间: {time_wall:.3f}")
print(f"特定时间戳: {specific_time.to_sec():.3f}")
print(f"时间差: {time_diff.to_sec():.3f}")
print(f"10秒后的时间: {future_time.to_sec():.3f}")

在这里插入图片描述
正常运行过程时,ros都是以标准时间戳输出的信息.(注意,想要获得ros的时间戳,必须要初始化节点,也就是rospy.init_node(“time_node”))

2.2 时间获取机制

rospy.Time.now() 的行为取决于 use_sim_time 参数:

  • use_sim_time=false:返回系统真实时间
  • use_sim_time=true:返回从 /clock 话题接收到的仿真时间

3. 仿真时间与真实时间的区别

3.1 真实时间模式(Wall Time Mode)

# 设置为真实时间模式
rosparam set use_sim_time false

特点:

  • 时间与系统时钟同步
  • 时间流逝速度固定(1:1)
  • 适用于真实机器人系统

3.2 仿真时间模式(Simulation Time Mode)

# 设置为仿真时间模式
rosparam set use_sim_time true

特点:

  • 时间由仿真器或外部源控制
  • 可以暂停、加速或减速
  • 适用于仿真环境和数据回放

注意,设置这个参数并不能实时修改我的ros时间,意思就是,如果之前已经通过py来获取了真实的ros时间,此时动态设置use_sim_time并不会直接起作用,重启节点之后可以起作用.

然后设置了这个参数之后我们可以再次打印一下这个时间戳的信息:

import rospy
from rospy import Time, Duration
import time

rospy.init_node('time_comparison_node')

while not rospy.is_shutdown():

    # 获取当前ROS时间
    current_time = rospy.Time.now()
    # wall time 
    time_wall = time.time()

    # 创建特定时间戳
    specific_time = rospy.Time(secs=1234567890, nsecs=123456789)

    # 时间运算
    time_diff = current_time - specific_time
    future_time = current_time + rospy.Duration(10)  # 10秒后

    print(f"当前ROS时间: {current_time.to_sec():.3f}")
    print(f"当前墙钟时间: {time_wall:.3f}")
    print(f"特定时间戳: {specific_time.to_sec():.3f}")
    print(f"时间差: {time_diff.to_sec():.3f}")
    print(f"10秒后的时间: {future_time.to_sec():.3f}")
    
    time.sleep(1)

可以发现此时的时间表现为:
当前ROS时间: 0.000
当前墙钟时间: 1758607078.709
特定时间戳: 1234567890.123
时间差: -1234567890.123
也就是一直都是0!!

因为对于此时来说,ros的时间戳就是由话题来进行管理的了.接下来我们来发布这个话题.

4. Clock话题管理机制

4.1 Clock话题结构

/clock 话题使用 rosgraph_msgs/Clock 消息类型:

# rosgraph_msgs/Clock
time clock

4.2 时间发布者

仿真器(如Gazebo)或rosbag会发布clock消息:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
from rosgraph_msgs.msg import Clock

def clock_publisher():
    """时间发布节点示例"""
    rospy.init_node('clock_publisher', anonymous=True)
    
    # 创建clock发布者
    clock_pub = rospy.Publisher('/clock', Clock, queue_size=10)
    
    rate = rospy.Rate(100)  # 100Hz
    start_time = rospy.Time.now()
    
    while not rospy.is_shutdown():
        # 创建clock消息
        clock_msg = Clock()
        
        # 仿真时间(可以是任意时间流速)
        elapsed = rospy.Time.now() - start_time
        clock_msg.clock = start_time + rospy.Duration(elapsed.to_sec() * 2.0)  # 2倍速
        
        clock_pub.publish(clock_msg)
        # rate.sleep()

if __name__ == '__main__':
    try:
        clock_publisher()
    except rospy.ROSInterruptException:
        pass

在这里插入图片描述

可以看到,第一次没有clock的时候还是打印了ros的0的时间戳,后来发布了clock之后就可以获得我们发布的clock中的时间戳了。

5. use_sim_time 参数作用机

5.1 参数设置方法

# 方法1:命令行设置
rosparam set use_sim_time true

# 方法2:launch文件设置
<param name="use_sim_time" value="true" />

# 方法3:代码中设置
rospy.set_param('use_sim_time', True)

5.2 参数影响范围

  • 所有ROS节点:影响整个ROS系统的时间行为
  • 消息时间戳:影响消息头中的时间戳
  • TF变换:影响坐标变换的时间戳
  • 定时器:影响rospy.Timer的行为

5.3 切换注意事项

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy

def time_mode_switcher():
    """时间模式切换示例"""
    rospy.init_node('time_switcher')
    
    # 检查当前时间模式
    use_sim_time = rospy.get_param('use_sim_time', False)
    rospy.loginfo(f"当前时间模式: {'仿真时间' if use_sim_time else '真实时间'}")
    
    # 等待时间同步(仿真时间模式下)
    if use_sim_time:
        rospy.loginfo("等待时间同步...")
        rospy.wait_for_message('/clock', rospy.AnyMsg)
        rospy.loginfo("时间同步完成")
    
    # 显示当前时间
    current_time = rospy.Time.now()
    rospy.loginfo(f"当前ROS时间: {current_time.to_sec()}")

if __name__ == '__main__':
    time_mode_switcher()

6. Rosbag与时间控制

6.1 Rosbag时间发布机制

Rosbag在回放时会自动发布clock消息:

# 正常回放(发布clock)
rosbag play data.bag --clock

# 指定回放速度
rosbag play data.bag --clock --rate=2.0  # 2倍速回放

# 暂停回放
rosbag play data.bag --clock --pause

6.2 时间控制选项

# 从指定时间开始回放
rosbag play data.bag --clock --start=10.0

# 回放指定时长
rosbag play data.bag --clock --duration=30.0

# 循环回放
rosbag play data.bag --clock --loop

# 立即开始(不等待订阅者)
rosbag play data.bag --clock --immediate

到这里我们就能理解所有的时间的关系了,以及为什么可以通过clock话题来实现过去时间戳的统一化。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白云千载尽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值