【ROS2RUN源码解析:解决ROS2 run命令找不到问题的详细流程】

news2025/1/18 20:09:00

文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 小结

概要

当你在使用ROS2时遇到找不到可执行文件的错误时,首先需要执行以下步骤来诊断问题。首先,使用命令printenv AMENT_PREFIX_PATH(或者ros2 pkg prefix加上包的名称)来检查你的功能包路径是否被正确设置。如果路径没有被正确设置,检查你的环境变量和source命令是否配置正确。接着,前往AMENT_PREFIX_PATH/lib/package_name/路径下,查看是否生成了可执行文件。确保你自己的可执行文件命名正确,并且拥有执行权限。如果以上步骤都没有问题,那么问题可能出现在其他地方,需要进一步检查。

另外,还有两个关键点需要特别注意:

ROS2 run命令参数解析: ROS2 run命令会对传递的参数进行解析和处理。这意味着,如果你在使用ros2 run时带有参数,ROS2会按照一定的规则进行解析,确保参数被正确传递给可执行文件。这个解析过程通常可以在源码中找到,具体函数可能被命名为add_arguments,你可以在相关源码文件中查找。

在子进程中执行: ROS2 run命令实际上是在一个子进程中执行的。这意味着,当你调用ros2 run时,它会启动一个新的子进程来运行你指定的可执行文件。这种操作通常通过subprocess.Popen(cmd)这样的方式实现。子进程的独立性确保了在执行期间不会影响到主进程,同时也提供了更好的错误隔离和管理。

因此,在排查问题时,除了注意环境变量和可执行文件的路径,也要关注ROS2 run命令对参数的处理方式,以及它是如何在子进程中执行的。这些细节通常能够帮助你更快地定位问题所在,从而进行有效的修复。

整体架构流程

