機器人編程趣味實踐17-混亂的記憶-
上一節,涉及了SLAM構建地圖,是不是這樣就完美了,仿真中的地圖都那么完整呢。
其實,并不是,看如下動態圖,cartographer效果:
有美好的時刻,也有迷茫的時光。
如果需要深入了解cartographer算法,推薦論文、源碼和文檔的綜合閱讀。
github.com/ros2/cartographer
github.com/ros2/cartographer_ros
google-cartographer.readthedocs.io/en/latest/
google-cartographer-ros.readthedocs.io/en/latest/index.html
推薦下載最新pdf,仔細閱讀!
Cartographer ROS 集成
Cartographer 是一個系統,可提供跨多個平臺和傳感器配置的 2D 和 3D 實時同步定位和地圖構建 (SLAM)。 該項目提供 Cartographer 的 ROS 集成。
有個好地圖,才能導航更“絲滑”!
當然ROS2提供了更多強大的SLAM工具,比如:slam_toolbox
github.com/SteveMacenski/slam_toolbox
介紹
Slam Toolbox 是一組用于 2D SLAM 的工具和功能,由 Steve Macenski 在 Simbe Robotics 期間構建,在三星研究院維護。
項目包含執行任何其他可用 SLAM 庫(免費和付費等)的大部分內容的能力。這包括:
普通的傻瓜式 2D SLAM 移動機器人技術人員期望(啟動、建圖、保存 pgm 文件)具有一些不錯的內置實用程序,例如保存地圖
隨時繼續優化、重新建圖或繼續建圖已保存(序列化)的姿勢圖
全生命周期建圖:加載保存的姿勢圖在空間中繼續建圖,同時還從新添加的掃描中刪除無關信息
建立在姿勢圖上的基于優化的定位模式。可選擇在沒有先驗地圖的情況下運行定位模式,用于具有局部閉環的“激光雷達里程計”模式
同步和異步建圖模式
運動圖合并(在工作中使用彈性圖操作合并技術)
基于插件的優化求解器,帶有新的優化的基于 Google Ceres 的插件
用于與工具交互的 RVIZ 插件
RVIZ 中的圖形操作工具,用于在映射期間操作節點和連接
地圖序列化和無損數據存儲
...更多,但這些是亮點
對于在現場生產機器人上運行,建議使用 snap: slam-toolbox,它進行了優化,使其速度提高了大約 10 倍。對于不需要在機器人上的其他開發人員級工具(rviz 插件等),需要 deb/source 安裝。
該軟件包已在高達約 30,000 平方英尺的 5x+ 實時和高達約 60,000 平方英尺的 3x 實時測繪建筑中進行了基準測試。使用的最大面積是 200,000 平方英尺。在同步模式下構建(即處理所有掃描,無論延遲如何),以及在異步模式下更大的空間。
支持同時導航和建圖!
構建地圖和導航同步進行,效率提升非常多!
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, ExecuteProcess, IncludeLaunchDescription
from launch.conditions import IfCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PythonExpression
from launch_ros.actions import Node
def generate_launch_description():
# Get the launch directory
bringup_dir = get_package_share_directory('nav2_bringup')
launch_dir = os.path.join(bringup_dir, 'launch')
# Create the launch configuration variables
slam = LaunchConfiguration('slam')
namespace = LaunchConfiguration('namespace')
use_namespace = LaunchConfiguration('use_namespace')
map_yaml_file = LaunchConfiguration('map')
use_sim_time = LaunchConfiguration('use_sim_time')
params_file = LaunchConfiguration('params_file')
default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename')
autostart = LaunchConfiguration('autostart')
# Launch configuration variables specific to simulation
rviz_config_file = LaunchConfiguration('rviz_config_file')
use_simulator = LaunchConfiguration('use_simulator')
use_robot_state_pub = LaunchConfiguration('use_robot_state_pub')
use_rviz = LaunchConfiguration('use_rviz')
headless = LaunchConfiguration('headless')
world = LaunchConfiguration('world')
# Map fully qualified names to relative ones so the node's namespace can be prepended.
# In case of the transforms (tf), currently, there doesn't seem to be a better alternative
# https://github.com/ros/geometry2/issues/32
# https://github.com/ros/robot_state_publisher/pull/30
# TODO(orduno) Substitute with `PushNodeRemapping`
# https://github.com/ros2/launch_ros/issues/56
remappings = [('/tf', 'tf'),
('/tf_static', 'tf_static')]
# Declare the launch arguments
declare_namespace_cmd = DeclareLaunchArgument(
'namespace',
default_value='',
description='Top-level namespace')
declare_use_namespace_cmd = DeclareLaunchArgument(
'use_namespace',
default_value='false',
description='Whether to apply a namespace to the navigation stack')
declare_slam_cmd = DeclareLaunchArgument(
'slam',
default_value='False',
description='Whether run a SLAM')
declare_map_yaml_cmd = DeclareLaunchArgument(
'map',
default_value=os.path.join(bringup_dir, 'maps', 'turtlebot3_world.yaml'),
description='Full path to map file to load')
declare_use_sim_time_cmd = DeclareLaunchArgument(
'use_sim_time',
default_value='true',
description='Use simulation (Gazebo) clock if true')
declare_params_file_cmd = DeclareLaunchArgument(
'params_file',
default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
description='Full path to the ROS2 parameters file to use for all launched nodes')
declare_bt_xml_cmd = DeclareLaunchArgument(
'default_bt_xml_filename',
default_value=os.path.join(
get_package_share_directory('nav2_bt_navigator'),
'behavior_trees', 'navigate_w_replanning_and_recovery.xml'),
description='Full path to the behavior tree xml file to use')
declare_autostart_cmd = DeclareLaunchArgument(
'autostart', default_value='true',
description='Automatically startup the nav2 stack')
declare_rviz_config_file_cmd = DeclareLaunchArgument(
'rviz_config_file',
default_value=os.path.join(bringup_dir, 'rviz', 'nav2_default_view.rviz'),
description='Full path to the RVIZ config file to use')
declare_use_simulator_cmd = DeclareLaunchArgument(
'use_simulator',
default_value='True',
description='Whether to start the simulator')
declare_use_robot_state_pub_cmd = DeclareLaunchArgument(
'use_robot_state_pub',
default_value='True',
description='Whether to start the robot state publisher')
declare_use_rviz_cmd = DeclareLaunchArgument(
'use_rviz',
default_value='True',
description='Whether to start RVIZ')
declare_simulator_cmd = DeclareLaunchArgument(
'headless',
default_value='False',
description='Whether to execute gzclient)')
declare_world_cmd = DeclareLaunchArgument(
'world',
# TODO(orduno) Switch back once ROS argument passing has been fixed upstream
# https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/91
# default_value=os.path.join(get_package_share_directory('turtlebot3_gazebo'),
# 'worlds/turtlebot3_worlds/waffle.model'),
default_value=os.path.join(bringup_dir, 'worlds', 'waffle.model'),
description='Full path to world model file to load')
# Specify the actions
start_gazebo_server_cmd = ExecuteProcess(
condition=IfCondition(use_simulator),
cmd=['gzserver', '-s', 'libgazebo_ros_init.so', world],
cwd=[launch_dir], output='screen')
start_gazebo_client_cmd = ExecuteProcess(
condition=IfCondition(PythonExpression([use_simulator, ' and not ', headless])),
cmd=['gzclient'],
cwd=[launch_dir], output='screen')
urdf = os.path.join(bringup_dir, 'urdf', 'turtlebot3_waffle.urdf')
start_robot_state_publisher_cmd = Node(
condition=IfCondition(use_robot_state_pub),
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
namespace=namespace,
output='screen',
parameters=[{'use_sim_time': use_sim_time}],
remappings=remappings,
arguments=[urdf])
rviz_cmd = IncludeLaunchDescription(
PythonLaunchDescriptionSource(os.path.join(launch_dir, 'rviz_launch.py')),
condition=IfCondition(use_rviz),
launch_arguments={'namespace': '',
'use_namespace': 'False',
'rviz_config': rviz_config_file}.items())
bringup_cmd = IncludeLaunchDescription(
PythonLaunchDescriptionSource(os.path.join(launch_dir, 'bringup_launch.py')),
launch_arguments={'namespace': namespace,
'use_namespace': use_namespace,
'slam': slam,
'map': map_yaml_file,
'use_sim_time': use_sim_time,
'params_file': params_file,
'default_bt_xml_filename': default_bt_xml_filename,
'autostart': autostart}.items())
# Create the launch description and populate
ld = LaunchDescription()
# Declare the launch options
ld.add_action(declare_namespace_cmd)
ld.add_action(declare_use_namespace_cmd)
ld.add_action(declare_slam_cmd)
ld.add_action(declare_map_yaml_cmd)
ld.add_action(declare_use_sim_time_cmd)
ld.add_action(declare_params_file_cmd)
ld.add_action(declare_bt_xml_cmd)
ld.add_action(declare_autostart_cmd)
ld.add_action(declare_rviz_config_file_cmd)
ld.add_action(declare_use_simulator_cmd)
ld.add_action(declare_use_robot_state_pub_cmd)
ld.add_action(declare_use_rviz_cmd)
ld.add_action(declare_simulator_cmd)
ld.add_action(declare_world_cmd)
# Add any conditioned actions
ld.add_action(start_gazebo_server_cmd)
ld.add_action(start_gazebo_client_cmd)
# Add the actions to launch all of the navigation nodes
ld.add_action(start_robot_state_publisher_cmd)
ld.add_action(rviz_cmd)
ld.add_action(bringup_cmd)
return ld
全生命周期建圖
LifeLong 建圖是能夠完全或部分建圖空間的概念,并且隨著時間的推移,隨著繼續與空間交互,完善和更新該地圖。注意允許在云中操作的應用程序,以及在共享空間中與許多機器人進行建圖(云分布式建圖)。雖然 Slam Toolbox 也可以用于空間的傻瓜式映射并將該地圖保存為 .pgm 文件,因為傳統上存儲地圖,但它還允許無損地保存姿勢圖和元數據以重新加載稍后使用相同或不同的機器人并繼續建圖空間。
全生命周期建圖包括幾個關鍵步驟
序列化和反序列化以存儲和重新加載地圖信息
KD-Tree 搜索匹配以在重新初始化時將機器人定位在其位置
基于姿勢圖優化的 SLAM 與 2D 掃描匹配抽象
這將允許用戶創建和更新現有地圖,然后序列化數據以用于其他地圖會話,這是大多數 SLAM 實現和幾乎所有平面 SLAM 實現所嚴重缺乏的。其他這樣做的好庫包括 RTab-Map 和 Cartorapher,盡管它們本身有自己的怪癖,使它們(在我看來)無法用于生產機器人應用程序。該庫提供的機制不僅可以保存數據,還可以保存姿勢圖和相關的元數據。這已被用于通過合并技術(采用 2 個或更多序列化對象并創建 1 個全局一致的對象)以及連續映射技術(隨著時間的推移更新 1 個相同的序列化映射對象并對其進行改進)來創建地圖。與 RTab-Map 或 Cartoprapher 相比,它的主要優勢在于項目所基于的底層(但經過大量修改)open_karto 庫的成熟度。 Karto 的掃描匹配器是眾所周知的非常好的 2D 激光掃描匹配器,并且在世界各地的公司中都可以找到 Karto 的修改版本。
Slam Toolbox 支持所有主要模式:
從預定義的碼頭開始(假設在開始區域附近)
從任何特定節點開始 - 選擇要在附近開始的節點 ID
從任何特定區域開始 - 在地圖框中指示要開始的當前姿勢,例如 AMCL
在 RVIZ 界面(請參閱下面的部分)中,將能夠在地圖中重新定位或使用 ROS 服務以圖形方式或編程方式繼續映射。
在撰寫本文時:有一個稱之為“真正全生命周期”建圖的高度實驗性實現,它確實支持隨著時間的推移刪除節點以及添加節點的方法,這導致了真正的終身建圖能力,因為計算是有界的通過刪除無關或過時的信息。如果想不斷優化地圖,建議在云中運行非完整 LifeLong 建圖模式以增加計算負擔。然而,一個真正且迫切需要的應用是使用多會話映射來更新地圖的一部分或一次映射半個區域,為 AMCL 或 Slam Toolbox 本地化模式創建完整的(然后是靜態的)地圖,這將在黑桃中處理。近期的計劃是在 LifeLong 映射中創建一種模式,以衰減舊節點以限制計算,并通過細化實驗節點使其在邊緣上運行。應該使用持續映射(終身)來構建完整的地圖,然后切換到姿勢圖變形定位模式,直到實現節點衰減,應該不會看到任何實質性的性能影響。
更多內容參考官方文檔!
機器人
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。