-1

I have a ROS code rostopic pub toggle_led std_msgs/Empty that basically starts once and keeps running until CTRL+C is pressed.
Now, I would like to automate this command from Python. I checked Calling an external command in Python but it only shows how to start the command.
How would I start and stop running this process as and when I want?

Community
  • 1
  • 1
Kanishka Ganguly
  • 1,252
  • 4
  • 18
  • 38
  • 1
    check this: http://stackoverflow.com/questions/4789837/how-to-terminate-a-python-subprocess-launched-with-shell-true – user3885927 Nov 21 '14 at 22:44
  • There a many ways to do this depending on the details of your requirements (what else is the script doing? do you want to run the script multile times and daemonize rostopic? is it gui or command line?). You really need to post your code if you want something more than a vague description of what to do. – tdelaney Nov 21 '14 at 22:47
  • @tdelaney I just want a generic solution that would work for any command line code. There are several such commands similar to this that would run until stopped manually. So, code would not be applicable here I believe. – Kanishka Ganguly Nov 21 '14 at 22:49

1 Answers1

2

How would I start and stop running this process as and when I want?

Well, you already know how to start it, as you said in the previous sentence.

How do you stop it? If you want to stop it exactly like a Ctrl-C,* you do that by calling send_signal on it, using CTRL_C_EVENT on Windows, or SIGTERM on Unix.** So:

import signal
import subprocess

try:
    sig = signal.CTRL_C_EVENT
except NameError:
    sig = signal.SIGTERM

p = subprocess.Popen(['/path/to/prog', '-opt', '42', 'arg'])
# ... later
p.send_signal(sig)

If you only care about Linux (or *nix in general), you can make this even simpler: terminate is guaranteed to do the same thing as send_signal(SIGTERM). So:

import subprocess
p = subprocess.Popen(['/path/to/prog', '-opt', '42', 'arg'])
# ... later
p.terminate()

Since you asked in a comment "Could you please explain the various parameters to subprocess.Popen()": Well, there are a whole lot of them (see Popen Constructor and Frequently Used Arguments in the docs, but I'm only using one, the args parameter.

Normally, you pass a list to args, with the name of the program as the first element in the list, and each separate command-line argument as a separate element. But if you want to use the shell, you pass a string for args, and add a shell=True as another argument.


* Note that "exactly like a Ctrl-C" may not actually be what you want on Windows, unless the program has a console and is a process group owner. This may mean you'll need to add creationflags=subprocess.CREATE_NEW_PROCESS_GROUP to the Popen call. Or it may not—e.g.., if you use shell=True.

** In Python, you can usually ignore the platform differences between CTRL_C_EVENT and SIGTERM and always use the latter, but subprocess.send_signal is one of the few places you can't. On Windows, send_signal(SIGTERM) will call terminate instead of sending a Ctrl-C. If you don't actually care exactly how the process gets stopped, just that it gets stopped somehow, then of course you can use SIGTERM… but in that case, you might as well just call terminate.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Could you please explain the various parameters to `subprocess.Popen()`? – Kanishka Ganguly Nov 21 '14 at 22:56
  • 2
    @KanishkaGanguly it is a list of the parameters of the command you want to run with subprocess, consider you want to run `ls -l` you would do: `p = subprocess.Popen(["ls","-l"])`. – igon Nov 21 '14 at 22:57
  • @abarnert This application is for Linux only, so Windows cases are moot. But I do get your point. – Kanishka Ganguly Nov 21 '14 at 23:02
  • @KanishkaGanguly: Well, that makes things even simpler. See my updated answer; you can just use `terminate` instead of `send_signal`, and then you don't even need the `signal` module. – abarnert Nov 22 '14 at 00:12