1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ROS 機(jī)器人技術(shù) - 添加一個(gè) TF 幀

        共 5220字,需瀏覽 11分鐘

         ·

        2020-08-01 22:18

        afefc172348485e29b51c36283b97f07.webp


        登龍

        這是我的第 140 篇原創(chuàng)


        在實(shí)際的機(jī)器人中往往有很多個(gè)傳感器,比如我們組目前用的小車(chē)上就有相機(jī),雷達(dá),IMU 等,為了能夠在 TF 系統(tǒng)中找到傳感器之間的轉(zhuǎn)換,就需要把每個(gè)傳感器的坐標(biāo)系加到系統(tǒng)的 TF 樹(shù)中,方法很簡(jiǎn)單,下面一起來(lái)學(xué)習(xí)下。

        一、TF 樹(shù)的注意事項(xiàng)

        在實(shí)際使用和調(diào)試 TF 的時(shí)候一定要時(shí)刻記?。?strong style="color:#000000;">TF 樹(shù)中的一個(gè)節(jié)點(diǎn)可以有多個(gè)子節(jié)點(diǎn),但是只能有一個(gè)父節(jié)點(diǎn),并且 TF 樹(shù)中不能出現(xiàn)回環(huán)!

        一個(gè)典型的 TF 樹(shù)如下:

        5b13399eab8e6f3fb641c28146dc0076.webp


        這個(gè) TF 樹(shù)中有 3 個(gè)坐標(biāo)系:

        • world:世界坐標(biāo)系
        • turtle1:烏龜 1 的坐標(biāo)系,父節(jié)點(diǎn)是 world
        • turtle2:烏龜 2 的坐標(biāo)系,父節(jié)點(diǎn)時(shí) world

        如果你再發(fā)布一個(gè)「xxx -> turtle1」的變換,那 turtle1 就有 2 個(gè)父節(jié)點(diǎn),這樣是不可行的,違反了 TF 樹(shù)的構(gòu)建規(guī)則,實(shí)際使用是一定要注意了,如果你想查看系統(tǒng)當(dāng)前的 TF 樹(shù),使用下面的命令:

        rosrun rqt_tf_tree rqt_tf_tree

        下面來(lái)學(xué)習(xí)如何為一個(gè)節(jié)點(diǎn)添加子坐標(biāo)系。

        二、添加子坐標(biāo)系

        同樣進(jìn)入 learning_tf2 包中:

        roscd learning_tf2

        然后在 src 下新建 frame_tf2_broadcaster.cpp 文件,代碼如下:

        #include 
             
        #include 
        #include 

        int main(int argc, char** argv)
        {
            ros::init(argc, argv, "my_tf2_broadcaster");
            ros::NodeHandle node;

            tf2_ros::TransformBroadcaster tfb;
            geometry_msgs::TransformStamped transformStamped;
          // 指定 carrot1 的父節(jié)點(diǎn)時(shí) turtle1 
            // 即添加一個(gè)新的 carrot1 子坐標(biāo)系到 turtle1 
            transformStamped.header.frame_id = "turtle1";
            transformStamped.child_frame_id = "carrot1";

            // carrot1 相對(duì)于 tutle1 做了 y 軸的偏移
            transformStamped.transform.translation.x = 0.0;
            transformStamped.transform.translation.y = 2.0;
            transformStamped.transform.translation.z = 0.0;

            tf2::Quaternion q;
            q.setRPY(000);

            transformStamped.transform.rotation.x = q.x();
            transformStamped.transform.rotation.y = q.y();
            transformStamped.transform.rotation.z = q.z();
            transformStamped.transform.rotation.w = q.w();

            ros::Rate rate(10.0);
            while (node.ok()) {
                transformStamped.header.stamp = ros::Time::now();

                // 這兩行表示讓該 carrot1 參考系隨著時(shí)間移動(dòng)
                transformStamped.transform.translation.x = 2.0 * sin(ros::Time::now().toSec());
                transformStamped.transform.translation.y = 2.0 * cos(ros::Time::now().toSec());

                // 將 carrot1 相對(duì)于 tutle1 的坐標(biāo)變換廣播到 TF 系統(tǒng)中
                tfb.sendTransform(transformStamped);
                rate.sleep();
                printf("sending\n");
            }
        };

        代碼中最關(guān)鍵的就是要正確指定發(fā)布轉(zhuǎn)換的 ID:

        • frame_id:父坐標(biāo)系名稱
        • child_frame_id:子坐標(biāo)系名稱

        然后添加編譯規(guī)則:

        add_executable(frame_tf2_broadcaster src/frame_tf2_broadcaster.cpp)
        target_link_libraries(frame_tf2_broadcaster ${catkin_LIBRARIES})

        編譯:

        catkin_make 

        在 launch 中添加啟動(dòng):


        <launch>
             
            <node pkg="turtlesim" type="turtlesim_node" name="sim"/>

            
            <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
            
            
            <param name="scale_linear" value="2" type="double"/>
            <param name="scale_angular" value="2" type="double"/>

            
            <node pkg="learning_tf2" type="turtle_tf2_broadcaster" args="/turtle1" name="turtle1_tf2_broadcaster" />
            
             
            <node pkg="learning_tf2" type="turtle_tf2_broadcaster" args="/turtle2" name="turtle2_tf2_broadcaster" />

            
            <node pkg="learning_tf2" type="turtle_tf2_listener" name="listener" />

            
            <node pkg="learning_tf2" type="frame_tf2_broadcaster" name="broadcaster_frame" />
        launch>

        開(kāi)始啟動(dòng)節(jié)點(diǎn):

        roslaunch learning_tf2 start_demo.launch

        不過(guò)你應(yīng)該發(fā)現(xiàn)小烏龜?shù)母S運(yùn)動(dòng)跟上一個(gè)實(shí)驗(yàn)一模一樣,我們自己添加的坐標(biāo)系沒(méi)有產(chǎn)生作用,這是為何呢?這是因?yàn)殡m然我們發(fā)布了新的變換,但是我們并沒(méi)有使用它,來(lái)修改下 listener 的代碼:

        transformStamped = listener.lookupTransform("/turtle2""/carrot1", ros::Time(0));

        /turtle1 坐標(biāo)系改為 /carrot1,因?yàn)槲覀円褂眯绿砑拥淖鴺?biāo)系,所以尋找變換的坐標(biāo)系參數(shù)就要填寫(xiě)新添加的坐標(biāo)系名稱,這樣系統(tǒng)才能正確找到新添加的變換,再次編譯重新運(yùn)行:

        catkin_make

        roslaunch learning_tf2 start_demo.launch

        你應(yīng)該會(huì)發(fā)現(xiàn)現(xiàn)在的小烏龜產(chǎn)生的跟隨運(yùn)動(dòng)與之前不一定了,兩者之間的 y 方向有一定的距離,這個(gè)距離就是我們發(fā)布變換時(shí)指定的坐標(biāo)系的相對(duì)位置:

        OK!TF 系統(tǒng)常用的基礎(chǔ)就學(xué)完了,目前因?yàn)轫?xiàng)目有用到 TF,所以寫(xiě)了幾篇基礎(chǔ)的文章,之前沒(méi)有看過(guò)的可以再回過(guò)頭看下:



        廈大同學(xué),與你分享編程,AI 算法等技術(shù)干貨!精品文章創(chuàng)作不易,謝謝關(guān)注,歡迎在看。


        59495246bb5602781bd89070e3fb315d.webp

        點(diǎn)擊閱讀原文,查看更多精彩文章!

        瀏覽 21
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            丝袜AV无码 | 啊高潮了嗯~喷水了~啊~ | 欢乐激情网 | 家庭乱伦一区二区 | 少妇动态图片 | 大香蕉久操网 | 国产女主播喷水视频在线 | 91成人国产 | 成人91色情A片 | 中文字幕人妻一区二区三区熟女 |