ROS(robot operation system)主要解决了两个问题:
1,进程间通信及主机间通信
2,代码管理
这篇笔记记录ROS进程间通信的方法。
ROS解决进程间通信的方法主要有:主题,服务及动态参数。
1,主题适合于多个节点需要频繁通信的场合,例如智能小车的超声波测距节点,不断的将距离数据发送给处理单元节点。
2,服务适合于不频繁通信的场合。某个节点A向节点B提交服务申请,节点B执行回调函数,并将结果返回给节点A。实际中,我发现调用服务(即便是最简单的服务)到返回结果,在时间上是有明显的延迟的,暂时还不清楚是程序执行耗时,还是ros::spin()间歇耗时。总之,调用服务比主题通信耗费资源更多。
3,动态参数是对目标进程的内存的写操作,适合于修改目标节点的参数。
==============================1,编写自定义.msg文件=========
cd ~/catkin_ws/src
在/src目录下,执行
catkin_create_pkg study_topic std_msgs rospy roscpp
生成study_topic包
在study_topic目录下
mkdir msg
生成msg文件夹
在msg目录下,用常用的编辑器gedit,vim…都可以
vim study.msg
生成study.msg文件,并编辑
string xingming
int32 xuehao
float32 shengao
可以看到.msg文件的内容,跟c的结构体的定义很相似。我猜,等会catkin会把.msg文件编译成消息的结构体,我们使用主题通信时,也会用到这个结构体通信。
接下来,我们要编写配置文档package.xml以及cmakelists。
vim package.xml
1,打开package.xml,加上两行
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
然后打开CMakeLists.txt
vim CMakeLists.txt
2,从最顶段开始,找到
find_package(catkin REQUIRED COMPONENTS
roscpp rospy std_msg)
修改,变成这个样子
find_package(catkin REQUIRED COMPONENTS
roscpp rospy std_msg message_generation)
注意去掉#号
find_package的作用是,使用catkin_make工具时,告诉catkin_make工具编译所需要的材料。例如,我们的代码中一般都会有#include “ros/ros.h”,然而我们并不知道ros.h头文件和库文件在哪里。如果我们使用cmake编译,这当然是允许的,我们就必须指定ros.h头文件和库文件的位置。而如果我们使用catkin_make工具编译,我们只需要在find_package中指定roscpp就可以了。
3,然后找到
add_message_file(
FILES
message1.msg
message2.msg)
修改成,
add_message_file(
FILES
study.msg)
注意去掉#号
这里是添加我们自定义的消息文件。
4,然后找到
generate_messages(
DEPENDENCIES
std_msgs)
去掉#号,不修改内容。
这里是以来括号里面的材料,生成消息。
5,找到catkin_package(),这个一般不用修改,只要保证函数的括号里面没有内容就可以了。
好了,现在完成了配置自定义消息的步骤。
接下来编译和测试。
1,返回catkin_ws目录,运行
catkin_make
2,编译完成后,要设置临时的环境变量
cd devel/
source setup.sh
3,然后测试自定义消息
rosmsg show study_topic/study
如果没有问题的化,会打印
string xingming
int32 xuehao
float32 shengao
也就是study.msg文件里的内容。
=================================2,会话===========
会话需要使用消息。消息可以是系统已经定义的格式,也可以是自定义的格式。如果使用自定义的格式,就需要先完成自定义消息的生成,也就是上面的内容。接下来,我们使用上面生成的自定义消息study.msg,进行两个节点的会话。
我们需要生成两个节点,student和teacher,会话名称是report,内容是student节点每隔1秒钟发布study.msg,teacher节点订阅report会话的内容。
先编写student节点。
在study_topic/src目录下,新建student.cpp文件
vim student.cpp
编辑文件,大概是这样子
#include "study_topic/study.h"
#include "ros/ros.h"
#include <string>
int main(int argc, char **argv)
{
ros::init(argc, argv, "student");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<study_topic::study>("report", 10);
ros::Rate loop_rate(1);
int count = 0;
std::string s = "dameinv";
while (ros::ok())
{
study_topic::study msg;
msg.xingming = s;
msg.xuehao = 1105;
msg.shengao = 165.0;
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
count++;
ROS_INFO("%s",msg.xingming.c_str());
}
return 0;
}
#include "study_topic/study.h"
这一行,是包含消息study.msg的头文件。然而在study_topic目录下,并没有study.h文件,我猜这是catkin的黑魔法吧。
ros::init(argc, argv, "student");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<study_topic::study>("report", 10);
这三行,分别是1,初始化名称是student的节点。
2,设置节点的句柄(可以认为是节点对象吗)n。
3,登记一个消息格式为study_topic::study(也就是自定义的study.msg),会话名称是report的发布者pub,队列最大容量为10。
study_topic::study msg;
msg.name = s;
msg.xuehao = 1105;
msg.shengao = 165.0;
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
这7行,分别是1,声明一个study_topic::study数据结构的消息对象msg
2,3,4,是对对象msg赋值。
5是发布该消息
6在这里不起作用,因为没有回调函数
7给循环制造一个中断,避免耗尽资源
接下来,编辑teacher节点
在study_topic/src目录下,新建teacher.cpp文件
vim teacher.cpp
编辑文件,大概是这样子
#include "study_topic/study.h"
#include "ros/ros.h"
#include <string>
void messageCallback(const study_topic::study::ConstPtr& msg)
{
ROS_INFO("%s ,xuehao is %d , shengao is %f ",msg->xingming.c_str() , msg->xuehao, msg->shengao);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "teacher");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("report",10, messageCallback);
ros::spin();
return 0;
}
这里,跟student节点最大的不同是:订阅节点并没有while循环,二是使用了ros::spin()。程序运行到ros::spin()这一行后,会每隔一小段时间,检测report会话中是否有新的信息,如果有,就执行回调函数。
接下来,要编译student.cpp 和 teacher.cpp文件。
打开cmaklist文件,
cd ..
vim CMakeLists.txt
找到,并修改成这样
include_directories(include ${catkin_INCLUDE_DIRS})
在这一行下面加入
add_executable(student src/student.cpp)
add_dependencies(student study_topic_generate_messages_cpp)
target_link_libraries(student ${catkin_LIBRARIES})
和
add_executable(teacher src/teacher.cpp)
add_dependencies(teacher study_topic_generate_messages_cpp)
target_link_libraries(teacher ${catkin_LIBRARIES})
这里,add_executable()生成可执行文件,add_dependencies确保对目标文件进行链接前,其依赖文件已经构建好,target_link_libraries()将可执行文件和库文件链接。
接下来,编译和测试
cd ~/catkin_ws
catking_make
打开三个终端,分别设置环境变量
cd ~/catkin_ws/devel
source setup.sh
然后三个终端一个运行核
roscore
一个运行student,另一个运行teacher
rosrun study_topic student
rosrun study_topic teacher
可以看到,在teacher节点,不断打印
[1499225414.978935550]: dameinv ,xuehao is 1105 , shengao is 165.000000
以及在student节点,不断打印[1499225414.978454462]: dameinv