这里以ros2 run demo_nodes_cpp talker
为示例
ros2 是python 文件, which ros2 :查看ros2位置
参考ros2加载过程
ros2run 目录下run.py
# Copyright 2017 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from argparse import REMAINDER
import shlex
from ros2cli.command import CommandExtension
from ros2pkg.api import package_name_completer
from ros2pkg.api import PackageNotFound
from ros2run.api import ExecutableNameCompleter
from ros2run.api import get_executable_path
from ros2run.api import MultipleExecutables
from ros2run.api import run_executable
class RunCommand(CommandExtension):
"""Run a package specific executable."""
def add_arguments(self, parser, cli_name):
arg = parser.add_argument(
'--prefix',
help='yong Prefix command, which should go before the executable. '
'Command must be wrapped in quotes if it contains spaces '
"(e.g. --prefix 'gdb -ex run --args').")
try:
from argcomplete.completers import SuppressCompleter
except ImportError:
pass
else:
arg.completer = SuppressCompleter()
arg = parser.add_argument(
'package_name',
help='Name of the ROS package')
arg.completer = package_name_completer
arg = parser.add_argument(
'executable_name',
help='Name of the executable')
arg.completer = ExecutableNameCompleter(
package_name_key='package_name')
parser.add_argument(
'argv', nargs=REMAINDER,
help='Pass arbitrary arguments to the executable')
def main(self, *, parser, args):
try:
#args.package_name : demo_nodes_cpp args.executable_name:talker
path = (
package_name=args.package_name,
executable_name=args.executable_name)
#path =/*/*/a/b/c/talker
except PackageNotFound:
raise RuntimeError(f"yong Package '{args.package_name}' not found")
except MultipleExecutables as e:
msg = 'Multiple executables found:'
for p in e.paths:
msg += f'\n- {p}'
raise RuntimeError(msg)
if path is None:
return 'No executable found'
prefix = shlex.split(args.prefix) if args.prefix is not None else None
return run_executable(path=path, argv=args.argv, prefix=prefix)
运行run_executable,它在ros2run目录下api文件夹下__init__.py
# Copyright 2017 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import subprocess
import sys
from ros2pkg.api import get_executable_paths
from ros2pkg.api import PackageNotFound
class MultipleExecutables(Exception):
def __init__(self, paths):
self.paths = paths
def get_executable_path(*, package_name, executable_name):
paths = get_executable_paths(package_name=package_name)
paths2base = {}
for p in paths:
basename = os.path.basename(p)
if basename == executable_name:
# pick exact match
paths2base[p] = basename
elif sys.platform == 'win32':
# check extensions listed in PATHEXT for match without extension
pathext = os.environ.get('PATHEXT', '').lower().split(os.pathsep)
ext = os.path.splitext(basename)[1].lower()
if ext in pathext and basename[:-len(ext)] == executable_name:
# pick match because of known extension
paths2base[p] = basename
if not paths2base:
return None
if len(paths2base) > 1:
raise MultipleExecutables(paths2base.keys())
return list(paths2base.keys())[0]
def run_executable(*, path, argv, prefix=None):
cmd = [path] + argv
# on Windows Python scripts are invokable through the interpreter
if os.name == 'nt' and path.endswith('.py'):
cmd.insert(0, sys.executable)
if prefix is not None:
cmd = prefix + cmd
#启动子进程运行cmd命令/*/*/talker
process = subprocess.Popen(cmd)
while process.returncode is None:
try:
process.communicate()
except KeyboardInterrupt:
# the subprocess will also receive the signal and should shut down
# therefore we continue here until the process has finished
pass
return process.returncode
class ExecutableNameCompleter:
"""Callable returning a list of executable names within a package."""
def __init__(self, *, package_name_key=None):
self.package_name_key = package_name_key
def __call__(self, prefix, parsed_args, **kwargs):
package_name = getattr(parsed_args, self.package_name_key)
try:
paths = get_executable_paths(package_name=package_name)
except PackageNotFound:
return []
return [os.path.basename(p) for p in paths]
编译
$colcon build --packages-select ros2run
$source /path/install/setup.bash
在执行ros2 run