话题、服务模式的ROS程序设计
1、创建工作空间
1.1什么是工作空间
工作空间就是存放工程开发相关的文件夹
- src:代码空间
- build:编译空间
- devel:开发空间
- install:安装空间
1.2创建工作空间
创建工作空间:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
创建编译空间:
cd ~/catkin_ws/catkin_make
设置环境变量:
source devel/setup.bash
检查环境变量:
echo $ROS_PACKAGE_PATH
1.3创建功能包
创建功能包:
cd ~/catkin_ws/src
catkin_create_pkg learning_communication std_msgs rospy roscpp
编译功能包:
cd ~/catkin_ws
catkin_make
source ~/catkin__ws/devel/setup.bash
2、ROS通信编程——话题编程
以一个例题为例演示
使用 ROS 话题(Topic) 机制实现消息发布与订阅
要求:编写代码实现 ROS 中消息的发布与订阅: 创建一个发布者,每隔 100ms 依次发送斐波拉契数列的数字到话题/fibonacci 中;创建一个订阅者,订阅该话题,输出订阅结果。如,订阅者依次输出: 1 1 2 3 5 8 ··
找到我们上文中创建的工作目录,我这里创建的目录为learning_communication
1.如何自定义话题消息
·定义msg文件
#发送到话题内的数字
int32 number
在工作空间catkin_ws/src内learning_communication的功能包内创建文件夹msg,并在msg内创建文件number.msg文件,在把上面的文件内容复制进文件。
·在package.xml中添加动态生成message的功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
·在CMakeLists.txt添加编译选项
1.在findpacksge(……)结尾添加messagegeneration
2.在写有关于message内容下面添加
add_message_files(
FILES
number.msg
)
generate_messages(
DEPENDENCIES
std_msgs
)
·在catkinpackage(….)结尾添加messageruntime
·回到工作空间的根目录下编译生成相应的头文件
cd catkin_ws
catkin_make
2、创建发布者和订阅者代码实现(C++)
在工作空间catkin*_ws/src内的learning_communication功能包src内创建文件编写代码
发布者number_publisher.cpp
#include<ros/ros.h>
#include"learning_communication/number.h"
int f(int count) {
if (count == 1 || count == 2) {
return 1;
}
else {
return f(count - 2) + f(count - 1);
}
}
int main(int argc, char** argv) {
setlocale(LC_ALL,"");
//ROS节点初始化
ros::init(argc, argv, "number_publisher");
//创建节点句柄
ros::NodeHandle n;
//创建一个publisher,发布名为/fibonacci的topic,消息类型为std_msgs::Int32,队>列长度为10
ros::Publisher fibonacci_pub = n.advertise<learning_communication::number>("/fibonacci", 100);
//设置循环频率
ros::Rate loop_rate(10);
int count = 1;
while (ros::ok()) {
//初始化geometry_sgs::Twist类型消息
homework_pkg::number1 msg;
msg.number = f(count);
//发布消息
fibonacci_pub.publish(msg);
ROS_INFO("%d",msg.number);
//按循环频率延时
loop_rate.sleep();
count++;
}
return 0;
}
订阅者number_subscriber.cpp
#include<ros/ros.h>
#include"learning_communication/number.h"
void poseCallback(const learning_communication::number::ConstPtr& msg)
{
//将接受到的消息打印出来
ROS_INFO("%d", msg->number);
}
int main(int argc, char** argv)
{
//初始化ROS节点
ros::init(argc, argv, "number_subscriber");
//创建节点句柄
ros::NodeHandle n;
//创建一个Subscriber,订阅名为/fibonacci的topic,注册回调函数poseCallback
ros::Subscriber number_sub = n.subscribe("/fibonacci", 1000, poseCallback);
//循环等待回调函数
ros::spin();
return 0;
}
3.编译并运行
编译规则设置
编译前先要在功能包内的CMakeList.txt内配置编译规则
·设置需要编译的代码和生成的可执行文件
·设置链接库
add_executable(number_publisher src/number_publisher.cpp)
target_link_libraries(number_publisher ${catkin_LIBRARIES})
add_executable(number_subscriber src/number_subscriber.cpp)
target_link_libraries(number_subscriber ${catkin_LIBRARIES})
addexecutable(numberpublisher src/numberpublisher.cpp),src/numberpublisher.cpp是指的前面编写代码的文件,numberpublisher是设置src/numberpublisher.cpp编译后形成的可执行文件的名字
targetlinklibraries(numberpublisher ${catkinLIBRARIES})是将可执行文件与对应的链接库链接。
最后回到根目录进行编译
cd catkin_ws
catkin_make
开三个终端,分别执行命令
roscore
rosrun learning_communication number_publisher
rosrun learning_communication number_subscriber
出现报错:Error: package ‘learning_communication’ not found
解决方法:
每开一个终端输入下列指令,将环境变量的配置脚本(source ~/catkin_ws/devel/setup.bash)添加到终端的配置文件(.bashrc)中即可解决问题
cd ~/catkin_ws
source devel/setup.bash
最后运行结果:
终端1:
终端2:
终端3:
3、ROS通信编程——服务编程
以一个例题为例演示
使用 ROS 服务(Service)机制实现同步请求与答复
要求:编写代码实现 ROS 中的服务请求与答复: 创建服务端,注册 Service,当服务端收到客户端 Service 请求(携带整型参数 a.b) 后,服务端返回 a.b 的和给客户端,客户端输出结果。如,客户端给服务端 Service 发送参数 3,9,服务端返回 12,客户端输出: 12。
如何自定义服务数据
定义srv文件
#客户端请求时发送的两个数据
int32 num1
int32 num2
---
#服务端响应时发送的两数据
int32 sum
在工作空间catkin_ws/src内learning_communication功能包内创建文件夹srv,并在srv内创建文件number.srv文件,在把上面的文件内容复制进文件。
在package.xml中添加动态生成message的功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
在CMakeLists.txt添加编译选项
1.在findpacksge(……)结尾添加messagegeneration
2.在写有关于service内容下面添加
add_service_files(
FILES
number.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
·在catkinpackage(….)结尾添加messageruntime
·回到工作空间的根目录下编译生成相应的头文件
cd ~、catkin_ws
catkin_make
2.创建服务端和客户端代码实现(C++)
在工作空间catkin_ws/src内learning_communication功能包src内创建文件编写代码
客户端number_client.cpp
#include "ros/ros.h"
#include "learning_communication/number.h"
int main(int argc, char **argv)
{
// 初始化 ROS 节点
ros::init(argc, argv, "xiaomei");
// 创建 ROS 句柄
ros::NodeHandle n;
// 创建 客户端 对象
ros::ServiceClient client = n.serviceClient<learning_communication::number>("number");
// 提交请求并处理响应
learning_communication::number a;
//提交请求
a.request.num1 = 3;
a.request.num2 = 9;
//处理响应
bool flag = client.call(a);
if (flag)
{
ROS_INFO(" 响应成功!两个数的和为:%d", a.response.sum);
}
else
{
ROS_INFO("响应失败");
}
// ros::spin()循环等待回调函数
ros::spin();
}
服务端number_server.cpp:
#include "ros/ros.h"
#include "learning_communication/number.h"
// 回调函数:bool 返回值由于标志是否处理成功
bool Callback(learning_communication::number::Request& req,
learning_communication::number::Response& resp)
{
//1处理请求
int num1 = req.num1;
int num2 = req.num2;
ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d", num1, num2);
//2组织响应
int sum = num1 + num2;
resp.sum = sum;
ROS_INFO("两个数的和:sum = %d", sum);
return true;
}
int main(int argc, char **argv)
{
// 初始化 ROS 节点
ros::init(argc, argv, "number_Server");
// 创建 ROS 句柄
ros::NodeHandle n;
// 创建 服务 对象
ros::ServiceServer server = n.advertiseService("number", Callback);
ROS_INFO("服务启动....");
// 回调函数处理请求并产生响应
// 由于请求有多个,需要调用 ros::spin()
}
3.编译并运行
编译规则设置
编译前先要在功能包 learning_communication内的CMakeList.txt内配置编译规则
设置需要编译的代码和生成的可执行文件
设置链接库
add_executable(number_client src/number_client.cpp)
target_link_libraries(number_client ${catkin_LIBRARIES})
add_executable(number_server src/number_server.cpp)
target_link_libraries(number_server ${catkin_LIBRARIES})
addexecutable(numberclient src/numberclient.cpp),src/numberclient.cpp是指的前面编写代码的文件,numberclient是设置src/numberclient.cpp编译后形成的可执行文件的名字
targetlinklibraries(numberclient ${catkinLIBRARIES})是将可执行文件与对应的链接库链接。
回到catkin_ws工作空间根目录下编译
cd ~/catkin_ws
catkin_make
开三个终端,分别执行命令
roscore
rosrun learning_communication number_client
rosrun learning_communication number_server
出现报错:Error: package ‘learning_communication’ not found
解决方法:
每开一个终端输入下列指令,将环境变量的配置脚本(source ~/catkin_ws/devel/setup.bash)添加到终端的配置文件(.bashrc)中即可解决问题
cd ~/catkin_ws
source devel/setup.bash
终端1:
终端2:
终端3:
图片中出现乱码是因为中文的乱码,改变编码即可
4、小结
本机作业是对上课所学知识的总结,上课感觉没怎么懂,下来自己实验和验证之后发现并不是很困难而且很容易和简单的去实现。主要一开始是对工作区域那几个文件夹的目录不太了解,了解之后就发现简单了很多