ROS服務與客戶端編寫詳解


說明

本文中包括服務、客戶端等名稱,其中服務包括兩重含義,既可以理解為與客戶端相對應的服務器,又可以理解為在服務器與客戶端之間傳遞數據的格式,需根據上下文進行理解。

srv文件

srv文件是ROS服務與客戶端機制中傳遞數據的格式,包括請求與響應兩個部分,請求部分是客戶端傳遞給服務的數據,響應部分則是服務返回給客戶端的數據。

srv文件會在catkin_make后自動生成一個類,這個類以“軟件包名稱::服務名”命名,使用這個類需要引入頭文件“軟件包名稱/服務名.h”(此處服務名指數據格式,與srv文件名相同),類中包含兩個成員變量request和response,以及兩個類定義Request和Response。成員變量request和response通過“.”運算符,可取得srv服務中請求或響應部分的具體值,以參與運算;而類Request和Response主要用於聲明變量,以供在函數間傳遞參數。

服務

在服務中(此處服務指與客戶端對應的服務器),需要完成如下內容:

  • 在主函數中
    • 初始化ROS,並指定節點名稱
    • 為節點創建句柄
    • 創建服務,同時指出服務名和服務中執行功能的回調函數名稱
    • 循環運行回調函數
  • 在主函數外
    • 編寫回調函數

在服務中,一些重要的變量如下:

  • 節點名,通過ros::init指定運行節點時用到的節點名,用引號包圍,對應下圖中的"kinematics_server"

  • 句柄,聲明句柄后,可利用句柄通過“.”運算符調用advertiseService方法,創建服務,對應下圖中的n

  • 服務名,通過上述advertiseService方法指定服務名,用引號包圍,創建客戶端時需要指明對應的服務名,對應下圖中的"trans_pose"

  • 服務(服務器)對象,屬於ros::ServiceServer類型,作為advertiseService方法的返回值,對應下圖中的service

  • 回調函數,同樣在advertiseService方法中指出,無需引號,當服務被請求時回調函數被執行以進行響應,回調函數通常需要以服務(此處服務指srv表明的數據格式)自動生成的類中定義的類型變量作為形參,從而實現根據服務傳遞的數據運算並返回運算結果,對應下圖中無引號的trans_pose

客戶端

在客戶端中,需要完成如下內容:

  •  在主函數中
    • 初始化ROS,並指定節點名稱
    • 為節點創建句柄
    • 創建客戶端,同時指出此客戶端請求的服務(指與客戶端對應的服務)名稱
    • 聲明服務類對象,通過此對象引用服務(指srv文件)中的請求與響應數據
    • 調用服務,傳入上述聲明的服務類對象

在客戶端中,一些重要的名稱與變量如下:

節點名,通過ros::init指定運行節點時用到的節點名,用引號包圍,對應下圖中的"kinematics_client"

  • 句柄,聲明句柄后,可利用句柄通過“.”運算符調用serviceClient方法,創建客戶端,對應下圖中的n

  • 服務名,在上述創建客戶端的serviceClient方法中需要指明客戶端所請求的服務名,用引號包圍,對應下圖中的"trans_pose"

  • 客戶端對象,屬於ros::ServiceClient類型,作為serviceClient方法的返回值,其具有call方法可用於調用服務,對應下圖中的client

  • 服務類型,在上述創建客戶端的serviceClient方法中需要指明客戶端所請求的服務類型,即傳遞的數據類型,用尖括號包圍,對應下圖中的<kinematics_demo::trans>

  • 服務類(srv文件生成的類)對象,用於引用服務(srv文件)中的請求與響應數據,對應下圖中的srv

附:

srv文件

float64 init_x
float64 init_y
float64 init_z
float64 delta_x
float64 delta_y
float64 delta_z
---
float64 x
float64 y
float64 z

服務

// 包括了ROS常用的頭文件
#include "ros/ros.h"

// 創建srv文件時生成的頭文件,其中kinematics_demo為軟件包名稱,trans為srv文件名稱,並在其后加上.h擴展名
#include "kinematics_demo/trans.h"

