How to keep ROS publisher publishing while executing a subprocess callback?

Question:

How can I keep the ROS Publisher publishing the messages while calling a sub-process:

import subprocess
import rospy

class Pub():
    def __init__(self):
        pass

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

    subprocess.run(cmd, shell=False, stdout=subprocess.PIPE)
    self.plan_pub.publish(msg)

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

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

||

Answers:

Since subprocess.call is a blocking call your subscription callback may take a long time.

Run the command described by args. Wait for command to complete, then return the returncode attribute.

ROS itself will not call the callback again while it is executed already. This means you are blocking this and potentially also other callbacks to be called in time.

The most simple solution would be to replace subprocess.call by subprocess.Popen which

Execute a child program in a new process

nonblocking.

But keep in mind that this potentially starts the process multiple times quite fast.

Think about starting the process only conditionally if not already running. This can be achieved by checking the process to be finished in another thread. Simple but effective, use boolean flag. Here is a small prototype:

def updateState(self, msg):
    #Start the process if not already running
    if not self._process_running:
        p = subprocess.Popen(...)
        self._process_running = True
        def wait_process():
            while p.poll() is None:
                time.sleep(0.1)
            self._process_running = False
        threading.Thread(target=wait_process).start()
    #Other callback code
    self.plan_pub.publish(msg)
Answered By: Fruchtzwerg
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.