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

为何下述ROS代码仅发布一条消息?是否为ROS Noetic已知Bug?

问题描述

在Ubuntu 20.04系统上运行ROS Noetic版本,编写测试代码调用两次publish()方法,但实际仅发布一条消息。首次调用publish()时出现调试日志:

[DEBUG] [1707520305.010403219]: Trying to publish message of type [std_msgs/String/992ce8a1687cec8c8bd883ec73ca41d1] on a publisher with type [std_msgs/String/992ce8a1687cec8c8bd883ec73ca41d1]

通过在另一终端执行rostopic echo test_topic验证确实仅收到一条消息,测试代码如下:

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

int main(int argc, char *argv[])
{
  ros::init(argc, argv, "test_pub_node");
  ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug);
  ros::NodeHandle nh;
  auto pub = nh.advertise<std_msgs::String>("test_topic", 1);
  auto msg = boost::make_shared<std_msgs::String>();
  msg->data = "hello";
  
  usleep(1.0e6);
  pub.publish(msg);

  ros::spinOnce();

  usleep(1.0e6);
  pub.publish(msg);

  ros::spinOnce();

  return 0;
}

请问这是否是ROS的已知Bug?


解答

这不是ROS的已知Bug,问题源于代码实现和ROS发布队列的机制:

  1. 队列大小限制:创建Publisher时设置的队列大小为1,ROS最多只会缓存1条待发送的消息。
  2. 重复消息优化:两次发布的是同一个boost::shared_ptr指向的相同内容的消息,ROS会判定为重复消息,当队列已满时,直接丢弃第二次的发布请求,不会将其加入队列。
  3. 节点退出时机:第二次publish后仅调用一次ros::spinOnce()就立即退出节点,ROS的后台发送线程可能还没来得及处理第二次发布请求就被终止。

修复方案

  • 增大队列大小:将nh.advertise<std_msgs::String>("test_topic", 1)改为nh.advertise<std_msgs::String>("test_topic", 2),让队列能容纳多条待发送消息。
  • 修改消息内容:每次发布不同的消息内容,比如第二次发布前修改msg->data = "hello second",ROS会识别为新消息,即使队列大小为1,也会处理该发布请求。
  • 延长节点存活时间:在最后一次ros::spinOnce()后添加短暂延迟,比如usleep(500000),确保ROS有足够时间发送完所有消息再退出。

修复后的示例代码:

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

int main(int argc, char *argv[])
{
  ros::init(argc, argv, "test_pub_node");
  ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug);
  ros::NodeHandle nh;
  // 增大队列大小到2
  auto pub = nh.advertise<std_msgs::String>("test_topic", 2);
  auto msg = boost::make_shared<std_msgs::String>();
  msg->data = "hello first";
  
  usleep(1.0e6);
  pub.publish(msg);

  ros::spinOnce();

  // 修改消息内容
  msg->data = "hello second";
  usleep(1.0e6);
  pub.publish(msg);

  ros::spinOnce();
  // 延长存活时间,确保消息发送完成
  usleep(500000);

  return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 12:00:31