如何将rospy.Subscriber获取的数据存入变量?程序阻塞问题求解
我来帮你理清并解决这两个核心问题:
1. 为什么访问Subscriber对象的position会报错?
首先要明确:rospy.Subscriber的作用是创建订阅者实例,它只负责管理消息的接收和回调触发,本身根本不会存储接收到的消息数据。你遇到的AttributeError: 'Subscriber' object has no attribute 'position',就是因为Subscriber对象从设计上就没有这个属性——消息数据只会在回调函数被触发时,通过传入的data参数传递给你。
正确的思路是:通过回调函数接收并存储消息,而非直接操作Subscriber对象。
2. rospy.spin()阻塞导致后续代码无法执行
rospy.spin()是一个阻塞式函数,它会让节点一直运行、处理回调,直到节点被关闭,所以调用它之后的代码永远不会被执行。根据你的需求(获取joint_states数据后执行打印和实例化操作),这里有几种针对性的解决方案:
方案1:单次获取消息(推荐,适合只需要一组数据的场景)
如果你的需求只是获取一次joint_states数据,完全不需要回调和spin,改用rospy.wait_for_message()即可——这个函数会阻塞直到收到指定话题的一条消息,直接返回消息对象:
from sensor_msgs.msg import JointState import rospy def joint_modifier(*args): choice = args[0] if choice == 2: # 阻塞等待获取一条joint_states消息 data = rospy.wait_for_message("joint_states", JointState) return data.position # 直接返回数据,不用全局变量 # 主程序调用 rospy.init_node("joint_listener") # 别忘了初始化节点! g_position = joint_modifier(2) print(g_position) leg_1 = Leg_attribute(g_position[0], ...) # 执行你的实例化逻辑
优点:代码逻辑线性清晰,不需要全局变量,适合一次性获取数据的场景。
方案2:持续获取消息但需执行后续逻辑
如果需要持续接收消息,但又要在获取到第一组数据后执行后续代码,可以用rate.sleep()代替rospy.spin(),自己控制循环:
from sensor_msgs.msg import JointState import rospy g_position = None # 初始化全局变量 def joint_callback(data): global g_position g_position = data.position # 每次收到消息就更新全局变量 def joint_modifier(*args): choice = args[0] if choice == 2: # 创建订阅者 listen = rospy.Subscriber("joint_states", JointState, joint_callback) rate = rospy.Rate(10) # 设置循环频率为10Hz # 循环等待直到获取到数据,同时处理回调 while g_position is None and not rospy.is_shutdown(): rate.sleep() # 若不需要继续接收消息,可取消订阅 listen.unregister() # 主程序调用 rospy.init_node("joint_listener") joint_modifier(2) print(g_position) leg_1 = Leg_attribute(g_position[0], ...)
这种方式既保证能接收到消息,又能在获取到数据后退出循环,让后续代码正常执行。
方案3:实时处理每条消息(适合持续更新场景)
如果你的需求是每次收到joint_states消息都要更新Leg_attribute实例,可以把后续逻辑直接放到回调函数里:
from sensor_msgs.msg import JointState import rospy def joint_callback(data): g_position = data.position print(g_position) leg_1 = Leg_attribute(g_position[0], ...) # 在这里添加对leg_1的实时处理逻辑 def joint_modifier(*args): choice = args[0] if choice == 2: rospy.Subscriber("joint_states", JointState, joint_callback) rospy.spin() # 保持节点运行,持续处理回调 # 主程序调用 rospy.init_node("joint_listener") joint_modifier(2)
注意:这种方式下,每次回调都会创建新的Leg_attribute实例,适合需要实时更新的场景。
内容的提问来源于stack exchange,提问作者Sai Raghava

