ROS基础(五):ROS中的时间与TF中的时间

一、Time 与 Duration

roscpp里有两种时间的表示方法,一种是时刻(ros::Time),一种是时长(ros::Duration)。

基本使用



ros::Time begin = ros::Time::now(); //获取当前时间
ros::Time at_some_time1(5,20000000);  //5.2s
ros::Time at_some_time2(5.2); //同上,重载了float类型和两个uint类型的构造函数
ros::Duration one_hour(60*60,0); //1h

double secs1 = at_some_time1.toSec();//将Time转为double型时间
double secs2 = one_hour.toSec();//将Duration转为double型时间

时间的加减

    ros::Time t1 = ros::Time::now() - ros::Duration(5.5); //t1是5.5s前的时刻,Time加减Duration返回都是Time
    ros::Time t2 = ros::Time::now() + ros::Duration(3.3);//t2是当前时刻往后推3.3s的时刻
    ros::Duration d1 = t2 - t1;//从t1到t2的时长,两个Time相减返回Duration类型
    ros::Duration d2 = d1 -ros::Duration(0,300);//两个Duration相减,还是Duration


sleep相关

    ros::Duration(0.5).sleep(); //用Duration对象的sleep方法休眠

    ros::Rate r(10); //10HZ
    while(ros::ok())
    {
    
    
        r.sleep();
        //定义好sleep的频率,Rate对象会自动让整个循环以10hz休眠,即使有任务执行占用了时间
    }

定时器

    ros::Timer timer1 = n.createTimer(ros::Duration(0.1), callback1);  //timer1每0.1s触发一次callback1函数
    ros::Timer timer2 = n.createTimer(ros::Duration(1.0), callback2);  //timer2每1.0s触发一次callback2函数

    ros::spin();  //千万别忘了spin,只有spin了才能真正去触发回调函数

二、TF中的时间

关于TF的详解:可以参考我之前的教程:


ROS基础(四):一文说尽TF坐标变换

本部分基于上文中实现的小乌龟跟随程序,继续做相关实验。

1. TF2中的time(0)


time1 = ros::Time(0);
time2 = ros::Time::now();

注意:

For tf2, time 0 means “the latest available” transform in the buffer.

所以,如果我们将下方代码中的ros::Time(0)更改为ros::Time::now()

  try{
    
    
    transformStamped = tfBuffer.lookupTransform("turtle2", "turtle1", ros::Time(0));
  } catch (tf2::TransformException &ex) {
    
    
    ROS_WARN("Could NOT transform turtle2 to turtle1: %s", ex.what());
  }

会出现如下报错:

[ WARN] [1610786104.938774121]: wait tf tree: Lookup would require extrapolation into the future. Requested time 1610786104.938642617 but the latest data is at time 1610786104.933745945, when looking up transform from frame [turtle1] to frame [turtle2]

大意就是,我们在试图获取未来的tf变换。

2. wait for transforms

上述出现报错,原因很简单,tf_listener有个buffer来存储所有坐标变换。tf_tree是由很多的broadcaster来维护的,每个broadcaster进入buffer的时候都要花费个几ms,所以如果请求now当前时刻的tf变换的话,我们应该等个几个ms再来获取信息。

由此,引出参数wait_for_transform

  try{
    
    
    transformStamped = tfBuffer.lookupTransform("turtle2", "turtle1", ros::Time::now(), 
                                                ros::Duration(3.0));
  } catch (tf2::TransformException &ex) {
    
    
    ROS_WARN("Could NOT transform turtle2 to turtle1: %s", ex.what());
  }

lookupTransform()最后加入参数wait_for_transform之后, 有两种结果:

  • 在等待时间内,要查询的两个/frame搭上线,退出等待。
  • 两个/frame没有连接上,就等到timeout结束

3. 带时间间隔的TF变换

本部分想要实现,second_turtle 跟着 first_turtle的5s前的状态来行动。

很直观的想法:

  try{
    
    
    ros::Time past = ros::Time::now() - ros::Duration(5.0);
    transformStamped = tfBuffer.lookupTransform("turtle2", "turtle1",
                               past, ros::Duration(1.0));

如上所示,我们将now减去5s

查看结果:

在这里插入图片描述
乌龟就像喝醉了酒一样,完全没有follow第一只乌龟。

究其原因,在求now的turtle1 to turtle2 时候,我们却使用 turtle1(5s前) to worldworld toturtle2(5s前) 来求解。

这导致turtle2一直被自己5s前的状态所牵扯。

正确的做法应该是:

now的turtle1 to turtle2 = turtle1(5s前) to world* worldto turtle2(now)

为了实现上述目标,tf2为我们提供如下接口:


  try{
    
    
    ros::Time now = ros::Time::now();
    ros::Time past = now - ros::Duration(5.0);
    transformStamped = tfBuffer.lookupTransform("turtle2", now,
                             "turtle1", past,
                             "world", ros::Duration(1.0));

其中6个参数的lookupTransform()版本参数含义:

  1. target frame,
  2. at this time …
  3. source frame,
  4. at past time.
  5. Specify the frame that does not change over time, in this case the “/world” frame
  6. the time-out

查看实验结果:

在这里插入图片描述没有问题!!

猜你喜欢

转载自blog.csdn.net/allenhsu6/article/details/112694790