ROS学习笔记7(ROS进阶)

10.1 Action通信

在这里插入图片描述

10.1.1 自定义action文件

基本上和msg,srv一样
先创建功能包
依赖:

roscpp rospy std_msgs actionlib actionlib_msgs

在这里插入图片描述
新建action功能包
在这里插入图片描述

int32 num
---
int32 result
---
float64 progress_bar

Cmake配置

66行,72行
在这里插入图片描述
107行
在这里插入图片描述

10.1.2 c++服务端实现

#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "demo1_action/AddintsAction.h"

using namespace ros;

typedef actionlib::SimpleActionServer<demo1_action::AddintsAction> Server;

void cb(const demo1_action::AddintsGoalConstPtr &goalPtr, Server *server)
{
    //解析目标数据
    int goal_num = goalPtr -> num;
    ROS_INFO("提交数据为:%d", goal_num);

    //产生连续反馈
    Rate rate(10);
    int result = 0;
    for(int i=1 ; i <= goal_num ; i++)
    {
        result += i;
        rate.sleep();
        demo1_action::AddintsFeedback feedback;
        feedback.progress_bar = i / (double)goal_num;
        server -> publishFeedback(feedback);
    }

    //最终相应结果
    demo1_action::AddintsResult r;
    r.result = result;
    server -> setSucceeded(r);
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "");
    init(argc, argv, "AddInts_server");
    NodeHandle nh;
    Server server(nh,"AddInts",boost::bind(&cb,_1,&server),false);
    server.start();
    spin();
    return 0;
}

Cmake配置和之前一样
在这里插入图片描述在编译时,出现boost库的报错(可能是boost兼容性问题)
在这里插入图片描述在Cmake的project()后面加上

add_compile_options(-std=c++11)
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
add_definitions(-DPTHREAD_STACK_MIN=16384)

在这里插入图片描述

10.1.3 客户端实现

#include "ros/ros.h"
#include"actionlib/client/simple_action_client.h"
#include "demo1_action/AddintsAction.h"

using namespace ros;

void done_cb(const actionlib::SimpleClientGoalState& state, const demo1_action::AddintsResultConstPtr& result)
{
    if(state.state_ == state.SUCCEEDED)
    {
        ROS_INFO("计算结果:%d",result->result);
    }
    else
    {
        ROS_ERROR("计算失败");
    }
}

void active_cb()
{
    ROS_INFO("Goal just went active");
}

void feedback_cb(const demo1_action::AddintsFeedbackConstPtr& feedback)
{
    ROS_INFO("当前进度:%.2f",feedback->progress_bar);
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    init(argc,argv,"AddInts_client");
    NodeHandle nh;
    actionlib::SimpleActionClient<demo1_action::AddintsAction> client(nh,"AddInts");
    ROS_INFO("Waiting for action server to start.");
    client.waitForServer();
    demo1_action::AddintsGoal goal;
    goal.num = 100;
    client.sendGoal(goal,&done_cb,&active_cb,&feedback_cb);
    spin();
    return 0;
}

Cmake配置和上面一样

代码详解

sendGoal
void sendGoal(const Goal & goal, 
              SimpleDoneCallback done_cb = SimpleDoneCallback(),
              SimpleActiveCallback active_cb = SimpleActiveCallback(), 
              SimpleFeedbackCallback feedback_cb = SimpleFeedbackCallback())

参数分别为:传入参数
完成时回调函数
激活回调参数
反馈回调参数

SimpleDoneCallback
void done_cb(const actionlib::SimpleClientGoalState& state, const demo1_action::AddintsResultConstPtr& result)

state:表示当前状态

state.state_ == state.SUCCEEDED

表示访问正常结束

client.waitForServer();

之前学习的等待方式还有

ros::service::waitForService("addInts");

但是实际上action通信不基于service,所以这个方法不适用

10.2 动态参数

可以用rqt打开工具进行调参,而不用反复启动

rqt

路径:plugins -> configuration -> dynamic reconfigure

10.2.1 客户端实现

新建功能包,依赖:

roscpp rospy std_msgs dynamic_reconfigure

新建cfg文件夹和cfg文件
在这里插入图片描述
添加可执行权限

chmod +x *.cfg
ll

在这里插入图片描述
Cmake配置
在这里插入图片描述
编写时建议改为.py文件,这样有补齐和语法高亮

#! /usr/bin/env python

#导包
from dynamic_reconfigure.parameter_generator_catkin import *

#创建一个参数生成器
gen = ParameterGenerator()

#往生成器添加参数
#add(name, paramtype, level, description, default, min, max, edit_method= "")
gen.add("int_param", int_t, 0, "整形参数", 10, 1, 100)

#配置节点,并退出
exit(gen.generate("demo2_dr", "dr_client", "dr"))

level用于标参数是否被修改过(一般写0)

10.2.2 服务端实现

编写文件

#include "ros/ros.h"
#include "dynamic_reconfigure/server.h"
#include "demo2_dr/drConfig.h"

