眼睛我會了、大腦我會了、手手:等一下!!!!
大家是不是常常有上面情況發生呢?XD
我自己的話是感觸非常深阿~
學習ROS2的經驗也是如此,其中印象深刻的有包括了launch。在學習階段的時候用的都是別人寫好的packages,基本上不會在啟動的時候發生什麼問題,不管是節點的啟動或是參數的設定都有預設範本了,因為沒有遇到錯誤就不會深入的去了解程式碼的意義。
除此之外,因為ROS1只能使用XML格式編寫launch文件,又因網路上的資源大多都還是ROS1,導致有時候即使看懂了ROS1的launch文件,要改寫成ROS2版本就會卡關。又或著是要自己從空文件寫出一個可以成功被啟動的launch文件,卻無從下手,一方面也是因為自己還沒真的熟用這些工具,一方面自己的學習方式很雜亂。
那我今天會嘗試著把我從無到有的launch文件寫法記錄下來,方便我未來省去掉重新找資料的時間。
在DAY10的最後有提到怎麼新建一個package
我的sim_ws工作空間中/src的結構,包含了新建的package和它底的include與src
root@Laptop:/sim_ws# tree -d ./src/
./src/
└── it_package
├── include #放.h的地方
│ └── it_package
└── src #放.cpp的地方
為了要放launch文件,我們就需要一個launch資料夾
root@Laptop:/sim_ws# tree -d ./src/
./src/
└── it_package
├── include #放.h的地方
│ └── it_package
├── launch #放launch的地方,可以是.py、.xml或.yaml
└── src #放.cpp的地方
(murmur...昨天之所以猶豫要不要先提寫訂閱/發布者就是和這裡有關。)
這兩個文件是在處理package的基本資訊,告訴電腦編譯方式、需要依賴的函式庫、函式庫連結之類的,我也是會基本而已...總之,要讓launch文件能在ros2 launch package` [tab]
時成功被提示,需要這些設定。
# 在package.xml添加
<exec_depend>ros2launch</exec_depend>
# 在CMakeLists.txt添加
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}
)
個人的建議是一開始先固定學習一個格式就好,如果從ROS1跳過來的話就寫xml,反之直接學ROS2的話就先專心把python格式看懂,那我目前大多數時間都是用ROS2,所以就以python為主。
以下是我自己某個package中的python格式launch.py,可以用來開啟gazebo、rviz2和我自己寫的節點。
跟昨天官方的差別是,我後來習慣把LaunchDescription()
當作一個變數ld
,先使用ld.add_action(pcl_node)
再return ld
,好處是我比較好清楚看懂現在哪些節點要被使用。
import os
from ament_index_python import get_package_share_directory
from launch import LaunchDescription
from launch.actions import ExecuteProcess
from launch.actions import DeclareLaunchArgument
from launch.actions import IncludeLaunchDescription
from launch.actions import GroupAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.actions import Node
from launch_ros.actions import PushRosNamespace
def generate_launch_description():
ld = LaunchDescription()
start_gazebo_cmd = ExecuteProcess(
cmd=['gazebo','/root/.gazebo/worlds/car_with_tunnel'],
output="screen"
)
start_rviz_cmd = Node(
package="rviz2",
executable="rviz2",
name="rviz2",
output="screen",
# arguments=[-d,""]
)
# 鍵盤控制node 但後來發現不適合放進launch文件
teleop_node =Node(
package="teleop_twist_keyboard",
executable="teleop_twist_keyboard",
name="teleop_node",
remappings=[
("cmd_vel", "demo/cmd_demo")]
)
# 我自己寫了pcl節點 但要等gazebo節點跑完才會成功被執行
# 故先註解不啟動
pcl_node = Node(
package="pcl_process",
executable="pc_boundary",
name="pc_boundary",
output="screen",
parameters=[
{'KS': 50},
{'RS':0.1},
{'AT':1.2}
]
)
ld.add_action(start_gazebo_cmd)
ld.add_action(start_rviz_cmd)
# ld.add_action(pcl_node)
return ld
上面pcl_node
和start_rviz_cmd
分別有用到parameters、arguments的部份,我當初也花了蠻多時間去弄懂兩者的差異,明天就來好好介紹一下parameters,並且跟launch中的arguments好好比較一下。