首先看了开源操作机器人系统-ros这本书(张建伟)第五章slam导航 5.1使用tf配置机器人
还有ros navigation 教程
http://wiki.ros.org/navigation/Tutorials/RobotSetup/TF
这里需要区分两种变换
1、坐标系变换
2、坐标变换
坐标系变换就是指一个坐标系怎么变换成另外一个坐标系
坐标变换就是指一个坐标系下点怎么变换成另外一个坐标系下坐标
这两个略微有所不同
tf tree维护的是坐标系变换
base_link到base_laser坐标系变换就是[0.1,0,0.2]
而base_laser到base_link就是[-0.1,0,-0.2]
坐标变换则是转动坐标系在固定坐标系下运动描述
具体可以看这篇博客
http://blog.exbot.net/archives/1686
博客主要知识点:
这里有个巧合,当然也不是巧合,那就是从child到parent的坐标变换等于从parent到child的frame transform,等于child在parent frame的姿态描述。这里牵扯到了线性代数里的基变换、线性变换、过渡矩阵的概念。
接下来是实际操作部分
下面这段代码实现了从user_set topic读取数据,在call_back中进行tf 广播,在主程序里进行look_up
#include <ros/ros.h> #include <tf/transform_broadcaster.h> #include <nav_msgs/Odometry.h> #include <geometry_msgs/Pose2D.h> #include <tf/transform_listener.h> #include <stdio.h> class test { private: ros::NodeHandle nh_; ros::Subscriber sub_; tf::TransformBroadcaster br_; bool data_ready; public: test(ros::NodeHandle& nh) { nh_=nh; sub_ = nh_.subscribe("/user_set", 10, &test::call_back,this); data_ready = false; } void call_back(const geometry_msgs::Pose2DPtr& msgs) { ROS_INFO("recive"); tf::Transform dest_transform; dest_transform.setOrigin(tf::Vector3(msgs->x,msgs->y,0)); tf::Quaternion q; q.setRPY(0, 0, msgs->theta); dest_transform.setRotation(q); br_.sendTransform(tf::StampedTransform(dest_transform, ros::Time::now(),"world","user_set_frame")); data_ready = true; } bool is_data_ready() { if(data_ready) return true; else return false; } }; int main(int argc, char** argv){ ros::init(argc, argv, "tf_broadcaster"); ros::NodeHandle node; test Otest(node); tf::TransformListener listener; tf::StampedTransform transform; while(ros::ok()) { if(!Otest.is_data_ready()) { ros::spinOnce(); continue; } ROS_INFO("lookup_transfoem;"); try { //查找的是world到user_set_frame“坐标变换”具体可以看见看教程 //http://wiki.ros.org/tf/Tutorials/Writing%20a%20tf%20listener%20%28C%2B%2B%29 //rosrun tf tf_echo求的是坐标系变换 listener.waitForTransform("world","user_set_frame",ros::Time::now(), ros::Duration(1.0)); listener.lookupTransform("world","user_set_frame",ros::Time(0),transform); } catch (tf::TransformException ex) { ROS_ERROR("%s",ex.what()); break; } tf::Vector3 vectortf = transform.getOrigin(); ROS_INFO("transform.x:%f,transform.y:%f,transform.z:%f",vectortf.x(),vectortf.y(),vectortf.z()); ros::spinOnce(); } return 0; }
Here, the real work is done, we query the listener for a specific transformation. Let's take a look at the four arguments:
- We want the transform from this frame ...
- ... to this frame.
-
The time at which we want to transform. Providing ros::Time(0) will just get us the latest available transform.
- The object in which we store the resulting transform.
知道tf变换后怎么进行坐标变换呢?
开源操作机器人系统-ros这本书(张建伟)第五章slam导航 5.1使用tf配置机器人