|
@@ -1,8 +1,10 @@
|
|
|
+# 1.启动管理工具-Launch
|
|
|
+
|
|
|
大家好,我是小鱼。今天我们来讲一讲机器人启动系统之Launch。
|
|
|
|
|
|
## 1.Launch启动工具介绍
|
|
|
|
|
|
-### 问题描述
|
|
|
+### 1.1 问题描述
|
|
|
|
|
|
对于一个机器人系统来说,往往由很多个不同功能的节点组成,启动一个机器人系统时往往需要启动多个节点,同时根据应用场景和机器人的不同,每个节点还会有不同的配置项。
|
|
|
|
|
@@ -35,53 +37,65 @@ ROS2的launch文件有三种格式,python、xml、yaml。其中ROS2官方推
|
|
|
|
|
|
我们的目标是编写一个launch文件,最后使用launch指令,同时启动服务端和客户端节点。
|
|
|
|
|
|
-#### 2.2.1 创建文件
|
|
|
+#### 2.2.1 创建功能包和launch文件
|
|
|
|
|
|
-在功能包`village_li`和`village_wang`目录下创建`launch`文件夹。
|
|
|
+创建文件夹和功能包,接着touch一个launch文件,后缀为`.py`。
|
|
|
|
|
|
-
|
|
|
+```
|
|
|
+mkdir -p chapt4/chapt4_ws/src
|
|
|
+cd chapt4/chapt4_ws/src
|
|
|
+ros2 pkg create robot_startup --build-type ament_cmake --destination-directory src
|
|
|
+mkdir -p src/robot_startup/launch
|
|
|
+touch src/robot_startup/launch/example_action.launch.py
|
|
|
+```
|
|
|
|
|
|
-#### 2.2.2 编写launch文件
|
|
|
+#### 2.2.2 启动多个节点的示例
|
|
|
|
|
|
-接着我们开始编写`launch`文件,在`village_li`目录下创建`village.launch.py`文件。
|
|
|
我们需要导入两个库,一个叫做LaunchDescription,用于对launch文件内容进行描述,一个是Node,用于声明节点所在的位置。
|
|
|
|
|
|
-接着我们就可以编写代码了,注意这里要定一个名字叫做`generate_launch_description`的函数,ROS2会对该函数名字做识别。
|
|
|
+> 注意这里要定一个名字叫做`generate_launch_description`的函数,ROS2会对该函数名字做识别。
|
|
|
|
|
|
```python
|
|
|
# 导入库
|
|
|
from launch import LaunchDescription
|
|
|
from launch_ros.actions import Node
|
|
|
|
|
|
-# 定义函数名称为:generate_launch_description
|
|
|
def generate_launch_description():
|
|
|
- # 创建Actions.Node对象li_node,标明李四所在位置
|
|
|
- li4_node = Node(
|
|
|
- package="village_li",
|
|
|
- executable="li4_node"
|
|
|
- )
|
|
|
- # 创建Actions.Node对象wang2_node,标明王二所在位置
|
|
|
- wang2_node = Node(
|
|
|
- package="village_wang",
|
|
|
- executable="wang2_node"
|
|
|
- )
|
|
|
+ """launch内容描述函数,由ros2 launch 扫描调用"""
|
|
|
+ action_robot_01 = Node(
|
|
|
+ package="example_action_rclcpp",
|
|
|
+ executable="action_robot_01"
|
|
|
+ )
|
|
|
+ action_control_01 = Node(
|
|
|
+ package="example_action_rclcpp",
|
|
|
+ executable="action_control_01"
|
|
|
+ )
|
|
|
# 创建LaunchDescription对象launch_description,用于描述launch文件
|
|
|
- launch_description = LaunchDescription([li4_node,wang2_node])
|
|
|
+ launch_description = LaunchDescription(
|
|
|
+ [action_robot_01, action_control_01])
|
|
|
# 返回让ROS2根据launch描述执行节点
|
|
|
return launch_description
|
|
|
+
|
|
|
```
|
|
|
|
|
|
-#### 2.2.3 修改setup.py将launch文件拷贝到安装目录
|
|
|
+#### 2.2.3 将launch文件拷贝到安装目录
|
|
|
|
|
|
如果你编写完成后直接编译你会发现install目录下根本没有你编写的launch文件,后续launch自然也找不到这个launch文件。
|
|
|
|
|
|
+因为我们用的是`ament_cmake`类型功能包,所以这里要使用cmake命令进行文件的拷贝
|
|
|
+
|
|
|
+```cmake
|
|
|
+install(DIRECTORY launch
|
|
|
+ DESTINATION share/${PROJECT_NAME})
|
|
|
+```
|
|
|
+
|
|
|
+如果是`ament_python`功能包版
|
|
|
+
|
|
|
```python
|
|
|
from setuptools import setup
|
|
|
from glob import glob
|
|
|
import os
|
|
|
|
|
|
-package_name = 'village_li'
|
|
|
-
|
|
|
setup(
|
|
|
name=package_name,
|
|
|
version='0.0.0',
|
|
@@ -92,24 +106,12 @@ setup(
|
|
|
('share/' + package_name, ['package.xml']),
|
|
|
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
|
|
|
],
|
|
|
- install_requires=['setuptools'],
|
|
|
- zip_safe=True,
|
|
|
- maintainer='ros2',
|
|
|
- maintainer_email='sangxin2014@sina.com',
|
|
|
- description='TODO: Package description',
|
|
|
- license='TODO: License declaration',
|
|
|
- tests_require=['pytest'],
|
|
|
- entry_points={
|
|
|
- 'console_scripts': [
|
|
|
- "li4_node = village_li.li4:main",
|
|
|
- "li3_node = village_li.li3:main"
|
|
|
- ],
|
|
|
},
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
-#### 2.2.4编译测试
|
|
|
+#### 2.2.4 编译测试
|
|
|
|
|
|
使用colcon指令编译我们的程序
|
|
|
|
|
@@ -117,125 +119,75 @@ setup(
|
|
|
colcon build
|
|
|
```
|
|
|
|
|
|
-编译完成后,我们source以下工作空间,就可以运行我们的village.launch.py文件了
|
|
|
+编译完成后,在`chapt5/chapt5_ws/install/robot_startup/share/robot_startup/launch`目录下你应该就可以看到被cmake拷贝过去的launch文件了。
|
|
|
+
|
|
|
+接着运行`
|
|
|
|
|
|
```sheel
|
|
|
+# source 第四章的工作目录,这样才能找到对应的节点,不信你可以不source试试
|
|
|
+source ../../chapt4/chapt4_ws/install/setup.bash
|
|
|
source install/setup.bash
|
|
|
-ros2 launch village_li village.launch.py
|
|
|
+ros2 launch robot_startup example_action.launch.py
|
|
|
+# 新终端
|
|
|
+ros2 node list #即可看到两个节点
|
|
|
```
|
|
|
|
|
|
-运行结果如下,可以看到李四和王二在统一终端和大家打了招呼,我们也可以使用,ros2 node list 看一看两个节点是否都存在。
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
|
|
|
-### 2.3 cmake编译类型功能包的launch文件安装
|
|
|
-
|
|
|
-如果是ament_cmake或者是cmake类型的功能包,我们需要在CmakeLists.txt中添加安装指令,将launch文件夹安装到install目录。
|
|
|
-
|
|
|
-```cmake
|
|
|
-install(DIRECTORY launch
|
|
|
- DESTINATION share/${PROJECT_NAME})
|
|
|
-```
|
|
|
+## 3 添加参数&修改命名空间
|
|
|
|
|
|
-将village_li/launch目录下的village.launch.py复制到village_wang/launch下,接着我们编译运行试一试
|
|
|
+接着我们尝试使用launch运行参数节点,并通过launch传递参数,和给节点以不同的命名空间。
|
|
|
|
|
|
-```
|
|
|
-colcon build
|
|
|
-ros2 launch village_wang village.launch.py
|
|
|
-```
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-## 3.将参数加入launch文件
|
|
|
-
|
|
|
-当我们启动节点时,可以对该节点的参数进行赋值,比如我们可以尝试在启动节点时修改李四写书的速度,改变王二卖书的价格。
|
|
|
-
|
|
|
-在node中给param赋值即可。
|
|
|
+新建`chapt5/chapt5_ws/src/robot_startup/launch/example_param_rclcpp.launch.py`。
|
|
|
|
|
|
+编写内容如下
|
|
|
|
|
|
```python
|
|
|
# 导入库
|
|
|
from launch import LaunchDescription
|
|
|
from launch_ros.actions import Node
|
|
|
|
|
|
-# 定义函数名称为:generate_launch_description
|
|
|
def generate_launch_description():
|
|
|
- # 创建Actions.Node对象li_node,标明李四所在位置
|
|
|
- li4_node = Node(
|
|
|
- package="village_li",
|
|
|
- executable="li4_node",
|
|
|
- output='screen', #四个可选项
|
|
|
- parameters=[{'write_timer_period': 1}]
|
|
|
- )
|
|
|
- # 创建Actions.Node对象wang2_node,标明王二所在位置
|
|
|
- wang2_node = Node(
|
|
|
- package="village_wang",
|
|
|
- executable="wang2_node",
|
|
|
- output='screen', #四个可选项
|
|
|
- parameters=[{'novel_price': 2}]
|
|
|
- )
|
|
|
+ """launch内容描述函数,由ros2 launch 扫描调用"""
|
|
|
+ parameters_basic1 = Node(
|
|
|
+ package="example_parameters_rclcpp",
|
|
|
+ namespace="rclcpp",
|
|
|
+ executable="parameters_basic",
|
|
|
+ parameters=[{'rcl_log_level': 40}]
|
|
|
+ )
|
|
|
+ parameters_basic2 = Node(
|
|
|
+ package="example_parameters_rclpy",
|
|
|
+ namespace="rclpy",
|
|
|
+ executable="parameters_basic",
|
|
|
+ parameters=[{'rcl_log_level': 50}]
|
|
|
+ )
|
|
|
# 创建LaunchDescription对象launch_description,用于描述launch文件
|
|
|
- launch_description = LaunchDescription([li4_node,wang2_node])
|
|
|
+ launch_description = LaunchDescription(
|
|
|
+ [parameters_basic1, parameters_basic2])
|
|
|
# 返回让ROS2根据launch描述执行节点
|
|
|
return launch_description
|
|
|
```
|
|
|
|
|
|
-大家自行运行尝试。
|
|
|
-
|
|
|
-## 4.命名空间修改
|
|
|
-
|
|
|
-我们可以修改命名空间,这样就可以区分两个同名节点。
|
|
|
-
|
|
|
-```python
|
|
|
-# 导入库
|
|
|
-from launch import LaunchDescription
|
|
|
-from launch_ros.actions import Node
|
|
|
-
|
|
|
-# 定义函数名称为:generate_launch_description
|
|
|
-def generate_launch_description():
|
|
|
+编译运行测试
|
|
|
|
|
|
+```shell
|
|
|
+# source 第四章的工作目录,这样才能找到对应的节点,不信你可以不source试试
|
|
|
+source ../../chapt4/chapt4_ws/install/setup.bash
|
|
|
+source install/setup.bash
|
|
|
+ros2 launch robot_startup example_param_rclcpp.launch.py
|
|
|
+# 新终端
|
|
|
+ros2 node list #即可看到两个节点
|
|
|
+```
|
|
|
|
|
|
- # 创建Actions.Node对象li_node,标明李四所在位置
|
|
|
- li4_node = Node(
|
|
|
- package="village_li",
|
|
|
- executable="li4_node",
|
|
|
- output='screen', #四个可选项
|
|
|
- parameters=[{'write_timer_period': 1}]
|
|
|
- )
|
|
|
- # 创建Actions.Node对象wang2_node,标明王二所在位置
|
|
|
- wang2_node = Node(
|
|
|
- package="village_wang",
|
|
|
- executable="wang2_node",
|
|
|
- parameters=[{'novel_price': 2}]
|
|
|
- )
|
|
|
-
|
|
|
- # 创建另外一个命名空间下的,创建Actions.Node对象li_node,标明李四所在位置
|
|
|
- li4_node2 = Node(
|
|
|
- package="village_li",
|
|
|
- namespace="mirror_town",
|
|
|
- executable="li4_node",
|
|
|
- parameters=[{'write_timer_period': 2}]
|
|
|
- )
|
|
|
- # 创建另外一个命名空间下的,Actions.Node对象wang2_node,标明王二所在位置
|
|
|
- wang2_node2 = Node(
|
|
|
- package="village_wang",
|
|
|
- namespace="mirror_town",
|
|
|
- executable="wang2_node",
|
|
|
- parameters=[{'novel_price': 1}]
|
|
|
- )
|
|
|
+
|
|
|
|
|
|
- # 创建LaunchDescription对象launch_description,用于描述launch文件
|
|
|
- launch_description = LaunchDescription([li4_node,wang2_node,wang2_node2,li4_node2])
|
|
|
- # 返回让ROS2根据launch描述执行节点
|
|
|
- return launch_description
|
|
|
-```
|
|
|
+## 4. 总结
|
|
|
|
|
|
-## 四、小总结
|
|
|
+今天只是简单讲了下,使用launch文件来同时启动多个节点,对节点的一些参数也可以在launch中配置。
|
|
|
|
|
|
-今天只是简单讲了下,使用launch文件来同时启动多个接待年,但对节点的一些参数也可以在launch中配置
|
|
|
+launch还有很多更深入的用法,范子琦同学总结的很不错,这里放个链接:
|
|
|
|
|
|
-最近在紧张的录制课程,比较忙,大家的一些问题回答没那么及时,今天就到这里,欢迎大家点赞分享~
|
|
|
+- http://www.robotsfan.com/posts/7a5950c4.html
|
|
|
|
|
|
|
|
|
|