using namespace ros;

//解析动态参数
void cb(demo2_dr::drConfig &config, uint32_t level)
{
    ROS_INFO("修改后的参数是:%d", config.int_param);
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "");
    init(argc, argv, "dr");
    //创建服务器对象
    dynamic_reconfigure::Server<demo2_dr::drConfig> server;
    //回调函数解析修改后的参数
    server.setCallback(boost::bind(&cb, _1, _2));
    spin();
    return 0;
}

Cmake配置同前
在这里插入图片描述

boost::bind()

bind用于将函数与其参数绑定,创建一个可调用对象

10.2.3 客户端

#! /usr/bin/env python

#导包
from dynamic_reconfigure.parameter_generator_catkin import *

#创建一个参数生成器
gen = ParameterGenerator()

#往生成器添加参数
#add(name, paramtype, level, description, default, min, max, edit_method= "")
gen.add("int_param", int_t, 0, "整形参数", 10, 1, 100)
gen.add("double_param", double_t, 0, "浮点参数", 1.57, 0, 3.14)
gen.add("str_param", str_t, 0, "字符串参数", "hello")
gen.add("bool_param", bool_t, 0, "布尔参数", True)

mylist = gen.enum([gen.const("small",int_t,0,"small car"),
                   gen.const("normal",int_t,1,"normal car"),
                   gen.const("big",int_t,2,"big car"),
                   ],"car_size")

gen.add("list_param", int_t, 0, "列表参数", 0,0,2, edit_method=mylist)
#配置节点,并退出
exit(gen.generate("demo2_dr", "dr_client", "dr"))

enum

在这里插入图片描述

#include "ros/ros.h"
#include "dynamic_reconfigure/server.h"
#include "demo2_dr/drConfig.h"

using namespace ros;

//解析动态参数
void cb(demo2_dr::drConfig &config, uint32_t level)
{
    ROS_INFO("修改后的参数是:%d,%.2f,%s,%d,%d",
              config.int_param,
              config.double_param,
              config.str_param.c_str(),
              config.bool_param,
              config.list_param
              );
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "");
    init(argc, argv, "dr");
    //创建服务器对象
    dynamic_reconfigure::Server<demo2_dr::drConfig> server;
    //回调函数解析修改后的参数
    server.setCallback(boost::bind(&cb, _1, _2));
    spin();
    return 0;
}

10.3 pluginlib

10.3.1 基本使用

新建功能包,依赖:

roscpp pluginlib

复制include文件路径,加到c_cpp_properties.json的includePath里面
在这里插入图片描述

基类构造

在include下创建.h文件

#ifndef DBX_BASE_H_
#define DBX_BASE_H_

namespace dbx_base_ns {

    /*
        注意:必须保证基类中包含无参构造
    */
    class Dbx_Base{
        protected:
            Dbx_Base(){}

        public:
            virtual double getlength() = 0;
            virtual void init(double side_length) = 0;
    };
};

#endif

衍生类构造

#ifndef DBX_PLUGINS_H_
#define DBX_PLUGINS_H_

#include "demo3_plugin/dbx_base.h"

namespace dbx_plugins_ns 
{
    class SanBian: public dbx_base_ns::Dbx_Base
    {
        private:
            double side_length;
        public:
            SanBian()
            {
                side_length = 0.0;
            }
            void init(double side_length)
            {
                this->side_length = side_length;
            }
            double getlength()
            {
                return 3 * side_length;
            }
    }

        class SiBian: public dbx_base_ns::Dbx_Base
    {
        private:
            double side_length;
        public:
            SiBian()
            {
                side_length = 0.0;
            }
            void init(double side_length)
            {
                this->side_length = side_length;
            }
            double getlength()
            {
                return 4 * side_length;
            }
    }
}

#endif

注册(将基类和衍生类关联)

在src下新建.cpp文件

#include "pluginlib/class_list_macros.h"
#include "demo3_plugin/dbx_base.h"
#include "demo3_plugin/dbx_plugins.h"

//参数1:字类 参数2:父类
PLUGINLIB_EXPORT_CLASS(dbx_plugins_ns::SanBian, dbx_base_ns::Dbx_Base)
PLUGINLIB_EXPORT_CLASS(dbx_plugins_ns::SiBian, dbx_base_ns::Dbx_Base)

Cmake配置
在这里插入图片描述

xml文件编写

新建xml文件
在这里插入图片描述

<!--
    定位动态链接库
        library 根标签下的 path 属性设置
    声明子类和父类
        library 的子标签 class 声明
-->
<library path="lib/libplus">
    <class type="dbx_plugins_ns::SanBian" base_class_type="dbx_base_ns::Dbx_Base">
        <description>正三边形</description>
    </class>

    <class type="dbx_plugins_ns::SiBian" base_class_type="dbx_base_ns::Dbx_Base">
        <description>正四边形</description>
    </class>
    
</library>

注意这里没有.so

导出插件

