一、话题编程
代码理解
发布者:talker
/*
* 发布chatter话题,消息类型String
*/
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
using namespace ros;
int main(int argc,char **argv)
{
init(argc,argv,"talker"); //节点初始化,起个名字
NodeHandle n; //节点句柄
Publisher chatter_pub = n.advertise<std_msgs::String>("chatter",100);//创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
Rate loop_rate(10); // 设置循环的频率
/* 向 Topic: chatter 发送消息, 发送频率为10Hz(1秒发10次);消息池最大容量100。 */
/* 它将会记录从上次调用Rate::sleep()到现在为止的时间,并且休眠正确的时间。在这个例子中,设置的频率为10hz */
int count=0;
while(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);
// 按照循环频率延时 休眠一下,使程序满足前面所设置的10hz的要求
loop_rate.sleep();
++count;
}
return 0;
}
订阅者:listener
/**
* 该例程将订阅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;
}
①ros::spin() 或 ros::spinOnce(),两者区别在于前者调用后不会再返回,也就是你的主程序到这儿就不往下执行了,而后者在调用后还可以继续执行之后的程序,程序写了相关的消息订阅函数,那千万千万千万不要忘了在相应位置加上ros::spin()或者ros::spinOnce()函数
简单测试
二、服务编程
代码理解
service
/**
* 该例程执行/turtle_command服务,服务数据类型std_srvs/Trigger
*/
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <std_srvs/Trigger.h>
using namespace ros;
Publisher turtle_vel_pub;
bool pubCommand = false;
//service回调函数,输入参数rep,输出参数res
bool commandCallback(std_srvs::Trigger::Request &rep,
std_srvs::Trigger::Response &res)
{
pubCommand = !pubCommand;
//显示请求数据
ROS_INFO("Publish turtle velocity command[%s]",pubCommand == true?"YES":"NO");
//设置反馈数据
res.success = true;
res.message = "Change turtle command state!";
return true;
}
int main(int argc,char** argv)
{
init(argc,argv,"turtle_command_server");
NodeHandle n;
//创建一个名为/turtle_command的server,注册回调函数commandCallback
ServiceServer command_service = n.advertiseService("/turtle_command",commandCallback);
//创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度为10
turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);
//循环等待回调函数
ROS_INFO("Ready to receive turtle command.");
//设置循环的频率
Rate loop_rate(10);
while(ok())
{
spinOnce();
//如果标志为true,则发布速度指令
if(pubCommand)
{
geometry_msgs::Twist vel_msg;
vel_msg.linear.x = 0.5;
vel_msg.angular.z = 0.2;
turtle_vel_pub.publish(vel_msg);
}
//按照循环频率延时
loop_rate.sleep();
}
}
geometry_msgs 给了我们很多的数据类型包,以后拿来用就好
client
/**
* 该例程将请求/spawn服务,服务数据类型turtlesim::Spawn
*/
#include <ros/ros.h>
#include <turtlesim/Spawn.h>
using namespace ros;
int main(int argc,char** argv)
{
//初始化ros节点
init(argc,argv,"turtle_spawn");
//创建节点句柄
NodeHandle node;
//发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
service::waitForService("/spawn");
ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
//初始化turtlesim::Spawn的请求数据
turtlesim::Spawn srv;
srv.request.x = 2.0;
srv.request.y = 2.0;
srv.request.name = "turtle2";
//请求服务调用
ROS_INFO("Call service to spawn turtle[x:%0.6f,y:%0.6f,name:%s]",srv.request.x,srv.request.y,srv.request.name);
//调用call ①发出请求②把数据srv发送出去③在这里等待回复
add_turtle.call(srv);
//显示服务调用结果
ROS_INFO("Spawn turtle successfully [name:%s]",srv.response.name.c_str());
return 0;
}
这里的Spawn:
rosservice: rosservice call [服务] -----> 相当于发命令的人(我)是 client
add_turtle.call([数据类型]);
[服务]:
①自己创建
ros::ServiceServer service = n.advertiseService("name",callback );
②等待,发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
ros::service::waitForService("/spawn");
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");