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簡化釋出轉換的任務
{
//建立一個TransformBroadcaster物件,並使用該物件對呼叫sendTransform函式,傳送base_link->base_laser的座標轉換
broadcaster.sendTransform(
//首先,我們傳遞旋轉轉換,它由四元數對於需要在兩個座標系之間發生的任何轉換。四元數由俯仰、滾動和偏航值構成,
//並建立一個Vector3對應於鐳射雷達的相對於基座的x偏移量10cm,z偏移距機器人基座20cm
//給正在釋出的轉換一個時間戳,我們只需要用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更改即可。