ROS中tf学习笔记

一、turtle_tf_broadcaster.cpp

#include <tf/transform_broadcaster.h>
//使用 TransformBroadcaster,我们需要包含头文件:tf/transform_broadcaster.h
#include <turtlesim/Pose.h>

std::string turtle_name;

void poseCallback(const turtlesim::PoseConstPtr& msg)
//ConstPtr& 为常量指针的引用
{
    
    
    static tf::TransformBroadcaster br;
    //创建一个 TransformBroadcaster ,我们需要它来广播转换
    tf::Transform transform;
    transform.setOrigin(tf::Vector3(msg->x, msg->y, 0.0));
    //创建一个transform对象,我们将turtle的2D位置信息转变为3D的transform中
    tf::Quaternion q;
    q.setRPY(0, 0, msg->theta);
    //创建一个四元数,把turtle中的欧拉角数据转换为四元数q
    transform.setRotation(q);
    //这里我们设定了旋转
    br.sendTransform(tf::StampedTransform(transform, ros::Time::now( ), "world", turtle_name));
    //这里才是执行部分,TransformBroadcaster 发布转换需要四个参数
    //1.发布转换本身
    //2.给发布的转换一个时间戳,需要用现在的时间标记它,使用ros::Time::now()获取现在的时间
    //3.发布父坐标系,例子中是“world”
    //4.发布子坐标系,例子中是“turtle_name”
}

int main(int argc, char** argv)  //argc表示接收的命令个数,argv表示传入的命令内容
//例如:已经编译好的程序为my.exe,在命令执行my.exe,则:此时argc就是1,接收的参数是1个,即参数argv[0]是“my.exe”
//在执行命令my.exe 1 2 3 则:此时argc就是4个,即参数argv[0]是“my.exe”,参数argv[1]是“1”,参数argv[2]是“2”,参数argv[3]是“3”
{
    
    
    ros::init(argc, argv, "my_tf_broadcaster");
    if (argc != 2){
    
    ROS_ERROR("need turtle name as argument"); return -1;};
    //return 如果什么都不接的话,其实就是void类型函数的返回,一般不再执行return后面的语句;
    //如果函数执行成功返回0,不成功返回非零,一般情况下非零值用-1表示;
    //return 0;一般用在主函数结束时,表示程序正常终止,即告诉系统程序正常。
    //return 1或者-1;表示返回一个代数值,一般用在子函数的结尾,表示程序异常终止
    turtle_name = argv[1];
    //传进来的参数命名前面定义的turtle_name
    ros::NodeHandle node;
    ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);

    ros::spin();
    return 0;
};

二、turtle_tf_listener.cpp

#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <turtlesim/Spawn.h>

int main(int argc, char** argv)
{
    
    
    ros::init(argc, argv, "my_tf_listener");

    ros::NodeHandle node;

    ros::service::waitForService("spawn");
    ros::ServiceClient add_turtle = 
    node.serviceClient<turtlesim::Spawn>("spawn");
    turtlesim::Spawn srv;
    add_turtle.call(srv);
    //创建一个serviceClient即请求服务的客户端
    //add_turtle.call(srv),客户端请求spawn服务,生成另一只turtlebot

    ros::Publisher turtle_vel =
    node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10);

    tf::TransformListener listener;  
    //创建一个TransformListener 对象

    ros::Rate rate(10.0);
    while (node.ok())
    {
    
    
        tf::StampedTransform transform;
        try
        {
    
    
            listener.lookupTransform("/turtle2", "/turtle1", 
                                                                   ros::Time(0), transform);
            //我们使用listener接收特定的转换,其中包含四个参数:
            // 1. /turtle1到/turtle2的坐标系转换  
            // 2. 使用ros::Time(0)得到最新可用的变换
            // 3. transform用来存储变换结果
        }
        catch(tf::TransformException ex)
        {
    
    
            ROS_ERROR("%s", ex.what());
            ros::Duration(1.0).sleep();
            continue;
            //使用try catch语句块来进行判断是否有异常;
            //try进行判断,如果有异常进入catch语句,ex.what()返回char数组
            //continue:结束本次循环,本次循环continue后的部分不再执行,开始下一次循环判断
            //这里注意区分break,break是永久终止循环,break后面的不再执行,while循环也不再执行
        }

        geometry_msgs::Twist vel_msg;
        vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(), transform.getOrigin().x());
        vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2)+
                                                                  pow(transform.getOrigin().y(), 2));
        //transform.getOrigin().x()获取transform中的变换数值,即得到turtle2在turtle1坐标系下的x值;
        //transform.getOrigin().y()得到turtle2在turtle1坐标系下的y值;
        //这里主要通过到turtle1的距离和角度的变换来计算turtle2的线速度和角速度
        turtle_vel.publish(vel_msg);
        //新的速度通过turtle2/cmd_cel话题来发布,更新turtle2的位姿
        rate.sleep();
    }
    return 0;
};

三、编译

1.CMakeList.txt

共三处需要做修改:
1.
在这里插入图片描述
2.
在这里插入图片描述
3.
在这里插入图片描述

2.package.xml

共一处需要进行修改:
在这里插入图片描述

3.编写launch文件start_demo.launch

在这里插入图片描述

四、执行

1.启动launch

//执行
roscore
roslaunch learning_tf start_demo.launch

在这里插入图片描述
Launch文件运行以后,可以看到turtle1_tf_broadcaster、turtle2_tf_broadcaster开始进行广播,同时turtlesim仿真节点启动。

2.启动listener

rosrun learning_tf  turtle_tf_listener

在这里插入图片描述
在这里插入图片描述
启动listener节点,listener程序中调用spawn服务产生turtle2,同时进行turtle1、turtle2之间的tf变换,运行过程中捕捉到一次error,即最开始没有正确进行turtle1与turtle2的tf变换,在进入下一次while循环时便能正确进行tf变换。

根据tf变换,给turtle2发布速度指令,产生上图所示的一个追逐过程。

3.启动键盘控制节点

rosrun turtlesim turtle_teleop_key

在这里插入图片描述
光标停留在运行键盘控制的终端下,使用上下左右键控制turtle1运动,turtle2会跟随发生变化,如下图所示:
在这里插入图片描述

小结

昨天北京迎来了2020年冬季的第一场雪,校园很美;
我觉得冬季更适合一个人静心看书,大家一起加油~

猜你喜欢

转载自blog.csdn.net/weixin_46181372/article/details/109890750
今日推荐