1. 程式人生 > >tf教程(七):Debugging tf problems

tf教程(七):Debugging tf problems

Debugging tf problems

Description: This tutorial gives a systematic approach for debugging tf related problems.

Tutorial Level: ADVANCED 

This tutorial walks you through the steps to debug a typical tf problem. It will apply the steps explained in the tf troubleshooting guide to an example using 

turtlesim. It will also use many of the tf debugging tools.

Starting the example

For this tutorial we set up a demo application which has a number of problems. The goal of this tutorial is to apply a systematic approach to find these problems.

First, let's just run an example and see what happens:

  $ roslaunch turtle_tf start_debug_demo.launch

You'll see the turtlesim come up. If you select the terminal window from where you launched the demo, you can use the arrow keys to drive one of the robot around. In the upper left corner there is a second robot.

If the demo would be working correctly, this second robot should be following the robot you can command with the arrow keys. Obviously, it does not... because we have to solve some problems first. What you do see, is the following error message:

  [ERROR] 1254263539.785016000: Frame id /turtle3 does not exist! When trying to transform between /turtle1 and /turtle3.

Finding the tf request

So, if you look at the debugging tf problems guide, you'll see we first need to find out what exactly we are asking tf to do. So, therefore we go into the part of the code that is using tf.

In the previous tutorials we created a tf broadcaster to publish the pose of a turtle to tf. In this tutorial we'll create a tf listener to start using tf.

How to create a tf listener

Let's first create the source files. Go to the package we created in the previous tutorial:

 $ roscd learning_tf

Fire up your favorite editor and paste the following code into a new file called src/turtle_tf_listener_debug.cpp.

切換行號顯示
   1 #include <ros/ros.h>
   2 #include <tf/transform_listener.h>
   3 #include <geometry_msgs/Twist.h>
   4 #include <turtlesim/Spawn.h>
   5 
   6 int main(int argc, char** argv){
   7   ros::init(argc, argv, "my_tf_listener");
   8 
   9   ros::NodeHandle node;
  10 
  11   ros::service::waitForService("spawn");
  12   ros::ServiceClient add_turtle =
  13     node.serviceClient<turtlesim::Spawn>("spawn");
  14   turtlesim::Spawn srv;
  15   add_turtle.call(srv);
  16 
  17   ros::Publisher turtle_vel =
  18     node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10);
  19 
  20   tf::TransformListener listener;
  21 
  22   ros::Rate rate(10.0);
  23   while (node.ok()){
  24     tf::StampedTransform transform;
  25     try{
  26       listener.lookupTransform("/turtle3", "/turtle1",
  27                                ros::Time::now(), transform);
  28     }
  29     catch (tf::TransformException &ex) {
  30       ROS_ERROR("%s",ex.what());
  31       ros::Duration(1.0).sleep();
  32       continue;
  33     }
  34 
  35     geometry_msgs::Twist vel_msg;
  36     vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
  37                                     transform.getOrigin().x());
  38     vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
  39                                   pow(transform.getOrigin().y(), 2));
  40     turtle_vel.publish(vel_msg);
  41 
  42     rate.sleep();
  43   }
  44   return 0;
  45 };

Take a look at lines 25-28: Here we do the actual request to tf. The first three arguments tell us directly what we are asking tf: transform from frame /turtle3 to frame /turtle1 at time "now".

Now, let's take a look at why this request to tf is failing.

Checking the Frames

First we want to find out if tf knows about our transform between /turtle3 and /turtle1:

  $ rosrun tf tf_echo turtle3 turtle1

The output tells us that frame turtle3 does not exist:

Exception thrown:Frame id /turtle3 does not exist! When trying to transform between /turtle1 and /turtle3.
The current list of frames is:
Frame /turtle1 exists with parent /world.
Frame /world exists with parent NO_PARENT.
Frame /turtle2 exists with parent /world.

The last three lines of the above message tell us what frames do exist. If you like to get a graphical representation of this, type:

  $ rosrun tf view_frames
  $ evince frames.pdf

And you'll get the following output.

frames.png

So obviously the problem is that we are requesting turtle3, which does not exist. To fix this bug, replace turtle3 with turtle2in lines 25-28:

切換行號顯示
   1   try{
   2     listener.lookupTransform("/turtle2", "/turtle1",
   3                              ros::Time::now(), transform);
   4   }

And now stop the running demo (Ctrl-c), build it, and run it again:

  $ make
  $ roslaunch learning_tf start_debug_demo.launch

And right away we run into the next problem:

