feat: apply LMS runtime vehicle spec

This commit is contained in:
2026-08-06 13:55:26 +09:00
parent 6c4594b21f
commit 75c5d08337
2 changed files with 40 additions and 3 deletions
+11 -1
View File
@@ -32,6 +32,10 @@ ARGUMENTS = [
DeclareLaunchArgument('level', default_value='None', choices=['None', '2d', '3d']), DeclareLaunchArgument('level', default_value='None', choices=['None', '2d', '3d']),
DeclareLaunchArgument('platform', default_value='mkmini'), DeclareLaunchArgument('platform', default_value='mkmini'),
DeclareLaunchArgument('robot', default_value='mkmini'), DeclareLaunchArgument('robot', default_value='mkmini'),
# LMS platform DB values. Empty keeps the checked-in platform profile unchanged.
DeclareLaunchArgument('runtime_wheelbase', default_value=''),
DeclareLaunchArgument('runtime_max_speed', default_value=''),
DeclareLaunchArgument('runtime_max_steering_angle', default_value=''),
DeclareLaunchArgument('vehicle_driver', default_value=''), # override (real, 미지정=platform 기본) DeclareLaunchArgument('vehicle_driver', default_value=''), # override (real, 미지정=platform 기본)
DeclareLaunchArgument('sensor_driver', default_value=''), # override (real, 미지정=platform 기본) DeclareLaunchArgument('sensor_driver', default_value=''), # override (real, 미지정=platform 기본)
DeclareLaunchArgument('extra_config_dirs', default_value=''), # 드라이버 ws 루트(콜론 구분) DeclareLaunchArgument('extra_config_dirs', default_value=''), # 드라이버 ws 루트(콜론 구분)
@@ -56,6 +60,9 @@ def build(context, *args, **kwargs):
level = LaunchConfiguration('level').perform(context) level = LaunchConfiguration('level').perform(context)
platform = LaunchConfiguration('platform').perform(context) platform = LaunchConfiguration('platform').perform(context)
robot = LaunchConfiguration('robot').perform(context) robot = LaunchConfiguration('robot').perform(context)
runtime_wheelbase = LaunchConfiguration('runtime_wheelbase').perform(context)
runtime_max_speed = LaunchConfiguration('runtime_max_speed').perform(context)
runtime_max_steering_angle = LaunchConfiguration('runtime_max_steering_angle').perform(context)
vehicle_driver = LaunchConfiguration('vehicle_driver').perform(context) vehicle_driver = LaunchConfiguration('vehicle_driver').perform(context)
sensor_driver = LaunchConfiguration('sensor_driver').perform(context) sensor_driver = LaunchConfiguration('sensor_driver').perform(context)
extra_config_dirs = LaunchConfiguration('extra_config_dirs').perform(context) extra_config_dirs = LaunchConfiguration('extra_config_dirs').perform(context)
@@ -76,7 +83,10 @@ def build(context, *args, **kwargs):
extra_config_dirs=extra_config_dirs, extra_config_dirs=extra_config_dirs,
sensor_driver_params=sensor_driver_params, sensor_driver_params=sensor_driver_params,
vehicle_driver_params=vehicle_driver_params, vehicle_driver_params=vehicle_driver_params,
simulator=simulator) simulator=simulator,
runtime_wheelbase=runtime_wheelbase,
runtime_max_speed=runtime_max_speed,
runtime_max_steering_angle=runtime_max_steering_angle)
sim = (sim_mode == 'true') sim = (sim_mode == 'true')
actions = [] actions = []
+29 -2
View File
@@ -11,6 +11,7 @@ ROS 를 import 하지 않으므로 오프라인 단위 테스트로 파라미터
import base64 import base64
import json import json
import math
import os import os
import yaml import yaml
@@ -75,6 +76,20 @@ def _to_launch_str(v):
return str(v) return str(v)
def _optional_runtime_number(raw, name):
"""Parse a runtime override while retaining the checked-in profile by default."""
value = str(raw or '').strip()
if not value:
return None
try:
parsed = float(value)
except ValueError as error:
raise ValueError(f"[profiles] invalid {name} runtime value: {raw!r}") from error
if not math.isfinite(parsed) or parsed < 0:
raise ValueError(f"[profiles] invalid {name} runtime value: {raw!r}")
return parsed
def _merge_params(prof, kind, raw_b64): def _merge_params(prof, kind, raw_b64):
"""yaml parameters 선언 default ← 사용자 오버라이드(base64 JSON) 병합. """yaml parameters 선언 default ← 사용자 오버라이드(base64 JSON) 병합.
@@ -99,7 +114,9 @@ def _merge_params(prof, kind, raw_b64):
def resolve_plan(pkg_share, platform_name, sim_mode, def resolve_plan(pkg_share, platform_name, sim_mode,
vehicle_driver_arg='', sensor_driver_arg='', vehicle_driver_arg='', sensor_driver_arg='',
extra_config_dirs='', sensor_driver_params='', extra_config_dirs='', sensor_driver_params='',
vehicle_driver_params='', simulator=''): vehicle_driver_params='', simulator='',
runtime_wheelbase='', runtime_max_speed='',
runtime_max_steering_angle=''):
"""platform/sim_mode/override 로 launch 플랜(dict) 해소. ROS 비의존. """platform/sim_mode/override 로 launch 플랜(dict) 해소. ROS 비의존.
sim_mode 는 'true'/'false' 문자열. override 가 빈 문자열이면 platform 기본값 사용. sim_mode 는 'true'/'false' 문자열. override 가 빈 문자열이면 platform 기본값 사용.
@@ -107,7 +124,15 @@ def resolve_plan(pkg_share, platform_name, sim_mode,
sensor_driver_params / vehicle_driver_params 는 base64(JSON) 사용자 오버라이드. sensor_driver_params / vehicle_driver_params 는 base64(JSON) 사용자 오버라이드.
""" """
sim = (str(sim_mode) == 'true') sim = (str(sim_mode) == 'true')
P = load_platform(pkg_share, platform_name) P = dict(load_platform(pkg_share, platform_name))
runtime_speed = _optional_runtime_number(runtime_max_speed, 'max_speed')
runtime_values = {
'wheelbase': _optional_runtime_number(runtime_wheelbase, 'wheelbase'),
'max_steering_angle': _optional_runtime_number(runtime_max_steering_angle, 'max_steering_angle'),
}
for name, value in runtime_values.items():
if value is not None:
P[name] = value
# 사용자 드라이버 ws 루트들 (pkg_share config 에 없는 프로파일 폴백 탐색 경로) # 사용자 드라이버 ws 루트들 (pkg_share config 에 없는 프로파일 폴백 탐색 경로)
extra_dirs = [d for d in str(extra_config_dirs).split(':') if d] extra_dirs = [d for d in str(extra_config_dirs).split(':') if d]
@@ -134,6 +159,8 @@ def resolve_plan(pkg_share, platform_name, sim_mode,
adapter_params = dict(VD.get('adapter_params') or {}) adapter_params = dict(VD.get('adapter_params') or {})
adapter_params['wheelbase'] = P['wheelbase'] adapter_params['wheelbase'] = P['wheelbase']
adapter_params['max_steering_angle'] = P['max_steering_angle'] adapter_params['max_steering_angle'] = P['max_steering_angle']
if runtime_speed is not None:
adapter_params['max_speed'] = runtime_speed
adapter_name = VD.get('adapter') or '' adapter_name = VD.get('adapter') or ''
spec = get_adapter(adapter_name) if adapter_name else None spec = get_adapter(adapter_name) if adapter_name else None