Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ROS机器人TF基础(坐标相关概念和实践)

ROS机器人TF基础(坐标相关概念和实践)

作者头像
zhangrelay
发布于 2020-09-06 12:49:46
发布于 2020-09-06 12:49:46
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

TF坐标变换基础

机器人建模和控制必须掌握坐标系和坐标变换等基础知识。机器人在空间中运动主要有两种形式:

  • 平移和旋转

也就是线速度和角速度。

坐标关系不仅包括机器人和外部环境,也包括机器人自身各部件,如本体,传感器(摄像头),控制器,执行器(电机)等。

TF概念如下图所示:

在日常生活中,如果将现实环境建立数学或物理模型必然也离不开坐标系,如下图:

常见的如GPS全局坐标,室内定位局部坐标等,在机器人领域示例如下:

教程不仅有理论介绍,还有云平台实践环境:

分别展示了两款机器人模型中的TF。

下面我们先把坐标系基本概念过一遍:

 示例演示:

  • roslaunch turtle_tf2 turtle_tf2_demo_cpp.launch

使用键盘控制控制第一个turtle,第二个跟随,如下图所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<launch>

  <!-- Turtlesim Node-->
  <node pkg="turtlesim" type="turtlesim_node" name="sim"/>

  <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
  <!-- Axes -->
  <param name="scale_linear" value="2" type="double"/>
  <param name="scale_angular" value="2" type="double"/>

  <node name="turtle1_tf2_broadcaster" pkg="turtle_tf2" type="turtle_tf2_broadcaster" respawn="false" output="screen" >
    <param name="turtle" type="string" value="turtle1" />
  </node>
  <node name="turtle2_tf2_broadcaster" pkg="turtle_tf2" type="turtle_tf2_broadcaster" respawn="false" output="screen" >
    <param name="turtle" type="string" value="turtle2" />
  </node>
  <node name="turtle_pointer" pkg="turtle_tf2" type="turtle_tf2_listener" respawn="false" output="screen" >
  </node>

</launch>

注意:由于noetic版本仅支持python3。

为了更方便的调试和查看坐标,ROS-TF2提供了大量的工具:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import rospy
import tf2_py as tf2
import yaml
import subprocess
from tf2_msgs.srv import FrameGraph
import tf2_ros

def main():
    rospy.init_node('view_frames')
    
    # listen to tf for 5 seconds
    rospy.loginfo('Listening to tf data during 5 seconds...')
    rospy.sleep(0.00001)
    buffer = tf2_ros.Buffer()
    listener = tf2_ros.TransformListener(buffer)
    rospy.sleep(5.0)

    rospy.loginfo('Generating graph in frames.pdf file...')
    rospy.wait_for_service('~tf2_frames')
    srv = rospy.ServiceProxy('~tf2_frames', FrameGraph)
    data = yaml.safe_load(srv().frame_yaml)
    with open('frames.gv', 'w') as f:
        f.write(generate_dot(data))
    subprocess.Popen('dot -Tpdf frames.gv -o frames.pdf'.split(' ')).communicate()

def generate_dot(data):
    if len(data) == 0:
        return 'digraph G { "No tf data received" }'

    dot = 'digraph G {\n'
    for el in data: 
        map = data[el]
        dot += '"'+map['parent']+'" -> "'+str(el)+'"'
        dot += '[label=" '
        dot += 'Broadcaster: '+map['broadcaster']+'\\n'
        dot += 'Average rate: '+str(map['rate'])+'\\n'
        dot += 'Buffer length: '+str(map['buffer_length'])+'\\n' 
        dot += 'Most recent transform: '+str(map['most_recent_transform'])+'\\n'
        dot += 'Oldest transform: '+str(map['oldest_transform'])+'\\n'
        dot += '"];\n'
        if not map['parent'] in data:
            root = map['parent']
    dot += 'edge [style=invis];\n'
    dot += ' subgraph cluster_legend { style=bold; color=black; label ="view_frames Result";\n'
    dot += '"Recorded at time: '+str(rospy.Time.now().to_sec())+'"[ shape=plaintext ] ;\n'
    dot += '}->"'+root+'";\n}'
    return dot


if __name__ == '__main__':
    main()

 坐标为静态关系:

坐标为动态关系:

 坐标与时间关系:

坐标与机器人关系:

这个坐标变换TF2工具的意义如上所示,但是可能会觉得不是很清楚,下面举个例子:

