您当前的位置: 首页 > 

我什么都布吉岛

暂无认证

  • 1浏览

    0关注

    292博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

ROS入门21讲笔记(六)代码形式写一个服务端

我什么都布吉岛 发布时间:2022-03-28 23:52:55 ,浏览量:1

上一节的课程详细的讲解了如何创建一个客户端C++代码并向一个已存在的服务发送请求,这一节我们将来学习如何自己创建一个服务,为了验证服务是有效的,我们将直接在终端(客户端)请求这个服务,为了证明服务是有效的,最好留下打印信息。

在此之前,先来了解以下ROS都给我们提供了那些内置服务类型(std_srvs):

  • Empty
  • Trigger
  • SetBool

其中Trigger和Empty类型是最常见的两种服务类型,对于Empty,服务器和客户端之间不会交换实际数据;对于Trigger则会交换服务数据,查看Trigger的类型,结果如下:

---
bool success   # indicate successful run of triggered service
string message # informational, e.g. for error messages

Trigger可以用来检查出发是否成功及一些有用的信息。

完整的流程如下:

#mermaid-svg-OLrWyzMw8IoiwYvv {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv .error-icon{fill:#552222;}#mermaid-svg-OLrWyzMw8IoiwYvv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OLrWyzMw8IoiwYvv .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-OLrWyzMw8IoiwYvv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OLrWyzMw8IoiwYvv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OLrWyzMw8IoiwYvv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OLrWyzMw8IoiwYvv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OLrWyzMw8IoiwYvv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OLrWyzMw8IoiwYvv .marker.cross{stroke:#333333;}#mermaid-svg-OLrWyzMw8IoiwYvv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OLrWyzMw8IoiwYvv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv .cluster-label text{fill:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv .cluster-label span{color:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv .label text,#mermaid-svg-OLrWyzMw8IoiwYvv span{fill:#333;color:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv .node rect,#mermaid-svg-OLrWyzMw8IoiwYvv .node circle,#mermaid-svg-OLrWyzMw8IoiwYvv .node ellipse,#mermaid-svg-OLrWyzMw8IoiwYvv .node polygon,#mermaid-svg-OLrWyzMw8IoiwYvv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OLrWyzMw8IoiwYvv .node .label{text-align:center;}#mermaid-svg-OLrWyzMw8IoiwYvv .node.clickable{cursor:pointer;}#mermaid-svg-OLrWyzMw8IoiwYvv .arrowheadPath{fill:#333333;}#mermaid-svg-OLrWyzMw8IoiwYvv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OLrWyzMw8IoiwYvv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OLrWyzMw8IoiwYvv .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-OLrWyzMw8IoiwYvv .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-OLrWyzMw8IoiwYvv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OLrWyzMw8IoiwYvv .cluster text{fill:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv .cluster span{color:#333;}#mermaid-svg-OLrWyzMw8IoiwYvv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OLrWyzMw8IoiwYvv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
开始
创建工作空间
创建package
编写服务节点代码
修改CMakeLists.txt并编译
roscore rosrun
rosservice pub 服务 数据
结束

因为前面已经创建过很多次workspace和package这里直接略过。

一、编写服务端代码

每当你需要发布一个话题,或者提供某项服务,离不开我们的节点管理器(ros::NodeHandle)。节点管理器可以调用:

  • advertiseService 注册某项服务并返回服务器实例
  • advertise 注册某个话题返回话题实例

用户可以通过话题实例发布数据pub,需要理解的是,服务器提供的服务是由回调函数定义的,每当一个请求进来就会调用回调函数,这个回调函数第一个参数是标准Trigger服务数据类型,在这个例子里,请求的终端将发送一个标准空数据给服务器,服务器能够感知这个请求,但是并没有办法获得任何有效信息,因为它是空的;服务器通过第二个参数是标准Trigger类型,回调函数里的参数都将会在返回给调用的客户端(这里的终端)。

如果其实到这里就可以验证服务器是否对客户端进行了响应,但是为了更加直观,作者用了海龟可视化界面来显示,并通过其发送/turtle1/cmd_vel话题控制海龟的启停。

所以这次编写的代码既涉及了服务又涉及到了话题,对于新手来说不是特别的友好。现在来看最终的程序:

#include 
#include 
#include            //标准服务数据类型std_srvs/Trigger


ros::Publisher turtle_vel_pub;          //构造一个Publisher对象实例,用来发送消息

bool pubCommand=false;

//回调函数第一个参数是标准服务数据Trigger::Request,请求者的数据将会由这个数据传入
//回调函数第二个参数是标准服务数据Trigger::Response,请求者也会收到服务器给的数据
bool commandCallback(std_srvs::Trigger::Request &req,std_srvs::Trigger::Response &res)
{
    pubCommand=!pubCommand;//取反

    ROS_INFO("Publish turtle velocity command[%s]",pubCommand==true?"YES":"NO");

    res.success=true;
    res.message="Change turtle command state";

    return true;
}

int main(int argc,char **argv)
{
    ros::init(argc,argv,"turtle_command_server");
    ros::NodeHandle n;
    
    //注册一个Service 服务提供者,其服务的名称为/turtle_comand,只要有客户端请求服务就会调用回调函数commandCallback(其实就是服务内容)
    ros::ServiceServer command_service=n.advertiseService("/turtle_command",commandCallback);
    //注册一个Topic   话题发布者,其发布的话题为/turtle1/cmd_vel,因为话题没有反馈,就没有回调函数这一说
    turtle_vel_pub = n.advertise("/turtle1/cmd_vel",10);
    ROS_INFO("Ready to receive turtle command.");

    ros::Rate loop_rate(10);
    while(ros::ok())
    {
        ros::spinOnce();//spinOnce处理一次回调函数
        if(pubCommand)
        {
            geometry_msgs::Twist vel_msg;
            vel_msg.linear.x=0.5;
            vel_msg.angular.z=0.2;
            turtle_vel_pub.publish(vel_msg);
            
        }
    }
 
    return 0;

}
二、编译运行

三、一些编程上的总结 对象含义advertise节点句柄通过此方法注册话题,这个话题类型由模板参数给定。实参是话题名和缓冲长度,返回一个服务器者advertiseService节点句柄通过此方法注册服务,这个服务没有模板参数。实参是服务名和回调函数,返回一个发布者ros::Rate r(数字)控制循环频率,单位时间次数publish(消息)发布者通过这个方法将指定消息发布出去spinOnce()处理一次callbackros::ok()ros是否需要退出(shutdown)std_msgs标准发布类型包std_srvs标准服务数据类型包ros::initros初始化操作

功能包中可能含有多个源文件,这些源文件可能会单独被编译成应用程序。

关注
打赏
1658157489
查看更多评论
立即登录/注册

微信扫码登录

0.0394s