博客转载自:https://www.ncnynl.com/archives/201702/1313.html

ROS与C++入门教程-tf-深入Time和TF

说明:

  • 介绍使用waitForTransform函数去等待TF树中的变换生效

TF和Time

  • 在前面的教程中,我们了解了tf如何跟踪坐标系树。
  • 此树随时间变化,tf存储每个变换的时间快照(默认情况下最多为10秒)。
  • 直到现在,我们使用lookupTransform()函数来获取该tf树中最新的可用变换,而不知道什么时候记录变换。
  • 本教程将教您如何在特定时间获取转换。
  • 在上个教程的文件上修改:
$ roscd learning_tf
$ vim src/turtle_tf_listener.cpp
  • 找到代码:
try{
listener.lookupTransform("/turtle2", "/carrot1",
ros::Time(0), transform);
  • 修改为:
try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time(0), transform);
  • 更改/turtle2跟随/turtle1,不是/carrot1,我们指定了时间为0,即获得最新有效的变换。
  • 改变获取当前时间的变换,即改为now(), 修改代码:
  try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time::now(), transform);
  • 编译运行:
  $ catkin_make
$ roslaunch learning_tf start_demo.launch
  • lookupTransform()函数提示失败:
[ERROR] [1287871653.885277559]: You requested a transform that is 0.018 miliseconds in the past, but the most recent transform in the tf buffer is 7.681 miliseconds old.
When trying to transform between /turtle1 and /turtle2.
  • 这是为什么? 每个监听器有一个缓冲区,它存储来自不同tf广播者的所有坐标变换。 当广播者发出变换时,变换进入缓冲区之前需要一些时间(通常是几个毫秒)。 因此,当您在时间“now”请求坐标系变换时,您应该等待几毫秒以获得该信息。

