使用Autolabor官方入门教程,注意事项
首页 - Autolabor开源ROS机器人底盘 - 官方网站
_______________________________________________________
比如生活中,我们家里有一个放零食的盒子,操作服务器就是这个盒子,用户和开发者都可以一起使用。
1.是ROS主题通信是基于最常用的通信模式模型,即:一个节点发布消息,另一个节点订阅消息
雷达------->导航(计算)-------->底盘
主题通信用于传递信息和运动控制指令,因此
雷达是发布的, 导航是订阅发布,底盘是订阅。
发布简单的三要素 - 订阅 - 中间要素

角色----> 流程 ----> 注意
1. master -----> 经理(媒人)
2. talker ------>发布者 (男方)
3.listner ------->订阅者 (女方)
master 根据话题 建立出版商和订阅者之间的联系
0. 男方提交信息 (房间,手机号) ——————发布者比订阅者有更多的信息
1. 女方提交信息 (房)
2. 媒人把男人的电话给女人
3. 女方打电话给男方(房间) 连接)
4. 男方响应(加微信/给微信)
5. 女方加男方微信
1.使用协议RPC和TCP;
2.步骤1和步骤0没有顺序关系
3.talker 和 listener多个可以存在
4.建立连接后,master可以关闭
5.上述流程已封装,直接调用即可
—————————————————————————
我们要设置 我们的实际操作部分只进行C 实现案例)
接下来 从头开始逐一介绍(VScode请参考上述链接修改配置,否则无法正常调试)
一 : 发布框架 发布逻辑
-----------------
建立 demo02_ws 工作空间
键入 code. 可以直接用vs打开工作空间
--------------------
---第一次是文件名,第二次是我们添加的包(后面的服务可以修改)
-----------------------------
(写代码的位置,在src在目录下新建一个cpp文件)
内容如下:
/* 需求: 实现基本主题通信,一方发布数据,另一方接收数据, 实现的关键点: 1.发送方 2.接收方 3.数据(这里是普通文本) PS: 两者需要设置相同的主题 新闻发布方: 循环发布信息:HelloWorld 后缀数字 实现流程: 1.包含头文件 2.初始化 ROS 节点:命名(唯一) 3.实例化 ROS 句柄 4.实例化 发布者 对象 5.组织发布的数据,并编写逻辑发布数据 */ // 1.包含头文件 #include "ros/ros.h" #include "std_msgs/String.h" ////普通文本类型的消息 #include <sstream> int main(int argc, char *argv[]) { //设置编码 setlocale(LC_ALL,""); //2.初始化 ROS 节点:命名(唯一) // 参数1和参数2 后期使用节点传值 // 参数3 是节点名称,是标识符,运行后需要保证,在 ROS 唯一的网络拓扑 ros::init(argc,argv,"talker"); //3.实例化 ROS 句柄 ros::NodeHandle nh;//该类封装了 ROS 一些常用功能 //4.实例化 发布者 对象 //泛型: 发布的新闻类型 //参数1: 要发布的话题 //参数2: 队列中保存最多的消息,超过此阀值时,先进先销毁(时间早先销毁) ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10); //5.组织发布的数据,并编写逻辑发布数据 ///数据(动态组织) std_msgs::String msg; // msg.data = "你好啊!!!!"; std::string msg_front = "Hello 你好!"; ///消息前缀 int count = 0; ///消息计数器 //逻辑(一秒10次) ros::Rate r(1); ///节点不死 while (ros::ok()) { //使用 stringstream 拼接字符串和编号 std::stringstream ss; ss << msg_front << count; msg.data = ss.str(); ///发布消息 pub.publish(msg); //加入调试,打印发送的信息 ROS_INFO("发送消息:%s",msg.data.c_str()); ///根据前面设定的贫困频率自动休眠 休眠时间 = 1/频率; r.sleep(); count ;///循环结束前,让 count 自增 ///暂无应用 ros::spinOnce(); } return 0; }
------------------------
映射名和定义名最好一样
(1)
(2)
然后shift+ctrl+b调试看看有没出错
-----------------------------------------
进入工作空间的方法:
————————————————————————————————————
二:订阅方
(1)新建订阅方文件(在src文件里)
具体内容:
/*
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)
消息订阅方:
订阅话题并打印接收到的消息
实现流程:
1.包含头文件
2.初始化 ROS 节点:命名(唯一)
3.实例化 ROS 句柄
4.实例化 订阅者 对象
5.处理订阅的消息(回调函数)
6.设置循环调用回调函数
*/
// 1.包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h"
void doMsg(const std_msgs::String::ConstPtr& msg_p){
ROS_INFO("我听见:%s",msg_p->data.c_str());
// ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化 ROS 节点:命名(唯一)
ros::init(argc,argv,"listener");
//3.实例化 ROS 句柄
ros::NodeHandle nh;
//4.实例化 订阅者 对象
ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
//5.处理订阅的消息(回调函数)
// 6.设置循环调用回调函数
ros::spin();//循环读取接收的数据,并调用回调函数处理
return 0;
}
-------------------------------
(2)修改 CmakeLists
与发布者相同,对比着上面修改一下名称即可
-------------------------------
(3)启动命令行
与上面相同,同时启动3个命令行
但是这次最后一个也是rosrun启动
---------------------------------
注意事项在所给的课件里面有提到
如果要使用计算图查看,就再建立一个命令行
就可以查看了
-----------------------------------------------
,建立一个新的文件夹和一个个人文件
(msg 与 person.msg)
内容如下:
我们要配置依赖关系
接着编译一下,可以生成我们过程中需要的文件
——————————————————————————
发布方:
配置vscode
在终端中打开
具体内容如下:
#include "ros/ros.h"
#include "plumbing_pub_sub/Person.h"
int main(int argc,char *aegv[])
{
setlocale(LC_ALL,"");
//1 初始化节点
ros::init(argc,argv,"banZhuRen");
//2 创建句柄
ros::NodeHandle nh;
//3 创立发布对象
ros::Pulisher pub = nh.advertise<plumbing_pub_sub::Person>("liaoTian",10);
// 4-1 创建发布数据
plumbing_pub_sub::Person person;
person.name = "张三";
person.age = 1;
person.height = 1.73;
// 4-2 创建发布频率
ros::Rate rate(1);
// 4-3 循环发布
while(ros::ok())
{
//修改被发布数据
person.age+=1;
//数据发布
pub.publish(person);
ROS_INFO("发布消为:%s,%d,%.2f",person.name.c_str(),person,age.c_str(),person.height.c_str());
//休眠
rate.sleep();
// 最好写
ros::spinOnce();
}
return 0;
}
接下来的内容与上面一样,
添加完成后再编译一下
-----------------------
-------------------------------------------
新建一个文件,然后写内容
void doPerson(const plumbing_pub_sub::Person::ConstPtr& person)
{
ROS_INFO("订阅消息为:%s,%d,%.2f",person.name.c_str(),person,age.c_str(),person.height.c_str());
}
int main(int argc.char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"jiaZhang");
ros::NodeHandle nh;
ros::Subscriber sub = nh/subscribe("liaoTian",10,doPerson);
ros::spin();
}
自定义与官方的区别在于,多了一个配置,其它的东西都是大同小异
—————————————————————————————————————
二- 服务通信
服务通信也是ROS中一种极其常用的通信模式,服务通信是基于模式的,是一种应答机制。也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。
机器人巡逻过程中,控制系统分析传感器数据发现可疑物体或人... 此时需要拍摄照片并留存
定义srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:
步骤如下:
-
按照固定格式创建srv文件
-
编辑配置文件
-
编译生成中间文件
调用svc 文件,流程如下:
- 编写服务端实现
- 编写客户端实现
- 编辑配置文件
- 编译并执行
----------------------------------------------
接下来为详细操作:
新建服务文件夹和文件()
package 和 Cmakelist下更改配置
--------------------------------------
在
/*
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析
服务器实现:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建 服务 对象
5.回调函数处理请求并产生响应
6.由于请求有多个,需要调用 ros::spin()
*/
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"
// bool 返回值由于标志是否处理成功
bool doReq(demo03_server_client::AddInts::Request& req,
demo03_server_client::AddInts::Response& resp){
int num1 = req.num1;
int num2 = req.num2;
ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);
//逻辑处理
if (num1 < 0 || num2 < 0)
{
ROS_ERROR("提交的数据异常:数据不可以为负数");
return false;
}
//如果没有异常,那么相加并将结果赋值给 resp
resp.sum = num1 + num2;
return true;
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"AddInts_Server");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建 服务 对象
ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
ROS_INFO("服务已经启动....");
// 5.回调函数处理请求并产生响应
// 6.由于请求有多个,需要调用 ros::spin()
ros::spin();
return 0;
}
接下来再第一个CMakeList里面继续修改(也就是大包的Cmake)
P137
add_excutable(demo01_server src/demo01_server.cpp)
P147
add_dependencies(demo01_server ${PROJECT_NAME}_gencpp)
p150 开始 下面注释去掉
target_link_libraries(demo01_server
${catkin_LIBRARIES})
配置完成后,打开三个命令行
roscore
cd demo03_ws/
source ./devel/setup.bash
rosrun plumbing_server_client demo01_server
就可以使用了
---------------------------------
三 - 参数服务器
参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:
- ROS Master (管理者)
- Talker (参数设置者)
- Listener (参数调用者)
ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。
(直接再虚拟机上操作)
---------------------------------------------------------------------------
实操控制乌龟运动
/*
编写 ROS 节点,控制小乌龟画圆
准备工作:
1.获取topic(已知: /turtle1/cmd_vel)
2.获取消息类型(已知: geometry_msgs/Twist)
3.运行前,注意先启动 turtlesim_node 节点
实现流程:
1.包含头文件
2.初始化 ROS 节点
3.创建发布者对象
4.循环发布运动控制消息
*/
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"control");
ros::NodeHandle nh;
// 3.创建发布者对象
ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",1000);
// 4.循环发布运动控制消息
//4-1.组织消息
geometry_msgs::Twist msg;
msg.linear.x = 1.0;
msg.linear.y = 0.0;
msg.linear.z = 0.0;
msg.angular.x = 0.0;
msg.angular.y = 0.0;
msg.angular.z = 2.0;
//4-2.设置发送频率
ros::Rate r(10);
//4-3.循环发送
while (ros::ok())
{
pub.publish(msg);
ros::spinOnce();
}
return 0;
}
-----------------------------------------------
订阅乌龟位姿(话题订阅)
-------准备工作-------
package配置
CmakeList配置
添加功能包
-----------
2.
内容如下:
/*
订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印
准备工作:
1.获取话题名称 /turtle1/pose
2.获取消息类型 turtlesim/Pose
3.运行前启动 turtlesim_node 与 turtle_teleop_key 节点
实现流程:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建订阅者对象
5.回调函数处理订阅的数据
6.spin
*/
#include "ros/ros.h"
#include "turtlesim/Pose.h"
void doPose(const turtlesim::Pose::ConstPtr& p){
ROS_INFO("乌龟位姿信息:x=%.2f,y=%.2f,theta=%.2f,lv=%.2f,av=%.2f",
p->x,p->y,p->theta,p->linear_velocity,p->angular_velocity
);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"sub_pose");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建订阅者对象
ros::Subscriber sub = nh.subscribe<turtlesim::Pose>("/turtle1/pose",1000,doPose);
// 5.回调函数处理订阅的数据
// 6.spin
ros::spin();
return 0;
}
再次配置CMakeList
----------------------------------------
cd demo02_ws/
source ./devel/setup.bash
rosrun plumbing_test test02_sub_pose