ROS学习笔记(十四) TF介绍(二)

TF介绍(二)

tf in c++

C++提供的TF数据类型:

名称数据类型
向量tf::Vector3
tf::Point
四元数tf::Quaternion
3*3矩阵(旋转矩阵)tf::Matrix3x3
位姿tf::pose
变换tf::Transform
带时间戳的以上类型tf::Stamped
带时间戳的变换tf::StampedTransform

注意tf::StampedTransform 和 geometry_msgs/TransformStamped.msg不同,tf::StampedTransform只能用在C++里,是C++的一个类,一种数据格式,不是一个消息。geometry_msgs/TransformStamped.msg是一个message,依赖于ROS,与语言无关(即是无论和种语言C++、Python、Java等,都可以发送该消息)。

数据转换:

在这里插入图片描述
TF中常见的数据转换有四元数、欧拉角、旋转矩阵之间的转换。tf中数据转化的类型都包含在#include<tf/tf.h>头文件中。
数据转换的API:
1. 定义空间点和空间向量

函数名称函数功能
tfScalar::tfDot(const Vector3 &v1, const Vector3 &v2)计算两个向量的点积
tfScalar length()计算向量的模
Vector3 &normalize()求与已知向量同方向的单位向量
tfScalar::tfAngle(const Vector3 &v1, const Vector3 &v2)计算两个向量的夹角
tfScalar::tfDistance(const Vector3 &v1, const Vector3 &v2)计算两个向量的距离
tfScalar::tfCross(const Vector3 &v1, const Vector3 &v2)计算两个向量的乘积

文件位置:test/coordinate_transform.cpp

#include<ros/ros.h>
#include<tf/tf.h>
int main(int argc,char** argv)
{
	ros::init(int argc,char** argv,"coordinate_transform");
	ros::NodeHandle node;
	tf::Vector3 v1(1,1,1);
	tf::Vector3 v2(1,0,1);
	
	std::cout<<"第1部分,定义空间点和空间向量"<<std::endl;
	std::cout<<"v1 : "<<"("<<v1[0]<<","<<v1[1]<<","<<v1[2]<<"),";
	std::cout<<"v2 : "<<"("<<v2[0]<<","<<v2[1]<<","<<v2[2]<<"),";
	std::cout<<"两个向量的点积:"<<tfDot(v1,v2)<<std::endl;

	std::cout<<"向量v2的模值:"<<v2.length()<<std::endl;

	tf::Vector3 v3;
	v3 = v2.normalize();
	std::cout<<"与向量v2的同方向的单位向量v3:"<<<<"("<<v3[0]<<","<<v3[1]<<","<<v3[2]<<")"<<std::endl;

	std::cout"两个向量的夹角(弧度):"<<tfAngle(v1,v2)<<std::endl;

	std::cout<<"两个向量的距离:"<<tfDistance(v1,v2)<<std::endl;
	
	tf::Vector3 v4;
	v4 = tfCross(v1,v2);
	std::cout<<"两个向量的乘积v4:"<<"("<<v4[0]<<","<<v4[1]<<","<<v4[2]<<")"<<std::endl;
	return 0;
}

2. 定义四元数

函数名称函数功能
setRPY(const tfScalar &yaw,const tfScalar &pitch, const tfScalar &roll)由欧拉角计算四元数
Vector3 getAxis()由四元数得到旋转轴
setRotation(const Vector3 &axis, conat tfScalar &angle)已知旋转轴和旋转角估计四元数
#include<ros/ros.h>
#include<tf/tf.h>