等待变换

  • tf提供了一个很好的工具,它将等待,直到变换可用。
  • 修改代码为:
 try{
ros::Time now = ros::Time::now();
listener.waitForTransform("/turtle2", "/turtle1",
now, ros::Duration(3.0));
listener.lookupTransform("/turtle2", "/turtle1",
now, transform);
  • waitForTransform() 四个参数:

    • 1.需要等待变换从坐标系turtle2
    • 2.到坐标系turtle1
    • 3.在now时间
    • 4.超时时间,不要等待超过此最大持续时间
  • 注意:使用ros::Time::now()是为了这个例子。通常这将是希望被转换的数据的时间戳。

  • 所以waitForTransform()实际上会阻塞直到两个海龟之间的变换可用(这通常需要几毫秒)

  • 或者如果变换不可用,直到达到超时。

  • 编译运行:

  $ catkin_make
$ roslaunch learning_tf start_demo.launch
  • 但等待,您可能仍会看到错误一次(错误msg可能会有所不同):
[ERROR] [1287872014.408401177]: You requested a transform that is 3.009 seconds in the past, but the tf buffer only has a history of 2.688 seconds.
When trying to transform between /turtle1 and /turtle2.

  

这是因为turtle2需要非零时间来生成并开始发布tf帧。 因此,第一次请求现在时间的/turtle2坐标系可能不存在,当请求转换时,转换可能不存在,并且第一次失败。 在第一次变换之后,所有的变换都存在,
并且乌龟的行为如预期的那样。

检查结果

  • 现在,你应该能够使用箭头键(确保你的终端窗口是活跃的,而不是你的模拟器窗口),你会看到第二只乌龟跟随第一只乌龟!
  • 所以,你注意到乌龟的行为没有明显的区别。 这是因为实际的时间差只有几个毫秒。 但是为什么我们从Time(0)到now()进行这种改变? 只是教你关于tf缓冲区和与它相关的时间延迟。对于真实的tf用例,使用Time(0)通常是完全正常的。

ROS与C++入门教程-tf-Time travel(时间穿梭

说明:

  • 介绍tf的高级时间穿梭功能

Time travel

  • 利用上一个教程的文件。
  • 打开src/turtle_tf_listener.cpp,找到25-30,如下:
  try{
ros::Time now = ros::Time::now();
listener.waitForTransform("/turtle2", "/turtle1",
now, ros::Duration(1.0));
listener.lookupTransform("/turtle2", "/turtle1",
now, transform);
  • 现在,不是让turtle2去到turtle1当前时间的地方,而让turtle2去turtle1是5秒前的地方:
try{
ros::Time past = ros::Time::now() - ros::Duration(5.0);
listener.waitForTransform("/turtle2", "/turtle1",
past, ros::Duration(1.0));
listener.lookupTransform("/turtle2", "/turtle1",
past, transform);
  • 编译运行:
$ make  or  catkin_make
$ roslaunch learning_tf start_demo.launch
  • 你会期望看到什么? 在第一个5秒钟,第二只乌龟不知道去哪里,因为我们还没有第一只乌龟5秒的历史。

  • 但是这5秒后呢?效果图:

  • 类似截图,你的海龟是不可控制? 那么发生了什么?

  • 我们问TF:相对于/turtle2 5秒前,/turtle1 5秒前的姿势是什么?

  • 这意味着我们控制/turtle2基于5秒前的位置以及/turtle1在5秒前的位置。

  • 那应该问:相对于/turtle2目前的位置,/turtle1 5秒前的姿势是什么?

高级API

  • 回答上面问题,依赖高级API,示例代码:
  try{
ros::Time now = ros::Time::now();
ros::Time past = now - ros::Duration(5.0);
listener.waitForTransform("/turtle2", now,
"/turtle1", past,
"/world", ros::Duration(1.0));
listener.lookupTransform("/turtle2", now,
"/turtle1", past,
"/world", transform);
  • 这个lookupTransform()API,有六个参数:

      1. 变换从坐标系turtle2
      1. 在now时间
      1. 到turtle1坐标系
      1. 在past时间
      1. 指定不随时间改变的坐标系,这里是world
      1. 变换结果保存的变量
  • waitForTransform()跟lookupTransform()一样有6个相应参数。

  • 效果图示:

  • 这个图显示了tf在后台做什么。

  • 在past时间,它计算从turtle1到world坐标系的变换。

  • 在world坐标系,tf时间从past到now。

  • 在now时间,tf计算从world到turtle2坐标系的变换。

检查结果:

  • 编译运行:
$ catkin_make
$ roslaunch learning_tf start_demo.launch
  • 效果:turtle2是指向turtle1 5秒前的地方!

ROS tf-深入Time和TF的更多相关文章

  1. tf.nn.conv2d 和 tf.nn.max_pool 中 padding 分别为 'VALID' 和 'SAME' 的直觉上的经验和测试代码

    这个地方一开始是迷糊的,写代码做比较分析,总结出直觉上的经验. 某人若想看精准的解释,移步这个网址(http://blog.csdn.net/fireflychh/article/details/73 ...

  2. 深度学习原理与框架-图像补全(原理与代码) 1.tf.nn.moments(求平均值和标准差) 2.tf.control_dependencies(先执行内部操作) 3.tf.cond(判别执行前或后函数) 4.tf.nn.atrous_conv2d 5.tf.nn.conv2d_transpose(反卷积) 7.tf.train.get_checkpoint_state(判断sess是否存在

    1. tf.nn.moments(x, axes=[0, 1, 2])  # 对前三个维度求平均值和标准差,结果为最后一个维度,即对每个feature_map求平均值和标准差 参数说明:x为输入的fe ...

  3. TF之RNN:TF的RNN中的常用的两种定义scope的方式get_variable和Variable—Jason niu

    # tensorflow中的两种定义scope(命名变量)的方式tf.get_variable和tf.Variable.Tensorflow当中有两种途径生成变量 variable import te ...

  4. 深度学习原理与框架-Tensorflow基本操作-变量常用操作 1.tf.random_normal(生成正态分布随机数) 2.tf.random_shuffle(进行洗牌操作) 3. tf.assign(赋值操作) 4.tf.convert_to_tensor(转换为tensor类型) 5.tf.add(相加操作) tf.divide(相乘操作) 6.tf.placeholder(输入数据占位

    1. 使用tf.random_normal([2, 3], mean=-1, stddev=4) 创建一个正态分布的随机数 参数说明:[2, 3]表示随机数的维度,mean表示平均值,stddev表示 ...

  5. tensorflow中 tf.train.slice_input_producer 和 tf.train.batch 函数(转)

    tensorflow数据读取机制 tensorflow中为了充分利用GPU,减少GPU等待数据的空闲时间,使用了两个线程分别执行数据读入和数据计算. 具体来说就是使用一个线程源源不断的将硬盘中的图片数 ...

  6. TensorFlow 辨异 —— tf.add(a, b) 与 a+b(tf.assign 与 =)、tf.nn.bias_add 与 tf.add(转)

    1. tf.add(a, b) 与 a+b 在神经网络前向传播的过程中,经常可见如下两种形式的代码: tf.add(tf.matmul(x, w), b) tf.matmul(x, w) + b 简而 ...

  7. tensorflow中共享变量 tf.get_variable 和命名空间 tf.variable_scope

    tensorflow中有很多需要变量共享的场合,比如在多个GPU上训练网络时网络参数和训练数据就需要共享. tf通过 tf.get_variable() 可以建立或者获取一个共享的变量. tf.get ...

  8. tensorflow中 tf.train.slice_input_producer 和 tf.train.batch 函数

    tensorflow数据读取机制 tensorflow中为了充分利用GPU,减少GPU等待数据的空闲时间,使用了两个线程分别执行数据读入和数据计算. 具体来说就是使用一个线程源源不断的将硬盘中的图片数 ...

  9. tensorflow 基本函数(1.tf.split, 2.tf.concat,3.tf.squeeze, 4.tf.less_equal, 5.tf.where, 6.tf.gather, 7.tf.cast, 8.tf.expand_dims, 9.tf.argmax, 10.tf.reshape, 11.tf.stack, 12tf.less, 13.tf.boolean_mask

    1.  tf.split(3, group, input)  # 拆分函数    3 表示的是在第三个维度上, group表示拆分的次数, input 表示输入的值 import tensorflow ...

  10. 关于 tf.nn.softmax_cross_entropy_with_logits 及 tf.clip_by_value

    In order to train our model, we need to define what it means for the model to be good. Well, actuall ...

随机推荐

  1. 算法笔记codeup-Contest100000566

    ABCD太直接了就不放了 E 求一元二次方根   C语言 #include <stdio.h> #include <math.h> int main() { ; ; ; sca ...

  2. 事务@Transactional

    在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例外(RunTimeExcep ...

  3. oracle获取时间段之间的所有日期

    SELECT TO_CHAR(ADD_MONTHS(TO_DATE('2014-10', 'yyyy-MM'), ROWNUM - 1), 'yyyy-MM') as monthlist FROM D ...

  4. ETL工程师笔试题

    1.参考答案 1)建表 CREATE TABLE `ta` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `cx` varchar(20) DEFAULT NUL ...

  5. WinForm利用AForge.NET调用电脑摄像头进行拍照和视频

    当然了,你需要去官网下载类库,http://www.aforgenet.com/ 调用本机摄像头常用的组件: AForge AForge.Controls AForge.Imaging AForge. ...

  6. LOJ#2343. 「JOI 2016 Final」集邮比赛 2

    题目地址 https://loj.ac/problem/2343 题解 首先处理出\(f[i]\)表示以当前位置开头(J,O,I)的合法方案数.这个显然可以\(O(n)\)处理出来.然后考虑在每个位置 ...

  7. Spring框架的JDBC模板技术和事物

    Spring框架的JDBC模板技术         技术分析之Spring框架的JDBC模板技术概述  1. Spring框架中提供了很多持久层的模板类来简化编程,使用模板类编写程序会变的简单     ...

  8. ArrayList 集合 简单运用

     集合 遍历 import java.util.ArrayList; class Demo02 { public static void main(String[] args) { // 创建Arra ...

  9. PDB文件会影响性能吗?

    有人问了这样的问题:"我工作的公司正极力反对用生成的调试信息构建发布模式二进制文件,这也是我注册该类的原因之一.他们担心演示会受到影响.我的问题是,在发布模式下生成符号的最佳命令行参数是什么 ...

  10. SVN 常用 查看日志

    1.日志查看,有时候会遇到查看一下之前改过的代码,或者恢复某某某个版本,这时就需要用到SVN的查看日志功能了,如图 2.日志列表,这里能看到各个版本的所有信息,包含了版本号 提交人 提交时间 提交时所 ...