观察上图绿点的位置,通常我们需要机器人本体坐标,但是传感器并非安装在本体中心,而传感器获取的各类信息都是相对传感器的数据,而非机器人本体,TF2工具可以直接维护这些位置姿态坐标关系,将其转换为机器人本体坐标。

tf2常用功能包:

examples-tf2-py: 使用tf2库的Python API示例。

geometry2: 用于在ros,tf2中引入默认软件包第二代坐标变换库的元软件包。

robot-state-publisher: 状态发布后,对于使用tf2的系统中的所有组件都可用。 该包使用机器人的运动学树模型将机器人的关节角度作为输入,并发布机器人链接的3D姿势。

ros-base: 一个扩展“ ros_core”并包含其他基本功能(如tf2和urdf)的软件包。

tf2: tf2保持时间缓冲的树结构中的坐标系之间的关系,并允许用户在任意所需的时间点在任意两个坐标系之间转换点,向量等。

tf2-ros: 该软件包包含适用于Python和C ++的tf2库的ROS绑定。

其他库:tf2-bullet, tf2-eigen, tf2-geometry-msgs, tf2-kdl, tf2-msgs, tf2-py, tf2-sensor-msgs, tf2-tools。

机器人模型与TF2工具应用案例:

ROS1(noetic,melodic,kinetic,indigo):

注意:xacro,sdf等格式适合Gazebo,urdf格式适合rviz。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
rosrun xacro xacro -o model_out.urdf model_in.urdf.xacro

使用如下命令打开一个机器人模型(此处不要求掌握,后续详细介绍):

roslaunch robot1_description display.launch model:=robot1_base1.urdf

rqt-tf-tree:

rosrun tf2_tools echo.py base_link wheel_1

rosrun tf2_tools view_frames.py

ROS2(foxy,dashing):

机器人urdf模型通用!!!

ros2 launch urdf_tutorial display.launch.py model:=src/urdf/robot1_base1.urdf

下图和ros1几乎一样:

同样也能使用各类工具:

ros2 run tf2_tools view_frames.py

ROS1和ROS2几乎一致!

下一节,将通过URDF构建机器人模型,以ROS2(foxy)讲解为主!主要是ROS1相关URDF功能如何顺利移植到ROS2中!

附录(ros2 foxy):

display.launch.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import launch
from launch.substitutions import Command, LaunchConfiguration
import launch_ros
import os


def generate_launch_description():
    pkg_share = launch_ros.substitutions.FindPackageShare(package='urdf_tutorial').find('urdf_tutorial')
    default_model_path = os.path.join(pkg_share, 'urdf/01-myfirst.urdf')
    default_rviz_config_path = os.path.join(pkg_share, 'rviz/urdf.rviz')

    robot_state_publisher_node = launch_ros.actions.Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        parameters=[{'robot_description': Command(['xacro ', LaunchConfiguration('model')])}]
    )
    joint_state_publisher_node = launch_ros.actions.Node(
        package='joint_state_publisher',
        executable='joint_state_publisher',
        name='joint_state_publisher',
        condition=launch.conditions.UnlessCondition(LaunchConfiguration('gui'))
    )
    joint_state_publisher_gui_node = launch_ros.actions.Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui',
        name='joint_state_publisher_gui',
        condition=launch.conditions.IfCondition(LaunchConfiguration('gui'))
    )
    rviz_node = launch_ros.actions.Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen',
        arguments=['-d', LaunchConfiguration('rvizconfig')],
    )

    return launch.LaunchDescription([
        launch.actions.DeclareLaunchArgument(name='gui', default_value='True',
                                             description='Flag to enable joint_state_publisher_gui'),
        launch.actions.DeclareLaunchArgument(name='model', default_value=default_model_path,
                                             description='Absolute path to robot urdf file'),
        launch.actions.DeclareLaunchArgument(name='rvizconfig', default_value=default_rviz_config_path,
                                             description='Absolute path to rviz config file'),
        joint_state_publisher_node,
        joint_state_publisher_gui_node,
        robot_state_publisher_node,
        rviz_node
    ])

robot1_base1.urdf

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" ?>

