subprocess.popen-进程在与 SMACH 一起使用时停止 运行

subprocess.popen-process stops running while using it with SMACH

我只是想在 SMACH 中从 python 启动一个 rosbag 命令。我发现这样做的一种方法是使用子流程。我的目标是一旦 rosbag 启动,状态机就转换到状态 T2(并保持在那里)。

但是,当在 SMACH 状态下使用 subprocess.popen 启动 rosbag 然后使用 rostopic echo 'topic' 时,rosbag 似乎首先正确发布数据,然后突然停止发布数据,并且仅在我使用 Ctrl+C 结束 SMACH,rosbag 继续发布更多数据,然后它也会停止。

对此有任何合理的解释吗(我可能错过了一个参数,还是不可能保持节点 运行ning 那样)?或者有没有更好的方法来启动 rosbag 并让 运行 在后台?

(顺便说一句,一些其他命令,如一些 roslaunch-commands 在通过 subprocess.popen 启动后似乎停止工作!)

我的代码如下所示:

#!/usr/bin/env python3

import os
import signal
import subprocess
import smach
import smach_ros
import rospy
import time
from gnss_navigation.srv import *

class t1(smach.State):
    def __init__(self, outcomes=['successful', 'failed', 'preempted']):
        smach.State.__init__(self, outcomes)

    def execute(self, userdata):
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        try:
            process1 = subprocess.Popen('rosbag play /home/faps/bags/2020-05-07-11-18-18.bag', stdout=subprocess.PIPE,
                                        shell=True, preexec_fn=os.setsid)
        except Exception:
            return 'failed'
        return 'successful'

class t2(smach.State):
    def __init__(self, outcomes=['successful', 'failed', 'preempted']):
        smach.State.__init__(self, outcomes)

    def execute(self, userdata):
        #time.sleep(2)
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        return 'successful'


if __name__=="__main__":
    rospy.init_node('test_state_machine')

    sm_1 = smach.StateMachine(outcomes=['success', 'error', 'preempted'])
    with sm_1:
        smach.StateMachine.add('T1', t1(), transitions={'successful': 'T2', 'failed': 'error'})
        smach.StateMachine.add('T2', t2(), transitions={'successful': 'T2', 'failed': 'error', 'preempted':'preempted'})

    # Execute SMACH plan
    outcome = sm_1.execute()
    print('exit-outcome:' + outcome)
    # Wait for ctrl-c to stop the application
    rospy.spin()

的答案评论部分所述,将 subprocess.PIPE 用作 stdout 时会出现问题.

因此,我用来解决问题的两种可能方案是:

  1. 如果您不关心 print-outs 和其他东西 -> 使用 devnull 作为输出:

    FNULL = open(os.devnull, 'w')
    process = subprocess.Popen('your command', stdout=FNULL, stderr=subprocess.STDOUT,
                                         shell=True, preexec_fn=os.setsid)
    
  2. 如果您确实需要 print-outs 和东西 -> 创建一个 log-file 并将其用作输出:

    log_file = open('path_to_log/log.txt', 'w')
    process = subprocess.Popen('your command', stdout=log_file, stderr=subprocess.STDOUT,
                                        shell=True, preexec_fn=os.setsid)