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)
687

被折叠的 条评论
为什么被折叠?



