美文网首页
ros系统入门笔记(三)

ros系统入门笔记(三)

作者: Allen的光影天地 | 来源:发表于2019-02-19 11:14 被阅读2次

    roscpp ——ros提供给cpp的接口(client library)

    用C++语言与ros系统的topic,service,parameter以及timer等做交互的接口

    相关调用函数

    roscpp主要包括

    依次对上图的相关函数做解释,其中最重要的是第二部分,NodeHandle

    void ros::init(); // 解析node参数,为本node命名
    

    1. ros::NodeHandle Class

    NodeHandle其实是c++的一个类
    下面介绍该类中常用的成员函数

    // 话题的publisher和subscriber,返回值仍然是个类
    ros::Publisher advertise(const string &topic, uint32_t queue_size);
    ros::Subscriber subscribe(const string &topic, uint32_t queue_size, void(*)(M));
    // service的server和client
    ros::ServiceServer advertiseServer(const string &service, bool(*srv_func)(Mreq &, Mres &));
    ros::ServiceClient serviceClient(const string &service, bool persistent=false);
    // 查询参数,与赋值参数
    bool getParam(const string &key, void &val);
    bool setParam(const string &key, void val);
    

    具体使用方法举例:

    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise(...);
    

    2. ros::master Namespace(是一个命名空间)

    与类的区别:namespace没有对象,调用他的函数的时候,直接写就可以,不需要创建master对象。例如:

    ros::master::check(); // 检查是否启动
    ---
    using namespace ros::master
    check();
    

    常用函数如下图:


    master常用函数

    3. ros::this_node NameSpace(是命名空间)

    相关函数

    4. ros::Service NameSpace(命名空间)

    相关函数

    5. ros::names NameSpace(命名空间)

    相关函数

    以上namespace的相关函数,没必要记住,要求:知道有这样的函数,用的时候回来查找即可!

    举例说明

    1. topic_demo

    功能描述:
    两个node,一个发布模拟GPS信息,一个接受并处理该信息

    步骤:

    1. 建立对应包pkg
    $ cd ~/catkin_ws/src
    $ catkin_create_pkg topic_demo roscpp rospy std_msgs
    
    1. 建立对应文件夹msg并添加massage格式文件:*.msg
    $ cd topic_demo
    $ mkdir msg
    $ cd msg
    $ vim gps.msg
    ---
    gps.msg
    ---
    float32 x
    float32 y
    string state
    

    写完的msg文件需要进行catkin_make编译,生成对应路径的.h头文件,然后在代码中include进去

    // 对应路径
    ~/catkin_ws/devel/include/topic_demo/gps.h
    // 代码中include方法
    #include </topic_demo/gps.h>
    topic_demo::gps msg;
    
    1. talker.cpp
    #include <ros/ros.c>
    #include <topic_demo/gps.h>  // msg的头文件,生成一个包含msg的类
    
    // main函数规矩,第一个参数是参数个数,第二个参数是具体参数值
    int main(int argc, char** argv){
        ros::init(argc, argv, "talker"); // 解析参数,命名节点node
        ros::NodeHandle nh; // 创建node句柄,实例化node
    
        topic_demo::gps msg;
        msg.x = 1.0;
        msg.y = 1.0;
        msg.state = 'working';
    
        ros::Publisher publisher = nh.advertise<topic_demo::gps>("gps_info", 1);
        ros::Rate loop_rate(1.0);   // 定义循环发送的频率
        while(ros::ok){
            msg.x = 1.03 * msg.x;
            msg.y = 1.01 * msg.y;
    
            ROS_INFO("talker:GPS: X = %f, Y = %f", msg.x, msg.y)
            publisher.publish(msg);
            loop_rate.sleep();
        }
        return 0;
    }
    
    1. listener.cpp
    #include <ros/ros.c>
    #include <topic_demo/gps.h>     // msg的头文件,生成一个包含msg的类
    #include <std_msgs/Float32.h>   // ros提供的32位浮点数类型 
    void gpsCallback(const topic_demo::gps::ConstPtr &msg){
        std_msgs::Float32 distance; // distance 是一个结构体,内存存放在distance.data中
        distance.data = sqrt(pow(msg->x,2) + pow(msg->y,2));
        ROS_INFO("Listener: distance from origin = %f, State = %s", distance.data, msg->state.c_str());
    }
    
    // main函数规矩,第一个参数是参数个数,第二个参数是具体参数值
    int main(int argc, char** argv){
        ros::init(argc, argv, "listener"); // 解析参数,命名节点node
        ros::NodeHandle nh; // 创建node句柄,实例化node
    
        // 参数含义:topic名字, 队列长度L通常为1, 回调函数
        ros::Subscriber sub = nh.subscribe("gps_info", 1, gpsCallback);
        // 反复调用当前可以触发的回调函数,阻塞
        // 还有一种只调用一次回调函数的方法:ros::spinOnce();
        ros::spin();
        return 0;
    }
    
    1. 更新CMakelist.txt 和 Package.xml


      cmake的写法,注意红色部分
      package.xml的写法

    2. service_demo

    功能描述:两个node,一个分布请求,一个接受处理信息,并返回信息
    步骤:

    1. package
    $ cd ~/catkin_ws/src
    $ catkin_create_pkg service_demo roscpp rospy std_msgs
    
    1. srv
    $ cd service_demo/
    $ mkdir srv
    $ cd srv
    $ vim Greeting.srv
    ---
    // request方的数据格式
    string name
    int32 age
    ---
    // reply的数据格式
    string feedback
    

    catkin_make 编译之后会生成对应头文件:
    ~/catkin_ws/devel/include/service_demo/Greeting.h
    .../GreetingRequest.h
    .../GreetingResponse.h

    1. server.cpp
    #include <ros/ros.h>
    #include <service_demo/Greeting.h>
    #include "string"
    
    // req和res 都是结构体 包含在对应的Greeting.h 的头文件中
    bool handle_function(service_demo::Greeting::Request &req, service_demo::Greeting::Response &res){
        // 处理函数,先将req数据打印出来
        ROS_INFO("Request from %s with age %d", req.name.c_str(), req.age());
        // 
        res.feedback = "Hi" + req.name + "I am server!";
        return true;
    }
    
    
    int main(int argc, char** argv){
        ros::init(argc, argv, "greetings_server"); // 为本node命名
        ros::NodeHandle nh;
        ros::ServiceServer server = nh.advertiseServer("greetings", handle_function); // 提供服务,回调函数返回的是bool变量
        
        ros::spin();
        
        return 0;
    }
    
    1. client.cpp
    #include <ros/ros.h>
    #include <service_demo/Greeting.h>
    
    // 包名叫service_demo
    int main(int argc, char ** argv){
        ros::init(argc,argv, "greetings_client"); // 该节点的名字
        ros::NodeHandle nh;
        ros::ServerClient client = nh.serverClient<service_demo::Greeting>("greetings"); // 参数为该服务的名字
        
        service_demo::Greeting request;
        request.name = "allen";
        request.age = 24;
    
        if(client.call(request)){
            ROS_INFO("Response from Server: %s", request.response.feedbadk.c_str());
        }else {
            ROS_ERROR("Failed to call server greetings");
        }
        return 0;
    
    }
    
    1. CMakeList.txt 和 package.xml

    3. param_demo

    #include<ros/ros.h>
    
    int main(int argc, char **argv){
        ros::init(argc, argv, "param_demo");
        ros::NodeHandle nh;
        int parameter1, parameter2, parameter3, parameter4, parameter5;
        
        //Get Param的三种方法
        //① ros::param::get()获取参数“param1”的value,写入到parameter1上
        bool ifget1 = ros::param::get("param1", parameter1);
        
        //② ros::NodeHandle::getParam()获取参数,与①作用相同
        bool ifget2 = nh.getParam("param2",parameter2);
        
        //③ ros::NodeHandle::param()类似于①和②
        //但如果get不到指定的param,它可以给param指定一个默认值(如33333)
            nh.param("param3", parameter3, 33333);
        
        if(ifget1)
            ROS_INFO("Get param1 = %d", parameter1);
        else
            ROS_WARN("Didn't retrieve param1");
        if(ifget2)
            ROS_INFO("Get param2 = %d", parameter2);
        else
            ROS_WARN("Didn't retrieve param2");
        if(nh.hasParam("param3"))
            ROS_INFO("Get param3 = %d", parameter3);
        else
            ROS_WARN("Didn't retrieve param3");
    
    
        //Set Param的两种方法
        //① ros::param::set()设置参数
        parameter4 = 4;
        ros::param::set("param4", parameter4);
    
        //② ros::NodeHandle::setParam()设置参数
        parameter5 = 5;
        nh.setParam("param5",parameter5);
        
        ROS_INFO("Param4 is set to be %d", parameter4);
        ROS_INFO("Param5 is set to be %d", parameter5);
    
    
        //Check Param的两种方法
        //① ros::NodeHandle::hasParam()
        bool ifparam5 = nh.hasParam("param5");
    
        //② ros::param::has()
        bool ifparam6 = ros::param::has("param6");
    
        if(ifparam5) 
            ROS_INFO("Param5 exists");
        else
            ROS_INFO("Param5 doesn't exist");
        if(ifparam6) 
            ROS_INFO("Param6 exists");
        else
            ROS_INFO("Param6 doesn't exist");
    
    
        //Delete Param的两种方法
        //① ros::NodeHandle::deleteParam()
        bool ifdeleted5 = nh.deleteParam("param5");
    
        //② ros::param::del()
        bool ifdeleted6 = ros::param::del("param6");
        
    
        if(ifdeleted5)
            ROS_INFO("Param5 deleted");
        else
            ROS_INFO("Param5 not deleted");
        if(ifdeleted6)
            ROS_INFO("Param6 deleted");
        else
            ROS_INFO("Param6 not deleted");
    
    
        ros::Rate rate(0.3);
        while(ros::ok()){
            int parameter = 0;
            
            ROS_INFO("=============Loop==============");
            //roscpp中尚未有ros::param::getallparams()之类的方法
            if(ros::param::get("param1", parameter))
                ROS_INFO("parameter param1 = %d", parameter);
            if(ros::param::get("param2", parameter))
                ROS_INFO("parameter param2 = %d", parameter);
            if(ros::param::get("param3", parameter))
                ROS_INFO("parameter param3 = %d", parameter);
            if(ros::param::get("param4", parameter))
                ROS_INFO("parameter param4 = %d", parameter);
            if(ros::param::get("param5", parameter))
                ROS_INFO("parameter param5 = %d", parameter);
            if(ros::param::get("param6", parameter))
                ROS_INFO("parameter param6 = %d", parameter);
            rate.sleep();
        }
    }
    

    相关文章

      网友评论

          本文标题:ros系统入门笔记(三)

          本文链接:https://www.haomeiwen.com/subject/srqxyqtx.html