在上一篇博客里面我们创建了ros包,还新建了msg和srv现在让我们一起做点有意思的事情吧,让我们写的程序跑起来。
一 编写简单的Publisher和Subscriber
1.1 首先,进入目录新建一个src文件夹(如果没有source先source一下)
mkdir -p src
在src文件夹内新建一个文件talker.cpp
cd src
touch talker.cpp
在talker.cpp里面写入下面的内容
#include "ros/ros.h"//包括ROS中常用的公共部分的定义
#include "std_msgs/String.h"//消息包的头文件
#include "sstream"
int main(int argc,char **argv)
{
//ROS初始化 将节点命名为talker
ros::init(argc,argv,"talker");
//创建一个句柄到进程的节点,第一个表示初始化,最后一个NodeHandle会将所有的资源清除
ros::NodeHandle n;
//创建一个子类PUblish类型 叫chatter_pub 传送的信息为string类型,最多接受1000个
ros::Publisher chatter_pub=n.advertise<std_msgs::String>("chatter",1000);
//以10HZ来运行
ros::Rate loop_rate(10);
int count=0;
//当按下ctrl c时,rose::ok()会返回false
while(ros::ok())
{
//定义了一个要发布的msg
std_msgs::String msg;
//定义一个要在终端打印出来的ss
std::stringstream ss;
//给ss赋值
ss<<"hello world"<<count;
//给msg赋值,这里msg只有sting这一种类型
msg.data=ss.str();
//ROS_INFO相当于printf
ROS_INFO("%s",msg.data.c_str());
//把消息广播给任何人
chatter_pub.publish(msg);
//回调时使用
ros::spinOnce();
//在10hz以外的其他时间节点都是处于休眠状态的
loop_rate.sleep();
++count;
}
return 0;
}
1.2 编写
Subscriber 和之前一样在src中新建一个src/listener.cpp文件
touch listener.cpp
同样我们在listener.cpp里面写入下面的代码
#include "ros/ros.h"
#include "std_msgs/Sring.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::init(argc,argv,"listener");
ros::NodeHandle n;
//在接收到消息时调用chatterCallback函数
ros::Subscriber sub =n.subscribe("chatter",1000,chatterCallback);
//没有接收到消息时,一直循环
ros::spin();
return 0;
}
现在万事具备,只要编译一下就好
cd ~/robochengzi/
catkin_make
二 执行Publisher和Subscriber
好激动人心的一步到了,之前做的那么多终于要拿出来运行了
首先运行ros(这一步不成功是安装的问题,问题有很多种先百度解决)
roscore
打开新的终端
首先source一下然后运行程序
cd ~/robochengzi/
source ./devel/setup.bash
rosrun robot talker
运行成功的结果是这样的
[ INFO] [1517237329.554897985]: hello world 24
[ INFO] [1517237329.654934314]: hello world 25
[ INFO] [1517237329.754879845]: hello world 26
[ INFO] [1517237329.854875335]: hello world 27
[ INFO] [1517237329.954874894]: hello world 28
[ INFO] [1517237330.055077860]: hello world 29
[ INFO] [1517237330.154935016]: hello world 30
[ INFO] [1517237330.254920792]: hello world 31
[ INFO] [1517237330.354878216]: hello world 32
[ INFO] [1517237330.454899610]: hello world 33
[ INFO] [1517237330.554937169]: hello world 34
运行到这都没有问题,说明已经基本成功了后面一个也是一样运行
同样新打开一个终端,source一下然后运行程序就好
cd ~/robochengzi/
source ./devel/setup.bash
rosrun robot listener
运行成功的结果如下
[ INFO] [1517237548.156052887]: I heard: [hello world 2210]
[ INFO] [1517237548.255744517]: I heard: [hello world 2211]
[ INFO] [1517237548.355945225]: I heard: [hello world 2212]
[ INFO] [1517237548.455125980]: I heard: [hello world 2213]
[ INFO] [1517237548.555806475]: I heard: [hello world 2214]
[ INFO] [1517237548.655804706]: I heard: [hello world 2215]
三 编写简单的Service和Client
和上面一样我们在src文件里面新建两个文件 add_two_ints_server.cpp 和add_two_ints_client.cpp
cd src
touch add_two_ints_server.cpp
touch add_two_ints_client.cpp
分别在两个文件里面粘贴下面的代码
add_two_ints_server.cpp
#include "ros/ros.h"
//之前创建的srv文件生成的头文件
#include "beginner_tutorials/AddTwoInts.h"
//回调函数 接收srv文件中定义的请求和响应类型,并返回一个bool值
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
{
res.sum=req.a+req.b;
ROS_INFO("request:x%ld,y=%ld",(long int)req.a,(long int)req.b);
ROS_INFO("sending back respond:[%ld]",(long int)res.sum);
return true;
}
int main(int argc,char ** argv)
{
ros::init(argc,argv,"add_two_ints_server");
ros::NodeHandle n;
ros::Serviceserver service=n.advertiseService("add_two_ints",add);
ROS_INFO("Ready to add two ints.");
ros::spin();
return 0;
}
add_two_ints_client.cpp
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>
int main(int argc,char **argv)
{
ros::init(argc,argv,"add_two_ints_client");
if(argc!=3)
{
ROS_INFO("usage:add_two_ints_client X Y");
return 1;
}
ros::NodeHandle n;
//创建一个客户端 该对象用于以后的回调
ros::ServiceClient client=n.serviceClient<beginner_tutorials::AddTwoInts>
("add_two_ints");
beginner_tutorials::AddTwoInts srv;
srv.request.a=atoll(argv[1]);
srv.request.b=atoll(argv[2]);
if(client.call(srv))
{
ROS_INFO("Sum:%ld",(long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_two_ints");
return 1;
}
return 0;
}
最后,我们在Cmakelist里面加上这两个文件
在文件的最下面加上
add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)
add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)
编译一下
catkin_make
四 执行Service和Client
首先,运行roscore
roscore
然后启动两个节点
rosrun robot add_two_ints_serve
rosrun robot add_two_ints_client 2 4
这两行命令必须要在两个新的终端内执行,在每个新终端都必须加上source 命令,
source ./devel/setup.bash
最后,如果它如愿的返回答案为6的话,那么恭喜你完成了基础部分的教学。
其实,最好的教程是官网的维基,我们的博客只能算是过来人的一种经验,后续我们继续学习move_base 包,我们一起从零开始做一个小激光slam机器人出来。