TF學習筆記7(除錯)
本教程將指導您完成除錯典型tf問題的步驟。
它將使用tf故障排除指南中說明的步驟應用於使用turtlesim的示例,還將使用許多tf除錯工具。
1 開始這個例子
在本教程中,我們設定了一個具有許多問題的演示應用程式。
本教程的目標是應用系統方法來發現這些問題。
首先,讓我們舉一個例子,並看看會發生什麼:
$ roslaunch turtle_tf start_debug_demo.launch
你會看到turtlesim出現了。
如果從啟動Demo的終端,選擇終端視窗,則可以使用箭頭鍵驅動其中一個機器人,並且在左上角有第二個機器人。
如果演示工作正常,則第二個機器人應該跟隨您可以使用箭頭鍵命令的機器人。
顯然,它沒有...因為我們必須首先解決一些問題。您看到的是以下錯誤訊息:
[ERROR] 1254263539.785016000: Frame id /turtle3 does not exist! When trying to transform between /turtle1 and /turtle3.
2 找到tf請求
所以,如果你看看除錯問題指南,你會發現我們首先需要找出我們要求TF做什麼。
因此,我們進入使用tf的程式碼部分。
在之前的教程中,我們建立了一個tf廣播器,用於將烏龜的姿勢釋出到tf。
在本教程中,我們將建立一個tf監聽器以開始使用tf。
3 如何建立一個tf監聽器
我們先建立原始檔。轉到我們在上一個教程中建立的包:
$ roscd learning_tf
啟動您喜歡的編輯器並將以下程式碼貼上到名為src / turtle_tf_listener_debug.cpp的新檔案中。
https://raw.github.com/ros/geometry_tutorials/hydro-devel/turtle_tf/src/turtle_tf_listener_debug.cpp
#include <ros/ros.h> #include <tf/transform_listener.h> #include <geometry_msgs/Twist.h> #include <turtlesim/Spawn.h> int main(int argc, char** argv){ ros::init(argc, argv, "my_tf_listener"); ros::NodeHandle node; ros::service::waitForService("spawn"); ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("spawn"); turtlesim::Spawn srv; add_turtle.call(srv); ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10); tf::TransformListener listener; ros::Rate rate(10.0); while (node.ok()){ tf::StampedTransform transform; try{ listener.lookupTransform("/turtle3", "/turtle1", ros::Time::now(), transform); } catch (tf::TransformException &ex) { ROS_ERROR("%s",ex.what()); ros::Duration(1.0).sleep(); continue; } geometry_msgs::Twist vel_msg; vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(), transform.getOrigin().x()); vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) + pow(transform.getOrigin().y(), 2)); turtle_vel.publish(vel_msg); rate.sleep(); } return 0; };
看看第25-28行:這裡我們對tf做了實際的請求。前三個引數直接告訴了我們在要求TF做什麼:
從座標系/ turtle3 變換到座標系/ turtle1,在時間“now”。
現在,讓我們來看看為什麼這個請求失敗了。
4 檢查座標
首先,我們想知道tf是否知道/ turtle3和/ turtle1之間的轉換:
$ rosrun tf tf_echo turtle3 turtle1
輸出告訴我們frame turtle3不存在:
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.
上述訊息的最後三行告訴我們確實存在哪些座標系。如果您想獲得此圖形表示,請鍵入:
$ rosrun tf view_frames
$ evince frames.pdf
你會得到以下輸出。
顯然問題是我們要求turtle3,它不存在。要修復此錯誤,請在第25-28行中將turtle3替換為turtle2:
try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time::now(), transform);
}
現在停止執行演示(Ctrl-c),構建它,然後再次執行它:
$ make
$ roslaunch learning_tf start_debug_demo.launch
然後我們馬上遇到下一個問題:
[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.
5 檢查時間戳
現在我們解決了座標名稱問題,現在是時候檢視時間戳了。
請記住,我們正試圖在“now”時間在turtle2和turtle1之間進行轉換。要獲得有關時間的統計資訊,請執行:
$ rosrun tf tf_monitor turtle2 turtle1
結果應如下所示:
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 delay for the chain from turtle2 to turtle1。
輸出顯示平均延遲為8毫秒。
這意味著tf只能在經過8毫秒後才能在海龜之間進行轉換。因此,如果我們要求在8毫秒之前而不是“現在”之間進行海龜之間的轉換,tf would be able to give us an answer sometimes.。讓我們通過將第25-28行改為:
try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time::now()-ros::Duration(0.1), transform);
}
所以在新程式碼中,我們要求100毫秒之前的海龜之間的轉換(為什麼不是8?為了安全......)。
停止演示(Ctrl-c),構建並執行:
在catkin工作區的頂部資料夾中重新構建包:
$ catkin_make
然後再次執行該示例
$ roslaunch learning_tf start_debug_demo.launch
你最後應該看到烏龜移動了!
我們做的最後一個修復並不是你想要做的,只是為了確保這是我們的問題。真正的修復將如下所示:
try{
listener.lookupTransform("/turtle2", "/turtle1",
ros::Time(0), transform);
}
或者像這樣:
try{
ros::Time now = ros::Time::now();
listener.waitForTransform("/turtle2", "/turtle1",
now, ros::Duration(1.0));
listener.lookupTransform("/turtle2", "/turtle1",
now, transform);
}