一、节点与节点管理器
1.节点:
(1)是执行单元,每个节点在机器人系统中完成某些功能相当于系统中某个具体进程,例如windows中exe文件,例如图像识别等,节点间可以完成通讯。(2)不同节点可使用不同编程语言,可分布式运行在不同主机。(3)节点在系统中的名称必须唯一。
2.节点管理器(ros master):
(1) 相当于控制中心,ros里面所有节点的管理者,是控制中心。为节点提供命名和注册服务。(2)跟踪和话题记录,服务通信,辅助节点相互查找,建立连接。(3)提供参数服务器,理解为全局字典,节点使用此服务器储存和检索运行时的参数。
二、话题通信(节点之间的两种核心通信方式)
1.Topic话题通信
(1)单向,重复传递信息,节点之间用来传递数据的重要总线。(2)使用发布/订阅模型,数据由发布者传到订阅者,同一话题的发布者和订阅者可以不唯一。
message消息
(1)通道中传输的图像数据或者命令,指令数据等都有自己的数据结构定义,这种定义成为消息.它具有一定的类型和数据结构,包括ros提供的标准类型和用户自定义类型,比如图像RGB是几位的这种具体信息。详细的定义称为消息,图像数据这个数据管道称为话题(2)使用编程语言无关的.msg文件定义,编译过程中生成对应的代码文件。也可自己创建接口.msg。
(1)双向传输,来往一次,带有反馈机制,处理完成,或接收完成会返回一个response。使用客户端/服务器模型,客户端发送请求数据,服务器完成处理后返回应答数据。(2)可自定义服务内容(request,response数据结构),使用编程语言无关的.srv文件定义请求和应答数据结构,编译过程中生成对应的代码文件。
话题与服务区别
三、参数
rosmaster里面有参数服务器,会保存参数作为全局 共享字典,所有节点可以通过网络访问这些共享字典,字典里的数据类型也可多变,int,char...
Talker设置setParam一个参数名叫foo,参数值为1。Listener访问master,通过getParam获取foo的参数值。底层机制为RPC调用,且并不适合存储动态发生变化的数据。
四、文件系统
主要涉及ros代码开发的管理。(1)代码一般放在功能包下管理,功能包一般具体完成某项功能,例如图像识别等。(2)针对一系列同等目标的一些功能包组成的一个更大的功能包叫做元功能包,例如同时包含驱动,图像识别,等围绕图像处理的一个大工程。(3)功能包清单描述功能包的具体内容:作者信息,功能包依赖等。
一、ros命令行工具
1.常用命令
例如:剖析仿真器节点背后蕴含的ros机制
(1)roscore用于启动ROS Master,同时ROS Master是所有节点的管理器,运行ros时必须运行的指令。(2)rosrun命令用于运行某个功能包里面的某个节点的命令,语法 rosrun 功能包名 节点,(双击tap键可以自动列出功能包里面的所有节点)。(3)再运行第三个节点,其中turtle_teleop_key表示运行键盘控制节点。
命令行工具介绍:
1.rqt_graph:用来显示系统计的工具(rqt是基于qt的可视化工具),这里turtlesim是仿真器
节点,teleop_turtle键盘控制节点。其中turtle1/cmd_vel是节点间的话题,用来做通信,话题里面的具体数据内容就是指令的内容。
2.rosnode:用于显示系统中所有节点相关信息的指令。直接打rosnode会提示可接哪些功能。
(1)rosnode list:把系统中所有节点都列出来的指令。
/rosout是只要启动roscore就会默认启动的话题,用来接收信息在屏幕上显示。
(2)rosnode info /节点名:查看某一个节点的具体信息
3.rostopic:后可接很多命令,直接rostpic可回车查看
rostopic list:打印当前系统的所有话题列表
rostopic pub /话题名/话题内容...(双击tap键自动补全):
Twist是发布的指令的数据内容,消息结构(linear是线速度,angular是角速度rad/s)
,pub后加参数 -r 10 表示循环继续执行,每秒发布10次。z轴是指旋转。
4.rosmsg(查看各种命令同理):
rosmsg show /消息名 :查看当前发布具体消息(Twist)的结构
5.rosservice(服务相关的命令行指令)
可以用rosservice call /spawn... 创建新海龟,因为使用的service,所以创建成功后有反馈信息
6.rosbag: 其中rosbag record记录当前系统的所有话题数据并保存下来,然后下次使用可以复现。
7. pwd功能:查看当前的路径。
一、工作空间
1. 相当于ros里面的工程文件,主要分为四个文件夹。src(代码空间):用来存放功能包的代码,配置文件,以及launch文件都是存放在src代码空间中。build(编译空间):,存放编译过程中产生的中间文件,基本上不用关心这个文件夹。devel(开发空间):会放置编译生成的可执行文件和库,脚本等,编译的文件都会在这里运行。install(安装空间):用install指令安装的结果是放在该空间里面的。
2.创建工作空间。
(1)catkin_init_workspace 把当前文件夹变成一个ROS工作空间的属性。
(2)在ros工作空间进行编译时,要回到工作空间的根目录,也就是catkin_ws,catkin_make会进行文件编译
3.创建功能包:
pkg 功能包名字
一、参数模型
1.rosmaster中有一个全局服务器,例如Parameter Server,它是一个全局字典,用来保存各个节点的配置参数(保存的高度等参数,各个节点可以访问),虽然各个node节点可能不位于不同电脑中,但只要在同一个ros环境中,就可以访问,查询参数,因此可将Parameter Serve理解为全局变量的存储空间,也就是参数服务器的模型。
二、参数服务器的使用方法
1.创建功能包
2.参数命令行使用
用小海龟举例,查看rosparam的使用方式。在ros里面,如果参数比较多的话,会使用YAML参数文件,把所有的参数都列出来,一次性加载到ros的parameter server里面。
通过终端查看
比如看海龟历程里面有多少个参数:用rosparam list
得到某个参数的值:rosparam get /参数名(有路径要写上完整路径)
/rosversion查看版本号
修改某个变量的值:rosparam set /完整参数名 修改的值
改变了背景颜色设置,再通过:rosservice call /clear "{}",相当于service服务发送一个空请求。发送请求后,仿真器就会查询rgb值,然后会根据新的值刷新背景颜色。
用rosparam把参数保存成一个文件,保存至默认的主文件路径:rosparam dump 文件名(要标明保存的格式)
补充:还可以通过修改保存的文件里面得参数,进行修改。
若要更新数据,更换背景颜色,则需使用另外一个命令:rosparam load 文件名 (路径不能忘)
表示从该文件读取数据。
再用相同的 rosservice call /clear "{}" 命令,刷新背景颜色。
删除某个参数:rosparam delete /参数名
可见/turtlesim/background_g被删除,刷新后变成绿色背景
3.命令行操作在程序中得实现。
通过c++程序实现:
/**
* 该例程设置/读取海龟例程中
**/
#include
#include
#include
#include
int main(int argc, char **argv)
{
int red,green,blue;
//ROS节点初始化
ros::init(argc,argv,"parameter_config");
//创建节点句柄
ros::NodeHandle node;
//读取背景颜色参数
ros::param::get("/turtlesim/background_r",red);
ros::param::get("/turtlesim/background_g",green);
ros::param::get("/turtlesim/background_b",blue);
ROS_INFO("Get Background Color[%d, %d, %d]",red ,green ,blue);
//设置颜色背景参数
ros::param::set("/turtlesim/background_r",255);
ros::param::set("/turtlesim/background_g",255);
ros::param::set("/turtlesim/background_b",255);
ROS_INFO("Set Background Color[255,255, 255]");
//读取颜色背景参数,刷新背景颜色
ros::param::get("/turtlesim/background_r",red);
ros::param::get("/turtlesim/background_g",green);
ros::param::get("/turtlesim/background_b",blue);
ROS_INFO("Get Background Color[%d, %d, %d]",red ,green ,blue);
//调用服务,刷新背景颜色
ros::service::waitForService("/clean");
ros::serviceClient clear_background = node.serviceClient("/clean");
std_srvs::Empty srv;
clear_background.call(srv);
sleep(1);
return 0;
}
python不再赘述。
一、机器人中的坐标变换
1.用一个4*4的矩阵来描述机器人的平移和旋转
2.使用TF功能包来管理坐标系,TF功能包作用:
(1)有时间属性,默认会记录10秒钟之内机器人所有坐标系之间的位置关系。(10秒范围内都可查询)
(2)位置关系,机器人要抓取某物体,该物体相对于机器人终端的坐标系相对于机器人底盘坐标系的位置关系
TF功能包实现:广播和监听机制。启动roscore和TF后就会产生和TFtree,所有坐标系通过树型结构保存在TF树中。任意一个节点想查询两个坐标系之间的关系的话,可通过树查询得到。
举例:
1.直接描述坐标系间的结果,省去了人为计算。
2.海龟案例
一只海龟一直往前走,可以控制另一个在中心的海龟运动,另一只海龟会自动地跟随我们控制的海龟同步运动。
(1)安装turtle-tf事例的功能包
sudo apt-get install ros-"ROS对应版本"(本文是melodic)-turtle-tf
(2)启动launch文件,可以把launch文件理解为一个脚本,可以一次性启动很多节点。
roslaunch turtle_tf turtle_tf_demo.launch
(3)新建一个终端,运行海龟的键盘控制节点
rosrun turtlesim turtle_teleop_key
工具1:查看当前ros环境下的tf是什么样的,通过view_frames工具查看。新建终端,可直接可视化查看到整个系统中所有TF直接的关系。
rosrun tf view_frames
监听5秒左右,保存5秒内所有坐标系之间的关系。
产生了一个frames.pdf文件,默认放在终端的当前路径下(这里是主文件夹中)
打开后:当前系统中TF坐标之间的位置关系。两只海龟仿生器中有三个坐标系
world是全局坐标系,表示的是整个仿生器的坐标原点也就是海龟运动图上的坐标零点。
turtle1和turtle2是分别位于两只海龟上的坐标系。这两个坐标系相对于world是运动的,且turtle一直靠向turtle2,最后希望turtle1和turtle2基本上重叠
这个方法可看TF间是否联通,用于运动,导航等。
工具2:tf_echo工具(命令行工具):可以帮我们查询树当中任意两个坐标系之间的位置关系
查看turtle1和turtle2间的关系:
rosrun tf tf_echo turtle1 turtle2
Translation表示在x,y,z坐标系中的平移,表示可以通过怎样的平移互相转换
Rotation表示旋转,左边系间可以通过怎样的旋转变成一样的姿态,Rotation中三行数据内容是等价的,只是通过三种不同的方式。(1)Quaternion:表示四元数的方式来描述姿态。(2)RPY(弧度):分别围绕X轴,Y轴,Z轴旋转,通过弧度单位来描述。(3)RPY(角度):通过三个坐标系的角度旋转角度来描述。
工具三:rviz(可视化工具):看到两个坐标系间的可视化关系
rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.rviz
把Fixed Frame改成world。然后点击add添加TF,用于显示TF位置关系。
再控制键盘使海龟运动,因此坐标系发生变化。将海龟之间的距离相当于用向量表示,turtle2沿着向量向turtle1移动,前面的信息利用起来(tf_echo所得),得到距离,再设定时间得海龟速度,等等原理使得海龟运动的可视化。
底层原理,turtle2和turtle1间的关系,可以通过两者相对于world关系得到,也就是4*4的矩阵。
一、创建功能包:会讲到背后的原理,以及写代码来实现功能,因此要先创建功能包
二、在程序中实现tf广播
通过tf来广播任意两个坐标系之间的位置关系,就称之为tf广播器
1.c++代码
broadcaster创建:
/**
* 该例程产生tf数据,并计算、发布turtle2的速度指令
*/
#include
#include
#include //监听海龟实时位置
std::string turtle_name;
void poseCallback(const turtlesim::PoseConstPtr& msg)
{
//创建tf的广播器
static tf::TransformBroadcaster br;
//初始化tf数据
tf::Transform transform;
Transform.setOrigin(tf::Vector3(msg->x,msg->y,0.0)); //设置平移参数
tf::Quaternion q; //通过四元数设置旋转参数
q.setRPY(0,0,msg->theta);
transform.setRoation(q); //此时transform保存了平移和旋转的位置关系
//广播world与海龟坐标之间的tf数据
//把信息传入TF树中 br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),"world",turtle_name));//发布数据
}
int main(int argc, char** argv) //通过输入参数来确定是执行turtle1还是turtle2
{
//初始化ROS节点
ros::init(argc,argv,"my_tf_broadcaster");
//输入参数作为海龟的名字
if (argc !=2)
{
ROS_ERROR("need turtle name as argument");
return -1;
}
turtle_name =argv[1];
//订阅海龟的位姿话题
ros::NodeHandle node;
ros::Subscriber sub = node.subscribe(turtle_name+"/pose",10,&poseCallback); //话题订阅者,订阅发布的海龟位置消息
//循环等待回调函数
ros::spin();
return 0;
};
2.从TF树当中获取任意两个坐标系间的位置关系,通过一下程序实现
监听器c++
/**
*该例程监听tf数据,并计算、发布turtle2的速度指令
*/
#include
#include
#include
#include
int main(int argc, char** argv)
{
//初始化ROS节点
ros::init(argc,argv,"my_tf_listener");
//创建节点句柄
ros::NodeHandle node;
//请求产生turtle2
ros::service::waitForService("/spawn");
ros::ServiceClient add_turtle = node.serviceClient("/spawn");
turtlesim::Spawn srv;
add_turtle.call(srv);
//创建发布turtle2速度控制指令的发布者
ros::Publisher turtle_vel = node.advertise("/turtle2/cmd_vel",10);
//创建tf的监视器
tf::TransformListener listener;
ros::Rate rate(10.0);//设置while循环的频率
while(node.ok())
{
//获取turtle1与turtle2坐标之间的tf数据
tf::StampedTransform transform; //transform用于保存旋转和平移关系
try
{
listener.waitForTransform("/turtle2","/turtle1",ros::Time(0),ros::Duration(3,0));
listener.lookupTransform("/turtle2","turtle1",ros::Time(0),transform);
}
catch(tf::TransformException &ex)
{
ROS_ERROR("%s",ex.what());
ros::Duration(1,0).sleep();
continue;
}
//根据turtke1和turtle2坐标系之间的位置关系,发布turtle2的速度控制指令
//对向量进行运算,再乘以时间系数得线速度,角速度等。
geometry_msgs::Twist vel_msg;
vel_msg.angular.z = 4.0*atan2(transform.getOrigin().y(),
transform.getOrigin().x());
vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(),2)+
pow(transform.getOrigin().y(),2));
turtle_vel.publish(vel_msg);
rate.sleep();
}
return 0;
};
可以通过创建的listener监听tf里面任意两个坐标系的位置关系
waitForTransform是等待变换,lookupTransform是查询变换。先等待turtle1和turtle2是否存在,如果存在就跳到lookupTransform
配置文件后进行进行编译:
没有直接roslaunch,而是多个节点运行
broadcaster用于创建,listener用于监听查询
__name:=相当于重映射名字
learning_tf下的可执行文件broadcaster进行了重命名(给节点改名),坐标系名字叫turtle1。然后会产生turtle1和world之间的关系
注意:需要新开两个终端运行,并且要提前catkin_make和配置刷新环境变量
rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
下一步:创建海龟2,并且把turtle2的速度指令不断发布出去,让它跟着turtle1运动:
同理,新开终端,也要catkin_make等一系列操作。
rosrun learning_tf turtle_tf_listener
再运行键盘控制节点
rosrun turtlesim turtle_teleop_key
一、
1.Launch文件:通过XML文件实现多节点的配置和启动。因此不用打开很多个终端。
每一个node都可以看作一个节点,且launch文件还可以自动启动rosmaster(不用再输入roscore了)
2.launch文件语法
(1)每一个launch文件都有根标签
(2)name:表示节点运行起来之后的名字,name会替代type,防止运行两个相同功能包节点重名的情况。
output:控制某个节点是不是要把它的信息打印到当前终端里面。
respawn:控制某个节点如果启动运行失败后进行重启。
require:表示我的launch文件中的某个节点是不是一定要启动起来。
ns:表示namespace,可以给每个节点做命名空间,防止冲突。
args:表示可以通过一些指令,给节点输入参数使用。
(3)
param:用来加载参数,这里是保存某一个参数。rosparam可以把一个参数文件中所有参数都保存到ros服务器中。
arg:表示在launch文件内部使用的一些局部变量,仅限于某个launch文件内,也可给node作为输入参数。对于它的调用,使用$(arg arg-name),最后的args=$(arg arg-name),表示作为参数输入
remap:重映射,把ROS中某些计算图资源重新命名
include:嵌套,通过Include互相包含,比如其他launch文件
(4)例子
output="screen"表示在终端显示
roslaunch命令专门用于启动launch文件,语法是 roslaunch 功能包名 功能包里的launch文件名
知识补充:
1.什么是CMakeLists.txt
在ROS中,`CMakeLists.txt` 文件是用来构建和编译ROS软件包的构建系统描述文件。它是基于CMake构建系统的配置文件,用于指导构建过程。
具体来说,`CMakeLists.txt` 文件定义了ROS软件包的编译选项、依赖项、链接库、可执行文件、节点、消息、服务等内容。它告诉CMake如何构建ROS软件包,包括需要编译的源代码文件、链接的库、生成的可执行文件等信息。
`CMakeLists.txt` 文件通常位于ROS软件包的根目录下,每个ROS软件包都需要一个对应的 `CMakeLists.txt` 文件。在构建过程中,ROS使用CMake来读取和解析 `CMakeLists.txt` 文件,并生成构建所需的Makefile。
通过修改 `CMakeLists.txt` 文件,可以指定ROS软件包的构建配置,例如添加新的源文件、链接外部库、定义节点、编译消息和服务等。在执行 `catkin_make` 或 `catkin build` 等构建命令时,ROS构建系统会根据 `CMakeLists.txt` 文件中的配置信息生成对应的构建规则和目标。
因此,`CMakeLists.txt` 文件在ROS中起着关键的作用,它是构建和编译ROS软件包的核心配置文件。