ROS筆記-tf2的介紹
首先,安裝一個tf2的演示demo
$ sudo apt-get install ros-${ROS_DISTRO}-turtle-tf2 ros-${ROS_DISTRO}-tf2-tools ros-${ROS_DISTRO}-tf
通過如下指令運行演示demo
roslaunch turtle_tf2 turtle_tf2_demo.launch
正常情況會報錯,提示“/usr/bin/env: 'python' : No such file or directory”
因為系統(tǒng)環(huán)境是20.04LTS+noetic,按照步驟裝ros的時候裝的是python3
解決方法:
運行命令 whereis python3
sudo ln -s /usr/bin/python3 /usr/bin/python
再運行roslaunch就能正常運行demo,這個demo就是一只小龜追自己操作的另外一只小龜,主要關(guān)注其具體的實現(xiàn)原理
通過rospack find turtle_tf2 找到turtle_tf2包的位置,進(jìn)去找到turtle_tf2_demo.launch

?根據(jù)launch文件可以看到
啟動了turtlesim包里的兩個節(jié)點,sim和teleop,節(jié)點類型分別為turtlesim_node、turtle_teleop_key,一般來說,node語句中的type表示節(jié)點類型或者同名的可執(zhí)行文件,name表示節(jié)點名
param 如果在node語句中則表示為/node_name/param_name,如該launch文件中雖然兩個param的name都是turtle,但是因為在不同的node中,因此實際的參數(shù)名應(yīng)該分別為:/turtle1_tf2_broadcaster/turtle和/turtle2_tf2_broadcaster/turtle,所以并不影響,他的value表示為參數(shù)源
其他的類似啟動節(jié)點或者定義參數(shù)都算好理解
介紹兩個tf2的工具,view_frames和tf_echo
view_frames 用法:$ rosrun tf2_tools view_frames.py
tf_echo 用法:rosrun tf tf_echo [reference_frame] [target_frame]
具體解釋在http://wiki.ros.org/tf2/Tutorials/Introduction%20to%20tf2上,小工具,先了解

用c++實現(xiàn)一個tf2 broadcaster


先看頭文件?#include <tf2_ros/transform_broadcaster.h>?
tf2包中有transformbroadcaster這樣一個廣播器,可以更方便的廣播位姿變換,要使用這個廣播器頭文件里面就需要包含/tf2_ros/transform_broadcaster.h
static tf2_ros::TransformBroadcaster br;
創(chuàng)建了一個TransformBroadcaster對象br 稍后會用它來發(fā)送位姿變換
geometry_msgs::TransformStamped transformStamped;
transformStamped.header.stamp = ros::Time::now();
transformStamped.header.frame_id = "world";
transformStamped.child_frame_id = turtle_name;
這里的教程原文解釋是 Here we create a Transform object and give it the appropriate metadata.
We need to give the transform being published a timestamp(時間戳),we'll just stamp it with the current time, ros::Time::now()
Then, we need to set the name of the parent frame of the link we're creating, in this case "world"
Finally, we need to set the name of the child node of the link we're creating, in this case this is the name of the turtle itself
接著是
transformStamped.transform.translation.x = msg->x;
transformStamped.transform.translation.y?= msg->y;
transformStamped.transform.translation.z?=?0.0;
tf2::Quaternion q;
q.setRPY(0, 0, msg->theta);
transformStamped.transform.rotation.x = q.x();
transformStamped.transform.rotation.y?= q.y();
transformStamped.transform.rotation.z?= q.z();
transformStamped.transform.rotation.w?= q.w();
這里表示將3D turtle pose的信息復(fù)制到3D transform中去?
最后通過
br.sendTransform(transformStamped);
用br將變換發(fā)送出去
Note: sendTransform and StampedTransform have opposite ordering of parent and child.
Note2: you can also publish static transforms on the same pattern by instantiating a StaticTransformBroadcaster instead of a TransfomBroadcaster.(詳細(xì)展開在:http://wiki.ros.org/tf2/Tutorials/Writing%20a%20tf2%20static%20broadcaster%20%28C%2B%2B%29)
main函數(shù)里的內(nèi)容教程中沒有分析,直接到下一步運行這個broadcaster,當(dāng)寫好一個節(jié)點.cpp文件之后,首先需要在包里的CMakeLists.txt文件中為這個.cpp文件添加如下項
add_executable(turtle_tf2_broadcaster src/turtle_tf2_broadcaster.cpp)
target_link_libraries(turtle_tf2_broadcaster ${catkin_LIBRARIES})
然后返回catkin_ws文件夾進(jìn)行catkin_make
當(dāng)文件編譯好了之后下一步就是創(chuàng)建對應(yīng)的launch文件

然后同樣在CMakeList.txt文件中加入
## Mark other files for installation (e.g. launch and bag files, etc.)
install(FILES start_demo.launch # myfile2?
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
完成上述步驟后就可以在終端運行
roslaunch learning_tf2 start_demo.launch
用c++實現(xiàn)一個tf2 listener
首先是創(chuàng)建源文件 src/turtle_tf2_listener.cpp


代碼解析
頭文件?#include <tf2_ros/transform_listener.h>
tf2包提供了TransformListener來使得位姿變換的接收更加方便,因此要使用TransformListener,我們需要包含對應(yīng)的頭文件
tf2_ros::Buffer? tfBuffer;
tf2_ros::TransformListener? tfListener(tfBuffer);
這里創(chuàng)建了一個TransformListener對象,當(dāng)Listener創(chuàng)建好后,它就會通過網(wǎng)絡(luò)來接收tf2的位姿變換信息,and buffers them for up to 10 seconds.(并將其緩沖長達(dá)10s:我的理解是將接收到的信息最多能緩存10s)
The TransformListener object should be scoped to persist otherwise its cache will be unable to fill and almost every query will fail. A common method is to make the TransformListener object a member variable of a class.(TransformListener對象的范圍應(yīng)該是持久化的,否則它的緩存將無法填充,幾乎所有的查詢都會失敗,一個常見的方法是讓該對象成為一個類別的成員變量。ps:機(jī)翻,并沒有看太懂)
try{ ??
? ? transformStamped = tfBuffer.lookupTransform("turtle2", "turtle1",?ros::Time(0)); }?
catch (tf2::TransformException &ex) { ??
? ? ROS_WARN("%s",ex.what()); ??
? ? ros::Duration(1.0).sleep(); ??
? ? continue;?
}
Here, the real work is done, we query the listener for a specific transformation. Let's take a look at the four arguments (關(guān)于lookup Transform()的解釋)
We want the tansform to this frame (target frame)...
...from this frame (source frame)
?The time at which we want to transform. Providing ros::Time(0) will just get us the latest available transform
Duration before timeout. (optinal, default = ros::Duration(0,0))
接下來是運行該代碼,與之前的broadcaster.cpp類似,需要先對其進(jìn)行編譯
在CMakeList.txt中加入
add_executable(turtle_tf2_listener src/turtle_tf2_listener.cpp)
target_link_libraries(turtle_tf2_listener ${catkin_LIBRARIES})
在start_demo.launch文件中加入
<node pkg="learning_tf2"? type="turtle_tf2_listener" ?name="listener" />
最后運行
roslaunch?learning_tf2 start_demo.launch
(對于broadcaster和listener這兩個cpp文件只能說是了解了個大概,還是有一些不太明白的地方,先暫且放在這里,以后用到再細(xì)看吧,關(guān)于tf2還有一些后續(xù)的教程在 http://wiki.ros.org/tf2/Tutorials/Writing%20a%20tf2%20listener%20%28C%2B%2B%29 )