ROS学习——(四)ROS的通信机制(下)

上一篇文章概括了ROS的通信机制以及介绍了话题通信,接下来继续完成整个ROS通信机制的搭建,包括服务通信和参数服务器,在话题通信中用C++来创建节点文件,接下来将用python来创建文件,以熟悉两种语言的执行方式。

服务通信

理论模型

在 ROS (Robot Operating System) 中,服务 (Service) 是一种同步通信机制,它允许节点之间进行请求-响应式的交互。这种通信方式的理论模型基于客户端和服务端的交互,具体包括以下几个关键部分:

  1. 服务端 (Service Server)

    • 服务端是提供服务的节点。它通常会在某个节点内部等待并监听来自客户端的请求。服务端会根据接收到的请求执行相应的操作,然后将结果作为响应返回给客户端。
    • 服务端通过 ROS 提供的 ros::ServiceServer 或 Python 的 rospy.Service 接口来实现。服务端首先需要定义一个服务类型,这个类型包括请求消息 (Request) 和响应消息 (Response)。
  2. 客户端 (Service Client)

    • 客户端是请求服务的节点,它通过发送请求消息给服务端,并等待服务端返回响应消息。客户端在得到服务端的响应后,可以继续处理后续任务。
    • 客户端通过 ROS 提供的 ros::ServiceClient 或 Python 的 rospy.ServiceProxy 接口来实现。客户端发送一个请求消息,ROS 会在后台处理与服务端的通信,直到服务端完成操作并返回响应。
  3. 服务类型 (Service Type)

    • 服务类型定义了请求消息和响应消息的结构。每个服务都有一个请求和响应部分,这些部分通过 ROS 消息类型来定义。请求和响应的消息格式是 ROS 中标准化的,通常是通过 .srv 文件来定义的。
  4. 同步通信

    • 服务通信是同步的,这意味着在客户端发送请求后,客户端会等待服务端的响应。在等待期间,客户端的执行会被阻塞,直到服务端返回结果。
    • 这种同步方式与 ROS 的消息发布-订阅机制(异步)不同,服务通信适用于那些需要请求某个计算并返回结果的场景。
  5. 工作流程

    • 服务端启动并注册服务。
    • 客户端调用服务并发送请求。
    • 服务端接收到请求后执行相应的操作并生成响应。
    • 服务端将响应返回给客户端。
    • 客户端接收到响应并继续后续操作。

客户端实现

1.导包
2.初始化 ros 节点
3.创建服务端对象
4.组织请求数据,发送请求
5.处理响应

代码示例:

import rospy
from server.srv import addintsRequest,addints
"""
    1.导包
    2.初始化ros节点
    3.创建服务端对象
    4.组织请求数据,发送请求
    5.处理响应

"""
if __name__ == "__main__":
    #初始化节点
    rospy.init_node("jiedianming")

    #给客户端对象赋值,告诉客户端话题名称,以及自创的srv文件
    client = rospy.ServiceProxy("add",addints)

    #发送请求,用call函数,发送srv中分割线上的数据,并接受响应(分割线下的)
    response = client.call(12,45)

    #处理响应
    rospy.loginfo("response is %d",response.sum)

服务端实现

1.导包
2.初始化 ros 节点
3.创建服务端对象
4.处理逻辑(回调函数)
5.spin()(回头)

示例代码:

import rospy
from server.srv import addintsResponse,addints
#from server.srv import *

"""
1.导包
2.初始化ros节点
3.创建服务端对象
4.处理逻辑(回调函数)
5.spin()(回头)


"""
def donum(request):
    num1 = request.num1
    num2 = request.num2
    sum = num1 + num2
    response = addintsResponse()
    response.sum = sum

    rospy.loginfo("num1 = %d, num2 = %d, sum = %d ",num1,num2,sum)
    return response
    

if __name__ == "__main__":
    # 2. 初始化节点
    rospy.init_node("pppp")
    # 3. 创建服务端
    server = rospy.Service("add",addints,donum)#服务话题 服务类型 回调函数
    # 4. 处理逻辑(回调)
    # 5. spin()
    rospy.spin()

运行服务

当创建完节点后我们将启动服务

  1. 在 scripts 目录下打开终端

     chmod +x *.py//获取可执行权限
    
  2. CMakelist:

    catkin_install_python(PROGRAMS
      scripts/server01_p.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )
    

(这段代码的功能是,当你执行 catkin_makecatkin build 时,它会自动将 scripts 文件夹中的 Python 脚本(例如 demo01.py)复制到 ROS 包的 bin 目录中,这样脚本就可以像其他 ROS 可执行文件一样被调用。)

自定义srv

自定义srv创建方式和自定义msg的操作类似,可以看我上一篇文章,了解自定义msg创建过程

示例文件:

#客户端请求,传递到服务端的回调函数
int32 num1
int32 num2

---
#服务器响应
int32 sum

参数服务器

增与改

