IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 初学ROS中的订阅模式、服务模式、action模式 -> 正文阅读

[游戏开发]初学ROS中的订阅模式、服务模式、action模式

在ROS的通信方式中存在订阅-发布模式,服务模式,动作服务模式。

1、订阅-发布模式

使用订阅-发布模式进行通信,首先要知道主题的存在。发布者向主题发布消息,订阅者订阅主题获取消息。其中订阅者不知道消息的来源,发布者不知道谁在接收。 如下图所示:
在这里插入图片描述

1.1、简单案例

  • 发布者
#include <ros/ros.h>

#include "example_ros_msg/VecOfDoubles.h"

int main(int argc, char * argv[])
{
    ros::init(argc, argv, "vec_plu");
    ros::NodeHandle n;
    ros::Publisher pub = n.advertise<example_ros_msg::VecOfDoubles>("vec_topic",1);
    example_ros_msg::VecOfDoubles msg;
    double counter=0;
    ros::Rate naptime(1.0);
    msg.dbl_vec.resize(3);
    msg.dbl_vec[0] = 1.414;
    msg.dbl_vec[1] = 2.71828;
    msg.dbl_vec[2] = 3.1416;
    msg.dbl_vec.push_back(counter);
    while (ros::ok())
    {
        counter+=1;
        msg.dbl_vec.push_back(counter);
        pub.publish(msg);
        naptime.sleep();
    }
    
    // ros::spin();
    // ros::shutdown();
    return 0;
}

  • 订阅者
#include <ros/ros.h>
#include "example_ros_msg/VecOfDoubles.h"

void callBack(const example_ros_msg::VecOfDoubles&masg)
{
    std::vector<double> vec = masg.dbl_vec;
    int si = vec.size();
    for(int i=0;i<si;i++ )
    {
        ROS_INFO("vec[%d] = %f",i,vec[i]);
    }
    ROS_INFO("\n");
}

int main(int argc, char * argv[])
{
    ros::init(argc, argv, "vec_sub");
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("vec_topic",1,callBack);
    // ros::spin();
    // ros::shutdown();
    ros::spin();
    return 0;
}

  • 修改CMakeLists进行编译
add_executable(vec_mag_plu src/vector_push.cpp)
add_executable(vec_mag_sub src/vec_size_sub.cpp)
target_link_libraries(vec_mag_plu
  ${catkin_LIBRARIES}
)
target_link_libraries(vec_mag_sub
  ${catkin_LIBRARIES}
)
#并且修改相对应的引用文件

2、服务模式

服务模式是一种请求应答模式,在进行请求之前需要定义服务的消息类型进行规范请求

2.1、服务消息

服务消息是一种包含请求内容以及应答内心的消息包,需要按照一定的流程进行创建。格式类型如下图所示
在这里插入图片描述

  • 服务消息创建
    1、在功能包创建srv文件目录
    2、在srv中创建examsrv.srv文件并按照上图方式组建消息
    3、修改CMakeLists,Package.xml进行生成
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
  message_generation
)
add_service_files(
  FILES
  examsrv.srv
  # Service2.srv
)

========package.xml
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

编译后会在devel/include/包名 中生成examsrv.h,examsrvRequest.h,examsrvResponse.h

2.2、简单的服务模式案例

  • 服务
#include <ros/ros.h>

#include "example_ros_msg/examsrv.h"
#include<iostream>
#include<string>
using namespace std;

bool callBack(example_ros_msg::examsrvRequest&request,example_ros_msg::examsrvResponse&response)
{
    ROS_INFO("callback activated");
    string in_name(request.name);
    response.on_the_list = false;
    if(in_name.compare("Bob")==0)
    {
        ROS_INFO("asked about Bob");
        response.age=32;
        response.good_guy = false;
        response.on_the_list = true;
        response.nickname="BobTherrible";
    }
    if(in_name.compare("Ted")==0)
    {
        ROS_INFO("asked about Ted");
        response.age=22;
        response.good_guy = true;
        response.on_the_list = true;
        response.nickname="TedTherrible";
    }
    return true;
}

