diff --git a/src/vehicle_pkg/launch/vehicle.launch.py b/src/vehicle_pkg/launch/vehicle.launch.py index 1c9c267..22e5b85 100755 --- a/src/vehicle_pkg/launch/vehicle.launch.py +++ b/src/vehicle_pkg/launch/vehicle.launch.py @@ -32,6 +32,10 @@ ARGUMENTS = [ DeclareLaunchArgument('level', default_value='None', choices=['None', '2d', '3d']), DeclareLaunchArgument('platform', 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('sensor_driver', default_value=''), # override (real, 미지정=platform 기본) DeclareLaunchArgument('extra_config_dirs', default_value=''), # 드라이버 ws 루트(콜론 구분) @@ -56,6 +60,9 @@ def build(context, *args, **kwargs): level = LaunchConfiguration('level').perform(context) platform = LaunchConfiguration('platform').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) sensor_driver = LaunchConfiguration('sensor_driver').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, sensor_driver_params=sensor_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') actions = [] diff --git a/src/vehicle_pkg/vehicle_pkg/profiles.py b/src/vehicle_pkg/vehicle_pkg/profiles.py index 0e454b4..43ebdef 100755 --- a/src/vehicle_pkg/vehicle_pkg/profiles.py +++ b/src/vehicle_pkg/vehicle_pkg/profiles.py @@ -11,6 +11,7 @@ ROS 를 import 하지 않으므로 오프라인 단위 테스트로 파라미터 import base64 import json +import math import os import yaml @@ -75,6 +76,20 @@ def _to_launch_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): """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, vehicle_driver_arg='', sensor_driver_arg='', 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 비의존. 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) 사용자 오버라이드. """ 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 에 없는 프로파일 폴백 탐색 경로) 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['wheelbase'] = P['wheelbase'] 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 '' spec = get_adapter(adapter_name) if adapter_name else None