Python类实现ROS发布订阅节点异常:订阅节点未生效
问题分析与修复方案
核心问题
你的代码存在两个关键问题:
- 发布逻辑阻塞程序:
Publisher类的__init__方法包含无限while循环,实例化该类后程序会一直卡在循环里,永远执行不到sub = Subscriber()这一行——订阅者根本没被初始化,所以rostopic info看不到订阅者。 - 重复初始化节点:ROS规定一个进程只能调用一次
rospy.init_node,你在两个类中都调用了该函数,违反了规范。
修复后的代码
#!/usr/bin/python3 import rospy from std_msgs.msg import String import threading class CommandPublisher: def __init__(self): self.pub = rospy.Publisher('command', String, queue_size=10) self.rate = rospy.Rate(1) self.is_running = True def publish_loop(self): while self.is_running and not rospy.is_shutdown(): command = f"Time is {rospy.get_time()}" rospy.loginfo(command) self.pub.publish(command) self.rate.sleep() def stop(self): self.is_running = False class CommandSubscriber: def __init__(self): rospy.Subscriber('command', String, self.callback) def callback(self, data): rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data) def main(): # 全局仅初始化一次ROS节点 rospy.init_node('command_node', anonymous=True) pub = CommandPublisher() sub = CommandSubscriber() # 用线程启动发布循环,避免阻塞主线程 pub_thread = threading.Thread(target=pub.publish_loop) pub_thread.start() try: # 主线程进入spin,处理订阅回调 rospy.spin() except KeyboardInterrupt: # 捕获中断信号,优雅停止发布线程 pub.stop() pub_thread.join() if __name__ == "__main__": main()
关键改动说明
- 拆分发布逻辑:将原来写在
__init__里的阻塞循环移到单独的publish_loop方法,避免类初始化时直接卡死程序。 - 线程并行执行:用
threading.Thread启动发布循环,让主线程可以正常运行rospy.spin()处理订阅回调。 - 统一节点初始化:仅在main函数中调用一次
rospy.init_node,符合ROS单进程单节点的规范。 - 优雅退出处理:添加
stop方法和中断捕获,保证程序终止时发布线程能正常结束。
验证效果
运行修改后的代码后,执行rostopic info /command就能同时看到发布者和订阅者,订阅者也会正常打印收到的消息。
内容的提问来源于stack exchange,提问作者Sabyasachi
相关产品推荐
相关产品推荐

