最简单的发布和订阅消息
1、发布
/**
* 该例程将发布chatter话题,消息类型String
*/
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "string_publisher");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
// 设置循环的频率
ros::Rate loop_rate(10);
int count = 0;
while (ros::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);
// 按照循环频率延时
loop_rate.sleep();
++count;
}
return 0;
}
2、订阅
/**
* 该例程将订阅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, "string_subscriber");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
// 循环等待回调函数
ros::spin();
return 0;
}
加释:
chatterCallback(const std_msgs::String::ConstPtr& msg) 的输入参数上面const ConstPtr& 常指针,指针指向的类型是const std_msgs::String
3、CMakeLists.txt
空格和回车的作用是一样的
#添加可执行文件
add_executable(string_publisher src/string_publisher.cpp)
#链接库
target_link_libraries(string_publisher ${catkin_LIBRARIES})
add_executable(string_subscriber src/string_subscriber.cpp)
target_link_libraries(string_subscriber ${catkin_LIBRARIES})
4、编译、设置环境变量
catkin_make
source devel/setup.bash
如果遇到一种情况:刚刚写了包,包中写了文件,编译过了,但是在运行的时候利用Tab健没有找到包下面的文件,这个时候要source devel/setup.bash (最好是刚开始建立工作空间的时候就添加到bashrc中)
自定义消息
1、定义msg文件
在功能包下面建立msg文件夹,然后在msg文件夹下建立personMsg.msg 里边写自定义的消息
2、package.xml添加功能包依赖
<build_export_depend>message_generation</build_export_depend>
<exec_depend>message_runtime</exec_depend>
3、CMakeLists.txt添加编译选项(按照上面那张图去填写)
4、编译 如果出现错误根据错误提示修改,一般都是小细节上的,问题不大,可能是package.xml缺少std_msgs依赖
动态产生头文件
学一下ROS_INFO的写法
最简单的服务端和客户端
服务端(server)、客户端(client)是没有消息缓存机制的
服务端
/**
* 该例程将提供print_string服务,std_srvs::SetBool
*/
#include "ros/ros.h"
#include "std_srvs/SetBool.h"
// service回调函数,输入参数req,输出参数res
bool print(std_srvs::SetBool::Request &req,
std_srvs::SetBool::Response &res)
{
// 打印字符串
if(req.data)
{
ROS_INFO("Hello ROS!");
res.success = true;
res.message = "Print Successully";
}
else
{
res.success = false;
res.message = "Print Failed";
}
return true;
}
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "string_server");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个名为print_string的server,注册回调函数print()
ros::ServiceServer service = n.advertiseService("print_string", print);
// 循环等待回调函数
ROS_INFO("Ready to print hello string.");
ros::spin();
return 0;
}
客户端
/**
* 该例程将请求print_string服务,std_srvs::SetBool
*/
#include "ros/ros.h"
#include "std_srvs/SetBool.h"
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "string_client");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个client,service消息类型是std_srvs::SetBool
ros::ServiceClient client = n.serviceClient<std_srvs::SetBool>("print_string");
// 创建std_srvs::SetBool类型的service消息
std_srvs::SetBool srv;
srv.request.data = true;
// 发布service请求,等待应答结果
if (client.call(srv))
{
ROS_INFO("Response : [%s] %s", srv.response.success?"True":"False",
srv.response.message.c_str());
}
else
{
ROS_ERROR("Failed to call service print_string");
return 1;
}
return 0;
}
修改CMakeLists.txt
add_executable(string_server src/string_server.cpp)
target_link_libraries(string_server ${catkin_LIBRARIES})
add_executable(string_client src/string_client.cpp)
target_link_libraries(string_client ${catkin_LIBRARIES})