- SignalDesk2 hr ago
Original Summary
0. 写在前面 在L站好久没发帖子,从三级掉了下来。发一些 ROS2 的学习笔记,参考鱼香ROS。如果对大家有帮助则更好。 1. Transform 1.1 实现坐标变换 ros2 run tf2_ros static_transform_publisher --x 0.1 --y 0.0 --z 0.2 --roll 0.0 --pitch 0.0 --yaw 0.0 --frame-id base_link --child-frame-id base_laser static_transform_publisher :Static Transform Publisher(静态坐标变换发布器)也就是两个坐标系之间的位置和姿态关系永远不变。比如激光雷达通过螺丝固定在机器人底盘上,那么雷达相对于底盘的位置不会变,因此就适合使用静态 TF。 平移的参数的单位均为米 旋转的参数为弧度制 --frame-id :父坐标系 --child-frame-id :子坐标系 所有的参数描述的都是子坐标系相对于父坐标系的位置 1.2 RViz2 可视化 在终端中输入 rviz2 选择 Fixed Frame ,把 map 改为 base_laser 点击 Add ,选择 TF ,点击 OK 坐标变换就可以可视化了 1.3 查看变换关系 在终端中输入 ros2 run tf2_tools view_frames 会在你终端当前目录下生成一个pdf文件,里面描述坐标变换的关系 1.4 TF 的本质 在有TF发布时打开新的终端查看话题和消息接口可看出tf本质就是topic通讯 2. 通过 Python 发布坐标 背景 2.1 Python 发布静态坐标 两坐标系间相对静止 import rclpy from rclpy.node import Node from tf2_ros import StaticTransformBroadcaster from geometry_msgs.msg import TransformStamped from tf_transformations import quaternion_from_euler import math class StaticTFBroadcaster(Node): def __init__(self): super().__init__('static_tf_broadcaster') self.static_broadcaster_ = StaticTransformBroadcaster(self) self.publish_static_tf() def publish_static_tf(self): transform = TransformStamped() transform.header.frame_id = 'base_link' transform.child_frame_id = 'camera_link' transform.header.stamp = self.get_clock().now().to_msg() transform.transform.translation.x = 0.5 transform.transform.translation.y = 0.3 transform.transform.translation.z = 0.6 q = quaternion_from_euler(math.radians(180), 0, 0) transform.transform.rotation.x = q[0] transform.transform.rotation.y = q[1] transform.transform.rotation.z = q[2] transform.transform.rotation.w = q[3] self.static_broadcaster_.sendTransform(transform) self.get_logger().info(f'发布静态TF:{transform}') def main(): rclpy.init() node = StaticTFBroadcaster() rclpy.spin(node) rclpy.shutdown() 发布静态坐标后新建终端输入 ros2 run tf2_ros tf2_echo base_link camera_link 查看 base_link 和 camera_link 之间的坐标关系 2.2 Python 发布动态坐标 两坐标系之间相对运动 import rclpy from rclpy.node import Node from tf2_ros import TransformBroadcaster from geometry_msgs.msg import TransformStamped from tf_transformations import quaternion_from_euler import math class TFBroadcaster(Node): def __init__(self): super().__init__('tf_broadcaster') self.broadcaster_ = TransformBroadcaster(self) self.timer_ = self.create_timer(0.01, self.publish_tf) def publish_tf(self): transform = TransformStamped() transform.header.frame_id = 'camera_link' transform.child_frame_id = 'bottle_link' transform.header.stamp = self.get_clock().now().to_msg() transform.transform.translation.x = 0.3 transform.transform.translation.y = 0.2 transform.transform.translation.z = 0.5 q = quaternion_from_euler(0, 0, 0) transform.transform.rotation.x = q[0] transform.transform.rotation.y = q[1] transform.transform.rotation.z = q[2] transform.transform.rotation.w = q[3] self.broadcaster_.sendTransform(transform) self.get_logger().info(f'发布动态TF:{transform}') def main(): rclpy.init() node = TFBroadcaster() rclpy.spin(node) rclpy.shutdown() 在 [2.1 Python 发布静态坐标](## 2.1 Python 发布静态坐标) 基础上打开新终端运行本节代码后输入 ros2 run tf2_ros tf2_echo camera_link bottle_link 即可查看坐标系 camera_link 和 bottle_link 的关系 2.3 Python 查询坐标关系 import rclpy from rclpy.node import Node from tf2_ros import TransformListener, Buffer from tf_transformations import euler_from_quaternion import math class TFListener(Node): def __init__(self): super().__init__('tf_broadcaster') self.buffer_ = Buffer() self.listener_ = TransformListener(self.buffer_, self) self.timer_ = self.create_timer(1.0, self.get_tf) def get_tf(self): try: result = self.buffer_.lookup_transform( 'base_link', 'bottle_link', rclpy.time.Time(seconds=0.0), rclpy.time.Duration(seconds=1.0) ) transform = result.transform self.get_logger().info(f'平移:{transform.translation}') self.get_logger().info(f'旋转:{transform.rotation}') rotation_euler = euler_from_quaternion([ transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w ]) self.get_logger().info(f'旋转RPY:{rotation_euler}') except Exception as e: self.get_logger().warn(f'获取坐标失败,原因:{str(e)}') def main(): rclpy.init() node = TFListener() rclpy.spin(node) rclpy.shutdown() 3. 通过 C++ 发布坐标 3.1 C++ 发布静态坐标 #include "rclcpp/rclcpp.hpp" #include "geometry_msgs/msg/transform_stamped.hpp" // 提供消息接口 #include "tf2/LinearMath/Quaternion.hpp" // 提供tf2::Quaternion #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp" // 消息类型转换函数 #include "tf2_ros/static_transform_broadcaster.hpp" // 静态坐标广播类 class StaticTFBroadcaster: public rclcpp::Node { private: std::shared_ptr<tf2_ros::StaticTransformBroadcaster> broadcaster_; public: StaticTFBroadcaster(/ args /): Node("static_tf_boardcaster") { this -> broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this); this -> publish_tf(); } void publish_tf() { geometry_msgs::msg::TransformStamped transform; transform.header.stamp = this -> get_clock() -> now(); transform.header.frame_id = "map"; transform.child_frame_id = "target_point"; transform.transform.translation.x = 5.0; transform.transform.translation.y = 3.0; transform.transform.translation.z = 0.0; tf2::Quaternion q; q.setRPY(0.0, 0.0, 60M_PI/180); transform.transform.rotation = tf2::toMsg(q); this -> broadcaster_ -> sendTransform(transform); RCLCPP_INFO(this->get_logger(), "已广播坐标"); } }; int main(int argc, char argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<StaticTFBroadcaster>(); rclcpp::spin(node); rclcpp::shutdown(); } 3.2 C++ 发布动态坐标 #include "rclcpp/rclcpp.hpp" #include "geometry_msgs/msg/transform_stamped.hpp" // 提供消息接口 #include "tf2/LinearMath/Quaternion.hpp" // 提供tf2::Quaternion #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp" // 消息类型转换函数 #include "tf2_ros/transform_broadcaster.hpp" // 动态坐标广播类 #include "chrono" using namespace std::chrono_literals; class TFBroadcaster: public rclcpp::Node { private: std::shared_ptr<tf2_ros::TransformBroadcaster> broadcaster_; rclcpp::TimerBase::SharedPtr timer_; public: TFBroadcaster(/* args
- 情报分类:技术学习与提效
- 分类依据:内容涉及技术、AI、软件工具或工程实践
- 信息来源:服务器 / LINUX DO - 最新话题
- 发布时间:2026/10/13 21:09:31
- No replies yet