package.xml下进行导出。
标签为功能包名称,${}表示功能包
在这里插入图片描述
调用命令查看功能包下的插件

rospack plugins --attrib=plugin demo3_plugin

在这里插入图片描述
新建cpp文件
在这里插入图片描述

#include "ros/ros.h"
#include "pluginlib/class_loader.h"
#include "demo3_plugin/dbx_base.h"

int main(int argc, char *argv[])
{
    //创建一个类加载器,参数1:包名 参数2:基类名
    pluginlib::ClassLoader<dbx_base_ns::Dbx_Base> loader("demo3_plugin", "dbx_base_ns::Dbx_Base");
    //使用类加载器实例化某个插件类
    boost::shared_ptr<dbx_base_ns::Dbx_Base> san = loader.createInstance("dbx_plugins_ns::SanBian");
    //使用插件
    san->init(10);
    double length = san->getlength();
    ROS_INFO("SanBian length: %.2f", length);
    return 0;
}

配置cmake同前
使用boost时记得在cmake的project后加上

add_compile_options(-std=c++11)
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
add_definitions(-DPTHREAD_STACK_MIN=16384)

10.4 nodelet

nodelet是ros的节点管理工具,用于调节节点通信

基本语法:

nodelet load pkg/Type manager - Launch a nodelet of type pkg/Type on manager manager
nodelet standalone pkg/Type   - Launch a nodelet of type pkg/Type in a standalone node
nodelet unload name manager   - Unload a nodelet a nodelet by name from manager
nodelet manager               - Launch a nodelet manager node

创建一个manager

rosrun nodelet nodelet manager __name:=DaSun

向manager添加节点

rosrun nodelet nodelet load nodelet_tutorial_math/Plus DaSun __name:=XiaoWang _value:=10

将新节点的输入输出与其他节点关联

rosrun nodelet nodelet load nodelet_tutorial_math/Plus DaSun __name:=ErGou _value:=50 /ErGou/in:=/XiaoWang/out

launch文件编写

<launch>
    <!-- 设置nodelet管理器 -->
    <node pkg="nodelet" type="nodelet" name="mymanager" args="manager" output="screen" />
    <!-- 启动节点1,名称为 n1, 参数 /n1/value 为100 -->
    <node pkg="nodelet" type="nodelet" name="n1" args="load nodelet_tutorial_math/Plus mymanager" output="screen" >
        <param name="value" value="100" />
    </node>
    <!-- 启动节点2,名称为 n2, 参数 /n2/value 为-50 -->
    <node pkg="nodelet" type="nodelet" name="n2" args="load nodelet_tutorial_math/Plus mymanager" output="screen" >
        <param name="value" value="-50" />
        <remap from="/n2/in" to="/n1/out" />
    </node>

</launch>

10.4.2 自定义

编写cpp文件

#include "ros/ros.h"
#include "nodelet/nodelet.h"
#include "pluginlib/class_list_macros.h"

namespace my_nodelet
{
    class MyPlus : public nodelet::Nodelet
    {
        public:
            MyPlus(){}
            void onInit()
            {
                ROS_INFO("hello world");
            }
    };
};

PLUGINLIB_EXPORT_CLASS(my_nodelet::MyPlus, nodelet::Nodelet)

配置cmake(同上,因为没有头文件,不用加include)
在这里插入图片描述
xml文件编写

<library path="lib/libmyplus">
    <class type="my_nodelet::MyPlus" base_class_type="nodelet::Nodelet" name="demo4_nodelet/MyPlus">
        <description>自定义插件</description>
    </class>
</library>

package.xml配置
注意标签是基类的功能包
在这里插入图片描述

10.4.3业务实现

修改上面的cpp文件

#include "ros/ros.h"
#include "nodelet/nodelet.h"
#include "pluginlib/class_list_macros.h"
#include "std_msgs/Float64.h"

namespace my_nodelet
{
    class MyPlus : public nodelet::Nodelet
    {
        private:
            ros::Publisher pub;
            ros::Subscriber sub;
            double value;

        public:
            MyPlus()
            {
                value = 0.0;
            }
            void onInit()
            {
                ROS_INFO("hello world");
                //获取 NodeHandle(私有)
                ros::NodeHandle nh = getPrivateNodeHandle();
                //通过NodeHandle创建订阅对象和发布对象,解析参数
                nh.getParam("value", value);
                pub = nh.advertise<std_msgs::Float64>("out", 10);
                sub = nh.subscribe<std_msgs::Float64>("in", 10, &MyPlus::cb, this);
                //订阅对象和发布对象的回调函数
            }

            void cb(const std_msgs::Float64::ConstPtr& msg)
            {
                //解析订阅到的消息
                double in = msg->data;
                //处理消息
                double out = in + value;
                //发布消息
                std_msgs::Float64 out_msg;
                out_msg.data = out;
                pub.publish(out_msg);
            }
    };
};

PLUGINLIB_EXPORT_CLASS(my_nodelet::MyPlus, nodelet::Nodelet)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值