fix: prioritize RTAB-Map localization for 3D sessions

This commit is contained in:
2026-08-10 11:31:23 +09:00
parent 8291e681ad
commit c4aec82f16
3 changed files with 58 additions and 19 deletions
@@ -10,14 +10,22 @@ def generate_launch_description():
default_value='amcl', default_value='amcl',
choices=['amcl', 'slam'], choices=['amcl', 'slam'],
) )
database_path = DeclareLaunchArgument(
'database_path',
default_value='',
description='Saved RTAB-Map database used only by 3D localization.',
)
node = Node( node = Node(
package='localization_pkg', package='localization_pkg',
executable='localization_manager', executable='localization_manager',
name='localization_manager', name='localization_manager',
output='screen', output='screen',
parameters=[{'localization_mode': LaunchConfiguration('localization_mode')}], parameters=[{
'localization_mode': LaunchConfiguration('localization_mode'),
'database_path': LaunchConfiguration('database_path'),
}],
) )
ld = LaunchDescription([localization_mode]) ld = LaunchDescription([localization_mode, database_path])
ld.add_action(node) ld.add_action(node)
return ld return ld
@@ -2,22 +2,29 @@
from ament_index_python.packages import get_package_share_directory from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument from launch.actions import DeclareLaunchArgument, GroupAction, OpaqueFunction
from launch.actions import GroupAction
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.actions import Node from launch_ros.actions import Node
from launch_ros.descriptions import ParameterFile from launch_ros.descriptions import ParameterFile
from launch.substitutions import PythonExpression from launch.substitutions import PythonExpression
from launch.conditions import IfCondition, UnlessCondition
from nav2_common.launch import RewrittenYaml from nav2_common.launch import RewrittenYaml
import os
ARGUMENTS = [ ARGUMENTS = [
DeclareLaunchArgument('sim_mode', default_value='false'),
DeclareLaunchArgument('robot', default_value='fr09', choices=['mkmini', 'fr09']), DeclareLaunchArgument('robot', default_value='fr09', choices=['mkmini', 'fr09']),
DeclareLaunchArgument('database_path', default_value=''),
] ]
def generate_launch_description(): def launch_setup(context, *args, **kwargs):
robot = LaunchConfiguration('robot') robot = LaunchConfiguration('robot')
sim_mode = LaunchConfiguration('sim_mode')
database_path = LaunchConfiguration('database_path').perform(context).strip()
if not database_path:
raise RuntimeError('3D localization requires database_path:=/modules/maps/<saved-map>.db')
if not os.path.isfile(database_path):
raise RuntimeError(f'3D localization database was not found: {database_path}')
remappings=[ remappings=[
('/tf', 'tf'), ('/tf', 'tf'),
@@ -33,9 +40,7 @@ def generate_launch_description():
pkg_localization, pkg_localization,
'config', 'config',
PythonExpression(["'rtabmap_' + '", robot, "' + '.yaml'"])]) PythonExpression(["'rtabmap_' + '", robot, "' + '.yaml'"])])
param_substitutions = { param_substitutions = {'use_sim_time': sim_mode}
'use_sim_time': 'true'
}
configured_params = ParameterFile( configured_params = ParameterFile(
RewrittenYaml( RewrittenYaml(
source_file=rtabmap_params_file, source_file=rtabmap_params_file,
@@ -50,15 +55,32 @@ def generate_launch_description():
executable='icp_odometry', executable='icp_odometry',
name='icp_odometry', name='icp_odometry',
output='screen', output='screen',
parameters=[configured_params, {'use_sim_time': True}], parameters=[configured_params, {'use_sim_time': sim_mode}],
remappings=remappings, remappings=remappings,
) ),
Node(
package='rtabmap_slam',
executable='rtabmap',
name='rtabmap',
output='screen',
parameters=[configured_params, {
'use_sim_time': sim_mode,
'database_path': database_path,
'Mem/IncrementalMemory': 'false',
'Mem/InitWMWithAllNodes': 'true',
'map_frame_id': 'map',
'odom_frame_id': 'icp_odom',
'publish_tf': True,
}],
remappings=remappings,
),
], ],
) )
return [load_nodes]
def generate_launch_description():
# Create launch description and add actions # Create launch description and add actions
ld = LaunchDescription(ARGUMENTS) ld = LaunchDescription(ARGUMENTS)
ld.add_action(load_nodes) ld.add_action(OpaqueFunction(function=launch_setup))
return ld return ld
@@ -20,7 +20,9 @@ class LocalizationManager(Node):
self.localization_process = None self.localization_process = None
self.config_received = False self.config_received = False
self.declare_parameter('localization_mode', 'amcl') self.declare_parameter('localization_mode', 'amcl')
self.declare_parameter('database_path', '')
self.localization_mode = self.get_parameter('localization_mode').value self.localization_mode = self.get_parameter('localization_mode').value
self.database_path = self.get_parameter('database_path').value
self.create_subscription(String, '/vehicle_config', self.handle_config, qos_profile=qos) self.create_subscription(String, '/vehicle_config', self.handle_config, qos_profile=qos)
@@ -31,6 +33,19 @@ class LocalizationManager(Node):
self.get_logger().info(f"Localization Received config: {msg.data}") self.get_logger().info(f"Localization Received config: {msg.data}")
config_data = json.loads(msg.data) config_data = json.loads(msg.data)
if config_data.get("level") == "3d":
if not self.database_path:
self.get_logger().error('3D localization requires a saved RTAB-Map database_path.')
return
self.get_logger().info('Starting RTAB-Map 3D localization mode.')
self.localization_process = subprocess.Popen(['ros2', 'launch',
'localization_pkg',
'localization3d.launch.py',
f'sim_mode:={config_data.get("sim_mode")}',
f'robot:={config_data.get("robot")}',
f'database_path:={self.database_path}'])
return
if self.localization_mode == 'slam': if self.localization_mode == 'slam':
self.get_logger().info('Starting SLAM Toolbox localization mode.') self.get_logger().info('Starting SLAM Toolbox localization mode.')
self.localization_process = subprocess.Popen(['ros2', 'launch', self.localization_process = subprocess.Popen(['ros2', 'launch',
@@ -46,12 +61,6 @@ class LocalizationManager(Node):
'localization2d.launch.py', 'localization2d.launch.py',
f'sim_mode:={config_data.get("sim_mode")}', f'sim_mode:={config_data.get("sim_mode")}',
f'robot:={config_data.get("robot")}']) f'robot:={config_data.get("robot")}'])
elif config_data.get("level") == "3d":
self.localization_process = subprocess.Popen(['ros2', 'launch',
'localization_pkg',
'localization3d.launch.py',
f'sim_mode:={config_data.get("sim_mode")}',
f'robot:={config_data.get("robot")}'])
pass pass
def destroy_node(self): def destroy_node(self):