[ERROR] 1254264620.183142000: You requested a transform that is 0.116 miliseconds in the past,
but the most recent transform in the tf buffer is 3.565 miliseconds old.
 When trying to transform between /turtle1 and /turtle2.

Checking the Timestamp

Now that we solved the frame name problem, it is time to look at the timestamps. Remember we are trying to get the transform between turtle2 and turtle1 at time "now". To get statistics on the timing, run:

  $ rosrun tf tf_monitor turtle2 turtle1

The result should look something like this:

RESULTS: for /turtle2 to /turtle1
Chain currently is: /turtle1 -> /turtle2
Net delay     avg = 0.008562: max = 0.05632

Frames:

Broadcasters:
Node: /broadcaster1 40.01641 Hz, Average Delay: 0.0001178 Max Delay: 0.000528
Node: /broadcaster2 40.01641 Hz, Average Delay: 0.0001258 Max Delay: 0.000309

The key part here is the delay for the chain from turtle2 to turtle1. The output shows there is an average delay of 8 milliseconds. This means that tf can only transform between the turtles after 8 milliseconds are passed. So, if we would be asking tf for the transformation between the turtles 8 milliseconds ago instead of "now", tf would be able to give us an answer sometimes. Let's test this quickly by changing lines 25-28 to:

切換行號顯示
   1   try{
   2     listener.lookupTransform("/turtle2", "/turtle1",
   3                              ros::Time::now()-ros::Duration(0.1), transform);
   4   }

So in the new code we are asking for the transform between the turtles 100 milliseconds ago (Why not 8? Just to be safe...). Stop the demo (Ctrl-c), build and run:

Re-build your package at the top folder of your catkin workspace:

  $ catkin_make

Then running the example again

  $ roslaunch learning_tf start_debug_demo.launch

And you should finally see the turtle move! turtle_tf_start.png

That last fix we made is not really what you want to do, it was just to make sure that was our problem. The real fix would look like this:

切換行號顯示
   1   try{
   2     listener.lookupTransform("/turtle2", "/turtle1",
   3                              ros::Time(0), transform);
   4   }

or like this:

切換行號顯示
   1   try{
   2     ros::Time now = ros::Time::now();
   3     listener.waitForTransform("/turtle2", "/turtle1", 
   4                               now, ros::Duration(1.0));
   5     listener.lookupTransform("/turtle2", "/turtle1",
   6                              now, transform);
   7   }

相關推薦

tf教程Debugging tf problems

Debugging tf problems Description: This tutorial gives a systematic approach for debugging tf related problems.Tutorial Level: ADVANCE

python3教程python 運算子

python有各種各樣的運算子,不僅僅是+-*/這種算數運算,還有類似於=、+=這種賦值運算。 python中總共有算術運算、賦值運算、比較(關係)運算、邏輯運算、身份運算、成員運算、位運算(二進位制)共7種運算分類。 下面我們將挑一些重要且常用的來進行了解。   算數

jmeter教程正則表示式簡介

在後面講關聯和斷言,都會涉及到正則表示式,那麼,就先簡單的介紹一下正則表示式吧。 正則表示式的定義,這裡就不說了,百度裡應該有。正則表示式可以做什麼?處理文字,也只能處理文字。正則表示式,也常被程式設計師戲稱為“火星文”,從這個稱謂可以看出,正則表示式很難看懂。難到什麼程式呢?當你寫完一個比較複

Linux小小白入門教程vi文字編輯命令

以下操作在Linux終端進行。Linux因為許可權非常嚴格,所以暫時所有的命令操作全部是在/home資料夾下的/yangjw資料夾下進行。/yangjw資料夾就是登入使用者名稱所在的資料夾,出了此資料

Spring Cloud基礎教程路由閘道器使用Zuul

一、概述Zuul的主要功能是路由轉發和過濾器。路由功能是微服務的一部分,比如/client-a/轉發到到a服務,/client-b/轉發到到b服務。zuul預設和Ribbon結合實現了負載均衡的功能。二、準備將服務註冊與發現這篇部落格中的Eureka-Client-A工程,複

【Unity3D基礎教程】給初學者看的Unity教程在Unity中構建健壯的單例模式Singleton

該部落格中的程式碼均出自我的開源專案 : 迷你微信 為什麼需要單例模式 遊戲中需要單例有以下幾個原因: 我們需要在遊戲開始前和結束前做一些操作,比如網路的連結和斷開,資源的載入和解除安裝,我們一般會把這部分邏輯放在單例裡。 單例可以控制初始化和銷燬順序,而靜態變數和場景中的GameObject都無法控制

抓包工具Fiddler的使用教程打斷點修改Response

