tf2介绍
安装依赖
sudo apt-get install ros-foxy-turtle-tf2-py ros-foxy-tf2-tools
transforms3d(它提供四元数和欧拉角转换功能)
pip3 install transforms3d
运行结果
启动turtle_tf2_demo.launch.py文件
ros2 launch turtle_tf2_py turtle_tf2_demo.launch.py
键盘控制turtlesim
ros2 run turtlesim turtle_teleop_key
使用键盘控制乌龟,可以看到一只乌龟会跟随另一只乌龟。
使用view_frames
ros2 run tf2_tools view_frames
生成的文件
frames.pdf
使用tf2_echo(报告通过 ROS 广播的任意两帧之间的转换)
ros2 run tf2_ros tf2_echo [reference_frame] [target_frame]
turtle2框架相对于turtle1框架的变换
ros2 run tf2_ros tf2_echo turtle2 turtle1
可以在终端显示turtle2框架相对于turtle1框架的变换
tf2广播器(broadcaster)
先决条件
创建工作区间和功能包
创建一个turtle_tf2_broadcaster.py文件
from geometry_msgs.msg import TransformStamped
import rclpy
from rclpy.node import Node
from tf2_ros import TransformBroadcaster
import tf_transformations
from turtlesim.msg import Pose
class FramePublisher(Node):
def __init__(self):
super().__init__('turtle_tf2_frame_publisher')
self.declare_parameter('turtlename', 'turtle')
self.turtlename = self.get_parameter(
'turtlename').get_parameter_value().string_value
self.br = TransformBroadcaster(self)
self.subscription = self.create_subscription(
Pose,
f'/{self.turtlename}/pose',
self.handle_turtle_pose,
1)
self.subscription
def handle_turtle_pose(self, msg):
t = TransformStamped()
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = 'world'
t.child_frame_id = self.turtlename
t.transform.translation.x = msg.x
t.transform.translation.y = msg.y
t.transform.translation.z = 0.0
q = tf_transformations.quaternion_from_euler(0, 0, msg.theta)
t.transform.rotation.x = q[0]
t.transform.rotation.y = q[1]
t.transform.rotation.z = q[2]
t.transform.rotation.w = q[3]
self.br.sendTransform(t)
def main():
rclpy.init()
node = FramePublisher()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
rclpy.shutdown()
创建一个turtle_tf2_broadcaster.launch.py文件
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
name='sim'
),
Node(
package='py_package',
executable='turtle_tf2_broadcaster',
name='broadcaster1',
parameters=[
{'turtlename': 'turtle1'}
]
),
])
添加依赖
修改setup.py文件
'console_scripts': [
'turtle_tf2_broadcaster = py_package.turtle_tf2_broadcaster:main',
],
data_files=[
...
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
],
修改package.xml文件
<exec_depend>launch</exec_depend>
<exec_depend>launch_ros</exec_depend>
编译
colcon build
. install/setup.bash
运行结果
运行turtle_tf2_broadcaster.launch.py文件
(同时启动turtlesim节点和turtle_tf2_broadcaster节点)
ros2 launch learning_tf2_py turtle_tf2_broadcaster.launch.py
键盘控制turtlesim
ros2 run turtlesim turtle_teleop_key
使用tf2_echo工具检测海龟位姿是否广播到tf2
ros2 run tf2_ros tf2_echo world turtle1
可以在终端显示world框架相对于turtle1框架的变换
tf2侦听器(listener)
创建turtle_tf2_listener.py文件
import math
from geometry_msgs.msg import Twist
import rclpy
from rclpy.node import Node
from tf2_ros import TransformException
from tf2_ros.buffer import Buffer
from tf2_ros.transform_listener import TransformListener
from turtlesim.srv import Spawn
class FrameListener(Node):
def __init__(self):
super().__init__('turtle_tf2_frame_listener')
self.declare_parameter('target_frame', 'turtle1')
self.target_frame = self.get_parameter(
'target_frame').get_parameter_value().string_value
self.tf_buffer = Buffer()
self.tf_listener = TransformListener(self.tf_buffer, self)
self.spawner = self.create_client(Spawn, 'spawn')
self.turtle_spawning_service_ready = False
self.turtle_spawned = False
self.publisher = self.create_publisher(Twist, 'turtle2/cmd_vel', 1)
self.timer = self.create_timer(1.0, self.on_timer)
def on_timer(self):
from_frame_rel = self.target_frame
to_frame_rel = 'turtle2'
if self.turtle_spawning_service_ready:
if self.turtle_spawned:
try:
now = rclpy.time.Time()
trans = self.tf_buffer.lookup_transform(
to_frame_rel,
from_frame_rel,
now)
except TransformException as ex:
self.get_logger().info(
f'Could not transform {to_frame_rel} to {from_frame_rel}: {ex}')
return
msg = Twist()
scale_rotation_rate = 1.0
msg.angular.z = scale_rotation_rate * math.atan2(
trans.transform.translation.y,
trans.transform.translation.x)
scale_forward_speed = 0.5
msg.linear.x = scale_forward_speed * math.sqrt(
trans.transform.translation.x ** 2 +
trans.transform.translation.y ** 2)
self.publisher.publish(msg)
else:
if self.result.done():
self.get_logger().info(
f'Successfully spawned {self.result.result().name}')
self.turtle_spawned = True
else:
self.get_logger().info('Spawn is not finished')
else:
if self.spawner.service_is_ready():
request = Spawn.Request()
request.name = 'turtle2'
request.x = float(4)
request.y = float(2)
request.theta = float(0)
self.result = self.spawner.call_async(request)
self.turtle_spawning_service_ready = True
else:
self.get_logger().info('Service is not ready')
def main():
rclpy.init()
node = FrameListener()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
rclpy.shutdown()
创建turtle_tf2_listener.launch.py文件
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='py_package',
executable='turtle_tf2_listener',
name='listener',
parameters=[
{'target_frame': 'turtle2'}
]
),
])
添加依赖
'console_scripts': [
'turtle_tf2_listener = py_package.turtle_tf2_listener:main',
],
编译
colcon build
. install/setup.bash
运行结果
运行turtle_tf2_broadcaster.launch.py文件
ros2 launch learning_tf2_py turtle_tf2_broadcaster.launch.py
运行turtle_tf2_listener.launch.py文件
ros2 launch py_package turtle_tf2_listener.launch.py
键盘控制turtlesim
ros2 run turtlesim turtle_teleop_key
使用键盘控制turtle1,可以看到turtle2会跟随turtle1
这里turtle_tf2_broadcaster节点会广播(broadcaster) turtle1位姿
turtle_tf2_listener节点会监听(listener) turtle1位姿
参考链接
tf2 介绍
编写 tf2 广播器 (Python)
编写 tf2 侦听器 (Python)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)