zoukankan      html  css  js  c++  java
  • ros tf2使用示例

    关于ROS中使用tf/tf2获取到transformation之后的怎样处理,写一个例子作为参考:

    已知两组固定坐标系,B->A,D->C,其关系定义如代码 static_publisher.py所示

    #!/usr/bin/env python
    # static_publisher.py
    import rospy import sys import tf2_ros as tf2 import tf_conversions as tfc import geometry_msgs.msg from tf2_msgs.msg import TFMessage import math import numpy def __genTf(frameT, frameS, posTs, q): ts = geometry_msgs.msg.TransformStamped() ts.header.stamp = rospy.Time.now() ts.header.frame_id = frameT ts.child_frame_id = frameS ts.transform.translation.x = posTs[0] ts.transform.translation.y = posTs[1] ts.transform.translation.z = posTs[2] ts.transform.rotation.x = q[0] ts.transform.rotation.y = q[1] ts.transform.rotation.z = q[2] ts.transform.rotation.w = q[3] return ts def __main(): rospy.init_node("AB&CD") rate = rospy.Rate(100) tbf = tf2.Buffer() tl = tf2.TransformListener(tbf) t = TFMessage() sbc = tf2.StaticTransformBroadcaster() qA2B = tfc.transformations.quaternion_from_euler(math.pi, 0, math.pi / 2) ts1 = __genTf("A", "B", (-1, 0, 0.2), qA2B) t.transforms.append(ts1) qC2D = tfc.transformations.quaternion_from_euler(math.pi, 0, 0) ts2 = __genTf("C", "D", (0, 0, 1), qC2D) t.transforms.append(ts2) sbc.pub_tf.publish(t) rospy.spin() if __name__ == "__main__": __main()

    先假定D传感器的观测数据会发布在B坐标系下,而A是实际地图坐标系,求C物体坐标系(source frame, child frame)到A坐标系(destination frame, parent frame)的转换,代码如下:

    #!/usr/bin/env python
    # dynamic_publisher.py
    
    import rospy
    import sys
    import tf2_ros as tf2
    import tf_conversions as tfc
    import geometry_msgs.msg
    from tf2_msgs.msg import TFMessage
    import math
    import numpy
    
    def qRot(p, q):
        qInvert = tfc.transformations.quaternion_inverse
        qMultiply = tfc.transformations.quaternion_multiply
        qInv = qInvert(q)
        pNew = qMultiply(qMultiply(q, p), qInv)
        return pNew
    
    def qRotInv(p, q):
        qInvert = tfc.transformations.quaternion_inverse
        qMultiply = tfc.transformations.quaternion_multiply
        qInv = qInvert(q)
        pNew = qMultiply(qMultiply(qInv, p), q)
        return pNew
    
    
    def __genTf(frameT, frameS, posTs, q):
        ts = geometry_msgs.msg.TransformStamped()
        ts.header.stamp = rospy.Time.now()
        ts.header.frame_id = frameT
        ts.child_frame_id = frameS
        
        ts.transform.translation.x = posTs[0]
        ts.transform.translation.y = posTs[1]
        ts.transform.translation.z = posTs[2]
    
        ts.transform.rotation.x = q[0]
        ts.transform.rotation.y = q[1]
        ts.transform.rotation.z = q[2]
        ts.transform.rotation.w = q[3]
        return ts
    
    def __main():
        rospy.init_node("A2C")
        rate = rospy.Rate(1)
        tbf = tf2.Buffer()
        tl = tf2.TransformListener(tbf)
        
        a = 0
        pp = 0
        while not tbf.can_transform("C", "D", rospy.Time()) and not rospy.is_shutdown():
            print "waiting for static tf ready.{C-D}"
            rate.sleep()
            
        while not tbf.can_transform("D", "C", rospy.Time()) and not rospy.is_shutdown():
            print "waiting for static tf ready.{D-C}"
            rate.sleep()
            
        while not tbf.can_transform("A", "B", rospy.Time()) and not rospy.is_shutdown():
            print "waiting for static tf ready.{A-B}"
            rate.sleep()
            
        while not tbf.can_transform("B", "A", rospy.Time()) and not rospy.is_shutdown():
            print "waiting for static tf ready.{B-A}"
            rate.sleep()
            
        print ("all static tf ready")
                
        roundCount = 0
        rateFast = rospy.Rate(10)
        
        qInvert = tfc.transformations.quaternion_inverse
        qMultiply = tfc.transformations.quaternion_multiply
        while not rospy.is_shutdown():
            print("begin: " + str(roundCount))
            roundCount += 1
            # lookup_transform(desFrame, srcFrame, time)
            tfD2C = tbf.lookup_transform("C", "D", rospy.Time())
            tfC2D = tbf.lookup_transform("D", "C", rospy.Time())
            tfB2A = tbf.lookup_transform("A", "B", rospy.Time())
            tfA2B = tbf.lookup_transform("B", "A", rospy.Time())
            
            bc = tf2.TransformBroadcaster()
    
            tD2B = (2 * math.cos(a), 1 + 2 * math.sin(a), -1, 0)
            qD2B = tfc.transformations.quaternion_from_euler(0, 0, math.pi / 2 + a)
            
            ts = __genTf("B", "DB", tD2B, qD2B)
            bc.sendTransform(ts)
    
            # db -> da
            tfm = tfB2A
            r = tfm.transform.rotation
            ts = tfm.transform.translation
            qB2A = numpy.array([r.x, r.y, r.z, r.w])
            tB2A = numpy.array([ts.x, ts.y, ts.z, 0])
            qD2A = qMultiply(qB2A, qD2B)
            tD2A = qRot(tD2B, qB2A)  + tB2A
    
            ts = __genTf("A", "DA", tD2A, qD2A)
            bc.sendTransform(ts)
            
            # da -> ca
            tfm = tfC2D
            r = tfm.transform.rotation
            ts = tfm.transform.translation
            qC2D = numpy.array([r.x, r.y, r.z, r.w])
            tC2D = numpy.array([ts.x, ts.y, ts.z, 0])
            qC2A = qMultiply(qD2A, qC2D)
            tC2A = qRot(tC2D, qD2A) + tD2A
            ts = __genTf("A", "C", tC2A, qC2A)
            bc.sendTransform(ts)
    
            if a < math.pi * 2:
                a += 0.01
            else:
                a = 0
    
            rateFast.sleep()
    
    
    if __name__ == "__main__":
        __main() 

    上述代码首先模拟了传感器D发布自身在B上的绝对位置

    tD2B = (2 * math.cos(a), 1 + 2 * math.sin(a), -1, 0)
    qD2B = tfc.transformations.quaternion_from_euler(0, 0, math.pi / 2 + a)

    之后通过D->B,B->A得到D->A的坐标系转换,再通过C->D得到C->A的坐标系转换

    这里需要注意的是四元数乘法不遵守交换率,因此不要将转换次序弄错

    运行roscore, rviz,再运行python static_publisher.py, python dynamic_publisher.py, 在rviz选择frame A为主坐标系,之后可以看到D,DA,DB重合在一起围绕A做圆周运动

  • 相关阅读:
    MySQL 5.7 多主一从实现
    从 MySQL 全备的 SQL 文件中抽离出某张表的数据
    KUBERNETES 03:Pod 资源清单
    KUBERNETES 02:基本操作命令
    KUBERNETES 01:说明与安装
    DOCKER 08:搭建本地镜像仓库 Harbor
    DOCKER 07:docker swarm
    DOCKER 06:docker compose
    DOCKER 05:数据持久化
    DOCKER 04:容器资源限制和网络原理
  • 原文地址:https://www.cnblogs.com/astreye/p/7085375.html
Copyright © 2011-2022 走看看