You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ROS同一节点内回调函数中实现15秒限时消息发布的方法咨询

解决ROS节点定时15秒转发消息的问题

我来帮你搞定这个ROS节点的定时发布问题!你现在的需求是让节点只在15秒内把Topic1的消息转发到Topic2,因为发布逻辑在回调函数里,直接用时间判断确实有点棘手,不过有几种同一节点内就能实现的方案,我给你详细说下:

方案1:回调内判断时间差(全局时间变量)

这种方法是在节点启动时记录开始时间,每次回调触发时检查当前时间与开始时间的差值,小于15秒就发布消息,否则跳过。

#include <ros/ros.h>
// 根据你的实际消息类型替换,这里用std_msgs/String举例
#include <std_msgs/String.h>

ros::Publisher pub;
ros::Time start_time;
const double PUBLISH_DURATION = 15.0; // 定时15秒

void sub_cb(const std_msgs::String::ConstPtr& msg) {
    // 计算已流逝时间,判断是否在发布窗口内
    if ((ros::Time::now() - start_time).toSec() < PUBLISH_DURATION) {
        pub.publish(*msg);
        ROS_INFO("转发消息: %s", msg->data.c_str());
    } else {
        // 只打印一次停止提示,避免日志刷屏
        static bool stop_notified = false;
        if (!stop_notified) {
            ROS_INFO("15秒已到,停止转发消息");
            stop_notified = true;
        }
    }
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "msg_forwarder_node");
    ros::NodeHandle nh;

    pub = nh.advertise<std_msgs::String>("Topic2", 1);
    ros::Subscriber sub = nh.subscribe("Topic1", 1, sub_cb);

    // 记录节点启动后开始计时的时间
    start_time = ros::Time::now();

    ros::spin();
    return 0;
}

说明:通过全局的start_time标记计时起点,回调内每次触发都做时间判断,逻辑简单直接。用static变量确保停止提示只输出一次,避免冗余日志。

方案2:用ROS定时器控制发布开关

这种方法更优雅,通过一次性定时器在15秒后切换一个布尔标志位,回调内只需检查标志位即可决定是否发布,不需要每次计算时间差。

#include <ros/ros.h>
#include <std_msgs/String.h>

ros::Publisher pub;
bool allow_publish = true;

// 定时器回调:15秒后触发,关闭发布开关
void stop_publish_trigger(const ros::TimerEvent&) {
    allow_publish = false;
    ROS_INFO("15秒已到,停止转发消息");
}

void sub_cb(const std_msgs::String::ConstPtr& msg) {
    if (allow_publish) {
        pub.publish(*msg);
        ROS_INFO("转发消息: %s", msg->data.c_str());
    }
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "msg_forwarder_node");
    ros::NodeHandle nh;

    pub = nh.advertise<std_msgs::String>("Topic2", 1);
    ros::Subscriber sub = nh.subscribe("Topic1", 1, sub_cb);

    // 创建一次性定时器,15秒后触发停止发布
    ros::Timer stop_timer = nh.createTimer(ros::Duration(15.0), stop_publish_trigger, true);

    ros::spin();
    return 0;
}

说明:定时器会在节点启动15秒后自动触发,把allow_publish设为false,之后的回调就不会再发布消息。这种方式把时间控制逻辑和业务逻辑分离,代码更清晰。

方案3:用循环控制节点运行时长(直接退出节点)

如果15秒后节点不需要继续运行,可以直接在main函数里用循环控制运行时间,代替ros::spin(),时间到了就退出节点。

#include <ros/ros.h>
#include <std_msgs/String.h>

ros::Publisher pub;
void sub_cb(const std_msgs::String::ConstPtr& msg) {
    pub.publish(*msg);
    ROS_INFO("转发消息: %s", msg->data.c_str());
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "msg_forwarder_node");
    ros::NodeHandle nh;

    pub = nh.advertise<std_msgs::String>("Topic2", 1);
    ros::Subscriber sub = nh.subscribe("Topic1", 1, sub_cb);

    ros::Time start_time = ros::Time::now();
    ros::Rate loop_rate(10); // 循环频率10Hz,可根据需求调整

    // 循环运行15秒,期间处理回调
    while (ros::ok() && (ros::Time::now() - start_time).toSec() < 15.0) {
        ros::spinOnce(); // 处理一次回调队列
        loop_rate.sleep();
    }

    ROS_INFO("15秒已到,节点即将退出");
    return 0;
}

说明:ros::spinOnce()会处理所有待处理的回调请求,循环每100ms执行一次,确保消息能及时转发。15秒后循环结束,节点直接退出,自然停止发布。这种方式最直接,适合不需要节点后续运行的场景。


内容的提问来源于stack exchange,提问作者theone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 07:52:44