在ROS 2中,ros2 run 命令(源码地址:https://github.com/ros2/ros2cli.git)是一个至关重要的工具,它允许用户在指定的ROS包内运行可执行文件。本文将深入分析 ros2 run 命令的源代码,以及其中涉及的关键函数,以帮助您更好地理解其内部工作原理。

在我们的探讨中,将聚焦于 RunCommand 类及其所依赖的两个重要函数:get_executable_path 和 run_executable。通过解析这些关键函数,我们将揭示 ros2 run 命令背后的核心逻辑。

技术名词解释

在ROS 2中,ros2 run 命令的实现是通过 ros2cli 包提供的。具体而言,它的配置是通过 entry_points 来完成的。以下是相关的配置代码示例:

entry_points={
    'ros2cli.command': [
        'run = ros2run.command.run:RunCommand',
    ],
}

这段代码告诉ROS 2,当用户运行 ros2 run 命令时,应该调用 ros2run.command.run:RunCommand 这个类来处理。这种配置机制使得命令行工具的扩展变得非常灵活,开发者可以通过配置文件来定义新的命令和相应的处理类,从而实现命令行工具的功能扩展。

RunCommand 类是 ros2 run 命令的核心部分。以下是对 RunCommand 类的详细解读:

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."""

    # add_arguments函数用于定义命令行参数
    def add_arguments(self, parser, cli_name):
        # --prefix参数用于指定命令的前缀
        arg = parser.add_argument(
            '--prefix',
            help='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()
        # package_name参数用于指定ROS包的名称
        arg = parser.add_argument(
            'package_name',
            help='Name of the ROS package')
        arg.completer = package_name_completer
        # executable_name参数用于指定可执行文件的名称
        arg = parser.add_argument(
            'executable_name',
            help='Name of the executable')
        arg.completer = ExecutableNameCompleter(
            package_name_key='package_name')
        # argv参数用于传递给可执行文件的额外参数
        parser.add_argument(
            'argv', nargs=REMAINDER,
            help='Pass arbitrary arguments to the executable')

    # main函数是命令的入口点,处理用户输入并执行相应的操作
    def main(self, *, parser, args):
        try:
            # 获取可执行文件的路径
            path = get_executable_path(
                package_name=args.package_name,
                executable_name=args.executable_name)
        except PackageNotFound:
            raise RuntimeError(f"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)

在这段代码中,RunCommand 类继承自 CommandExtension 类,是一个用于解析命令行参数、查找可执行文件路径以及执行可执行文件的关键部分。以下是对这个类的主要功能进行解释:

add_arguments 函数定义了命令行参数。它包括 --prefix 参数(用于指定命令的前缀)、package_name 参数(指定ROS包的名称)、executable_name 参数(指定可执行文件的名称)以及 argv 参数(用于传递给可执行文件的额外参数)。

main 函数是命令的入口点。当用户输入命令并按下回车时,这个函数被调用。在 main 函数中,首先通过 get_executable_path 函数获取可执行文件的路径。如果找不到指定的包,会引发 PackageNotFound 异常。如果找到多个可执行文件,会引发 MultipleExecutables 异常。然后,如果找到可执行文件,会使用 run_executable 函数运行它。用户传递的前缀命令会被添加到执行命令之前。

这样,RunCommand 类负责处理用户输入的命令行参数,查找并运行相应的可执行文件。这个类的设计使得 ros2 run 命令具备了灵活性和可扩展性,可以方便地适应不同的使用场景。

get_executable_path 函数:

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:
            # 选择完全匹配的可执行文件
            paths2base[p] = basename
        elif sys.platform == 'win32':
            # 检查PATHEXT中列出的扩展名以进行匹配(无扩展名)
            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:
                # 选择有已知扩展名的匹配项
                paths2base[p] = basename
    if not paths2base:
        return None
    if len(paths2base) > 1:
        raise MultipleExecutables(paths2base.keys())
    return list(paths2base.keys())[0]

get_executable_path 函数用于查找指定ROS包内的可执行文件的路径。它的主要功能是在给定的ROS包内寻找与 executable_name 匹配的可执行文件。函数会根据操作系统和文件扩展名来选择最合适的可执行文件。具体步骤如下:

获取指定ROS包内的所有可执行文件路径。
遍历每个路径,检查文件名是否与 executable_name 完全匹配。如果匹配,将该路径作为匹配项。
如果在Windows系统下,并且文件是Python脚本(.py 文件),检查文件扩展名是否在PATHEXT 环境变量中,如果是,则也将该路径作为匹配项。
如果没有找到匹配项,返回 None。
如果找到多个匹配项,抛出 MultipleExecutables 异常。
如果只找到一个匹配项,返回该路径。

run_executable 函数:

def run_executable(*, path, argv, prefix=None):
    cmd = [path] + argv

    # 在Windows上,Python脚本通过解释器调用
    if os.name == 'nt' and path.endswith('.py'):
        cmd.insert(0, sys.executable)

    if prefix is not None:
        cmd = prefix + cmd

    process = subprocess.Popen(cmd)
    while process.returncode is None:
        try:
            process.communicate()
        except KeyboardInterrupt:
            # 子进程也会收到信号并应该关闭
            # 因此我们继续,直到进程完成
            pass
    if process.returncode != 0:
        if -process.returncode in signal.valid_signals() and os.name == 'posix':
            # 负值 -N 表示子进程由信号 N 终止
            print(ROS2RUN_MSG_PREFIX, signal.strsignal(-process.returncode))
        else:
            #

 打印一般的失败消息
            print(ROS2RUN_MSG_PREFIX, 'Process exited with failure %d' % (process.returncode))
    return process.returncode

run_executable 函数用于执行指定的可执行文件。它的主要功能是构建命令,并在子进程中运行该命令。函数还能够处理命令前缀(例如,gdb),并捕获子进程的输出。具体步骤如下:

构建命令,包括可执行文件路径和传递给该可执行文件的参数。
如果在Windows系统下,且可执行文件是Python脚本(.py 文件),在命令之前插入Python解释器路径。
如果有命令前缀(prefix),将命令前缀和命令拼接在一起。
使用 subprocess.Popen 创建一个新的子进程,运行构建好的命令。
等待子进程执行完毕,并捕获其输出。
如果子进程返回的退出码不为0,根据退出码输出相应的错误消息。
返回子进程的退出码。

这两个函数共同确保了 ros2 run 命令的功能:通过 get_executable_path 查找可执行文件路径,然后通过 run_executable 在子进程中运行该可执行文件,最终实现了ROS包内特定可执行文件的执行功能。

在ROS 2中,ros2 run 命令是一个重要的工具,允许用户在特定的ROS包内运行可执行文件。当我们使用这个命令时,ROS 2会通过调用 get_executable_paths 函数来查找指定ROS包内的可执行文件路径。这个函数的核心部分如下所示:

def get_executable_paths(*, package_name):
    prefix_path = get_prefix_path(package_name)
    if prefix_path is None:
        raise PackageNotFound(package_name)
    base_path = os.path.join(prefix_path, 'lib', package_name)
    executable_paths = []
    for dirpath, dirnames, filenames in os.walk(base_path):
        # 忽略以.开头的文件夹
        dirnames[:] = [d for d in dirnames if d[0] not in ['.']]
        dirnames.sort()
        # 选择可执行文件
        for filename in sorted(filenames):
            path = os.path.join(dirpath, filename)
            if os.access(path, os.X_OK):
                executable_paths.append(path)
    return executable_paths

这段代码的关键步骤在于 base_path = os.path.join(prefix_path, ‘lib’, package_name)。在这一步,可执行文件被搜索在前缀路径下的 lib 目录,然后再进入对应的功能包名称文件夹。在这个路径下,函数遍历所有文件,并选出具有执行权限的文件,将其路径添加到 executable_paths 列表中。

至于 prefix 是从哪里来的,这里有一个环境变量定义:AMENT_PREFIX_PATH。在使用 source 命令后,AMENT_PREFIX_PATH 会被设置为相应的路径,将包含可执行文件的路径添加进去。你可以使用 ros2 pkg prefix package_name 命令来确认一个功能包的 prefix。

因此,当你遇到找不到可执行文件的错误时,首先可以运行 printenv AMENT_PREFIX_PATH 命令,查看环境变量是否包含你的功能包路径。如果没有找到,检查是否正确使用了 source 命令,以及在 install 目录下是否存在该功能包。如果存在,继续检查第二步,打开对应路径 AMENT_PREFIX_PATH/lib/package_name/,看看是否有生成可执行文件,并且确认可执行文件的名称是否正确。如果名称正确,最后检查文件是否具有执行权限。

在这里插入图片描述

小结

总结来说,当在ROS 2中使用 ros2 run 命令时,确保按照以下步骤排查问题,以便成功找到并执行指定的可执行文件:

检查环境变量 AMENT_PREFIX_PATH: 运行 printenv AMENT_PREFIX_PATH 命令,确认环境变量是否包含你的功能包路径。如果没有找到,检查是否正确使用了 source 命令,以及在 install 目录下是否存在该功能包。

确认功能包的 prefix: 使用 ros2 pkg prefix package_name 命令确认功能包的 prefix。这个 prefix 是 AMENT_PREFIX_PATH 中的一个子路径,用于指定可执行文件的位置。

检查可执行文件的路径: 确认可执行文件是否位于 AMENT_PREFIX_PATH/lib/package_name/ 目录下。这是 ros2 run 命令搜索可执行文件的默认路径。

确认可执行文件的名称和权限: 确保可执行文件的名称正确,与在 ros2 run 命令中输入的名称一致。同时,确保文件具有执行权限,可以通过 chmod +x filename 命令来添加执行权限。

通过以上步骤的逐一排查,可以确保 ros2 run 命令能够顺利找到并执行指定的可执行文件,避免由于文件路径或权限问题引起的执行错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095850.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI :微软推出 AutoGen 框架,帮开发者创建基于大语言模型的复杂应用

本心、输入输出、结果 文章目录 AI :微软推出 AutoGen 框架,帮开发者创建基于大语言模型的复杂应用前言AutoGen 简介快速入门AutoGen 安装相关支持相关代码相关架构图弘扬爱国精神AI :微软推出 AutoGen 框架,帮开发者创建基于大语言模型的复杂应用 编辑:简简单单 Online z…

Chrome 浏览器关闭后再打开,需要重新登录账号,解决办法

最近(2023-10-15)每次打开 Chrome 浏览器,Chrome 自身账号以及各个网站账号都需要重新登录,电脑本身为家用,使用时间不多的情况下,频繁登录账号很痛苦,也很迷惑。现找到解决办法,记录…

基于SSM大学生竞赛活动平台

基于SSM大学生竞赛活动平台的设计与实现 开发语言:Java 数据库:MySQL 技术:SpringSpringMVCMyBatisVue 工具:IDEA/Ecilpse、Navicat、Maven 【主要功能】 前台系统主要功能实现:首页列表展示、自愿者招聘、竞赛新闻查…

汇编语言基础

引言 汇编语言是直接在硬件之上工作的编程语言,首先要了解硬件系统的结构,才能有效的应用汇编语言对其编程。汇编课程的研究重点放在如何利用硬件系统的编程结构和指令集有效灵活的控制系统进行工作。 基础知识 1.1机器语言 机器语言是机器指令的集合…

Stm32_标准库_13_串口蓝牙模块_手机与蓝牙模块通信

代码: #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Serial.h"char News[100] "";uint8_t flag 1;void Get_Hc05News(char *a){uint32_t i 0…

设计模式之是简单工厂模式

分类 设计模式一般分为三大类:创建型模式、结构型模式、行为型模式。 创建型模式:用于创建对象,共五种,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。结构型模式:用于处理类或对…

STM32 ---- 再次学习STM32F103C8T6/STM32F409IGT6

目录 一、环境搭建及介绍 关于STM32基础介绍 新建工程 外设案例 LED流水灯 蜂鸣器 上拉电阻和下拉电阻知识 电压比较器 c语言基础知识 类型、结构体、枚举 类型int8_t int16_t int32_t 宏替换 #define 和typedef用法 结构体两种填充方法 和 命名规则 枚举用法 常用…

云安全——云计算基础

0x00 前言 学习云安全,那么必然要对云计算相关的内容进行学习和了解,所以云安全会分为两个部分来进行,首先是云计算先关的内容。 0x01 云计算 广泛传播 云计算最早大范围传播是2006年,8月,在圣何塞【1】举办的SES&a…

Vs2017搭建QT开发环境

前置条件: vs2017 前提需要安装Qt的插件 : 若是没有,通过 “工具->扩展和更新->联机->Qt Visual Studio Tools”,安装Qt Visual Studio Tools 1、新建工程"文件->新建->项目",出现如下界面…

Yakit工具篇:爆破与未授权检测的使用

简介(来自官方文档) 爆破和未授权检测是网络安全领域中一种常见的测试技术,其主要目的是测试系统或应用程序中的口令是否强健,Yakit的爆破与未授权检测模块则实现了该部分的内容。 这个模块可以对多种常见协议和服务(如ftp、memcached、mon…

【操作系统】信号量机制(整型信号量、记录型信号量),用信号量实现进程互斥、同步、前驱关系

🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 Redis 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 信号量 一、信号量机制1.1 整型信号量1.2 记…

05_51单片机led流水线的实现

1:step创建一个新的项目并将程序烧录进入51单片机 以下是51单片机流水线代码的具体实现 #include <REGX52.H>void Delay500ms() //11.0592MHz {unsigned char i, j, k;i 4;j 129;k 119;do{do{while (--k);} while (--j);} while (--i); }void main(){while(1){P1 0…

深入理解React中的useEffect钩子函数

引言&#xff1a; React是一种流行的JavaScript库&#xff0c;它通过组件化和声明式编程的方式简化了前端开发。在React中&#xff0c;一个核心概念是组件的生命周期&#xff0c;其中包含了许多钩子函数&#xff0c;用于管理组件的不同阶段。其中之一就是useEffect钩子函数&…

完成了一个小项目:修改了一个用PHP+MySQL写的建网站用的CMS原程序

最近一段时间&#xff0c;我建了一个网站。建一个网站及简单也复杂。要功能合适&#xff0c;界面合适&#xff0c;也不是容易的事。开始用了一个现成的建站软件WordPress&#xff0c;但是对界面不满意。后来找了另外一个带源码的程序&#xff0c;修改该程序花了十多天时间。到目…

metaRTC7集成lvgl ui demo编译指南

概要 开源轻量级嵌入式图形库lvgl:Light and Versatile Graphics Library&#xff0c;最低只需8kb内存&#xff0c;可为任何 MCU、MPU 和显示类型创建漂亮的 UI。 metaRTC新增lvgl demo&#xff0c;可在linux下编译运行。 源码下载 https://github.com/metartc/metaRTC/rel…

Spring Cloud的革新:服务网格和云原生整合

文章目录 介绍Spring Cloud服务网格的兴起Spring Cloud与Service Mesh的整合1. 服务发现2. 负载均衡3. 故障处理4. 安全性 云原生整合结论 &#x1f389;欢迎来到架构设计专栏~Spring Cloud的革新&#xff1a;服务网格和云原生整合 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f37…

【力扣1876】长度为三且各字符不同的子字符串

&#x1f451;专栏内容&#xff1a;力扣刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、题目描述二、题目分析 一、题目描述 题目链接&#xff1a;长度为三且各字符不同的子字符串 如果一个字符串不含有任何…

一卷到底,大明哥带你横扫 Netty

上一个死磕 Java 专栏【死磕 NIO】(当然写的不是很好&#xff0c;争取今年将它重写一遍)是**【死磕 Netty】**的铺垫&#xff0c;对于我们 Java 程序员而言&#xff0c;我们在实际开发过程一般都不会直接使用 Java NIO 作为我们的网络编程框架&#xff0c;因为写出一套高质量的…

【C++初阶(二)缺省参数与函数重载】

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

Kwik Trip IT系统遭遇神秘的“网络事件”导致系统故障

导语 近日&#xff0c;美国连锁便利店和加油站Kwik Trip遭遇了一系列神秘的业务中断&#xff0c;这很可能是一次赎金软件攻击。本文将为您详细介绍此次事件的背景和影响&#xff0c;并探讨赎金软件攻击对企业和个人的危害。 神秘的“网络事件” Kwik Trip是一家在密歇根州、明尼…