int main(int argc,char ** argv)
{
	ros::init(argc,argv,"coordinate_transformation");
	ros::NodeHandle nh;
	
	std::cout<<"第2部分,定义四元数"<<std::endl;
	tfScalar yaw,pitch,roll;
	yaw=0;
	pitch=0;
	roll=0;
	std::cout<<"欧拉角rpy("<<yaw<<","<<pitch<<","<<yaw<<")";
	tf::Quaternion q;
	q.setRPY(yaw,pitch,roll);
	std::cout<<",转化到四元数q: "<<"("<<q[3]<<","<<q[0]<<","<<q[1]<<","<<q[2]<<")"<<std::endl;
	
	tf::Vector3 v5;
	v5 = q.getAxis();
	std::cout<<"四元数q的旋转轴v5"<<"("<<v5[0]<<","<<v5[1]<<","<<v5[2]<<")"<<std::endl;
	
	tf::Quaternion q2;
	q2 = setRotation(v5,1.570796);
	std::cout<<"旋转轴v5和旋转角度90度,转化到四元数q2:"<<"("<<q2[3]<<","<<q2[0]<<","<<q2[1]<<","<<q2[2]<<")"<<std::endl;
	return 0;
}

3. 定义旋转矩阵

函数名称函数功能
setRotation(const Quaternion &q)通过四元数得到旋转矩阵
getEulerYPR(tfScalar & yaw, tfScalar &pitch, tfScalar &roll)由旋转矩阵求欧拉角
#include<ros/ros.h>
#include<tf/tf.h>

int main(int argc,char **argv)
{	
	ros::init(argc,argv,"coordinate_transform");
	ros::NodeHandle nh;
	
	std::cout<<"第3部分,定义旋转矩阵"<<std::endl;
	tf::Quaternion q(1,0,0,0);
	tf::Matrix3x3 matrix;
	tf::Vector3 v6,v7,v8;
	matrix.setRotation(q);
	v6 = matrix[0];
	v7 = matrix[1];
	v8 = matrix[2];
	std::cout<<"四元数q2对应的旋转矩阵M:"<<v6[0]<<","<<v6[1]<<","<<v6[2]<<std::endl;
	std::cout<<"                       "<<v7[0]<<","<<v7[1]<<","<<v7[2]<<std::endl;
	std::cout<<"                       "<<v8[0]<<","<<v8[1]<<","<<v8[2]<<std::endl;
	
	tfScalar m_yaw,m_pitch,m_roll;
	matrix.getEulerYPR(m_yaw,m_pitch,m_roll);
	std::cout<<"由旋转矩阵M,得到欧拉角rpy("<<m_roll<<","<<m_pitch<<","<<m_yaw<<")"<<std::endl;
	retrun 0;
}

欧拉角与四元数的互换
文件位置:test/Euler2Quaternion.cpp

#include<ros/ros.h>
#include<tf/tf.h>

int main(int argc, char** argv)
{
	ros::init(argc, argv,"Euler2Quaternion");
	ros::NodeHandle nh;
	geometry_msgs::Quaternion q;
	double roll,pitch,yaw;
	while(ros::ok())
	{
		 std::cout<<"输入的欧拉角:roll,pitch,yaw:";
		 std::cin>>roll>>pitch>>yaw;
		 q = tf::creatQuaternionMsgFromRollPitchYaw(roll,pitch,yaw);
		 std::cout<<"输出的四元数为:w = "<<q.w<<",x = "<<q.x<<",y = "<<q.y<<",z = "<<q.z<<std::endl;
		 ros::spinOnce();
	}
	return 0;
)

文件位置:test/Quaternion2Euler.cpp

#include<ros/ros.h>
#include<tf/tf.h>

int main(int argc, char** argv)
{
	ros::init(argc,argv,"Quaternion2Euler");
	ros::NodeHandle nh;	

	tf::Quaternion q;
	nav_msgs::Odometry position
	double roll,pitch,yaw;
	while(ros::ok())
	{	
		std::cout<<"输入的四元数:w,x,y,z:";
		std::cin>>position.pose.pose.orientation.w>>position.pose.pose.orientation.x>>position.pose.pose.oriention.y>>position.pose.pose.orientation.z;
		tf::quaternionMsgToTF(position.pose.pose.orientation,q);
		//法2:tf::Vector3 m_vector;
		// 	  m_vector = q.getAxis();
		tf::Matrix3x3(q).getRPY(roll,pitch,yaw);
		std::cout<<"输出的欧拉角为:roll="<<roll<<",pitch="<<pitch<<",yaw="<<yaw<<std::endl;
		
		ros::spinOnce();
	}
	return 0;
}