<robot name="robot1_xacro" xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller" xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface" xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor">
  <link name="base_footprint">
    <visual>
      <geometry>
        <box size="0.001 0.001 0.001"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
    </visual>
    <inertial>
      <mass value="0.0001"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <gazebo reference="base_footprint">
    <material>Gazebo/Green</material>
    <turnGravityOff>false</turnGravityOff>
  </gazebo>
  <joint name="base_footprint_joint" type="fixed">
    <origin xyz="0 0 0"/>
    <parent link="base_footprint"/>
    <child link="base_link"/>
  </joint>
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.2 .3 .1"/>
      </geometry>
      <origin rpy="0 0 1.54" xyz="0 0 0.05"/>
      <material name="white">
        <color rgba="1 1 1 1"/>
      </material>
    </visual>
    <collision>
      <geometry>
        <box size="0.2 .3 0.1"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="10"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <link name="wheel_1">
    <visual>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="black">
        <color rgba="0 0 0 1"/>
      </material>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="1"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <link name="wheel_2">
    <visual>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="black"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="1"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <link name="wheel_3">
    <visual>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="black"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="1"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <link name="wheel_4">
    <visual>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="black"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.05" radius="0.05"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="1"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <joint name="base_to_wheel1" type="continuous">
    <parent link="base_link"/>
    <child link="wheel_1"/>
    <origin rpy="1.5707 0 0" xyz="0.1 0.15 0"/>
    <axis xyz="0 0 1"/>
  </joint>
  <joint name="base_to_wheel2" type="continuous">
    <axis xyz="0 0 1"/>
    <anchor xyz="0 0 0"/>
    <limit effort="100" velocity="100"/>
    <parent link="base_link"/>
    <child link="wheel_2"/>
    <origin rpy="1.5707 0 0" xyz="-0.1 0.15 0"/>
  </joint>
  <joint name="base_to_wheel3" type="continuous">
    <parent link="base_link"/>
    <axis xyz="0 0 1"/>
    <child link="wheel_3"/>
    <origin rpy="1.5707 0 0" xyz="0.1 -0.15 0"/>
  </joint>
  <joint name="base_to_wheel4" type="continuous">
    <parent link="base_link"/>
    <axis xyz="0 0 1"/>
    <child link="wheel_4"/>
    <origin rpy="1.5707 0 0" xyz="-0.1 -0.15 0"/>
  </joint>
</robot>

