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
相关产品推荐
相关产品推荐

