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

如何在执行子进程回调期间维持ROS Publisher持续发布消息?

解决方法

核心问题在于subprocess.run()是阻塞式调用,会占用回调函数的执行时间,导致ROS的事件循环无法及时处理其他任务,进而影响Publisher的正常工作。以下是两种可行的解决思路:

方法一:使用subprocess.Popen非阻塞启动子进程

subprocess.Popen启动子进程后会立即返回,不会阻塞当前回调函数,ROS主循环可以继续处理其他任务。如果不需要等待子进程完成就发布消息,直接调用即可;如果需要在子进程完成后再做后续处理,可以通过独立线程实现。

修改后的代码示例:

import subprocess
import rospy
import threading
from std_msgs.msg import String  # 补充缺失的消息类型导入

class Pub():
    def __init__(self):
        # 根据实际场景赋值以下路径参数
        self.planner_path = "path/to/your/planner.py"
        self.search_options = "your_search_alias"
        self.plan_path = "path/to/plan/file"
        self.domain_path = "path/to/domain.pddl"
        self.problem_path = "path/to/problem.pddl"

    def updateState(self, msg):
        cmd = ['python3', self.planner_path, "--alias", self.search_options, 
               "--plan-file", self.plan_path, self.domain_path, self.problem_path]

        # 非阻塞启动子进程
        proc = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        
        # 无需等待子进程完成,直接发布消息
        self.plan_pub.publish(msg)

        # 若需等待子进程完成后处理结果,启动独立线程(可选)
        threading.Thread(target=self._process_proc_result, args=(proc, msg)).start()

    def _process_proc_result(self, proc, msg):
        # 等待子进程结束并获取输出
        stdout, stderr = proc.communicate()
        rospy.loginfo(f"子进程执行完成,输出: {stdout.decode()}")
        # 可根据子进程输出修改msg后再发布
        # self.plan_pub.publish(modified_msg)

    def myPub(self):
        rospy.init_node('problem_formulator', anonymous=True)
        self.plan_pub = rospy.Publisher("plan", String, queue_size=10)
        # 修正回调函数引用,添加self
        rospy.Subscriber('model', String, self.updateState)
        rospy.spin()

if __name__ == "__main__":
    p_ = Pub()
    p_.myPub()

方法二:将子进程调用放入独立线程

直接把阻塞的subprocess.run()放到单独线程中执行,回调函数可以立即返回,ROS主循环不受阻塞影响。

修改后的代码示例:

import subprocess
import rospy
import threading
from std_msgs.msg import String

class Pub():
    def __init__(self):
        self.planner_path = "path/to/your/planner.py"
        self.search_options = "your_search_alias"
        self.plan_path = "path/to/plan/file"
        self.domain_path = "path/to/domain.pddl"
        self.problem_path = "path/to/problem.pddl"

    def _execute_planner(self, msg):
        cmd = ['python3', self.planner_path, "--alias", self.search_options, 
               "--plan-file", self.plan_path, self.domain_path, self.problem_path]
        # 阻塞执行子进程,因在独立线程中,不影响ROS主循环
        result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        rospy.loginfo(f"规划器执行完成,返回码: {result.returncode}")
        # 子进程完成后发布消息
        self.plan_pub.publish(msg)

    def updateState(self, msg):
        # 启动守护线程执行子进程调用
        threading.Thread(target=self._execute_planner, args=(msg,), daemon=True).start()

    def myPub(self):
        rospy.init_node('problem_formulator', anonymous=True)
        self.plan_pub = rospy.Publisher("plan", String, queue_size=10)
        rospy.Subscriber('model', String, self.updateState)
        rospy.spin()

if __name__ == "__main__":
    p_ = Pub()
    p_.myPub()

额外注意事项

  • 原代码中rospy.Subscriber的回调函数缺少self,会导致无法找到类方法,必须修正为self.updateState。
  • 必须导入from std_msgs.msg import String,否则无法识别消息类型。
  • 如果子进程会产生大量输出,建议及时处理stdout和stderr,避免缓冲区溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 21:55:25