
本文讲解如何在 ros 中正确实现跨文件共享话题数据,解决因节点阻塞、实例未激活导致的变量始终为 none 的问题,并提供可运行的修改方案。
本文讲解如何在 ros 中正确实现跨文件共享话题数据,解决因节点阻塞、实例未激活导致的变量始终为 none 的问题,并提供可运行的修改方案。
在 ROS 中,不同 Python 文件之间不能直接通过全局变量或模块属性共享实时更新的数据——因为每个脚本运行在独立进程(或线程)中,内存不共享。你遇到的 received_integer 始终为 None,根本原因有两个:
- rospy.spin() 是阻塞调用:它会挂起当前线程,等待 ROS 消息循环持续运行,导致后续代码(如 while True 循环)根本无法执行;
- other file 中仅创建了 listenerPy 实例,但未启动订阅逻辑:listener() 方法未被调用,rospy.Subscriber 未注册,回调永远不会触发,received_integer 自然不会被更新。
✅ 正确做法是:将监听逻辑与使用逻辑整合在同一进程内,并避免阻塞主线程。推荐采用非阻塞式回调 + 线程安全访问模式。以下是优化后的完整方案:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
✅ 修改 listener.py(移除 rospy.spin(),改用 rospy.Rate 控制循环)
#!/usr/bin/env python
import rospy
from std_msgs.msg import Int32
class ListenerPy:
def __init__(self):
self.received_integer = None
# 初始化节点(仅一次)
if not rospy.core.is_initialized():
rospy.init_node('listener', anonymous=True)
# 创建订阅者
rospy.Subscriber('chatter', Int32, self.callback)
def callback(self, data):
self.received_integer = data.data
rospy.loginfo(f"Received: {self.received_integer}")
def get_value(self):
"""线程安全地获取最新值(可选加锁,此处简单返回)"""
return self.received_integer✅ 修改 other_file.py(复用同一实例,主动轮询而非依赖阻塞 spin)
#!/usr/bin/env python
from listener import ListenerPy
from time import sleep
def main():
# 实例化监听器(自动初始化节点并订阅)
listener = ListenerPy()
rate = rospy.Rate(10) # 10 Hz 轮询频率
while not rospy.is_shutdown():
value = listener.get_value()
print(f"Current value: {value}")
rate.sleep() # 替代 sleep(1),与 ROS 时间系统同步
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
rospy.signal_shutdown("User interrupted")
print("\nShutting down.")⚠️ 关键注意事项:
- 不要同时运行两个独立节点:listener.py 和 other_file.py 若分别 rosrun,它们是两个独立节点,彼此无共享内存;必须在同一进程内协作;
- rospy.init_node() 只能调用一次:多次调用会报错,因此在 ListenerPy.__init__() 中添加 is_initialized() 判断;
- 避免 rospy.spin() + 主循环共存:spin() 专用于纯监听节点;若需边收边处理,应使用 Rate 控制主循环;
- 生产环境建议升级为 rospy.Service 或 actionlib:对复杂状态共享,更健壮的方式是封装为服务或参数服务器(rospy.set_param/get_param),但本例中类实例内共享已足够轻量可靠。
通过以上调整,other_file.py 将能实时读取到话题发布的整数值,不再输出 None。核心原则是:ROS 数据流驱动逻辑,而非轮询驱动节点生命周期。

















