ROS Indigo learning_tf-05 now() 和 Time(0)的区别 (Python版) — waitForTransform() 函数

本文深入探讨了ROS中tf库的now()与Time(0)的区别,解释了它们在坐标转换中的作用,以及如何使用waitForTransform()函数确保数据的准确性。通过实例代码,展示了在不同时间戳下获取坐标转换数据的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ROS Indigo learning_tf-05 now()Time(0)的区别 (Python版) — waitForTransform() 函数

我使用的虚拟机软件:VMware Workstation 11
使用的Ubuntu系统:Ubuntu 14.04.4 LTS
ROS 版本:ROS Indigo


一. 前言

这一节要做的事情:使用 tfnow()Time(0)的区别 。

为什么要讲这个,这是因为 ROStf 在进行坐标之间的转换变换不是实时的转换,它有一个缓冲器来存放一段时间的坐标转换数据,所以有时,可能没有当前时间的坐标转换数据,使用 lookupTransform() 函数就可以得到你想的某个时间的坐标数据,前提是缓冲区里要有这个时间的坐标数据,tf 的坐标转换是自动计算的,所以有时,你想得到当前的时间的坐标转换数据,你调用 lookupTransform() 函数去获取,但是缓冲器里还没有来得及去计算现在的坐标转换数据,就是说:现在还没有。如果你非要获取,就会出错,所以你要使用 waitForTransform() 函数来等待 tf 的坐标转换线程得到你想要的时间点的坐标转换数据。
简单的说:waitForTransform() 就是一个安全程序。

什么意思,下面编写程序,让大家深入理解:


二. 写程序


1 . 讲解