~Fin~


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
决策树(一)
你是否玩过20个问题的游戏? 游戏的规则很简单:参与游戏的一方在脑海里想着某个事物,其它参与者想他提问题,最多只允许提20个问题,问题的答案也只能用“对”或者“错”回答。问问题的人通过推断分解,逐步缩小猜测事物的范围。
用户6021899
2019/08/14
7240
机器学习之决策树二-C4.5原理与代码实现
本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9435712.html
用户7225427
2020/09/03
8310
机器学习之决策树二-C4.5原理与代码实现
《机器学习实战》 - 决策树
知道如何计算信息增益,我们就可以计算 每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
yiyun
2022/04/01
7720
《机器学习实战》 - 决策树
机器学习(四)—决策树
摘要:本文首先浅谈了自己对决策树的理解,进而通过Python一步步构造决策树,并通过Matplotlib更直观的绘制树形图,最后,选取相应的数据集对算法进行测试。
oYabea
2020/09/07
5070
机器学习(9)之ID3算法详解及python实现
关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第二 【Python】:排名第三 【算法】:排名第四 前言 决策树算法在机器学习中算是很经典的算法系列。它既可以作为分类算法,也可以作为回归算法,同时也特别适合集成学习比如随机森林。本文就对决策树算法ID3思想做个总结。 ID3算法的信息论基础 1970年代,一个叫昆兰的大牛找到了用信息论中的熵来度量决策树的决策选择过程,它的简洁和高效就引起了轰动,昆兰把这个算法叫做ID3。下面我们就看看ID3算法是怎么选择特征的。 首先,我们需要熟悉信
昱良
2018/04/04
1.5K0
机器学习(9)之ID3算法详解及python实现
决策树的构建、展示与决策
上一篇文章中,我们介绍了两个决策树构建算法 — ID3、C4.5: 决策树的构建 -- ID3 与 C4.5 算法 本文我们来看看如何使用这两个算法以及其他工具构建和展示我们的决策树。
用户3147702
2022/06/27
5000
决策树的构建、展示与决策
机器学习之决策树一-ID3原理与代码实现
本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9429257.html
用户7225427
2020/09/03
1.1K0
机器学习之决策树一-ID3原理与代码实现
决策树(Decision Tree)ID3算法
决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出。数据挖掘中决策树是一种经常要用到的技术,可以用于分析数据,同样也可以用来作预测。
Ai学习的老章
2019/04/08
7960
机器学习(12)之决策树总结与python实践(~附源码链接~)
关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第二 【Python】:排名第三 【算法】:排名第四 前言 在(机器学习(9)之ID3算法详解及python实现)中讲到了ID3算法,在(机器学习(11)之C4.5详解与Python实现(从解决ID3不足的视角))中论述了ID3算法的改进版C4.5算法。对于C4.5算法,也提到了它的不足,比如模型是用较为复杂的熵来度量,使用了相对较为复杂的多叉树,只能处理分类不能处理回归等。对于这些问题, CART算法大部分做了改进。由于CART算法可以
昱良
2018/04/04
4.3K0
机器学习(12)之决策树总结与python实践(~附源码链接~)
python机器学习实战(二)
http://www.cnblogs.com/fydeblog/p/7159775.html
努力努力再努力F
2018/09/11
1.4K0
python机器学习实战(二)
机器学习实战教程(三):决策树实战篇之为自己配个隐形眼镜
原文链接:https://cuijiahua.com/blog/2017/11/ml_3_decision_tree_2.html
圆方圆PYTHON学院
2019/01/03
1.7K0
机器学习实战教程(三):决策树实战篇之为自己配个隐形眼镜
机器学习之决策树三-CART原理与代码实现
本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9482885.html
用户7225427
2020/09/03
6660
机器学习之决策树三-CART原理与代码实现
【机器学习】决策树(理论与代码)
信息增益Gain(D)= 根节点信息熵(X) - 权重*分支节点信息熵和(Y)= X - Y
读书猿
2024/02/05
1800
【机器学习】决策树(理论与代码)
决策树之理解ID3算法和C4.5算法
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/53212112
用户1147447
2019/05/26
1.5K0
决策树之理解ID3算法和C4.5算法
回归树(一)
线性回归模型需要拟合全部的样本点(局部加权线性回归除外)。当数据拥有众多特征并且特征之间的关系十分复杂时,构建全局模型的想法就不切实际。一种可行的方法是将数据集切分成很多份容易建模的数据,然后再用线性回归技术来建模。如果切分后任然难以用线性模型拟合就继续切分。在这种切分方式下,递归和树结构就相当有用。
用户6021899
2019/08/14
1K0
Python机器学习从原理到实践(1):决策树分类算法
一、决策树原理 决策树是用样本的属性作为结点,用属性的取值作为分支的树结构。 决策树的根结点是所有样本中信息量最大的属性。树的中间结点是该结点为根的子树所包含的样本子集中信息量最大的属性。决策树的叶结点是样本的类别值。决策树是一种知识表示形式,它是对所有样本数据的高度概括决策树能准确地识别所有样本的类别,也能有效地识别新样本的类别。 决策树算法ID3的基本思想: 首先找出最有判别力的属性,把样例分成多个子集,每个子集又选择最有判别力的属性进行划分,一直进行到所有子集仅包含同一类型的数据为止。最后得到一棵决
机器学习AI算法工程
2018/03/13
1.4K0
Python机器学习从原理到实践(1):决策树分类算法
Python机器学习--决策树算法
一、决策树原理 决策树是用样本的属性作为结点,用属性的取值作为分支的树结构。 决策树的根结点是所有样本中信息量最大的属性。树的中间结点是该结点为根的子树所包含的样本子集中信息量最大的属性。决策树的叶结点是样本的类别值。决策树是一种知识表示形式,它是对所有样本数据的高度概括决策树能准确地识别所有样本的类别,也能有效地识别新样本的类别。 决策树算法ID3的基本思想: 首先找出最有判别力的属性,把样例分成多个子集,每个子集又选择最有判别力的属性进行划分,一直进行到所有子集仅包含同一类型的数据为止。最后得到一棵决
机器学习AI算法工程
2018/03/13
1.4K0
Python机器学习--决策树算法
机器学习 学习笔记(8) 决策树
一般的,一棵决策树包含一个根结点、若干内部结点和若干个叶结点,叶子结点对应于决策结果,而其他每个结点对应于一个属性测试,每个结点被包含的样本集合根据属性测试的结果被划分到子结点中,根结点包含样本全集。
2018/09/03
8680
机器学习 学习笔记(8) 决策树
【机器学习实战】第3章 决策树
第3章 决策树 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=
片刻
2018/01/05
1.1K0
【机器学习实战】第3章 决策树
机器学习笔记(四)——决策树的构建及可视化
本文以一个新的数据集(隐形眼镜数据集)为基础实现构建决策树、决策树的保存与加载、利用决策树分类、决策树的可视化,前文的知识不在过多概述,着重介绍这四个方面。
奶糖猫
2020/07/07
2.2K0
机器学习笔记(四)——决策树的构建及可视化
推荐阅读
相关推荐
决策树(一)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验