1. 程式人生 > >navigation(1) tf座標變換

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更改即可。