TF类

tf:TransformBroadcaster类

transformBroadcaster()
void sendTransform(const StampedTransform &transform)
void sendTransform(const std::vector<StampedTransform> &transform)
void sendTransform(const geometry_msgs::TransformStamped &transform)
void sendTransform(const std::vector<geometry_msgs::TransformStamped> &transform)

broadcaster相当于一个publisher。sendTransform作用就是封装publish函数。使用时,在Node中构建tf::TransformBroadcaster类,再调用sendTransform(),将transform发布到/tf的一段transform上。/tf里的transform重载了多种不同的函数类型。

文件位置:test/tf_briadcaster.cpp

#include<ros/ros.h>
#include<tf/tf.h>
#include<tf/transform_broadcaster.h>

int main(int argc,char **argv)
{
	ros::init(argc,argv,"tf_boradcaster");
	ros::NodeHandle nh;
	
	static tf::TransformBroadcaster br;
	tf::Quaternion q;
	//geometry_msgs::Quaternion qw;
	double roll=0,pitch=0,yaw=0,x=1.0,y=2.0,z=3.0;
	ros::Rate rate(1);
	while(ros::ok()):
	{
		yaw += 0.1;
		q.setRPY(roll,pitch,yaw);
		//qw.createQuaternionMsgFromRollPitchYaw(roll,pitch,yaw);
		transform.setOrigin(tf::Vector3(x,y,z));
		transform.setRotation(q);
		std::cout<<"发布tf变换:sendTransform函数"<<std::endl;
		br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),"base_link","link1"));
		std::cout<<"输出的四元数为:w="<<q[3]<<", x="<<q[0]<<", y="<<q[1]<<", z="<<q[2]<<std::endl;
		//std::cout<<"输出的四元数为:w="<<qw.w<<", x="<<qw.x<<", x="<<qw.y<<", y="<<qw.y<<",z="<<qw.z<<std::endl;
		rate::sleep();
		ros::spinOnce();
	}
	return 0;
}

tf::TransformListener类

void loopupTransform(const std::string &target_frame,const std::string &source_frame,const ros::Time &time,StampedTransform &transform)const
//第一个参数是目标坐标系,第二个参数为源坐标系(要得到这两个坐标系之间的转换关系),第三个参数为查询时刻,第四个参数为存储转换关系的位置。
//第三个参数通常用ros::Time(0),表示为最新的坐标转化关系,ros::time::now会因为延迟收发不能获取当前最新的坐标转换关系
bool canTransform()
//canTransform()是用来判断两个transform之间是否连通
bool waitForTransform()const
//waitForTransform()const是用来等待某两个transform之间的连通

文件位置:test.tf_listener.cpp

#include<ros/ros.h>
#include<tf/tf_transform.h>
#include<geometry_msgs/Twist.h>

int main(int argc, char** argv)
{
	ros::init(argc,argv,"tf_listener");
	ros::NodeHandle nh;
	
	tf::TransformLiatener listener;
	std::cout<<"1. 阻塞直到frame相通"<<std::endl;
	listener.waitTransform("base_link","link1",ros::Time(0),ros::Duration(4.0));
	ros::Rate rate(1);
	while(node.ok())
	{
		tf::StampedTransform transform;
		try
		{
			 std::cout<<"2. 监听对应的tf,返回平移和旋转"<<std::endl;
			 listener.loopupTransform("/base_link","link1",ros::Time(0),transform);
		}
		catch(tf::TransformException &ex)
		{
			ROS_ERROR("%s",ex.what());
			ros::Duration(1).sleep();
			continue;
		}
		std::cout<<"输出的位置坐标:x="<<tranform.getOrigin().x()<<",y="<<transform.getOrigin().y()<<",z="<<transform.getOrigin().z()<<std::endl;
		std::cout<<"输出的旋转四元数:w="<<transform.getRotation().getW()<<",x="<<transform.getRotation.getX()<<",y="<<transform.getRotation.getY()<<",z="<<transform.getRotation.getZ()<<std::endl;
		rate.sleep();
		rate.sleep();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值