ROS中的坐标转换1

1、坐标转换

坐标转换是指坐标系之间的平移以及旋转关系,如坐标系A,B,C。A,B之间存在一个转换关系 T B A T_{B}^{A} TBA,B与C之间存在转换关系 T C B T_{C}^{B} TCB,我们知道了B相对于A的关系,C相对于B的转换关系,同样我们可以A,C之间也存在着转换关系 T C A T_{C}^{A} TCA. 根据两者之间的转换关系可以得到 T C A T_{C}^{A} TCA= T B A T_{B}^{A} TBA * T C B T_{C}^{B} TCB.

如图所示
在这里插入图片描述

2、lookupTransform获取坐标系之间的转换关系

2.1 lookupTransform

原型:

void Transformer:: lookuptransform (const std::string & target_frame,const std::string & source_frame, const ros::Time & Time, StampedTransform & transform)
  • target_frame:目标坐标系,数据应该转到的坐标系
  • source_frame:源坐标系,数据来源坐标系
  • Time:时间,使用 ros::Time(0),使用ros::time::now()存在问题
  • transform:存在转换关系

使用步骤:

  1. 获取TransformListener监听器
tf::TransformListener*  tfListener= new tf::TransformListener;
  1. 定义StampedTransform保存关系
 tf::StampedTransform stfBaseToLink2, stfBaseToLink1, stfLink1ToLink2;
  1. 使用
    while (tferr) {
        tferr=false;
        try {
              tfListener->lookupTransform("base_link", "link1", ros::Time(0), tfLink2WrtBaseLink);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); 
                continue;            
            }   
    }

注意:要使用try…catch进行获取,而且一次可能获取不到。

3、基于lookupTransform证明 T C A T_{C}^{A} TCA= T B A T_{B}^{A} TBA * T C B T_{C}^{B} TCB.

  1. 获取B相对于A的转换关系( T B A T_{B}^{A} TBA
    while (tferr) {
        tferr=false;
        try {
              tfListener->lookupTransform("base_link", "link1", ros::Time(0), tfLink2WrtBaseLink);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep();
                continue;            
            }   
    }
  1. 获取C相对于B转换关系( T C B T_{C}^{B} TCB
    while (tferr) {
        tferr=false;
        try {
                tfListener->lookupTransform("link1", "link2", ros::Time(0), stfLink1ToLink2);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); // sleep for half a second
                continue;            
            }   
    }
  1. 进行把StampedTransform转换Transform
tf::Transform tfBaseToLink1(tfLink2WrtBaseLink.getBasis(),tfLink2WrtBaseLink.getOrigin())
tf::Transform tfBaseToLink2(stfLink1ToLink2.getBasis(),stfLink1ToLink2.getOrigin())
  1. 进行 T B A T_{B}^{A} TBA * T C B T_{C}^{B} TCB
altTfBaseToLink2 = tfBaseToLink1*tfLink1ToLink2;
  1. 获取C相对于A的转换关系( T C A T_{C}^{A} TCA
    while (tferr) {
        tferr=false;
        try {
                tfListener->lookupTransform("base_link", "link2", ros::Time(0), stfBaseToLink2);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); // sleep for half a second
                continue;            
            }   
    }
  1. 进行把StampedTransform转换Transform
tf::Transform tfBaseToLink2(stfBaseToLink2.getBasis(),stfBaseToLink2.getOrigin())
  1. 打印结果
    在这里插入图片描述
    全部代码(修改于ROS机器人编程示例)
#include <math.h>
#include <stdlib.h>
#include <string>
#include <vector>

#include <ros/ros.h> //ALWAYS need to include this

#include <geometry_msgs/Point.h>
#include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/PoseStamped.h>
#include <tf/transform_listener.h>
#include <tf/LinearMath/Vector3.h>
#include<iostream>
using namespace std;

void printTf(tf::Transform tf) {
    tf::Vector3 tfVec;
    tf::Matrix3x3 tfR;
    tf::Quaternion quat;
    tfVec = tf.getOrigin();
    cout<<"vector from reference frame to to child frame: "<<tfVec.getX()<<","<<tfVec.getY()<<","<<tfVec.getZ()<<endl;
    tfR = tf.getBasis();
    cout<<"orientation of child frame w/rt reference frame: "<<endl;
    tfVec = tfR.getRow(0);
    cout<<tfVec.getX()<<","<<tfVec.getY()<<","<<tfVec.getZ()<<endl;
    tfVec = tfR.getRow(1);
    cout<<tfVec.getX()<<","<<tfVec.getY()<<","<<tfVec.getZ()<<endl;    
    tfVec = tfR.getRow(2);
    cout<<tfVec.getX()<<","<<tfVec.getY()<<","<<tfVec.getZ()<<endl; 
    quat = tf.getRotation();
    cout<<"quaternion: " <<quat.x()<<", "<<quat.y()<<", "
            <<quat.z()<<", "<<quat.w()<<endl;   
}
tf::Transform get_tf_from_stamped_tf(tf::StampedTransform sTf) {
   tf::Transform tf(sTf.getBasis(),sTf.getOrigin()); //construct a transform using elements of sTf
   return tf;
}
void printStampedTf(tf::StampedTransform sTf){
    tf::Transform tf;
    cout<<"frame_id: "<<sTf.frame_id_<<endl;
    cout<<"child_frame_id: "<<sTf.child_frame_id_<<endl; 
    tf = get_tf_from_stamped_tf(sTf); //extract the tf from the stamped tf  
    printTf(tf); //and print its components      
    }

//fnc to print components of a stamped pose
void printStampedPose(geometry_msgs::PoseStamped stPose){
    cout<<"frame id = "<<stPose.header.frame_id<<endl;
    cout<<"origin: "<<stPose.pose.position.x<<", "<<stPose.pose.position.y<<", "<<stPose.pose.position.z<<endl;
    cout<<"quaternion: "<<stPose.pose.orientation.x<<", "<<stPose.pose.orientation.y<<", "
            <<stPose.pose.orientation.z<<", "<<stPose.pose.orientation.w<<endl;
}
int main(int argc, char * argv[])
{
    ros::init(argc, argv, "listentext");
    ros::NodeHandle nh;
    tf::TransformListener*  tfListener= new tf::TransformListener;
    tf::StampedTransform stfBaseToLink2, stfBaseToLink1, stfLink1ToLink2;
    tf::StampedTransform testStfBaseToLink2;

    tf::Transform tfBaseToLink1, tfLink1ToLink2, tfBaseToLink2, altTfBaseToLink2;
    bool tferr=true;
    ROS_INFO("waiting for tf between link2 and base_link...");
    tf::StampedTransform tfLink2WrtBaseLink; 
    while (tferr) {
        tferr=false;
        try {
                //try to lookup transform, link2-frame w/rt base_link frame; this will test if
            // a valid transform chain has been published from base_frame to link2
                tfListener->lookupTransform("base_link", "link1", ros::Time(0), tfLink2WrtBaseLink);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); // sleep for half a second
                continue;            
            }   
    }
    // printStampedTf(stfBaseToLink1);
    tfBaseToLink1 = get_tf_from_stamped_tf(tfLink2WrtBaseLink);
    tferr = true;
    while (tferr) {
        tferr=false;
        try {
                tfListener->lookupTransform("link1", "link2", ros::Time(0), stfLink1ToLink2);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); // sleep for half a second
                continue;            
            }   
    }
    tfLink1ToLink2 = get_tf_from_stamped_tf(stfLink1ToLink2);
    tferr = true;
    while (tferr) {
        tferr=false;
        try {
                tfListener->lookupTransform("base_link", "link2", ros::Time(0), stfBaseToLink2);
            } catch(tf::TransformException &exception) {
                ROS_WARN("%s; retrying...", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); // sleep for half a second
                continue;            
            }   
    }
    printStampedTf(stfBaseToLink2);
    tfBaseToLink2 = get_tf_from_stamped_tf(stfBaseToLink2);
    cout << endl << "baseLink to Link2:" << endl;
    printTf(tfBaseToLink2);
    cout<<"==============================";
    altTfBaseToLink2 = tfBaseToLink1*tfLink1ToLink2;
    cout << endl << "baseLinkToLin1 * Link1ToLin2: " << endl;
    printTf(altTfBaseToLink2);

    return 0;
}

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ROS坐标转换函数是通过tf2库来实现的。这个函数采用固定轴的旋转方式,先绕定轴x旋转(横滚),然后再绕定轴y (俯仰),最后绕定轴z(偏航)。从数学形式上说,这是绕定轴XYZ矩阵依次左乘,即R=R(z)R(y)R(x)的顺序。这种方式的好处是直观且便于人机交互。\[1\] 在动态坐标变换ROS系统会根据时间戳进行坐标系和坐标点的匹配,来保证坐标变换的准确性。当时间戳相差较大时,系统会报错。为了解决这个问题,需要在循环更新订阅端的无效时间戳,即每次循环都要更新时间戳。虽然buffer的时间戳一直不变,但是其内容是一直变得,在一直更新。因此,忽略时间戳并不会影响转换精度。\[2\] 在创建项目功能包时,需要依赖于tf2、tf2_ros、tf2_geometry_msgs、roscpp、rospy、std_msgs、geometry_msgs和turtlesim等库。在准备参数时,需要提供两组静态坐标变换的偏移量和四元数,即对应的son1和son2在世界坐标系下的坐标变换。\[3\] #### 引用[.reference_title] - *1* [SLAM坐标轴旋转及ros的接口解释](https://blog.csdn.net/qq_42911741/article/details/127728007)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [ros tf坐标](https://blog.csdn.net/gyxx1998/article/details/128529862)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [ROS tf2 坐标变换学习(一)](https://blog.csdn.net/weixin_43134049/article/details/124017749)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值