一、tf变换简介
机器人系统通常具有许多随时间变化的3D坐标系,例如世界坐标系(world frame),基准坐标系(base frame),夹具坐标系(gripper frame),头部坐标系(head frame)等。tf包可以随时记录所有这些坐标系,并可以解决如下问题:
- 5秒前,机器人头部坐标系相对于世界(全局)坐标系的关系是什么样的?
- 机器人夹取的物体相对于机器人的中心坐标的位置是什么?
- 机器人中心坐标系相对于全局坐标系的位置在哪里?
二、tf变换实例
1.实现一个tf广播器
- 定义一个tf广播器(TransformBroadcaster)
- 创建坐标变换值
-
发布坐标变换(sendTransform)
代码实现:src/turtle_tf_broadcaster.cpp.
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>
std::string turrtle_name;
void poseCallback(const turtlesim::PoseConstPtr& msg)
{
//创建一个tf广播器
static tf::TransformBroadcaster br;
//创建一个Transform对象,根据当前海龟的位置,设置相对与世界坐标系的坐标变换
tf::Transform transform;
transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );
tf::Quaternion q;
q.setRPY(0, 0, msg->theta);
transform.setRotation(q); //设置旋转
//发布坐标变换,(transform,发布时间戳,父坐标系,子坐标系)
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
}
int main(int argc, char** argv){
ros::init(argc, argv, "my_tf_broadcaster");
if (argc != 2){ROS_ERROR("need turtle name as argument"); return -1;};
turtle_name = argv[1];
//订阅turtle的位置(pose)信息
ros::NodeHandle node;
ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);
//循环等待
ros::spin();
return 0;
};
参考网站:小海龟例程broadcaster
2.实现一个TF监听器
- 定义一个tf监听器(TransformListener)
- 查找坐标变换(waitTransform.lookupTransform)
代码实现:src/turtle_tf_listener.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); //定义第二只海龟的速度发布器,发布频率为10hz ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10); //创建一个tf监听器 tf::TransformListener listener; ros::Rate rate(10.0); while (node.ok()){ tf::StampedTransform transform; try{ //查找两个海龟间的坐标变换 listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform); } catch (tf::TransformException &ex) { ROS_ERROR("%s",ex.what()); ros::Duration(1.0).sleep(); continue; } //基于两个海龟之间的坐标变换,计算turtle2的新的线性和角速度 //新速度发布在主题“turtle2 / cmd_vel”中,sim将使用它来更新turtle2的移动。 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; };
三、添加一个额外的固定坐标系
参考网站:Tutorials
四、学会使用waitTranform
参考网站:Tutorials
五、高级时间历史功能
参考网站:Tutorials
还有很多没有详细看,有时间再添加
参考网站:
官方wiki:tf_ROS.wik
海龟跟随小例程 :tf_demo
官方Tutorials:http://wiki.ros.org/tf/Tutorials
古月居tf:重读tf
listener参考网站:小海龟例程listener