ROS订阅者仅在调用input()指令后才收到目标点消息的问题咨询
问题原因
这是ROS1的回调调度机制导致的:
- ROS1的订阅者回调默认不会自动异步执行,所有待处理的消息回调都需要主线程主动调用
rospy.spin()或者rospy.spinOnce()才会被触发执行 - 你的代码实例化控制器类后直接执行
move2goal中的打印逻辑,全程没有触发回调处理的操作,订阅到的目标点消息一直滞留在消息队列中,self.goal_pose始终是初始化的默认值 - 加入
input()后程序进入阻塞等待用户输入的状态,ROS后台拿到CPU时间处理消息队列,触发update_goal回调更新目标点变量,因此输入结束后打印的就是正确的目标值
修复方案
可根据使用场景选择以下任意一种方案:
方案1:手动触发回调处理(改动最小)
在move2goal的循环逻辑中加入rospy.spinOnce()主动处理回调:
def move2goal(self): # 等待目标点接收完成 while not rospy.is_shutdown() and self.goal_pose.x == 0.0 and self.goal_pose.y == 0.0: rospy.spinOnce() # 处理一次待执行回调 self.rate.sleep() print("self.goal , is:") print(self.goal_pose.x, self.goal_pose.y) while calc.euclidean_distance(self.odom,self.goal_pose) >= const.DISTANCE_TOLERANCE: # 原有移动逻辑不变 rospy.spinOnce() # 每次循环都处理回调,支持运行中更新目标点 self.rate.sleep() self.stop_the_bot() rospy.spin()
注:如果你的合法目标点包含(0,0),可以在
__init__中新增标记位self.has_received_goal = False,在update_goal回调中将其设为True,循环判断该标记位即可避免误判。
方案2:回调触发移动逻辑
收到目标点后再启动移动流程,无需主动轮询:
def __init__(self): # 原有初始化逻辑不变 self.has_received_goal = False def update_goal(self,data): self.goal_pose = data self.goal_pose.x = round(self.goal_pose.x, 4) self.goal_pose.y = round(self.goal_pose.y, 4) if not self.has_received_goal: self.has_received_goal = True self.move2goal() # 收到第一个目标点后自动启动移动 if __name__ == '__main__': try: x = oferbot_controller() rospy.spin() # 直接进入自旋等待回调,无需主动调用move2goal except rospy.ROSInterruptException: pass
方案3:启用异步回调线程
开独立线程自动处理所有回调,原有业务逻辑无需修改:
def __init__(self): rospy.init_node(const.MOVE_NODE_NAME, anonymous=True) # 原有发布订阅初始化逻辑不变 # 新增以下两行启动异步回调处理 self.spinner = rospy.AsyncSpinner(1) self.spinner.start()
内容的提问来源于stack exchange,提问作者oferb
相关产品推荐
相关产品推荐

