0
点赞
收藏
分享

微信扫一扫

动态坐标变换(待续

香小蕉 2022-03-21 阅读 61

创建项目功能包依赖于 tf2、tf2_ros、tf2_geometry_msgs、roscpp rospy std_msgs geometry_msgs、turtlesim

C++:

1.1发布方:

#include "ros/ros.h"
#include "turtlesim/Pose.h"
#include "tf2_ros/transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"

/*
    发布方:需要订阅乌龟的位姿信息,转换成相当于窗体的坐标关系,并发布
     备:
        话题:/turtle1/pose
        消息: /turtle1/Pose

    流程:
    1.包含头文件
    2.设置编码、初始化、NodeHandle
    3.创建订阅对象,订阅/turtle1/pose
    4.回调函数处理订阅的消息:将位姿信息转换成坐标相对关系,并发布(关注)
    5.spin()
*/
void doPose(const turtlesim::Pose::ConstPtr& pose){
    //获取位姿信息,转换成坐标系相对关系(核心),并发布
    //a.创建发布对象
    static tf2_ros::TransformBroadcaster pub;
    //b.组织被发布的数据
    geometry_msgs::TransformStamped ts;
    ts.header.frame_id = "world";
    ts.header.stamp = ros::Time::now();
    ts.child_frame_id = "turtle1";
    //坐标偏移量设置
    ts.transform.translation.x = pose->x;
    ts.transform.translation.y = pose->y;
    ts.transform.translation.z = 0;
    //坐标系四元数
    /*
        位姿信息中没有四元数,但是有个偏航角度,又已知乌龟是 2D ,没有翻滚与俯仰角度,所以可以得出乌龟的欧拉角:0 0 theta
    */
    tf2::Quaternion qtn;
    qtn.setRPY(0,0,pose->theta);

    ts.transform.rotation.x = qtn.getX();
    ts.transform.rotation.y = qtn.getY();
    ts.transform.rotation.z = qtn.getZ();
    ts.transform.rotation.w = qtn.getW();

    //c.发布
    pub.sendTransform(ts);
}

int main(int argc, char *argv[])
{
    // 2.设置编码、初始化、NodeHandle
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"dynamic_pub");
    ros::NodeHandle nh;
    // 3.创建订阅对象,订阅/turtle1/pose
    ros::Subscriber sub = nh.subscribe("turtle1/pose",100,doPose);
    // 4.回调函数处理订阅的消息:将位姿信息转换成坐标相对关系,并发布(关注)
    
    // 5.spin()
    ros::spin();
    return 0;
}

在这里插入图片描述调用rviz比较直观
在这里插入图片描述

1.2 订阅方

与静态坐标系一样,修改几个参数就可
1.参考的坐标系
2.坐标点的时间戳
3.目标坐标系

#include "ros/ros.h"
#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"
#include "geometry_msgs/PointStamped.h"
#include "tf2_geometry_msgs/tf2_geometry_msgs.h"

/*
    订阅方:订阅发布的坐标系相对关系,传入一个坐标点,调用 tf 实现转换
    流程:
        1.包含头文件
        2.设置编码、节点初始化、NodeHandle(必须的)
        3.创建一个订阅对象  --->订阅坐标系相对关系
        4.组织一个坐标点数据
        5.转换算法,调用 tf 内置实现
        6.最后输出
*/

int main(int argc, char *argv[])
{
    // 2.设置编码、节点初始化、NodeHandle(必须的)
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"static_sub");
    ros::NodeHandle nh;
    // 3.创建一个订阅对象  --->订阅坐标系相对关系 (3-1  3-2 是结合使用的)
    // 3-1. 创建一个 buffer 缓存
    tf2_ros::Buffer buffer;
    // 3-2. 再创建一个监听对象(监听对象可以将订阅的数据存入 buffer )
    tf2_ros::TransformListener listen(buffer);
    // 4.组织一个坐标点数据
    geometry_msgs::PointStamped ps;
    //参考的坐标系
    ps.header.frame_id = "turtle1";
    //时间戳
    ps.header.stamp = ros::Time(0.0);
    ps.point.x = 2.0;
    ps.point.y = 3.0;
    ps.point.z = 5.0;
    //添加休眠  (文章“注”的部分添加休眠)
    // ros::Duration(2).sleep();
    // 5.转换算法,调用 tf 内置实现
    ros::Rate rate(10);
    while (ros::ok())
    {
        // 核心代码 ----  ps 转换为 base_link 的坐标点
        geometry_msgs::PointStamped ps_out;     
        /*
            调用了 buffer 的转换函数 transform 
            参数1:被转换的坐标点数据;
            参数2:目标坐标系;
            返回值:转换后的坐标点信息(输出的坐标系)

            注意:
            1.调用时必须包含头文件 tf2_geometry_msgs/tf2_geometry_msgs.h
            2.运行时存在的问题:抛出一个异常 base_link 不存在
                原因:订阅数据是一个耗时操作,可能在调用 transform 转换函数时,坐标系的相对关系还没有被订阅到,故出现异常
                解决:
                    方案1:在调用转换函数前执行休眠(简单)
                    方案2:进行异常处理
        */   

       try
       {
            ps_out = buffer.transform(ps,"world");  
            // 6.最后输出
            ROS_INFO("转换后的坐标值:(%.2f,%.2f,%.2f),参考的坐标系:%s",
                        ps_out.point.x,
                        ps_out.point.y,
                        ps_out.point.z,
                        ps_out.header.frame_id.c_str());
       }
       catch(const std::exception& e)
       {
        //    std::cerr << e.what() << '\n';
           ROS_INFO("异常消息:%s",e.what());
       }
       
        rate.sleep();
        ros::spinOnce();
    }
    return 0;
}

在这里插入图片描述
当启动键盘控制节点后,输出的坐标值会变

举报

相关推荐

0 条评论