使用ROS时,经常需要启动多个launch文件,有时一个个启动太麻烦,可以通过编写sh脚本实现快捷启动。

1 编写sh脚本文件启动多个launch文件(方式一)

该种方式是为每一个launch文件单独打开一个终端,且一般情况下同一launch文件中所有node的输出信息会显示在同一个终端中,除另有说明(详见本文章节 3)。

例代码如下:

#! /bin/bash

gnome-terminal -- bash -c "cd /home/hahaha/ws_ego; source devel/setup.bash; roslaunch ego_planner rviz.launch; exec bash"

echo “launch1  successfully started”
# 两个roslauch之间需要间隔一段时间,否则会相互抢占roscore,导致其中一个roslaunch失败,报runid错误
sleep 0.7s  

gnome-terminal -- bash -c "cd /home/hahaha/ws_ego; source devel/setup.bash; roslaunch ego_planner run_in_sim.launch; exec bash"

echo “launch2  successfully started”

说明:

  • #! /bin/bash: 第一行一定要是这句话,指明此脚本使用 /bin/bash 解释执行
  • gnome-terminal: 打开一个新的终端窗口,几个launch文件就写几个gnome-terminal
  • -c: 后面写需要执行的命令,用分号 : 分隔相邻的命令
  • exec bash: 可以确保执行脚本后保持窗口不消失,还需要配合前面的 -- bash 使用
  • sleep: 连续启动两个launch之间需要相隔一定时间,否则会相互抢占roscore,导致其中一个roslaunch失败,报runid错误
  • -t ' 是指定新建窗口或标签页的名称,但是不知道为啥在这里没有作用

2 编写sh脚本文件启动多个launch文件(方式二)

该种方式是将所有launch文件都在一个相同的终端中打开,且一般情况下所有launch文件中所有node的输出信息会显示在该终端中,除另有说明(详见本文章节 3)。

示例代码如下:

roslaunch phy_simulator rviz.launch            & sleep 1; # vis
roslaunch phy_simulator phy_simulator_parking.launch & sleep 1; # simulator
roslaunch ai_agent_planner moving_obstacle.launch & sleep 1.0;
roslaunch planning_integrated map.launch & sleep 1; # just for visualization
roslaunch planning_integrated park.launch & sleep 1; # focus this!
wait

说明:

(1)脚本首行不是 #!/bin/bash 的原因说明

在 Unix 和 Linux 系统中,脚本文件必须以 #! 开头,并指定解释器路径,才能正确地被系统识别为可执行的脚本文件。例如,如果要使用 Bash 解释器来执行脚本文件,就需要在文件的第一行添加 #!/bin/bash。

然而,在这个脚本中,既没有使用 #!/bin/bash 指定 Bash 解释器,也没有使用其他解释器路径。实际上,这个脚本的开头并不是以 #! 开头,因此系统会默认将其作为一个普通的文本文件进行处理。然后,当用户在终端中执行该脚本时,会使用当前终端所使用的 Shell 解释器来运行这个脚本。

因此,这个脚本可以在不使用 #!/bin/bash 的情况下成功执行,但这种做法并不推荐。在编写脚本文件时,应该始终使用 #! 语法来指定脚本所需的解释器,以确保脚本能够正确地被系统识别和执行。

(2)脚本中 & 符号和 wait 命令的使用说明

在 shell 脚本中,wait 命令的作用是等待所有在当前 shell 中启动的进程都结束后再退出脚本。它通常与 & 符号一起使用,也就是将某个命令放在后台运行,并立即返回控制权给 shell,使脚本可以继续执行后续的其他命令,然后通过 wait 命令等待后台进程执行完毕。

在本例程中,& 符号将 roslaunch 命令放到后台运行,同时脚本继续执行接下来的命令。sleep 命令会暂停脚本执行指定的时间,以确保前面的命令已经完成了启动工作。最后,wait 命令会等待所有后台进程都结束后才退出脚本,以避免可能出现未完成的进程或僵尸进程等问题。

(3)脚本中 & 符号用法补充说明

& 符号如果放置在命令的最后面,那么它表示将该命令放到后台运行,例如: roslaunch phy_simulator rviz.launch &
如果放置在两个命令之间,那么它表示同时执行这两个命令,而且前一个命令在后台运行,后一个命令在前台运行,例如:roslaunch phy_simulator rviz.launch & sleep 1

(4)程序后台运行时其仍会将信息输出到当前终端显示

当一个命令被放到后台运行时,它的标准输出仍然会被发送到当前终端,并且可能会与其它正在运行的程序的输出混合。

如果希望将后台进程的输出保存到文件中,可以使用重定向符号 > 或者 >> 将输出重定向到文件中,例如:

$ ./my_program > output.log &

这样,my_program 程序的标准输出就会被重定向到名为 output.log 的文件中,而不是显示在终端上。如果希望同时重定向标准输出和标准错误流,可以使用 2>&1 将标准错误流重定向到标准输出,例如:

$ ./my_program > output.log 2>&1 &

这样,my_program 程序的标准输出和标准错误流都会被重定向到名为 output.log 的文件中。

(5)后台执行程序相关命令补充知识

  • jobs -------------- 查看在后台执行的进程

  • fg %n ------------ 将后台执行进程n调到前台执行,n表示jobnumber(通过jobs查看的进程编号,而非pid)

  • ctrl+z ------------ 将在前台执行的进程,放到后台并挂起

  • bg %n ----------- 将在后台挂起的进程,继续执行

  • ctrl+c ------------ 前台进程终止

  • kill %n ----------- 杀掉后台运行的进程,n表示jobnumber(通过jobs查看的进程编号,而非pid)

3 单一launch文件为某node单独新开一个终端运行的方法

运行 roslaunch 时,所有的 node 共用一个相同的 terminal,这对于一些需要从控制台输入的 node 很不方便。可以使用 node 标签下的 launch-prefix 属性,来使得某个节点在另一个新开的 terminal中运行。该属性相当于在执行启动命令时加上一段命令前缀。

launch-prefix="gnome-terminal --",即等价于 gnome-terminal -- rosrun beginner_tutorials listener

实际应用例子如下:

<launch>

    <!--  该 node 在当前的终端中输出结果  -->
	<node  name = "talker" pkg = "beginner_tutorials" type = "talker" output = "screen">
    </node>
   
    <!--  该 node 在新开的终端中输出结果  -->
    <node  name = "listener" pkg = "beginner_tutorials" type = "listener" output = "screen" launch-prefix="gnome-terminal  --">
    </node>

</launch>

说明:

launch-prefix="gnome-terminal --tab -t 'new terminal' --"--tab 是新建标签页, --window 是新建窗口(默认情况),-t 'new terminal' 是指定新建窗口或标签页的名称。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