第二章作业

第一题 练习ROS Tutorials教程

如图1.1所示,熟悉了tutorials中所使用的基本命令。

机械臂编程python_机器学习


图1.11.1 使用catkin_make

在一个工作空间下:catkin_make

catkin_make install(可选,与devel功能类似)

编译完成后使用ls命令即可看到build、devel、src文件,如图1.2,工作空间结构如图1.3。

机械臂编程python_回调函数_02


图1.2

机械臂编程python_linux_03


图1.31.2 总结

ROS开发大致分为四个步骤:

1)创作工作空间:catkin_init_workspace

2)编译工作空间:cd~catkin_ws、catkin_make

3)设置环境变量:vim .bash.rc 在里面添加:

source home/机械臂编程python_回调函数_04echo $ROS_PACKAGE_PATH

/home/amov/catkin_ws/src:/opt/ros/melodic/share

这就是我的设置工作空间的环境变量,也可以有效的进行二次开发(即将ROS自带的功能包部分功能替换成自己想要实现的功能),因为ROS在找的时候优先找排在前面的功能包。

机械臂编程python_机械臂编程python_05


图1.4 ROS开发流程图

创建功能包

catkin_creat_pkg <package_name> [depend1]…[dependn]

注意:同一个工作空间下,不允许存在同名功能包;不同的工作空间下,允许存在同名的功能包。

第二题 建立工作空间,并编译本讲代码

如图2.1所示。

机械臂编程python_回调函数_06

图2.1 编译完成

第三题 运行本讲代码中的话题、服务、动作、TF例程

3.1 话题

打开终端运行master,在运行rosrun learning_communication listener与rosrun learning_communication talker这两个节点。效果如图3.1所示。

机械臂编程python_机械臂编程python_07


图3.1 运行topic效果

3.2服务

打开终端运行master,在运行rosrun learning_communication client与rosrun learning_communication server这两个节点。效果如图3.2所示。

机械臂编程python_回调函数_08


图3.2 运行service效果

3.3 动作

打开终端运行master,在运行rosrun learning_communication DoDishes_client与rosrun learning_communication DoDishes_server这两个节点。效果如图3.3所示。

机械臂编程python_回调函数_09

图3.3 运行action效果

3.4 TF例程

打开终端运行master,在运行:

roslaunch learning_tf start_demo_with_listener.launch这个launch文件。效果如图3.4所示。

机械臂编程python_linux_10

图3.4 运行TF例程效果

第四题 熟悉代码实现原理

4.1 Publisher节点的实现

机械臂编程python_linux_11

图4.1 Publisher节点的实现

下面逐行剖析以上代码中Publisher几点的实现过程。

4.1.1 头文件部分

#include “ros/ros.h”

#include “std_msgs/String.h”

为了避免包含繁杂的ROS功能包头文件,ros/ros.h已经帮我们包含了大部分ROS中通用的头文件。节点会发布String类型的消息,所以需要先包含该消息类型的头文件String.h。该头文件根据String.msg的消息结构定义自动生成,我们也可以自定义消息结构,并生成所需要的头文件。

4.1.2 初始化部分

ros::init(argc, argv, “talker”);

初始化ROS节点。该初始化的init函数包含三个参数,前两个参数是命令行或launch文件的输入参数,可以用来完成命名重映射等功能;第三个参数定义了Publisher节点的名称,而且该名称在运行的ROS中必须是独一无二的,不允许同时存在相同名称的两个节点。

ros::NodeHandle n;

创建一个节点句柄,方便对节点资源的使用和管理。

ros::Publisher chatter_pub = n.advertise<std_msgs::String>(“chatter”, 1000);

在ROS Master端注册一个Publisher,并告诉Publisher节点将会发布以chatter为话题名的String类型的消息。第二个参数表示消息发布队列的大小。

ros::Rate loop_rate(10);

设置循环频率,单位是Hz,这里设置的是10 Hz。当调用Rate::sleep()时,ROS节点会根据此处设置的频率休眠相应的时间,以保证循环维持一致的时间周期。

4.1.3 循环部分

int count = 0;

while (ros::ok())

进入节点的主循环,在节点未发生异常的情况将一直再循环中进行,一旦发生异常,ros::ok()就会返回false,跳出循环。

这里的异常情况主要包括:

(1)收到SIGING信号(Ctrl+C);

(2)被另外一个相同名称的节点提掉线;

(3)节点调用了关闭函数ros::shutdown();

(4)所有的ros::NodeHandles句柄被销毁。

std_msgs::String msg;

std::stringstream ss;

ss << “hello world " << count;

msg.data = ss.str();

初始化即将发布的消息。ROS中定义了很多通用的消息类型,这里我们使用了最为简单的String消息类型,该消息类型只有一个成员,即date,用来存储字符串数据。

chatter_pub.publish(msg);

发布封装完毕的消息msg。消息发布后,Master会查找订阅该话题的节点,并且帮助两个节点建立连接,完成消息的传输。

ROS_INFO(”%s", msg.data.c_str());

ROS_INFO类似于C/C++中的print/cout函数,用来打印日志信息。这里我们将发布的数据在本地打印,以确保发出的数据符合要求。

ros::spinOnce();

ros::spinOnce是用来处理节点订阅话题的所有回调函数。

注意:虽然目前的发布节点并没有订阅任何消息,spinOnce函数不是必须的,但是为了保证功能无误,建议所有的节点都默认加入该函数。

loop_rate.sleep();

现在Publisher一个周期的工作已经完成,可以让节点休息一段时间了,调用休眠函数,节点进入休眠状态。当然,节点不可能一直休眠下去,别忘了之前设置了10HZ的休眠时间,节点休眠100ms以后又会开始下一个周期的循环工作。

上面就是实现一个Publisher的所有流程,下面再来总结这个流程:

(1)初始化ROS节点

(2)向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型

(3)定义消息内容

(4)按照一定频率循环发布消息

4.2 Subscriber节点的实现

机械臂编程python_机械臂编程python_12


图4.2 Subscriber节点的实现

下面剖析以上代码中Subscriber节点的实现过程。

4.2.1 回调函数部分

void chatterCallback(const std_msgs::String::ConstPtr& msg)
 {
 // 将接收到的消息打印出来
 ROS_INFO(“I heard: [%s]”, msg->data.c_str());
 }

回调函数是订阅节点接收消息的基础机制,当有消息到达时会自动以消息指针作为参数,再调用回调函数,完成对消息内容的处理。如上是一个简单的回调函数,用来接收Publisher发布的String消息,并将数据打印出来。

4.2.2 主函数部分

主函数中ROS节点初始化部分的代码与Publisher的相同,不再赘述。

ros::Subscriber sub = n.subscribe(“chatter”, 1000, chatterCallback);

订阅节点首先需要声明自己订阅的消息话题,该消息信息会在ROS Master中注册,以便帮助话题名称相同的发布者与订阅者两节点建立连接,完成数据传输。ros::NodeHandle.subscribe()用来创建一个Subscriber。第一个参数是消息话题;第二个参数是接收消息队列的大小;第三个参数是接收到话题消息后的回调函数。

ros::spin();

接着,节点将进入循环状态,当有消息到达时,会尽快调用函数完成的处理。ros::spin()在ros::ok()返回false时退出。

以上就是订阅节点的实现,下面总结实现Subscriber的简要流程。

(1)初始化ROS节点

(2)订阅所需要的话题

(3)循环等待话题消息,接收到消息后进入回调函数

(4)在回调函数中完成消息的处理