int main(int argc, char * argv[])
{
    ros::init(argc, argv, "srv_node");
    ros::NodeHandle n;
    ros::ServiceServer ser = n.advertiseService("lookup_by_name",callBack);
    ROS_INFO("Ready to look up names");
    ros::spin();
    // ros::shutdown();
    return 0;
}

  • 请求
#include <ros/ros.h>
#include "example_ros_msg/examsrv.h"
#include<iostream>
#include<string>
using namespace std;

int main(int argc, char * argv[])
{
    ros::init(argc, argv, "exam_client");
    ros::NodeHandle n;
    ros::ServiceClient sc = n.serviceClient<example_ros_msg::examsrv>("lookup_by_name");
    example_ros_msg::examsrv srvmasg;
    bool on_the_list = false;
    string in_name;
    while (ros::ok())
    {
       cin>>in_name;
       if(in_name.compare("x")==0)
       {
           return 0;
       }
        srvmasg.request.name = in_name;
        if(sc.call(srvmasg))
        {
            if(srvmasg.response.on_the_list){
                cout<<srvmasg.request.name<<" is know as "<<srvmasg.response.nickname<<endl;
                if(srvmasg.response.good_guy)
                {
                    cout<<"good"<<endl;
                }
                else{
                    cout<<"bad"<<endl;
                }
            }
            else
            {
                cout<<srvmasg.request.name<<" is not know  "<<endl;
            }
        }else
        {
            ROS_ERROR("failed to call service lookup_by_name");
            return 1;
        }
    }
    
    // ros::spin();
    // ros::shutdown();
    return 0;
}

  • 修改CMakeLists
add_executable(name_srv src/examsrv.cpp)
add_executable(name_cli src/examsrvclient.cpp)
target_link_libraries(name_srv
  ${catkin_LIBRARIES}
)
target_link_libraries(name_cli
  ${catkin_LIBRARIES}
)

3、action服务

与服务模式相比action服务增加了反馈机制,可以在获得请求目标后,对目标的执行过程进行反馈。通信模型如图所示
在这里插入图片描述
当服务接收到目标以后会为每一个目标创建一个状态机,跟踪目标状态。状态机如下
在这里插入图片描述

状态机的命令有

  • setAccepted - 在检查一个目标之后,开始处理

  • setRejected - 在检查一个目标后,决定永远不处理它,因为它是一个无效的请求(超出界限,资源不可用,无效等)

  • setSucceeded -通知目标已成功处理

  • setAborted - 通知目标在处理过程中遇到错误,必须中止

  • setCanceled - 通知目标由于取消请求而不再被处理

中间状态有

  • Pending - 目标还没有被操作服务器处理

  • Active - 目标当前正在由操作服务器处理

  • Recalling - 目标尚未被处理,并且已从操作客户端接收到取消请求,但操作服务器尚未确认目标已被取消

  • Preempting - 目标正在处理中,并且从操作客户端收到了一个取消请求,但操作服务器尚未确认目标已被取消

最终状态

  • Rejected - 目标被操作服务器拒绝,没有进行处理,也没有来自操作客户机的取消请求

  • Succeeded - 动作服务器成功地实现了目标

  • Aborted - 目标由操作服务器终止,而没有来自操作客户机的取消外部请求

  • Recalled - 在操作服务器开始处理目标之前,目标被另一个目标或取消请求取消

  • Preempted - 目标的处理被另一个目标或发送到操作服务器的取消请求取消

3.1、消息创建

像服务模式一样需要创建服务消息,其消息类型如下图所示
在这里插入图片描述

  • 在功能包创建action目录,在目录中创建demo.action并按照上方填写消息
  • 修改CMackLists
add_action_files(
  FILES
  demo.action
  # Action2.action
)
其他的同上方的服务信息

3.2、简单案例

  • action服务
#include<actionlib/server/simple_action_server.h>
#include<example_action_server/demoAction.h>
int g_count = 0;
bool g_count_failure = false;
class ExampleActionSever{
    private:
    ros::NodeHandle nh_;
    actionlib::SimpleActionServer<example_action_server::demoAction> as_;
    example_action_server::demoGoal goal;
    example_action_server::demoResult result_;
    example_action_server::demoFeedback feedback_;
    int countdown_val_;
    public:
    ExampleActionSever();
    ~ExampleActionSever(){

    }

