launch系统可以分开进行讨论,大致可以分为如下
- 进程和各种节点样式的调用约定
- 事件报告系统
- 系统描述和静态分析
- 系统描述的执行和验证
- 测试
下面几节的目的是列举出launch系统可以做什么事情,以及如何交互,但是他不是必须要求的。
Calling Conventions
为了启动一个launch系统,我们首先要思考的是如何理解被启动的描述文件。
calling convention(调用约定)的意思是描述描述launch系统与它正在执行和监视的任何东西之间的“接口”或“契约”。该合同涵盖了初始执行、运行期间的活动、launch系统的信号处理和行为以及关闭。
操作系统进程
这些实体最基础的版本就是操作系统进程
Execution(执行器)
launch系统需要知道如何执行他们,为此,需要
- 可执行文件的名字
- 环境变量((
PATH
,LD_LIBRARY_PATH
,DL_PRELOAD
, etc…)) - 命令行参数
- 工作目录
- launch前缀
Runtime
在运行的时候,launch系统会监控操作系统进程所有的
- stdout pipe
- stderr pipe
launch系统可以选择捕获这些管道,用于记录或抑制输出到控制台,或者它可以将这些管道连接到一个现有的pty(远程连接的虚拟终端),比如终端的stdout和/或stderr管道或一个空管道(例如/dev/null)。
当捕获进程的输出管道时, launch系统可以以用户可以实时处理的方式报告这些数据,或者可以通过用户定义的过滤器传递数据,在过滤器匹配时生成用户处理的事件。
Termination
如果操作系统进程终止,并因此返回一个返回代码,launch系统将报告该事件,并可以以用户定义的方式处理它。终止包括预期的终止(如返回main()或使用exit())和意外的终止(如中止陷阱或分割故障或总线错误)。
ROS1允许一些常用的退出处理方式
- require=true: 如果这个进程退出就结束整个launch
- respawn=true: 如果这个进程退出了,就以一样的设置方式重启
- respawn_delay=N:如果需要重启,设置重启间隔的时间
启动系统可以启动一个操作系统进程的终止过程。首先在子进程上发送SIGINT
信号。如果这并没有导致进程的终止,那么基于启动系统的配置可能会发生以下几件事:
- 经过一段时间,发送SIGTERM
- 经过一段时间,发送SIGKILL
在默认情况下,launch系统会
- 发送SIGINT
- 经过一段时间,发送SIGTERM
- 经过一段时间,发送SIGKILL
当一个事件(内置的或用户生成的)启动关闭时,launch系统将启动这个进程,例如,当一个具有require=true退出处理程序的进程终止时,或者当launch系统本身收到SIGINT信号时。
如果启动系统本身收到SIGTERM信号,它将向所有子进程发送SIGKILL信号并立即退出。
之前规则的基本原理是,如果有人试图发送SIGTERM给launch系统,他们可能是在向发射系统发送SIGINT后不耐烦地这样做,因此发射系统应该尝试快速退出。快速退出有望避免鼓励用户SIGKILL启动系统,这可能会导致子进程不正确地关闭,甚至可能成为僵死进程。
Shell Evaluation
Remote Operating System Processes
ROS Nodes
任何操作系统进程都可以通过拥有至少一个ROS节点而变得特定于ROS的进程。在进程中拥有一个或多个“普通”ROS节点并不会增加新的标准化方法来将信息输入或输出包含这些节点的操作系统进程,尽管可以在运行时访问ROS主题、服务、参数等。但是,它确实在执行过程中添加了一些特定类型的输入,而且它还会影响进程对信号的反应。
这适用于普通的结点,对于ROS结点管理来说,他有更多的功能
执行
除了“操作系统进程”部分的“执行”部分,其中包含ROS节点的进程则需要考虑其他元素,例如:
包名+执行节点名 而不是 执行节点名
ROS 特定的环境变量(如 ROS_DOMAIN_ID, RMW_IMPLEMENTATION)
- ROS 特定的命令行参数
- Varies for single Node processes and multi Node processes
- Change node name or namespace
- Remap topics, services, actions, parameters, etc…
- Initialize parameter values
在每一种情况下,ROS特定的构造都可以用“操作系统进程”的“执行”小节描述的现有机制来表示,也就是说,ROS特定的构造可以扩展为命令行参数或环境变量。因此,launch系统能够接受ROS特定的声明,例如“将‘image’重新映射到‘left/image’”,并将它们隐式地转换为正常操作系统进程可以使用的术语,比如环境变量或命令行参数,例如在命令行参数中添加image:=left/image。然而,一个给定的ROS特定声明被转换成什么,取决于在这个过程中如何使用节点,但后面的章节将详细介绍这一点。
Runtime
在运行时,“普通”ROS节点不会暴露操作系统进程之外的任何新内容。它确实有ROS主题、服务、参数等,但没有一个是标准化的,在这个时候对launch系统有用。
它也不会以任何特殊的方式对stdin作出反应,但是包含ROS节点的进程确实倾向于为SIGINT提供一个信号处理程序,它会进行更优雅的关闭,但这不是强制的。发送SIGINT信号通常会导致大多数节点在使用rclcpp中的“spin”函数或轮询rclcpp::ok()时关闭,这是推荐的。
Termination
除了操作系统进程(返回代码)所观察到的外,ROS节点(节点,而不是进程)的终止在外部是不可观察的。
Managed ROS Nodes
ROS node 是有生命周期的,即Managed ROS Nodes,每一个ROS节点会有额外的runtime 状态,他可以直接通过launch系统访问和使用。或者将其传递给事件系统,或者在将其传递给事件系统之前进行聚合。
“Managed ROS Nodes”再次建立在以前的实体上,它继承了正常ROS节点以及操作系统进程的所有执行、运行和终止特征。
执行
Managed ROS Nodes 在执行时不会在“普通”ROS节点的添加之上添加任何额外的输入或特定配置,至少此时不会。以后可能会发生变化,所以请参考设计文档3或有关该主题的未来文档。
Runtime
在运行时,Managed ROS Nodes 在节点状态发生变化时发出事件。这至少是在一个主题上发出的,但也可以通过其他方式捕获、聚合和/或交流。这些状态变化可以由启动系统本身或用户使用,它们都可以对这些变化作出反应。
例如,用户可以这样表达“当节点A进入Active状态时,启动节点B和C”或“如果节点A退出并返回代码或进入Finalized状态,关闭一切”。
Termination
Managed ROS Nodes 在终止时有一些额外的可观察效果(节点,不一定是包含它的进程)。Managed节点在终止时通过shutingdown过渡状态后,进入最终状态。因为这些是状态转换,所以可以通过生命周期事件系统观察到它们,至少可以通过ROS主题lifecycle_state(可能会发生更改)。
托管ROS节点如何过渡到最终状态(或任何其他状态)的机制将不在本文档中决定。相反,实现或一些其他特定于生命周期的文档将涵盖这些内容。但是,您可以想象这个转换可以由Node本身自动处理,或者通过启动发送一个状态转换请求,或者通过启动发送一个特定的信号。
处理单个节点
本节以及后面的小节的内容会描述不同的可能的节点组合。在每一个例子中,他们都继承了 “ROS nodes” or the “Managed ROS nodes”的行为方式。但在本小中 , “如何”通信ROS特定的option 被更详细地描述。
最简单的例子是一个进程中有一个ROS结点,这在ROS1中非常常见,在ROS1中一个节点一个进程,但是在ROS2中,一个进程可以有多个节点。
因为只有一个ROS节点,所以命令行参数不需要显式地说明它们应用于哪个节点。例如,改变单个节点的命名空间可以用命令行参数__ns:=new_namespace来表示。
即便这里只有一个节点,也不需要在进程启动时启动该节点,也不需要在节点关闭和/或销毁时结束进程。
如果这个节点是一个managed node, 他就可以使用生命周期事件来追溯节点的生命周期。实际上,具有单个节点的进程可以启动一个节点,运行一段时间,然后销毁它,然后再次创建它。
因此,单节点进程的最大影响是可以简化命令行参数和环境变量的配置。
处理多个节点
处理多节点和处理单个节点是非常类似的,但是在配置,传参方面需要细化对哪个节点进行设置。remapping文档详细介绍了如何使用命令行参数有选择地配置多个节点,因此请在这里查看最新的详细信息。
考虑一个程序,有两个相机驱动node,名字分别为camera1
和camera2
,我们可以通过如下方式来配置命名空间camera1:__ns:=left camera2:__ns:=right
.
动态加载节点
动态加载节点意味着在容器进程中生成它,而容器进程在被要求加载节点之前并不知道该节点。容器进程是一个独立的可执行文件,它在自身内部加载和执行节点。
Container Process API
Event Subsystem
本文的这一部分介绍了启动系统中的事件子系统,它负责生成事件并将它们报告给用户和它自己,以便可以处理这些事件。
按来源分类的事件
来源于事件子系统的事件可以分为两类:launch系统可以直接观察到的,以及其他系统可以直接观察到的。因此,如果我们想让其他应用程序或用户使用这些事件,那么只有启动系统可以观察到的事件必须通过事件系统公开。