I'm currently looking into creating a general configuration tool for ROS (Robot Operating System). Using subprocess.POpen()
and Tkinter
I'm creating a treeview
like this:
The first two columns are rather simple to create due to the neat way rospack list
(a command that lists all packages that are installed on the system including the ones that are inside the respective workspace where the developer creates his own packages) works:
ros_packages_install_retrieve = subprocess.Popen(["rospack list"], shell=True, stdout=subprocess.PIPE)
ros_packages_installed = []
for ros_package in ros_packages_install_retrieve.stdout.readlines():
ros_package_adapted = ros_package.split(" ")
ros_package_adapted[1] = ros_package_adapted[1][:-1]
ros_packages_installed.append(ros_package_adapted)
The Requires column is the tricky one due to a problem with calling rospack depends <package>
(lists (if any) all packages the <package>
requires to be present on the system in order to build and/or run). For each package that is inside ros_packages_installed
I call the following function:
def get_deps(ros_package):
ros_package_deps_retrieve = subprocess.Popen(["rospack", "depends", ros_package], shell=True, stdout=subprocess.PIPE)
ros_package_deps = []
for ros_package_dep in ros_package_deps_retrieve.stdout.readlines():
ros_package_dep = ros_package_dep.split("\n")
ros_package_dep = ros_package_dep[:-1]
ros_package_deps.append(ros_package_dep)
return ros_package_deps
The problem is that I'm getting
[rospack] Error: no package given
and the return value is always an empty list. I even tried concatenating the ros_package
argument to the command itself but all in vain.
During my futile attempts I found something rather strange. Both list
and depends
are actually arguments that are passed to rospack
. In fact if you call rospack
only you will get an error telling you to call rospack help
to see the available arguments.
Therefore I tried splitting these things up and passed ["rospack", "list"]
and ["rospack", "depends", "ros_package"]
to the two POpen
calls. For my surprise I got
[rospack] Error: no command given. Try 'rospack help' [rospack]
[rospack] Error: no command given. Try 'rospack help'
which at least for me is a rather strange behaviour.
This is a confusion with how to run Popen. You should either pass a single string with shell=True
:
ros_package_deps_retrieve = subprocess.Popen("rospack depends %s"rospack, shell=True, stdout=subprocess.PIPE)
or pass it as a completely separate list, and use shell=False
(the default, not necessary to specify):
ros_package_deps_retrieve = subprocess.Popen(["rospack", "depends", rospack], stdout=subprocess.PIPE)
See the documentation here: https://docs.python.org/2/library/subprocess.html#popen-constructor
Important pieces (below are relevant quotes from the docs):
If shell is True, it is recommended to pass args as a string rather than as a sequence. ...
If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself.
So when you pass shell=True
and pass it like ['rospack', 'list']
, rospack
ends up being the command, and list
becomes an argument to the shell, not what you wanted.
When shell=False
and you pass it like ['rospack depends', rosmodule]
, that makes the string 'rospack depends'
the command to run, which doesn't exist and therefore fails.