一、简单实操
1.创建/打开一个功能包
mkdir -p my_ws/src
cd my_ws/src
ros2 pkg create my_pkg_example --build-type ament_python
2.创建Launch文件的存放目录
将所有启动文件都存储在launch包内的目录中。
目录结构如下所示:
src/
my_pkg_example/
launch/
package.xml
py_launch_example/
resource/
setup.cfg
setup.py
test/
3.修改setup.py文件
为了让 colcon 找到启动文件,我们需要使用 参数告知 Python 的安装工具我们的启动data_files文件setup。
import os
from glob import glob
from setuptools import setup
package_name = 'my_pkg_example'
setup(
# Other parameters ...
data_files=[
# ... Other data files
# Include all launch files.
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*launch.[pxy][yma]*')))
]
)
4.编写Launch文件
在launch目录中,创建一个名为my_test.launch.py文件
import launch
import launch_ros.actions
def generate_launch_description():
return launch.LaunchDescription([
launch_ros.actions.Node(
package='demo_nodes_cpp',
executable='talker',
name='talker'),
])
5.最后就可以构建并运行啦!
colcon build
ros2 launch my_pkg_example my_test.launch.py
二、大型项目中的使用技巧
1.完整代码示例
在/launch文件夹中创建一个文件launch_turtlesim.launch.py 内容如下:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
def generate_launch_description():
turtlesim_world_1 = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('launch_tutorial'), 'launch'),
'/turtlesim_world_1.launch.py'])
)
broadcaster_listener_nodes = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('launch_tutorial'), 'launch'),
'/broadcaster_listener.launch.py']),
launch_arguments={'target_frame': 'carrot1'}.items(),
)
mimic_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('launch_tutorial'), 'launch'),
'/mimic.launch.py'])
)
fixed_frame_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('launch_tutorial'), 'launch'),
'/fixed_broadcaster.launch.py'])
)
rviz_node = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('launch_tutorial'), 'launch'),
'/turtlesim_rviz.launch.py'])
)
return LaunchDescription([
turtlesim_world_1,
broadcaster_listener_nodes,
mimic_node,
fixed_frame_node,
rviz_node
])
2.内包含turtlesim_world_1.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():
config = os.path.join(
get_package_share_directory('launch_tutorial'),
'config',
'turtlesim.yaml'
)
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtlesim2',
name='sim',
parameters=[config]
)
])
3.参数设置
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():
config = os.path.join(
get_package_share_directory('launch_tutorial'),
'config',
'turtlesim.yaml'
)
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtlesim2',
name='sim',
parameters=[config]
)
])
现我们在 /config 文件夹中创建一个配置文件turtlesim.yaml ,它将由我们的启动文件加载。
/turtlesim2/sim:
ros__parameters:
background_b: 255
background_g: 86
background_r: 150
/turtlesim3/sim:
background_b
background_g
background_r
我们可以使用通配符语法,而不是为使用相同参数的同一节点创建新配置
/**:
ros__parameters:
background_b: 255
background_g: 86
background_r: 150
加载相同的 YAML 文件不会影响第三个turtlesim 世界的外观。原因是它的参数存储在另一个命名空间下。
4.ROS2节点复用
现在创建一个broadcaster_listener.launch.py文件
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
DeclareLaunchArgument(
'target_frame', default_value='turtle1',
description='Target frame name.'
),
Node(
package='turtle_tf2_py',
executable='turtle_tf2_broadcaster',
name='broadcaster1',
parameters=[
{'turtlename': 'turtle1'}
]
),
Node(
package='turtle_tf2_py',
executable='turtle_tf2_broadcaster',
name='broadcaster2',
parameters=[
{'turtlename': 'turtle2'}
]
),
Node(
package='turtle_tf2_py',
executable='turtle_tf2_listener',
name='listener',
parameters=[
{'target_frame': LaunchConfiguration('target_frame')}
]
),
])
在此文件中,我们声明了target_frame默认值为 的启动参数turtle1。默认值意味着启动文件可以接收参数以转发到其节点,或者如果未提供参数,它将传递默认值到其节点。
之后,我们turtle_tf2_broadcaster在启动期间使用不同的名称和参数两次使用该节点。这允许我们复制相同的节点而不会发生冲突。
我们还启动一个turtle_tf2_listener节点并设置target_frame上面声明和获取的参数。
5.参数覆盖
我们broadcaster_listener.launch.py在顶级启动文件中调用了该文件。除此之外,我们还传递了它的target_frame启动参数,如下所示:
broadcaster_listener_nodes = IncludeLaunchDescription(
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('launch_tutorial'), 'launch'),
'/broadcaster_listener.launch.py']),
launch_arguments={'target_frame': 'carrot1'}.items(),
)
此语法允许我们将默认目标目标框架更改为carrot1。如果您想turtle2跟随turtle1而不是跟随carrot1,只需删除定义的行即可launch_arguments。这将分配target_frame其默认值,即turtle1
6.重新映射
现在创建一个mimic.launch.py文件
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='mimic',
name='mimic',
remappings=[
('/input/pose', '/turtle2/pose'),
('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
]
)
])
该启动文件将启动mimic节点,该节点将向一个turtlesim发出命令以跟随另一个。
该节点旨在接收主题上的目标姿势/input/pose。
在我们的例子中,我们想要从/turtle2/pose主题重新映射目标姿势。
最后,我们将/output/cmd_vel主题重新映射到/turtlesim2/turtle1/cmd_vel。
7.千万记住更新setup.py
import os
from glob import glob
from setuptools import setup
...
data_files=[
...
(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', '*.yaml'))),
],