ROS(一)主题

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

猜你喜欢

转载自blog.csdn.net/qq_32231743/article/details/74281226