navigation(1) tf坐标变换

               navigation是一个二维导航堆栈,它接收来自里程计、传感器流和目标姿态的信息,并输出发送到移动底盘。而其中各处的坐标变换由tf树来完成。

               Tf坐标变换<在robot_setup_tf_tutorial包中>

     Base_link 与base_laser会产生两个坐标系 即基于移动基座和基于激光雷达,如下图1所示:

                                                                       图1 小车模型图

假设激光雷达向前10cm 在移动基座上方20cm 就可以将base_link与base_laser联系起来,即(x:0.1m,y:0.0m,z:0.2m)。具体坐标变换知识可参考《机器人学导论》第二章 空间描述和变换 进行学习。下面是代码实现部分:

下面是代码部分:

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

int main(int argc, char** argv)
{
    ros::init(argc, argv, "robot_tf_publisher" );  //初始化 第三个参数是节点名称
    
ros::NodeHandele n;  //创建一个节点

    ros::Rate r(100);

    tf::TransformBroadcaster broadcaster;   //TransformBroadcaster简化发布转换的任务
  
 while(n.ok())             //ros::ok()函数返回值,在下列情况返回false:1、SIGINT句柄接收到Ctrl+C命令来结束;2、被名称相同的                                         节点提出ROS网络3、ros::shutdown()被应用的另一部分唤醒
  
 {   
        //创建一个TransformBroadcaster对象,并使用该对象对调用sendTransform函数,发送base_link->base_laser的坐标转换
      
 broadcaster.sendTransform( 
          //首先,我们传递旋转转换,它由四元数对于需要在两个坐标系之间发生的任何转换。四元数由俯仰、滚动和偏航值构成,
           //并创建一个Vector3对应于激光雷达的相对于基座的x偏移量10cm,z偏移距机器人基座20cm
          
 tf::StampedTransform(tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0.1, 0.0, 0.2)),
            
            //给正在发布的转换一个时间戳,我们只需要用ros::Time::now()
          
 ros::Time::now(),
            
            //正在创建的链接的父节点
          
 "Base_link", 
            
            //正在创建的链接的子节点
          
 "base_laser"));
        
             r.sleep();
    }

}

     上面,我们创建了一个节点来发布base_laser->base_link。现在,我们将编写一个节点,该节点将使用该转换在”base_laser”帧中获取一个点,并将其转换为”base_link”帧中的一个点。以此完成坐标的转换工作。下面是代码部分:

#include <ros/ros.h>

#include <geometry_msgs/PointStamped.h> //我们需要创建一个TF:TransformListener。 一个TransformListener对象通过ROS自动订阅转换消息主题

#include <tf/transform_listener.h>      //并管理通过线路传入的所有转换数据

void transformPoint(const tf::TransformListener& listener)

{

//我们将在base_laser帧中创建一个要转换为base_link帧的点

//我们将创建一个函数,给定一个TransformListener,获取"base_laser"帧中的一个点,并将其转换为"base_link"框架,这个函数将作为在程序main()中创建的ros::Timer的回调函数,每秒钟都会触发一次。

geometry_msgs::PointStamped laser_point;

laser_point.header.frame_id = "base_laser";

 

//对于我们的简单示例,我们将使用最新可用的转换

laser_point.header.stamp = ros::Time();

//空间中的任意一点

laser_point.point.x = 1.0;

laser_point.point.y = 0.2;

laser_point.point.z = 0.0;

//在这里我们将创建geometry_msgs::PointStamped类型的点,它包含一个头,允许我们将时间戳和Frame_id与消息连接起来

//我们将激光点信息的标记字段设置为ROS:Time()这个特殊时间值,它允许我们询问TransformListener用于最新的可用转换。

//标头的Frame_id字段,我们将其设置为"base_laser",因为我们要在"base_laser"框架中创建一个点,最后,我们将为点.设置一些数据.选择x:1.0、y:0.2和z:0.0的值。

try {

geometry_msgs::PointStamped base_point;

 

//我们使用TransformListener对象调用transformPoint函数(要将点转化成的目标框架,要转换的点,转换后的点(信息存储点))

listener.transformPoint("base_link", laser_point, base_point);

ROS_INFO("base_laser:(%.2f, %.2f, %.2f)----->base_link:(%.2f, %.2f, %.2f) at time %.2f",

                   laser_point.point.x, laser_point.point.y, laser_point.point.z,

                   base_point.point.x, base_point.point.y, base_point.point.z, base_point.header.stamp.toSec())

     };

catch (tf::TransformException& ex) {

ROS_ERROR("Received an exception trying to transform a point from \"base_laser\" to \"base_link\":%s", ex.what());

       }

}

int main(int argc, char** argv) {

          ros::init(argc, argv, "robot_tf_listener");

         ros::NodeHandle n;

         tf::TransformListener listener(ros::Duration(10));

          //每秒钟变换一个角度

         ros::Timer timer = n.createTimer(ros::Duration(1.0), boost::bind(&transformPoint, boost::ref(listener)));

         ros::spin();

}

再将CMakeLists.txt更改即可。

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值