// 軟件包名與srv文件名共同組成一個類名(kinematics_demo::trans),此類包括兩個成員變量request、response和兩個類定義Request、Response
// 服務中執行主要功能的回調函數的原型
bool trans_pose(kinematics_demo::trans::Request &req,
                kinematics_demo::trans::Response &res);

int main(int argc, char **argv)
{
    // 初始化ROS,並指定節點名稱為kindmatics_sever
    ros::init(argc, argv, "kinematics_server");

    // 為節點創建句柄n
    ros::NodeHandle n;

    // 創建名稱是trans_pose的服務,並注冊回調函數trans_pose
    // 第一個trans_pose為服務名稱,第二個trans_pose為回調函數名
    ros::ServiceServer service = n.advertiseService("trans_pose", trans_pose);
    ROS_INFO("Kinematics server");

    // 循環等待回調函數
    ros::spin();

    return 0;
}

bool trans_pose(kinematics_demo::trans::Request &req,
                kinematics_demo::trans::Response &res)
{
    res.x = req.init_x + req.delta_x;
    res.y = req.init_y + req.delta_y;
    res.z = req.init_z + req.delta_z;
    
    ROS_INFO("Pose before trans: (%f, %f, %f)", (double)req.init_x, (double)req.init_y, (double)req.init_z);
    ROS_INFO("Pose trans:        (%f, %f, %f)", (double)req.delta_x, (double)req.delta_y, (double)req.delta_z);
    ROS_INFO("Pose after trans:  (%f, %f, %f)", (double)res.x, (double)res.y, (double)res.z);

    return true;
}

客戶端

// 包括了ROS常用的頭文件
#include "ros/ros.h"
// 創建srv文件時生成的頭文件,其中kinematics_demo為軟件包名稱,trans為srv文件名稱,並在其后加上.h擴展名
#include "kinematics_demo/trans.h"
#include <cstdlib>

// 第一個形參argc(argument counter)表示main函數的參數個數
// 第二個形參argv(argument value)表示main函數的參數值
// 也可寫為int main(int argc, char *argv[]),即由指針組成的數組,數組中每個元素都是指向char的指針
// 當不帶參數運行主函數時,操作系統向主函數傳遞的參數argc為1,而argv[0](是一個指針)指向程序的路徑及名稱
// 當帶參數運行主函數時,操作系統向主函數傳遞的參數argc為1加上參數個數,argv[0]意義不變,從arg[1]開始依次指向參數字符串

int main(int argc, char **argv)
{
    // 初始化ROS,並指定節點名稱為kindmatics_client
    ros::init(argc, argv, "kinematics_client");

    // 當參數個數不為7(即未傳入6個參數,與默認的1個參數共7個)
    if (argc != 7)
    {
        ROS_INFO("usage: kinematics_client init_x, init_y, init_z, delta_x, delta_y, delta_z");
        return 1;
    }

    // 為節點創建句柄n
    ros::NodeHandle n;

    // 為名稱是trans_pose的服務創建客戶端,並賦給名稱為client的ros::ServiceClient的對象
    // 尖括號中為<軟件包名::srv文件名>
    ros::ServiceClient client = n.serviceClient<kinematics_demo::trans>("trans_pose");
    
    // 實例化一個自動生成的服務類,即聲明一個kinematics_demo::trans對象srv
    // *注:此處服務的意義與服務器的服務並不相同,此服務強調服務內容而非動作,與srv文件所表示的服務相同
    // 即軟件包名與srv文件名二者共同組成一個類名,用此類名聲明一個對象srv 
    kinematics_demo::trans srv;

    // 上面實例化的名為srv的服務類,包括兩個成員變量request、response和兩個類定義Request、Response
    // 為request成員賦值
    srv.request.init_x = atof(argv[1]);
    srv.request.init_y = atof(argv[2]);
    srv.request.init_z = atof(argv[3]);
    srv.request.delta_x = atof(argv[4]);
    srv.request.delta_y = atof(argv[5]);
    srv.request.delta_z = atof(argv[6]);

    // 客戶端調用服務
    if(client.call(srv))
    {
        ROS_INFO("Pose after trans: (%f, %f, %f)", (double)srv.response.x, (double)srv.response.y, (double)srv.response.z);
    }
    else
    {
        ROS_ERROR("Failed to call service");
        return 1;
    }
    
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM