使用Autolabor官方入门教程,笔记内容为注意事项
首页 - Autolabor开源ROS机器人底盘 - 官方网站
_______________________________________________________
例如在生活中,我们在家里有一个放零食的箱子,而操作服务器就是这个箱子,无论是使用者还是开发者都可以共同使用他。
1.话题通信 是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息
雷达------->导航(计算)-------->底盘
在传递消息和传递运动控制指令时,就使用了话题通信,那么
雷达就是发布, 导航是订阅发布,底盘是订阅。
简单的三要素,发布 - 订阅 - 中间要素
角色----> 流程 ----> 注意
(1)角色:
1. master -----> 管理者(媒婆)
2. talker ------>发布者 (男方)
3. listner ------->订阅者 (女方)
(2)流程 :
master 可以根据话题 建立发布者和订阅者之间的连接
0. 男方提交信息 (房,手机号) ——————发布者比订阅者信息多
1. 女方提交信息 (房)
2. 媒婆把男方电话发给女方
3. 女方打电话给男方(房 连接)
4. 男方响应(加微信/给微信)
5. 女方加男方微信
(3)注意:
1.使用的协议由RPC和TCP;
2.步骤1和步骤0没有顺序关系
3.talker 和 listener可以存在多个
4.建立连接后,master就可以关闭了
5.上述流程已经封装,直接调用就好
—————————————————————————
我们要设置 发布 和 订阅方(分别进行)- (我们的实操部分只进行C++实现案例)
接下来 将从头开始一一介绍(VScode的配置请参照上面的链接进行修改,否则无法正常调试)
-----------------
(1)建立工作空间
建立 demo02_ws 工作空间
键入 code. 可以直接用vs打开工作空间
--------------------
(2)添加包 (头文件)---第一次为文件名,第二次为我们添加的包(后面服务可作修改)
-----------------------------
(3)新建一个发布者文件(写代码的位置,在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
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("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;
}
------------------------
(4)在 CmakeLists 里面修改参数 (映射名字和定义名字最好一样)
修改下面两处
(1)
然后shift+ctrl+b调试看看有没出错
-----------------------------------------
(5)启动ros核心 roscore rosrun rostopic(下面还会有具体说明)
进入工作空间的方法:
————————————————————————————————————
(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("chatter",10,doMsg);
//5.处理订阅的消息(回调函数)
// 6.设置循环调用回调函数
ros::spin();//循环读取接收的数据,并调用回调函数处理
return 0;
}
-------------------------------
(2)修改 CmakeLists
与发布者相同,对比着上面修改一下名称即可
-------------------------------
(3)启动命令行
与上面相同,同时启动3个命令行
但是这次最后一个也是rosrun启动
---------------------------------
注意事项在所给的课件里面有提到
就可以查看了
-----------------------------------------------
(1)在上面的基础上继续完成,建立一个新的文件夹和一个个人文件
(msg 与 person.msg)
内容如下:
(2)接着,进行配置 (两处)
package.xml
CmakeList
我们要配置依赖关系
接着编译一下,可以生成我们过程中需要的文件
——————————————————————————
1.前置步骤 配置vscode
在终端中打开
(2)新建一个自定义发布文件(仍然在之前建立的plu包下的src文件)
具体内容如下:
#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("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;
}
接下来的内容与上面一样,但是cmakelists里面多配置一个
添加完成后再编译一下
-----------------------
(3)运行
roscore
-------------------------------------------
对于订阅方也相同
新建一个文件,然后写内容
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();
}
Cmakelist的三个配置也一样
自定义与官方的区别在于,多了一个配置,其它的东西都是大同小异
—————————————————————————————————————
服务通信也是ROS中一种极其常用的通信模式,服务通信是基于请求响应模式的,是一种应答机制。也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。
机器人巡逻过程中,控制系统分析传感器数据发现可疑物体或人... 此时需要拍摄照片并留存
定义srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:
按照固定格式创建srv文件
编辑配置文件
编译生成中间文件
----------------------------------------------
接下来为详细操作:
(1)创建新的功能包
新建服务文件夹和文件(srv 与 Addints.srv)
package 和 Cmakelist下更改配置
--------------------------------------
在 src 目录下建立deno01_server.cpp
具体内容如下:
/*
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析
服务器实现:
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)----修改内容如下
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 节点,控制小乌龟画圆
准备工作:
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("/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;
}
修改CMakeList配置:
启动命令行运行:
-----------------------------------------------
-------准备工作-------
1. 新建launch文件(节点)
2. 启动launch节点
3. 通过命令方式获得位姿
-----------------------------
以程序方式来打印位姿
package配置
CmakeList配置
添加功能包
-----------
2.新建文件:test02_sub_pose
内容如下:
/*
订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印
准备工作:
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("/turtle1/pose",1000,doPose);
// 5.回调函数处理订阅的数据
// 6.spin
ros::spin();
return 0;
}
再次配置CMakeList
----------------------------------------
启动乌龟(启动launch文件)后,再新建命令行
cd demo02_ws/
source ./devel/setup.bash
rosrun plumbing_test test02_sub_pose