tf::transformPose 坐标系变换

本文介绍在使用tf::transformPose进行坐标变换时出现的错误:Lookup would require extrapolation into the future,并提供了解决方案。主要是通过修改时间戳来避免未来数据的预测问题。

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

使用tf::transformPose进行坐标变换时候报错:

[ERROR] [1456669076.279804500]: Lookup would require extrapolation into the future.
 Requested time 1456669076.279616253 but the latest data is at time 1456669076.159341977,
  when looking up transform from frame …

原始变换代码类似如下:

#include <tf/transform_listener.h>
#include <nav_msgs/Odometry.h>
#include <ros/ros.h>
void odomCallBack(const nav_msgs::Odometry::ConstPtr& odom)
{
    // transform from "odom" to "map"
    tf::TransformListener listener;

    geometry_msgs::PoseStamped pose_odom;
    pose_odom.header = odom->header;
    pose_odom.pose = odom->pose.pose;

    geometry_msgs::PoseStamped pose_map;

    try{
    //  listener.waitForTransform(...);  //这里省略这个书写,实际中可能会用到
        listener.transformPose("map", pose_odom, pose_map);
    }
    catch( tf::TransformException ex)
    {
        ROS_WARN("transfrom exception : %s",ex.what());
        return;
    }

    ROS_INFO_STREAM(pose_map);
}

报错原因是由于tf的会把监听的内容存放到一个缓存中,然后再读取相关的内容,而这个过程可能会有几毫秒的延迟,也就是,tf的监听器并不能监听到“现在”的变换,
更改这个错误需要改变时间戳,不能使用ros::Time::now(),或者传感器给定的默认时间戳,需要使用ros::Time()替换原来的时间戳。
增加下面一行:

pose_odom.header.stamp = ros::Time();

更改后完整程序为:

#include <tf/transform_listener.h>
#include <nav_msgs/Odometry.h>
#include <ros/ros.h>
void odomCallBack(const nav_msgs::Odometry::ConstPtr& odom)
{
    // transform from "odom" to "map"
    tf::TransformListener listener;

    geometry_msgs::PoseStamped pose_odom;
    pose_odom.header = odom->header;
    pose_odom.header.stamp = ros::Time();  //增加了这行
    pose_odom.pose = odom->pose.pose;

    geometry_msgs::PoseStamped pose_map;

    try{
    //  listener.waitForTransform(...);  //这里省略这个书写,实际中可能会用到
        listener.transformPose("map", pose_odom, pose_map);
    }
    catch( tf::TransformException ex)
    {
        ROS_WARN("transfrom exception : %s",ex.what());
        return;
    }

    ROS_INFO_STREAM(pose_map);
}

参考:
https://blog.youkuaiyun.com/start_from_scratch/article/details/50762293
https://www.cnblogs.com/qyit/p/11418847.html

在ROS中实现机器人坐标变换并计算激光雷达数据在底盘坐标系下的坐标,首先需要在系统中定义相应的话题和服务。我们将假设已经定义了两个关键节点:一个负责广播机器人的坐标变化(通常是通过odom topic),另一个负责接收激光雷达的数据(通常是通过scan topic)。以下是基本步骤和代码实现: 1. **创建坐标变换服务**: 在`robot_base`包内创建一个服务,例如`base_to_lidar_transform.srv`,定义一个`TransformRequest`和`TransformResponse`结构体: ```cpp // base_to_lidar_transform.srv struct TransformRequest { geometry_msgs::PoseStamped robot_pose; // 机器人底盘坐标系中的位置 std::string lidar_frame_id; // 激光雷达坐标系 ID }; struct TransformResponse { geometry_msgs::PoseStamped transformed_pose; // 激光雷达坐标系中的位置 }; ``` 2. **机器人坐标变换服务实现**: 在`robot_base`包的`server.cpp`(或相应文件)中,编写服务提供者: ```cpp #include "base_to_lidar_transform.h" // ... (其他头文件) bool handleTransform_srv(service::Server<TransformRequest, TransformResponse> &server) { // 从请求中获取参数 auto request = server.request(); PoseWithCovarianceStamped robot_pose = request.robot_pose.pose; std::string lidar_frame_id = request.lidar_frame_id; // 根据激光雷达和机器人底盘的关系计算变换 // 这部分取决于实际的坐标系转换矩阵或算法,假设有个函数transformPose TransformResponse response = transformPose(robot_pose, lidar_frame_id); server.set_response(response); return true; } ``` 3. **广播机器人坐标**: 在`robot_driver`包中,假设有一个发布`odom`话题的节点,你可以直接使用预定义的odom消息: ```cpp // ... (其他头文件) #include "tf2_ros/buffer.h" #include "tf2_ros/static_transform_publisher.h" void odomCallback(const nav_msgs::Odometry::ConstPtr& odom_msg) { static tf2_ros::Buffer buffer; static tf2_ros::TransformBroadcaster broadcaster; // 获取机器人底盘坐标系到世界坐标系变换 // 假设已经将odom数据解析出来并存储在world_from_robot变量中 broadcaster.sendTransform(world_from_robot, ros::Time.now(), "/odom", "/map"); // 发布到odom话题 } ``` 4. **订阅并调用服务**: 在`laser_radar_node`包内,订阅扫描数据并调用坐标变换服务: ```cpp // ... (其他头文件) #include "base_to_lidar_transform_client.h" void scanCallback(const sensor_msgs::LaserScan::ConstPtr& scan_msg) { TransformRequest req; req.robot_pose = getRobotPoseFromOdom(); // 从odom提取机器人位置 req.lidar_frame_id = "lidar_frame"; // 假设这是激光雷达帧ID // 调用服务,等待响应 TransformResponse resp; if (serviceClient.call(req, resp)) { laserDataInBaseFrame = resp.transformed_pose.pose.position; // 存储结果 } else { ROS_WARN("Failed to call base_to_lidar_transform service"); } } ``` 请注意,这只是一个基础示例,实际的坐标变换可能涉及到复杂的数学运算和传感器融合技术,例如TFTransform Framework)的使用。此外,`getRobotPoseFromOdom()`和`getLaserDataInBaseFrame()`函数也需要你自己实现。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值