前言
系统环境: Ubuntu 18.04,硬盘安装。
ROS版本: melodic
深蓝学院(古月居)胡春旭ROS理论与实践笔记整理。
1. Launch启动文件
使用一个终端,一个语句,即可实现多节点的启动和配置。使用Launch文件时不需要roscore
。
Launch启动文件的标签如下:
标签名 |
说明 |
使用范例 |
<launch> |
launch文件中的根元素采用launch 标签定义 |
<launch>...</launch> |
<node> |
启动节点 |
<node pkg="package-name" type = "executable-name"/> |
pkg |
节点所在的功能包名称 |
在node标签中,pkg="package-name" |
type |
节点的可执行文件名称 |
在node标签中,type = "executable-name" |
name |
节点运行时的名称,会替换掉ros::init 中设置好的节点名 |
在node标签中,name = "talker" |
output |
表示节点的日志是否在终端显示 |
在node标签中,output="screen" |
respawn |
节点运行失败时自动重启 |
在node标签中,respawn = "true" |
required |
修饰的节点是启动的必须项,启动失败就会报错 |
在node标签中,required = "true" |
ns |
给节点设置一个命名空间 |
<rosparam file = "params.yaml" command = "load" ns = "params/"> 前面就会多一个"params/"的命名空间。 |
args |
通过命令行给main函数传递的参数 |
|
<param> 与<rosparam> |
设置ROS系统运行中的参数,全局变量,存储在参数服务器中 |
<param name = "output_frame" value = "odom"/>
<rosparam file = "params.yaml" command = "load" ns = "params/"> |
<arg> |
launch文件内部的局部变量,仅限于launch文件使用 |
<arg name = "arg-name" default = "arg-value"/> 调用:
<param name = "foo" value = "$(arg arg-name)"/>
<node name="node" pkg = "package" type = "type" args = "$(arg arg-name)"/> |
<remap> |
重映射ROS计算图资源的命名 |
<remap from = "/turtlebot/cmd_vel" to="/cmd_vel"/> |
<include> |
包含其他launch文件,类似C语言中的头文件包含。 file:包含的其他launch文件路径 |
<include file="$(dirname)/other.launch"> |
更多标签:ROS wiki
launch文件示例与分析:
1 2 3 4 5 6 7 8
| <launch> <node pkg="learning_communication" type="person_subscriber" name="talker" /> <node pkg="learning_communication" type="person_publisher" name="listener" /> </launch>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <launch> <param name="/turtle_number" value="2"/> <arg name="TurtleName1" default="Tom" /> <arg name="TurtleName2" default="Jerry" /> <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"> <param name="turtle_name1" value="$(arg TurtleName1)"/> <param name="turtle_name2" value="$(arg TurtleName2)"/> <rosparam file="$(find learning_launch)/config/param.yaml" command="load"/> </node> <node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output="screen"/>
</launch>
|
其中的param.yaml为:
1 2 3 4 5 6 7 8
| A: 123 B: "hello"
group: C: 456 D: "hello"
|
此时调用rosparam list
,可以查看设置好的全局变量:
调用rosparam get
可以查看全局变量具体的值:
1 2 3 4 5 6 7
| <launch> <include file="$(find learning_launch)/launch/simple.launch" /> <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"> <remap from="/turtle1/cmd_vel" to="/cmd_vel"/> </node> </launch>
|
此时运行rostopic list
,就会发现,原来名为/turtle1/cmd_vel
的话题已经变成了/cmd_vel
。
$(find ...)
是用来定位到一个package,增强了项目的可移植性。若想在自己的项目中实现find,需要有CMakeLists.txt和package.xml,并对这两个文件进行编辑。参考:实现launch中的find位置
2. Modeling in Robotics基础
理解TF功能包的基础知识。
2.1 欧拉角
欧拉角的表示:先绕当前z轴旋转ϕ,再绕当前y轴旋转θ,再绕当前z轴旋转ψ。
展开:
最终化简为:
欧拉角的计算:对最后一列和最后一行元素利用正交性进行分类讨论:
情况一:若r33=±1,则θ=0有解,ϕ+θ的和为定值,存在无限多组解。
情况二:若 r332<1 ,则 θ,ϕ,θ 有解。
2.2 RPY
如果按照固定的世界坐标轴旋转,那么有两种RPY:
2.2 转轴/角度(轴角)
轴角的定义为:
给定任意一个旋转矩阵R,转角 θ 和转轴 k 可由下列式子得到:
2.2 四元数
老欧的ppt中,四元数由转轴/角度表示法定义而来,类似于欧拉角,是一种姿态的表示方式:
2.3 刚性转动
刚性变换可由齐次变换(homogeneous transformation)矩阵来表示。齐次变换矩阵是一个具有 O=[R0d1],R∈SO(3);d∈R3 形式的4×4的矩阵。具体分解可看老欧ppt:
3 TF功能包
- TF功能包能干什么?
- 五秒钟之前,机器人头部坐标系相对于全局坐标系的关系是什么样的?
- 机器人夹取的物体相对于机器人中心坐标系的位置在哪里?
- 机器人中心坐标系相对于全局坐标系的位置在哪里?
- TF坐标变换如何实现?
3.1 查看TF树
1 2 3 4
| $ sudo apt-get install ros-melodic-turtle-tf $ roslaunch turtle_tf turtle_tf_demo.launch $ rosrun turtlesim turtle_teleop_key $ rosrun tf view_frames
|
- 在home文件夹下会出现一个frames.pdf:
3.2 查看齐次变换矩阵
查看两个海龟之间的rotation matrix R 和translation matrix d 可以使用命令行工具或者可视化工具。
设海龟1相对于海龟2的齐次变换矩阵为 H12 ,则 H12=H10×H02 。
其中角标0代表世界的基础矩阵base frame。
1 2
| $ rosrun tf tf_echo turtle1 turtle2
|
结果:
1
| $ rosrun rviz rviz -d `rospack find turtle_tf` /rviz/turtle_rviz.rviz
|
3.3 如何实现一个tf广播器
- 定义TF广播器(TransformBroadcaster)
- 创建坐标变换值
- 发布坐标变换(SendTransform)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
#include <ros/ros.h> #include <tf/transform_broadcaster.h> #include <turtlesim/Pose.h>
std::string turtle_name;
void poseCallback(const turtlesim::PoseConstPtr& msg) { static tf::TransformBroadcaster br;
tf::Transform transform; transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) ); tf::Quaternion q; q.setRPY(0, 0, msg->theta); transform.setRotation(q);
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name)); }
int main(int argc, char** argv) { 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; };
|
3.4 如何实现一个tf监听器
- 定义TF监听器;(TransformListener)
- 查找坐标变换;(waitForTransform、lookupTransform)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
#include <ros/ros.h> #include <tf/transform_listener.h> #include <geometry_msgs/Twist.h> #include <turtlesim/Spawn.h>
int main(int argc, char** argv) { ros::init(argc, argv, "my_tf_listener");
ros::NodeHandle node;
ros::service::waitForService("/spawn"); ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn"); turtlesim::Spawn srv; add_turtle.call(srv);
ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel", 10);
tf::TransformListener listener;
ros::Rate rate(10.0); while (node.ok()) { tf::StampedTransform 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; }
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; };
|
3.5 配置launch文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <launch>
<node pkg="turtlesim" type="turtlesim_node" name="sim"/> <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/> <node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster" /> <node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster" /> <node pkg="learning_tf" type="turtle_tf_listener" name="listener" />
</launch>
|
4. 可视化显示与仿真工具
- 日志输出工具--
$ rqt_console
- 计算图可视化工具--
$ rqt_graph
- 数据绘图工具--
$ rqt_plot
- 图像渲染工具--
$ rqt_image_view
1 2 3 4 5 6 7 8
| $ rqt_console
$ rqt_graph
$ rqt_plot
$ rqt_image_view
|
4.1 数据可视化界面Rviz
Rviz是一款三维可视化工具,可以很好的兼容基于ROS软件框架的机器人平台。
- 在rviz中,可以使用可拓展标记语言XML对机器人、周围物体等任意实物进行尺寸、质量、位置、材质、关节等属性的描述,并且在界面中呈现出来。
- 同时,rviz还可以通过图形化的方式,实时显示机器人传感器的信息、机器人的运动状态、周围环境的变化等信息。
- 总而言之,rviz通过机器人模型参数、机器人发布的传感信息等数据,为用户进行所有可检测信息的图形化显示。用户和开发者也可以在rviz的控制界面下,通过按钮、滑动条、数值等方式,控制机器人的行为。
- 启动:
基于rviz可以自定义人机交互界面。rviz是一个数据显示平台(需要数据)。
4.2 数据仿真界面Gazebo
Gazebo是一个数据仿真平台(创造数据)。它是一个三维动态物理仿真器,能准确高效的仿真在复杂的室内外环境下机器人群体。与游戏引擎类似,Gazebo能对一整套传感器进行高度逼真的物理仿真、为程序和用户提供交互接口。它典型的应用场景包括:
- 测试机器人算法
- 机器人的设计
- 现实情境下的回溯测试
- 启动:
1 2
| $ roslaunch gazebo_ros mud_world.launch
|
- 为了保证模型加载顺利,需要提前将模型文件库下载并放置到
~/.gazebo/models
下。下载地址