在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;
}
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;
}
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 - 通知目标由于取消请求而不再被处理
中间状态有
最终状态
-
Rejected - 目标被操作服务器拒绝,没有进行处理,也没有来自操作客户机的取消请求 -
Succeeded - 动作服务器成功地实现了目标 -
Aborted - 目标由操作服务器终止,而没有来自操作客户机的取消外部请求 -
Recalled - 在操作服务器开始处理目标之前,目标被另一个目标或取消请求取消 -
Preempted - 目标的处理被另一个目标或发送到操作服务器的取消请求取消
3.1、消息创建
像服务模式一样需要创建服务消息,其消息类型如下图所示
- 在功能包创建action目录,在目录中创建demo.action并按照上方填写消息
- 修改CMackLists
add_action_files(
FILES
demo.action
# Action2.action
)
其他的同上方的服务信息
3.2、简单案例
#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;
}
#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;
}
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
|