接下里繼續我們的Fiddler教程 之前的教程中有講到如何通過修改CustomRules.js檔案來達到修改Response資料的目的,今天我們來分享如何在打斷點的時候修改Response 之前有講到,若是修改響應的資料,應該在after res

【TeeChart Pro ActiveX教程使用函式

下載TeeChart Pro ActiveX最新版本 在上一篇文章中,我們介紹到了在Teechart Pro ActiveX中的功能特點和新增功能,今天我們接著講定義資料來源、功能期間和週期樣式 (一)定義資料來源 上一節中的示例重點介紹如何使用Datasource通過程式碼填充Function.S

【TeeChart Pro ActiveX教程使用函式

下載TeeChart Pro ActiveX最新版本 功能型別 1 功能特點 TeeChart Pro功能是一個系列,幾乎可以是任何系列型別,應用代數函式,資料來源是另一個圖表系列。 所有函式都派生自Teefunction類並繼承TeeFunction的Period屬性。 TeeCh

TensorFlow 從入門到精通TensorFlow tf.nn.conv2d 一路追查

讀者可能還記得本系列部落格(二)和(六)中 tf.nn 模組,其中最關心的是 conv2d 這個函式。首先將部落格(二) MNIST 例程中 convolutional.py 關鍵原始碼列出: def model(data, train=False): """The

SkinUI入門教程 第四組UI元件進度條、分割條、滾動條和滑塊

7.1 進度條 進度條由CSkinProgress類來代表,繼承於CSkinView,支援CSkinView的所有屬性和方法。 通過給進度條設定不同的圖片資源,可以得到各種形態的進度條。 進度條效果圖 佈局檔案如下: <SkinDialog DefaultWidth="400" DefaultHei

iptables實用教程管理鏈和策略

否則 命令顯示 accept 目的 number cep 存在 當前 末尾 概念和原理請參考上一篇文章“iptables實用教程(一)”。 本文講解如果管理iptables中的鏈和策略。 下面的代碼格式中,下劃線表示是一個占位符,需要根據實際情況輸入參數,不帶下劃線的表示是

JAVA學習方法重載與方法重寫、thiskeyword和superkeyword

格式 hello new 初始 per 而且 方法重寫 學習 方式 方法重載與方法重寫、thiskeyword和superkeyword 1、方法重載 重載可以使具有同樣名稱但不同數目和類型參數的類傳遞給方法。 註: 一是重載方法的參數列表必須與被重載的方法不同

方便大家學習的Node.js教程理解Node.js

圖形 -1 iter pri attribute set run 相對 mage 理解Node.js 為了理解Node.js是如何工作的,首先你需要理解一些使得Javascript適用於服務器端開發的關鍵特性。Javascript是一門簡單而又靈活的語言,這種靈

Nginx實用教程配置文件入門

affinity type 服務 源碼編譯 設置時間 shutdown ber 可用 控制指令 Nginx配置文件結構 nginx配置文件由指令(directive)組成,指令分為兩種形式,簡單指令和區塊指令。 一條簡單指令由指令名、參數和結尾的分號(;)組成,例如:

Nginx實用教程啟動、停止、重載配置

style 負載 繼續 local con doc lin 配置文件的修改 tex Nginx是一個功能強大的web服務器和負載均衡軟件,由俄羅斯人開發。Nginx包括一個master進程和數個worker進程,master進程用於讀取、解析配置文件和管理worker進程,

ActiveReports 9實戰教程1 手把手搭建好開發環境Visual Studio 2013 社區版

line tool mmu tin style textbox ble mil nts ActiveReports 9剛剛公布3天。微軟就公布了 Visual Studio Community 2013 開發環境。Visual Studio Community 2013

【Unity3D基礎教程】給初學者看的Unity教程如何學習Unity3D

cos 詳解 component lock index unity3d遊戲 design 技術棧 log 【Unity3D基礎教程】給初學者看的Unity教程(零):如何學習Unity3D http://www.cnblogs.com/neverdie/p/How_To_

Git 教程時光穿梭

rac call 替換 img posit key 誤刪 ranch 定位在 我們已經成功地添加並提交了一個readme.txt文件,現在,是時候繼續工作了,於是,我們繼續修改readme.txt文件,改成如下內容: Git is a distributed version

Git 教程倉庫與分支

ide 不但 clas version span 右上角 director discard pre 遠程倉庫 到目前為止,我們已經掌握了如何在Git倉庫裏對一個文件進行時光穿梭,你再也不用擔心文件備份或者丟失的問題了。 可是有用過集中式版本控制系統SVN的童鞋會站出來說,這