zoukankan      html  css  js  c++  java
  • ROS之话题的发布与订阅

    消息:

    msg文件就是一个描述ROS中所使用消息类型的简单文本。它们会被用来生成不同语言的源代码。
    注意,在构建的时候,我们只需要"message_generation"。然而,在运行的时候,我们只需要"message_runtime"。
    查看package.xml, 确保它包含以下两条语句:
    <build_depend>message_generation</build_depend>
    <run_depend>message_runtime</run_depend>
    在 CMakeLists.txt文件中,利用find_packag函数,增加对message_generation的依赖:
    catkin_package( … CATKIN_DEPENDS message_runtime … …)
    add_message_files( FILES Num.msg)
    generate_messages()

    1、创建工作空间:

    mkdir -p ~/ROS_Learning_ws/src
    cd ~/ROS_Learning_ws/src
    catkin_init_workspace	#初始化工作空间
    cd ~/ROS_Learning_ws
    catkin_make	#编译工作空间
    
    source devel/setup.bash	#将该工作空间加入环境变量
    

    2创建功能包:

    创建工作空间后,工作空间可以顺利通过编译,此时工作空间不存在功能包,即还没有功能实现。需要使用catkin_create_pkg创建功能包。

    cd ~/ROS_Leraning/src
    catkin_create_pkg learning_communication  std_msgs  roscpp  rospy
    

    catkin_create_pkg命令行格式:catkin_create_pkg [package_name] [depend1] [depend2] [depend3]。因此上述命令行中的std_msgs和roscpp分别为功能包ROS_Test1的依赖项。

    std_msgs:包含了常见的消息类型,表示基本数据类型和其他基本的消息构造。

    roscpp:表示该功能包通过c++实现ROS的各种功能。提供了一个客户端库,c++开发者可以调用接口迅速完成主题、服务等相关工作。

    rospy:表示该功能包通过python实现ROS的各种功能。提供了一个客户端库,python开发者可以调用接口迅速完成主题、服务等相关工作。

    此时执行以下命令可以查看功能包的依赖项。  

    rospack depends learning_communication    #查看功能包依赖项

    3、编译功能包:

     返回到工作空间根目录:

    cd ~/ROS_Learning
    catkin_make
    

    4、创建发布和订阅节点

    在功能包下的src文件下,即learning_communication/src创建发布话题节点文件:talker.cpp   内容如下:

     //该例程将发布chatter话题,消息类型String
     
    #include <sstream>
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    int main(int argc, char **argv)
    {
        // ROS节点初始化
        ros::init(argc, argv, "talker");
    
        // 创建节点句柄
        ros::NodeHandle n;
    
        // 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
        ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
    
        // 设置循环的频率
        ros::Rate loop_rate(10);
    
        int count = 0;
        while (ros::ok())
        {
            // 初始化std_msgs::String类型的消息
            std_msgs::String msg;
            std::stringstream ss;
            ss << "hello world " << count;
            msg.data = ss.str();
    
            // 发布消息
            ROS_INFO("%s", msg.data.c_str());
            chatter_pub.publish(msg);
    
            // 循环等待回调函数
            ros::spinOnce();
    
            // 按照循环频率延时
            loop_rate.sleep();
            ++count;
        }
    
        return 0;
    }
    

    在功能包下的src文件下,即learning_communication/src创建订阅话题节点文件:listener.cpp   内容如下:  

    //该例程将订阅chatter话题,消息类型String
    
     
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    // 接收到订阅的消息后,会进入消息回调函数
    void chatterCallback(const std_msgs::String::ConstPtr& msg)
    {
        // 将接收到的消息打印出来
        ROS_INFO("I heard: [%s]", msg->data.c_str());
    }
    
    int main(int argc, char **argv)
    {
        // 初始化ROS节点
        ros::init(argc, argv, "listener");
    
        // 创建节点句柄
        ros::NodeHandle n;
    
        // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
        ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
    
        // 循环等待回调函数
        ros::spin();
    
        return 0;
    }
    

    在一个功能包内可以同时发布可创建多个实例化节点句柄,创建多个发布函数,创建多个订阅回调函数。  

    5、创建CMake文件:

    learning_communication包根目录下找到CMakeLists.txt文件在文件结尾端添加如下:

    add_executable(talker src/talker.cpp)    #将talker.cpp文件编译成可执行文件talker
    target_link_libraries(talker ${catkin_LIBRARIES})      #为可执行文件talker添加链接库 
    add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp) #添加可执行文件的消息依赖

    add_executable(listener src/listener.cpp)
    target_link_libraries(listener ${catkin_LIBRARIES})
    add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)

    以上内容编辑完成以后,进行节点编译:

    回到工作空间根目录进行编译:

    cd ~/ROS_Learning
    catkin_make
    

    编译完成后运行

    roscore
    rosrun learning_communication talker   #需开启新终端
    rosrun learning_communication listener  #需开启新终端
    

    运行结果如下图:

    补充:

    ros::ok()返回false的条件:

    1. SIGINT收到(Ctrl-C)信号
    2. 另一个同名节点启动,会先中止之前的同名节点
    3. ros::shutdown()被调用
    4. 所有的ros::NodeHandles被销毁

    spinOnce()与spin()区别:
    spinOnce()与spin()是兄弟函数,学名叫做消息回调处理函数。区别如下:

    spinOnce()函数调用后,会继续执行后续的代码段。例如talker中,执行该函数后会继续执行loop_rate.sleep()。
    spin()调用后,程序不会返回,不会执行后续的代码段。例如listener中,执行该函数后,程序不会返回。

  • 相关阅读:
    《JavaScript高级程序设计》笔记:客户端检测(九)
    《JavaScript高级程序设计》笔记:BOM(八)
    《JavaScript高级程序设计》笔记:函数表达式(七)
    《JavaScript高级程序设计》笔记:面向对象的程序设计(六)
    小tips:JS的Truthy和Falsy(真值与假值)
    footer固定在页面底部的实现方法总结
    WEB前端需要了解的XML相关基础知识
    vuex最简单、最直白、最全的入门文档
    原生JS替代jQuery的各种方法汇总
    数据挖掘优秀工具对比
  • 原文地址:https://www.cnblogs.com/qilai/p/13974458.html
Copyright © 2011-2022 走看看