SLAM中常见包含坐标变换的函数

一、TF

        1、tf_broadcaster----sendTransform()函数---T(父_子)

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

int main(int argc, char** argv) 
{ 
    ros::init(argc, argv, "tf_broadcaster"); 
    ros::NodeHandle n; 
    ros::Rate loop_rate(100); 
    tf::TransformBroadcaster broadcaster; 
    tf::Transform father2child; 
    father2child.setOrigin(tf::Vector3(0, 0, -1)); 
    // 任意的旋转都可以由两个互为相反数的四元数表示。
    father2child.setRotation(tf::Quaternion(-0.5, -0.5, 0.5, 0.5));  // [x, y, z, w]
    // father2child.setRotation(tf::Quaternion(0.5, 0.5, -0.5, -0.5)); // [x, y, z, w]
    
    Eigen::Quaterniond q;
    q.x() = -0.5;
    q.y() = -0.5;
    q.z() = 0.5;
    q.w() = 0.5;

    Eigen::Matrix3d R = q.toRotationMatrix();
    std::cout << "Rotation Matrix R:" << std::endl << R << std::endl;

    while(n.ok()) 
    { 
        // 发布 坐标变换信息 到话题 /tf
        // 注意坐标系变换 和 坐标变换
        // 函数发布一个从 父坐标系 到 子坐标系 的变换关系。以父坐标系为基准 即 T(父_子)
        // 从 father到 child的坐标系变换(frame transform)等同于把一个点从 child坐标系向 father坐标系的坐标变换,等于 child坐标系在 father坐标系的姿态描述
        broadcaster.sendTransform(tf::StampedTransform(father2child, ros::Time::now(), "father_frame_id_", "child_frame_id_")); //广播的是 T(父_子)
        // broadcaster.sendTransform(tf::StampedTransform(tf::Transform(tf::Quaternion(0, 0, 0, 0), tf::Vector3(0, 0, 0)), ros::Time::now(),"father_frame_id_","child_frame_id_")); 
        loop_rate.sleep(); 
    } 
    return 0; 
}

运行结果:

        2、tf_listener----waitForTransform()函数

#include <ros/ros.h> 
#include <tf/transform_listener.h> 
#include <geometry_msgs/PointStamped.h> 
#include <iostream> 

int main(int argc,char** argv) 
{ 
    ros::init(argc,argv,"tf_listener_test"); 
    ros::NodeHandle n; 
     
    ros::Rate loop_rate(100); 
    tf::TransformListener listener; 
    geometry_msgs::PointStamped father_pos; 
    father_pos.header.frame_id = "father_frame_id_";
    father_pos.header.stamp = ros::Time(); 
    father_pos.point.x =  1; 
    father_pos.point.y =  1; 
    father_pos.point.z =  1;

    geometry_msgs::PointStamped child_pos; 
    

    while(n.ok()) 
    {   
        try{
            // 测试结果:均可以正常运行,说明 tf 内部做好了转换
            // 方式①
            // if (listener.waitForTransform("child_frame_id_", "father_frame_id_", ros::Time(0), ros::Duration(3))) // ros::Duration(3) 表示一个持续时间为3秒的时间间隔
            // { 
            //     listener.transformPoint("child_frame_id_", father_pos, child_pos);  // 将激光点的位置转换到child坐标系
            //     ROS_INFO("pointpos in child:  (%.2f, %.2f. %.2f) ", child_pos.point.x, child_pos.point.y, child_pos.point.z); 
            //     ROS_INFO("pointpos in father: (%.2f, %.2f, %.2f) ", father_pos.point.x, father_pos.point.y, father_pos.point.z); 
            // } 
            // 方式②
            if (listener.waitForTransform("father_frame_id_", "child_frame_id_", ros::Time(0), ros::Duration(3)))
            { 
                listener.transformPoint("child_frame_id_", father_pos, child_pos);  
                ROS_INFO("pointpos in child:  (%.2f, %.2f. %.2f) ", child_pos.point.x, child_pos.point.y, child_pos.point.z); 
                ROS_INFO("pointpos in father: (%.2f, %.2f, %.2f) ", father_pos.point.x, father_pos.point.y, father_pos.point.z); 
            } 

            loop_rate.sleep(); 
        }
        catch(const std::exception &ex){
            ROS_WARN("catch tf: %s", ex.what());
        }
    }   
}

运行结果:方式①和方式②运行结果相同

[ INFO] [1723259218.944746957]: pointpos in child:  (1.00, -2.00. -1.00)
[ INFO] [1723259218.954646563]: pointpos in father: (1.00, 1.00, 1.00) 

        3、tf_listener----lookupTransform()函数

#include <ros/ros.h> 
#include <tf/transform_listener.h> 
#include <geometry_msgs/PointStamped.h> 
#include <iostream> 
#include <Eigen/Geometry>

void my_StampedTransform_2_Matrix(const tf::StampedTransform& transform, Eigen::Matrix4f& transform_matrix) {

    Eigen::Vector3f tl(transform.getOrigin().getX(), transform.getOrigin().getY(), transform.getOrigin().getZ());
    
    Eigen::Quaternionf quaternion;
    quaternion.x() = transform.getRotation().getX();
    quaternion.y() = transform.getRotation().getY();
    quaternion.z() = transform.getRotation().getZ();
    quaternion.w() = transform.getRotation().getW();

    Eigen::Matrix3f rotation_matrix = quaternion.toRotationMatrix();
    transform_matrix = Eigen::Matrix4f::Identity();
    transform_matrix.block<3,3>(0,0) = rotation_matrix;
    transform_matrix.block<3,1>(0,3) = tl;

    std::cout << "my-旋转矩阵R: " << std::endl;
    std::cout << transform_matrix<< std::endl;
}



