赞
踩
每当我们运行一个ROS节点,都需要打开一个新的终端运行一个命令。机器人系统中节点很多,每次都这样启动好麻烦呀。有没有一种方式可以一次性启动所有节点呢?答案当然是肯定的,那就是Launch启动文件,它是ROS系统中多节点启动与配置的一种脚本。
Launch文件是基于Python描述的
核心目的是启动节点,在命令行中输入的各种参数,在launch文件中也有很多的代码模板,还可以是使用Python原有的编程功能。
$ ros2 run learning_launch simple.launch.py
from launch import LaunchDescription #Launch文件的描述类
from launch_ros.actions import Node #节点启动的描述类
def generate_launch_description():
return LaunchDescription([
Node(
package='learning_topic'
executable='topic_helloworld_pub'
),
Node(
package='learning_topic'
executable='topic_helloworld_sub'
),
])
'''
# 配置一个节点的启动
# 节点所在的功能包
# 节点的可执行文件
'''
我们想要运行一个Rviz可视化上位机,并且加载某一个配置文件,使用命令行的话,是这样的:
$ ros2 run rviz2 rviz2 -d <PACKAGE-PATH>/rviz/turtle_rviz.rviz
命令后边还得跟一长串配置文件的路径,如果放在launch文件里,启动就优雅很多了:
$ ros2 launch learning_launch rviz.launch.py
代码解析
learning_launch/rviz.launch.py
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
rviz_config=os.path.join(
get_package_share_directory('learning_launch'),
'rviz',
'turtle_rviz.rviz'
)
return LaunchDescription([
Node(
package='rviz2', #节点所在功能包
executable='rviz2', #可执行文件
name='rviz2', #对节点重新命名
arguments=['-d',rviz_config] #加载命令行参数
)
])
ROS社区中的资源非常多,当我们使用别人代码的时候,经常会发现通信的话题名称不太符合我们的要求,能否对类似的资源重新命名呢?
为了提高软件的复用性,ROS提供了资源重映射的机制,可以帮助我们解决类似的问题。
举例:启动一个终端,运行如下例程,很快会看到出现了两个小海龟仿真器界面;再打开一个终端,发布如下话题,让海龟1动起来,海龟2也会一起运动:
$ ros2 launch learning_launch remapping.launch.py
$ ros2 topic pub -- turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
learning_launch/remapping.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def geneate_launch_description(): # 自动生成launch文件的函数
return LaunchDesrcription( # 返回launch文件的描述信息
Node( # 配置一个节点的启动
paskage='turtlesim', # 节点所在的功能包
namespace='turtlesim1', # 节点所在的命名空间
executable='turtlesim_node', # 节点的可执行文件名
name='sim'
),
Node(
paskage='turtlesim',
namespace='turtlesim2',
executable='turtlesim_node',
name='sim'
)
Node(
paskage='turtlesim',
executable='mimic',
name='mimic'
remappings=[
('/input/pose','/turtlesim1/turtle1/pose'),
('/output/cmd_vel','turtlesim2/turtle1/cmd_vel')
]
)
)
'''
运行此launch文件后,使用ros2 topic list查询服务可知,现在正在运行的话题有:
/turtlesim1/turtle1/cmd_vel
/turtlesim1/turtle1/color_sensor
/turtlesim1/turtle1/pose
/turtlesim2/turtle1/cmd_vel
/turtlesim2/turtle1/color_sensor
/turtlesim2/turtle1/pose
...
前面的1和2就是launch文件里面设置的命名空间!
功能包中的mimic节点的功能就是订阅位置话题,然后转化成速度指令发送出去,因此当控制海龟1运动时,海龟2也运动!
'''
$ ros2 launch learning_launch parameters.launch.py
在启动的海龟仿真器中,我们看到背景颜色被改变了,这个颜色参数的设置就是在launch文件中完成的。
from launch import LaunchDescription # launch文件的描述类
from launch.actions import DeclareLaunchArgument # 声明launch文件内使用的Argument类
from launch.substitutions import LaunchConfiguration, TextSubstitution
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
background_r_launch_arg = DeclareLaunchArgument(
'background_r', default_value=TextSubstitution(text='0') # 创建一个Launch文件内参数(arg)background_r
)
background_g_launch_arg = DeclareLaunchArgument(
'background_g', default_value=TextSubstitution(text='84') # 创建一个Launch文件内参数(arg)background_g
)
background_b_launch_arg = DeclareLaunchArgument(
'background_b', default_value=TextSubstitution(text='122') # 创建一个Launch文件内参数(arg)background_b
)
return LaunchDescription([ # 返回launch文件的描述信息
background_r_launch_arg, # 调用以上创建的参数(arg)
background_g_launch_arg,
background_b_launch_arg,
Node( # 配置一个节点的启动
package='turtlesim',
executable='turtlesim_node', # 节点所在的功能包
name='sim', # 对节点重新命名
parameters=[{ # ROS参数列表
'background_r': LaunchConfiguration('background_r'), # 创建参数background_r
'background_g': LaunchConfiguration('background_g'), # 创建参数background_g
'background_b': LaunchConfiguration('background_b'), # 创建参数background_b
}]
),
])
以上例程我们在launch文件中一个一个的设置参数,略显麻烦,当参数比较多的时候,建议使用参数文件进行加载。
learning_launch/parameters_yaml.launch.py
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
config = os.path.join( # 找到参数文件的完整路径
get_package_share_directory('learning_launch'),
'config',
'turtlesim.yaml'
)
return LaunchDescription([ # 返回launch文件的描述信息
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
executable='turtlesim_node', # 节点的可执行文件名
namespace='turtlesim2', # 节点所在的命名空间
name='sim', # 对节点重新命名
parameters=[config] # 加载参数文件
)
])
这里的config路径对应的文件内容是:
/turtlesim2/sim:
ros_parameters:
background_b: 0
background_g: 0
background_r: 0
在复杂的机器人系统中,launch文件也会有很多,此时我们可以使用类似编程中的include机制,让launch文件互相包含。
learning_launch/namespaces.launch.py
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch.actions import IncludeLaunchDescription # 节点启动的描述类
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import GroupAction # launch文件中的执行动作
from launch_ros.actions import PushRosNamespace # ROS命名空间配置
def generate_launch_description(): # 自动生成launch文件的函数
parameter_yaml = IncludeLaunchDescription( # 包含指定路径下的另外一个launch文件
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('learning_launch'), 'launch'),
'/parameters_nonamespace.launch.py'])
)
parameter_yaml_with_namespace = GroupAction( # 对指定launch文件中启动的功能加上命名空间
actions=[
PushRosNamespace('turtlesim2'),
parameter_yaml]
)
return LaunchDescription([ # 返回launch文件的描述信息
parameter_yaml_with_namespace
])
一定不要忘记,编写完aunch文件后要在setup.py里面的data_files里面添加这些文件的路径,否则在编译的过程中系统不会把这些文件拷贝到安装空间里面去(install)。
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
(os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.*'))),
(os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.*'))),
],
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。