C++:
`#include "ros/ros.h"

int main(int argc, char *argv[])
{   
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"paramset");

    ros::NodeHandle nh;
    //方案1:句柄
    nh.setParam("name","xiaoming");
    nh.setParam("radius",0.15);
    //方案2:参数对象
    ros::param::set("name","xiaoming");
    ros::param::set("radius",0.15);

    //修改
    //方案1:句柄
    nh.setParam("name","xiaoming");
    nh.setParam("radius",0.155);
    //方案2:参数对象
    ros::param::set("name","xiaoming");
    ros::param::set("radius",0.175);

    return 0;

}
python:
import rospy

if __name__ == "__main__":
    rospy.init_node("parameter")

    rospy.set_param("type","cheche")

在 ROS 中,ros::NodeHandle 提供了多种方法用于与参数服务器交互,这些方法允许获取、设置、检查和搜索参数。下面是你提到的几种常见的 NodeHandle 参数操作函数的详细介绍:

  1. nh.param 函数
    nh.param 用于获取或设置一个参数的值。如果该参数不存在,且你为其指定了默认值,那么它会返回默认值。
    语法:
    bool ros::NodeHandle::param(const std::string& param_name, T& param, const T& default_value) const;
  • param_name:需要获取或设置的参数的名称。
  • param:变量,用于存储从参数服务器获取的值。
  • default_value:如果参数在服务器中不存在,返回的默认值。

示例:

int loop_rate; 
nh.param("loop_rate", loop_rate, 10);  // 如果 "loop_rate" 参数不存在,则默认值为 10

`

  1. nh.getParam 函数
    nh.getParam 用于从参数服务器获取指定名称的参数。如果参数不存在,它会返回 false,并且参数变量不会被修改。
    语法:
    bool ros::NodeHandle::getParam(const std::string& param_name, T& param) const;
  • param_name:需要获取的参数的名称。
  • param:用于存储从参数服务器获取的值。

示例:

int loop_rate; 
if (nh.getParam("loop_rate", loop_rate)) {    
ROS_INFO("Loop rate is: %d", loop_rate);
} else {     
ROS_WARN("Parameter 'loop_rate' not found!");
}
  1. nh.paramNames 函数
    nh.paramNames 返回当前节点的所有参数名称的列表。你可以用它来获取所有已设置的参数的名称。
    语法:
    std::vector<std::string> ros::NodeHandle::getParamNames() const;
  • 返回值:一个包含所有参数名称的 std::vector<std::string>

示例:

std::vector<std::string> param_names = nh.getParamNames(); 
for (const auto& param_name : param_names) {     
ROS_INFO("Parameter: %s", param_name.c_str());
}
  1. nh.hasParam 函数
    nh.hasParam 用于检查某个参数是否存在于参数服务器上。如果参数存在,它返回 true,否则返回 false
    语法:
    bool ros::NodeHandle::hasParam(const std::string& param_name) const;
  • param_name:需要检查的参数名称。
  • 返回值:如果参数存在,返回 true;如果参数不存在,返回 false

示例:

if (nh.hasParam("loop_rate")) {     
ROS_INFO("Parameter 'loop_rate' exists."); 
} else {    
ROS_WARN("Parameter 'loop_rate' does not exist."); 
}
  1. nh.searchParam 函数
    nh.searchParam 用于在父级节点和当前节点中查找给定的参数名称。如果找到了,返回该参数的完整名称。
    语法:
    std::string ros::NodeHandle::searchParam(const std::string& param_name) const;
  • param_name:需要查找的参数名称。
  • 返回值:参数的完整名称(如果找到),否则返回空字符串。

示例:

std::string full_param_name = nh.searchParam("loop_rate"); 
if (!full_param_name.empty()) {     
ROS_INFO("Found parameter '%s' with full name: %s", "loop_rate", full_param_name.c_str());
} 
else {    
ROS_WARN("Parameter 'loop_rate' not found.");
}

`

总结:

  1. nh.param:获取参数并设置默认值。
  2. nh.getParam:从参数服务器获取参数,失败时返回 false
  3. nh.getParamNames:返回所有参数名称的列表。
  4. nh.hasParam:检查某个参数是否存在。
  5. nh.searchParam:在父节点和当前节点中查找某个参数的完整名称。

在ROS中,函数中的“键”通常是指在函数调用或参数传递中使用的“键值对”(key-value pair)。这些键通常指代某些参数的名称,而对应的值则是参数的具体内容。

在ROS中,许多函数或方法都使用参数字典(如ros::param)来传递配置信息。例如,节点启动时可以从参数服务器中获取值,这些值会以“键-值”对的方式组织,以下是一些常见的例子:

  1. ROS参数服务器:可以通过键(key)来获取或设置参数(value)。

    • 例如:ros::param::get("key_name", value); 其中 "key_name" 是键,value 是存储对应数据的变量。
  2. 发布者和订阅者:在创建发布者和订阅者时,也可能传递一些配置参数,例如队列大小、消息类型等,这些可以看作是函数调用中的“键”。

    • 例如:ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 1000); 这里 "topic_name" 可以视为一个键。

在 ROS 中,“键” 主要是用来标识和获取相关的参数或配置项的标识符。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值