int main(int argc,char** argv) 
{ 
    ros::init(argc,argv,"tf_listener_test"); 
    ros::NodeHandle n; 
     
    ros::Rate loop_rate(100); 
    tf::TransformListener listener; 

    Eigen::Vector4f father_point(1, 1, 1, 1);

    while(n.ok()) 
    {   
        if (listener.waitForTransform("father_frame_id_","child_frame_id_",ros::Time(0),ros::Duration(3))) // ros::Duration(3) 表示一个持续时间为3秒的时间间隔
        { 

            // tf::StampedTransform 是 ROS 中用于表示带有时间戳的坐标变换的数据类型。它包含了坐标变换的旋转和平移信息,以及与之相关的时间戳信息。
            tf::StampedTransform myTransform; 

            // // 方式①
            // // 获取 父坐标系 到 子坐标系 的变换
            // // 或者说 子坐标系 在 父坐标系下的坐标值
            // listener.lookupTransform("father_frame_id_", "child_frame_id_", ros::Time(0), myTransform); // myTransform 即 T(父_子)

            // // 输出变换的平移部分
            // ROS_INFO("Translation: (%f, %f, %f)", myTransform.getOrigin().getX(), myTransform.getOrigin().getY(), myTransform.getOrigin().getZ());
            // // 输出变换的旋转部分 [x, y, z, w]   Quaternion: 0.5 0.5 -0.5 -0.5
            // ROS_INFO("Rotation [x, y, z, w]: (%f, %f, %f, %f)", myTransform.getRotation().getX(), myTransform.getRotation().getY(), myTransform.getRotation().getZ(), myTransform.getRotation().getW());

            // Eigen::Matrix4f T1;
            // my_StampedTransform_2_Matrix(myTransform, T1);

            // Eigen::Vector4f child_point = T1.inverse() * father_point;
            // ROS_INFO("child_point: (%f, %f, %f, %f) ", child_point.x(), child_point.y(), child_point.z(), child_point.w()); 

            // 方式②
            listener.lookupTransform("child_frame_id_", "father_frame_id_", ros::Time(0), myTransform); // myTransform 即 T(子_父)

            // 输出变换的平移部分
            ROS_INFO("Translation: (%f, %f, %f)", myTransform.getOrigin().getX(), myTransform.getOrigin().getY(), myTransform.getOrigin().getZ());
            // 输出变换的旋转部分 [x, y, z, w]   Quaternion: 0.5 0.5 -0.5 0.5
            ROS_INFO("Rotation [x, y, z, w]: (%f, %f, %f, %f)", myTransform.getRotation().getX(), myTransform.getRotation().getY(), myTransform.getRotation().getZ(), myTransform.getRotation().getW());

            Eigen::Matrix4f T1;
            my_StampedTransform_2_Matrix(myTransform, T1);

            Eigen::Vector4f child_point = T1 * father_point;
            ROS_INFO("child_point: (%f, %f, %f, %f) ", child_point.x(), child_point.y(), child_point.z(), child_point.w()); 

        } 
        loop_rate.sleep(); 
    } 
}

运行结果:方式①和方式②运行结果不同

方式①运行结果: T_father_child

[ INFO] [1723262555.188721557]: Translation: (0.000000, 0.000000, -1.000000)
[ INFO] [1723262555.188734684]: Rotation [x, y, z, w]: (0.500000, 0.500000, -0.500000, -0.500000)
my-旋转矩阵R: 
 0  0 -1  0
 1  0  0  0
 0 -1  0 -1
 0  0  0  1
[ INFO] [1723262555.188756822]: child_point: (1.000000, -2.000000, -1.000000, 1.000000) 

方式②运行结果: T_child_father

[ INFO] [1723266471.083481570]: Translation: (0.000000, -1.000000, 0.000000)
[ INFO] [1723266471.083510776]: Rotation [x, y, z, w]: (0.500000, 0.500000, -0.500000, 0.500000)
my-旋转矩阵R: 
 0  1  0  0
 0  0 -1 -1
-1  0  0  0
 0  0  0  1
[ INFO] [1723266471.083533838]: child_point: (1.000000, -2.000000, -1.000000, 1.000000) 

lookupTransform()函数介绍:该函数获取的 transform 是 T_target_source

  /** \brief Get the transform between two frames by frame ID.
   * \param target_frame The frame to which data should be transformed
   * \param source_frame The frame where the data originated
   * \param time The time at which the value of the transform is desired. (0 will get the latest)
   * \param transform The transform reference to fill.  
   *
   * Possible exceptions tf::LookupException, tf::ConnectivityException,
   * tf::MaxDepthException, tf::ExtrapolationException
   */
  void lookupTransform(const std::string& target_frame, const std::string& source_frame,
                       const ros::Time& time, StampedTransform& transform) const;

二、PCL

1.pcl::transformPointCloud()函数

        其中 transform 为 T_out_in,表示将 in坐标系 下的点云转移到 out坐标系 下。

  template <typename PointT> void 
  transformPointCloud (const pcl::PointCloud<PointT> &cloud_in, 
                       pcl::PointCloud<PointT> &cloud_out, 
                       const Eigen::Matrix4f &transform,
                       bool copy_all_fields = true)

2.

3.

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值