feat(experement): add planner scene mode without reference runner

This commit is contained in:
Даниил Грабарь
2026-11-11 00:08:42 +10:00
parent cdda081b4f
commit d66c9d3fa2
4 changed files with 67 additions and 7 deletions
@@ -17,7 +17,7 @@ import yaml
EXPERIMENT_IDS = tuple(range(1, 21)) EXPERIMENT_IDS = tuple(range(1, 21))
MODES = ('view', 'execute') MODES = ('view', 'execute', 'planner')
DEFAULT_START_DELAY_SEC = 3.0 DEFAULT_START_DELAY_SEC = 3.0
DEFAULT_TRACE_DIR = '~/.ros/iiwa_experement/runs' DEFAULT_TRACE_DIR = '~/.ros/iiwa_experement/runs'
LOCAL_PROTOS = ( LOCAL_PROTOS = (
@@ -110,6 +110,11 @@ def supervisor_process(
) )
def mode_read_only(mode: str) -> bool:
"""Only ``view`` is passive; execute and planner accept grab commands."""
return mode == 'view'
def runtime_actions( def runtime_actions(
experiment_id: int, experiment_id: int,
scene_config: str, scene_config: str,
@@ -126,7 +131,10 @@ def runtime_actions(
package_share = Path(get_package_share_directory('iiwa_experement')) package_share = Path(get_package_share_directory('iiwa_experement'))
if geometry_path is None: if geometry_path is None:
geometry_path = str(package_share / 'config' / 'geometry.yaml') geometry_path = str(package_share / 'config' / 'geometry.yaml')
read_only = mode != 'execute' # Only the passive view mode locks the supervisor. Both the reference
# executor and the external-graph planner need to accept grab/dock
# commands; the planner mode simply never starts the reference runner.
read_only = mode_read_only(mode)
actions = [ actions = [
IncludeLaunchDescription( IncludeLaunchDescription(
PythonLaunchDescriptionSource( PythonLaunchDescriptionSource(
@@ -264,7 +272,9 @@ def generate_launch_description():
default_value='view', default_value='view',
description=( description=(
'view = open the prepared scene without motion; ' 'view = open the prepared scene without motion; '
'execute = run the reference sequence after start_delay_sec.' 'execute = run the reference sequence after start_delay_sec; '
'planner = writable scene for an externally supplied graph, '
'no reference sequence.'
), ),
), ),
DeclareLaunchArgument( DeclareLaunchArgument(
+47 -2
View File
@@ -45,12 +45,17 @@ def test_invalid_experiment_ids_are_rejected(raw):
validate_experiment_id(raw) validate_experiment_id(raw)
@pytest.mark.parametrize('raw, expected', [('view', 'view'), ('execute', 'execute'), (' VIEW ', 'view')]) @pytest.mark.parametrize('raw, expected', [
('view', 'view'),
('execute', 'execute'),
('planner', 'planner'),
(' VIEW ', 'view'),
])
def test_valid_modes(raw, expected): def test_valid_modes(raw, expected):
assert validate_mode(raw) == expected assert validate_mode(raw) == expected
@pytest.mark.parametrize('raw', ['', 'run', 'VIEW '[:-1] + 'x', '1']) @pytest.mark.parametrize('raw', ['', 'run', 'VIEW '[:-1] + 'x', '1', 'plan'])
def test_invalid_modes_are_rejected(raw): def test_invalid_modes_are_rejected(raw):
with pytest.raises(ValueError): with pytest.raises(ValueError):
validate_mode(raw) validate_mode(raw)
@@ -138,6 +143,46 @@ def test_execute_adds_the_reference_runner_after_the_supervisor():
assert any(type(action) is ExecuteProcess for action in actions) assert any(type(action) is ExecuteProcess for action in actions)
def _process_arguments(process):
return [item[0].text for item in process.cmd if item and item[0].text]
def test_planner_is_writable_and_has_no_reference_runner():
module = load_launch_module()
actions = module.runtime_actions(
experiment_id=20,
scene_config='/tmp/scenes.yaml',
setting_path='/tmp/setting.yaml',
mode='planner',
)
assert not any(
isinstance(action, Node) and action.node_executable == 'reference_runner'
for action in actions
)
processes = [action for action in actions if type(action) is ExecuteProcess]
assert len(processes) == 1
assert 'read_only:=false' in _process_arguments(processes[0])
assert module.mode_read_only('planner') is False
parameters = module.supervisor_parameters(
20, '/tmp/scenes.yaml', '/tmp/geometry.yaml', False,
)
assert parameters['read_only'] is False
def test_view_remains_read_only_after_adding_the_planner_mode():
module = load_launch_module()
actions = module.runtime_actions(
experiment_id=1,
scene_config='/tmp/scenes.yaml',
setting_path='/tmp/setting.yaml',
mode='view',
)
processes = [action for action in actions if type(action) is ExecuteProcess]
assert 'read_only:=true' in _process_arguments(processes[0])
assert module.mode_read_only('view') is True
assert module.mode_read_only('execute') is False
def test_runtime_actions_can_register_cleanup(tmp_path): def test_runtime_actions_can_register_cleanup(tmp_path):
module = load_launch_module() module = load_launch_module()
actions = module.runtime_actions( actions = module.runtime_actions(
@@ -14,12 +14,17 @@ from iiwa_experement.runtime_config import (
) )
@pytest.mark.parametrize('raw, expected', [('view', 'view'), (' Execute ', 'execute')]) @pytest.mark.parametrize('raw, expected', [
('view', 'view'),
(' Execute ', 'execute'),
('planner', 'planner'),
(' PLANNER ', 'planner'),
])
def test_mode_validation(raw, expected): def test_mode_validation(raw, expected):
assert validate_mode(raw) == expected assert validate_mode(raw) == expected
@pytest.mark.parametrize('raw', ['', 'motion', 'execute!']) @pytest.mark.parametrize('raw', ['', 'motion', 'execute!', 'plan'])
def test_mode_validation_rejects_unknown_modes(raw): def test_mode_validation_rejects_unknown_modes(raw):
with pytest.raises(ValueError): with pytest.raises(ValueError):
validate_mode(raw) validate_mode(raw)