代码就是下面这个样子: learning_tf 软件包中的 nodes/turtle_tf_listener.py :
将源代码中:

    ----
    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        try: 
            (trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', rospy.Time(0))
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
            continue
    ----

修改为:

    ----
    rate = rospy.Rate(10.0)
    listener.waitForTransform("/turtle2", "/turtle1", rospy.Time(), rospy.Duration(4.0))
    while not rospy.is_shutdown():
        try: 
            now = rospy.Time.now()
                 listener.waitForTransform('/turtle2', '/turtle1', now, rospy.Duration(4.0))         
            (trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', now)
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
            continue
    ----

Q: 如果你在 try 里使用了 waitForTransform() 函数,但是在 while 外并没有 waitForTransform() ,程序就不正常运行。 为什么必须要有while外的 waitForTransform() 函数?为什么要调用 waitForTransform() 函数?

A: 在程序的开始,我们 再生/spawn 服务)了一个 turtle2 ,但是在 waitForTransform() 函数执行的时候,tf 里可能还没有 turtle2 坐标系,就是 turtle2 还没有 再生 完成。
所以,第一个 waitForTransform() 函数将会等到 turtle2 坐标系 再生 完成。
第二个 waitForTransform() 函数将会等到 now 时间的坐标系转换完成,在缓冲器中有。

waitForTransform() 函数的4个形参:

waitForTransform( [父类坐标系], [子类坐标系], [在这一时刻], rospy.Duration(4.0) )

rospy.Duration(4.0) : 为 waitForTransform() 函数 的结束条件:最多等待 4 秒,如果提前得到了坐标的转换信息,直接结束等待。


2 . 编写代码

learning_tf 程序包中的 nodes 路径下,新建一个文件:turtle_tf_listener_timeTravel.py

roscd learning_tf/node/
gedit turtle_tf_listener_timeTravel.py

下面是完整的程序。将这段程序复制到 turtle_tf_listener_timeTravel.py 文件里面:

#!/usr/bin/env python

import roslib
roslib.load_manifest('learning_tf')
import rospy
import math
import tf
import geometry_msgs.msg
import turtlesim.srv

if __name__ == '__main__':
    rospy.init_node('tf_turtle')
    listener = tf.TransformListener()

    rospy.wait_for_service('spawn')
    spawner = rospy.ServiceProxy('spawn', turtlesim.srv.Spawn)
    spawner(4, 2, 0, 'turtle2')

    turtle_vel = rospy.Publisher('turtle2/cmd_vel', geometry_msgs.msg.Twist, queue_size=1)

    rate = rospy.Rate(10.0)
    listener.waitForTransform("/turtle2", "/turtle1", rospy.Time(), rospy.Duration(4.0))
    while not rospy.is_shutdown():
        try: 
            now = rospy.Time.now()
            listener.waitForTransform('/turtle2', '/turtle1', now, rospy.Duration(4.0))         
            (trans,rot) = listener.lookupTransform('/turtle2', '/turtle1', now)
        except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
            continue

        angular = 4 * math.atan2(trans[1], trans[0])
        linear  = 0.5 * math.sqrt(trans[0] ** 2 + trans[1] ** 2)
        cmd = geometry_msgs.msg.Twist()
        cmd.linear.x = linear
        cmd.angular.z = angular
        turtle_vel.publish(cmd)
        rate.sleep()

给这个文件添加可执行权限:

chmod 777 turtle_tf_listener_timeTravel.py

3 . 编写启动文件

learning_tf 程序包中的 launch 路径下,新建一个文件:start_demo5.launch:

roscd learning_tf/launch/
gedit start_demo5.launch

将下面的代码拷贝进去。(下面这段代码就是通过 start_demo2.launch 文件改写的,基本和它一模一样)

<launch>
    <!-- Turtlesim Node -->
    <node pkg="turtlesim" type="turtlesim_node" name="sim" />
    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen" />

    <node name="turtle1_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py" respawn="false" output="screen" >
        <param name="turtle" type="string" value="turtle1" />
    </node>
    <node name="turtle2_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py" respawn="false" output="screen" >
        <param name="turtle" type="string" value="turtle2" />
    </node>

    <node pkg="learning_tf" type="turtle_tf_listener_timeTravel.py" name="listener" />

</launch>

4 . 运行

运行 start_demo5.launch 这个启动脚本文件:

$ roslaunch  learning_tf start_demo5.launch 

运行效果:看起来和之前 “ 编写一个 监听器 程序 ”这一节的运行效果一样 。

这里写图片描述

Q: 你肯定会问这样的问题: rospy.Time.now()rospy.Time(0) 有什么不同吗?运行时的效果都一样?

A: 虽然,你注意到 小海龟的行为 没有明显的变化。那是因为:实际的时间只差几毫秒的不同。但是我们为什么有时使用Time(0) ,有时使用 now()。我这里只是想告诉你:tf 缓冲和时间延迟是相关联的。在实际使用 tf 时,这2个可以认为是等同的。

  • Time(0) : 是 tf 缓存里的第一个 tf 信息。
  • now() : 是当前这个时间的 tf 信息。
<think>好的,用户想了解如何使用ROS 2创建一个Python包,具体是关于命令ros2 pkg create --build-type ament_python learning_pkg_python的说明示例。我需要根据提供的引用内容来组织回答。 首先,我得回顾用户提供的引用资料。引用1提到了创建Python包的命令,包括--dependencies参数,可能用户需要知道依赖项的作用。引用2解释了ament_python构建类型使用setup.py,这需要说明文件结构。引用34可能涉及服务实现包的用途,但用户的问题主要是创建包,所以可能重点在步骤示例上。 用户需要详细的步骤说明示例。我应该分步骤讲解命令结构、目录结构、关键文件(如setup.py、package.xml)的配置,并给出示例代码。可能还需要解释ament_python其他构建类型的区别,但用户明确提到Python包,所以可以略过其他类型。 要注意的是,用户可能想知道如何添加依赖节点,所以需要包括如何修改package.xmlsetup.py,以及创建节点的示例。同时,引用3中的服务相关代码可能可以作为扩展内容,但用户的问题主要是创建包,所以示例可能更基础。 需要确保回答符合系统指令:行内数学公式用$...$,独立公式用$$...$$,但这里可能用不上数学公式。使用中文,结构清晰,分步骤,并在最后生成相关问题。 可能的问题点:是否有必要详细解释每个文件参数的作用?比如setup.py中的entry_pointspackage.xml中的依赖声明。用户可能需要这些细节来正确配置自己的包。此外,编译运行命令也是关键步骤,需要包括进去。 最后,根据引用资料,生成相关问题,比如如何添加依赖、如何创建节点、构建类型比较等。需要确保问题相关且有依据。</think>以下是使用ROS 2创建Python包的详细说明及示例: ### 一、创建Python包的命令解析 命令格式: ```bash ros2 pkg create --build-type ament_python <package_name> ``` 以`learning_pkg_python`为例: ```bash ros2 pkg create --build-type ament_python learning_pkg_python --dependencies rclpy ``` - `--build-type ament_python`:指定使用Python构建系统[^2] - `--dependencies`:声明依赖项(如rclpy、std_msgs等) ### 二、包目录结构 生成的目录包含: ``` learning_pkg_python/ ├─ package.xml ├─ setup.py ├─ setup.cfg └─ learning_pkg_python/ └─ __init__.py ``` ### 三、关键文件配置 1. **package.xml** ```xml <exec_depend>rclpy</exec_depend> <!-- 声明运行时依赖 --> <export> <build_type>ament_python</build_type> </export> ``` 2. **setup.py** ```python from setuptools import setup setup( name='learning_pkg_python', version='0.0.0', packages=[...], install_requires=['setuptools'], zip_safe=True, entry_points={ 'console_scripts': [ 'my_node = learning_pkg_python.my_node:main' ], }, ) ``` ### 四、创建节点示例 1. 在包目录中新建`my_node.py`: ```python #!/usr/bin/env python3 import rclpy from rclpy.node import Node class MyNode(Node): def __init__(self): super().__init__('my_node') self.get_logger().info('节点已启动!') def main(args=None): rclpy.init(args=args) node = MyNode() rclpy.spin(node) rclpy.shutdown() if __name__ == '__main__': main() ``` ### 五、编译与运行 ```bash colcon build --packages-select learning_pkg_python source install/setup.bash ros2 run learning_pkg_python my_node ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值