    void executeCB(const actionlib::SimpleActionServer<example_action_server::demoAction>::GoalConstPtr&goal);
};

ExampleActionSever::ExampleActionSever():as_(nh_,"time_action",boost::bind(&ExampleActionSever::executeCB,this,_1),false)
{
    ROS_INFO("in construction of exampleActon....");
    as_.start();
}

void ExampleActionSever::executeCB(const actionlib::SimpleActionServer<example_action_server::demoAction>::GoalConstPtr&goal)
{
    ROS_INFO("in executeCB");
    ROS_INFO("goal input is:%d",goal->input);

    ros::Rate timer(1.0);
    countdown_val_ = goal->input;
    while (countdown_val_>0)
    {
        ROS_INFO("countdown=%d",countdown_val_);
        if(as_.isPreemptRequested()){
            ROS_INFO("goal cancelled!");
            as_.setAborted(result_);
            return;
        }
        feedback_.fdbk = countdown_val_;
        as_.publishFeedback(feedback_);
        countdown_val_--;
        timer.sleep();
    }
    result_.output  = countdown_val_;
    as_.setSucceeded(result_);
    
    
}

int main(int argc ,char*argv[])
{
    ros::init(argc,argv,"examatciontime");
    ExampleActionSever ex;
    ROS_INFO("go spin.....");
    while (!g_count_failure)
    {
        ros::spinOnce();
    }
    return 0;
}
  • action 客户端
#include<ros/ros.h>
#include<actionlib/client/simple_action_client.h>
#include<example_action_server/demoAction.h>

using namespace std;
bool g_goal_action = false;
int g_result_output = -1;
int g_fdbk = -1;

void doneCb(const actionlib::SimpleClientGoalState& state,const example_action_server::demoResultConstPtr& result)
{
    ROS_INFO("doneCb: server responded with state [%s]",state.toString().c_str());
    ROS_INFO("got result output=%d",result->output);
    g_result_output = result->output;
    g_goal_action = false;
}
void feedbackCB(const example_action_server::demoFeedbackConstPtr& fdbk_msg)
{
    ROS_INFO("feedback status = %d",fdbk_msg->fdbk);
    g_fdbk = fdbk_msg->fdbk;
}

void activeCB()
{
    ROS_INFO("Goal just went active");
    g_goal_action = true;
}

int main(int argc,char*argv[])
{
    ros::init(argc,argv,"exampleactionclienttime");
    ros::NodeHandle n;
    ros::Rate main_timer(1.0);
    example_action_server::demoGoal goal;
    actionlib::SimpleActionClient<example_action_server::demoAction> actionClient("time_action",true);
    ROS_INFO("waiting for server");
    bool server_exists = actionClient.waitForServer(ros::Duration(1.0));
    if(!server_exists)
    {
        ROS_WARN("not wait for server");
        server_exists = actionClient.waitForServer(ros::Duration(1.0));
    }

    ROS_INFO("connnect to action server");

    int countdown_goal=1;
    while (countdown_goal>=0)
    {
        cout<<"enter a desired timer value,in seconds(0 to abort,<0 to quit):";
        cin>>countdown_goal;
        if(countdown_goal==0)
        {
            ROS_INFO("cancelling goal");
            actionClient.cancelGoal();
        }
        if(countdown_goal<0)
        {
            ROS_INFO("this client is quitting");
            return 0;
        }
        ROS_INFO("send timer goal = %d seconds to timer action server",countdown_goal);
        goal.input = countdown_goal;
        actionClient.sendGoal(goal,&doneCb,&activeCB,&feedbackCB);
    }

    return 0;
    
}
  • 修改CMakeLists
add_executable(exampletimeActionClient src/example_action_w_clent.cpp)
add_executable(exampletimeAction src/example_action_w_fdbk.cpp)
target_link_libraries(exampletimeActionClient
  ${catkin_LIBRARIES}
)
target_link_libraries(exampletimeAction
  ${catkin_LIBRARIES}
)

记录为了让自己在回忆
参考
1
2
3

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 19:10:32  更:2022-04-22 19:12:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:39:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码