diff --git a/predicators/approaches/human_low_level_control_approach.py b/predicators/approaches/human_low_level_control_approach.py index 9b6ae3f34..54ed56a8f 100644 --- a/predicators/approaches/human_low_level_control_approach.py +++ b/predicators/approaches/human_low_level_control_approach.py @@ -32,7 +32,7 @@ class HumanLowLevelControlApproach(BaseApproach): """A human-in-the-loop approach for low-level robot control via keyboard. - Unlike the HumanInteractionApproach which selects high-level options via + Unlike the HumanOptionControlApproach which selects high-level options via terminal, this approach generates raw joint position Actions based on keyboard input from the terminal. diff --git a/predicators/approaches/human_interaction_approach.py b/predicators/approaches/human_option_control_approach.py similarity index 92% rename from predicators/approaches/human_interaction_approach.py rename to predicators/approaches/human_option_control_approach.py index 1d132c655..0f069f635 100644 --- a/predicators/approaches/human_interaction_approach.py +++ b/predicators/approaches/human_option_control_approach.py @@ -1,5 +1,25 @@ -"""A human-in-the-loop approach where the user manually selects processes via -terminal prompts at each decision point.""" +"""A human-in-the-loop approach where the user manually selects options via +terminal prompts at each decision point. + +This is the high-level (option/skill) counterpart to +``human_low_level_control_approach``: that one prompts for raw actions, +this one prompts for parameterized skills (e.g. ``SwitchOn``, ``Wait``) +and their arguments. ``Wait`` runs until the abstract atoms change. + +Example (PyBullet Fan):: + + python predicators/main.py --env pybullet_fan \\ + --approach human_option_control --seed 0 \\ + --pybullet_max_vel_norm 0.1 \\ + --pybullet_sim_steps_per_action 5 --use_gui \\ + --num_train_tasks 1 --num_test_tasks 1 + +Swap ``--env`` for any other env that ships a Wait/process model +(``pybullet_boil``, ``pybullet_coffee``, ``pybullet_grow``). Set +``--human_option_control_approach_use_scripted_option True`` together +with ``--scripted_option_dir`` / ``--script_option_file_name`` to replay +a pre-written option plan instead of prompting interactively. +""" from typing import Callable, List, Optional, Sequence, Set, cast @@ -17,7 +37,7 @@ State, Task, Type, _GroundEndogenousProcess, _Option -class HumanInteractionApproach(BilevelProcessPlanningApproach): +class HumanOptionControlApproach(BilevelProcessPlanningApproach): """A human-in-the-loop approach for process-based planning. At each decision point, displays applicable processes to the user @@ -46,7 +66,7 @@ def __init__(self, @classmethod def get_name(cls) -> str: - return "human_interaction" + return "human_option_control" @property def is_learning_based(self) -> bool: @@ -65,7 +85,7 @@ def _solve(self, task: Task, timeout: int) -> Callable[[State], Action]: del timeout # Unused parameter # If scripted option is enabled, use the scripted plan - if CFG.human_interaction_approach_use_scripted_option: + if CFG.human_option_control_approach_use_scripted_option: try: option_plan = self._load_scripted_option_plan(task) except Exception as e: @@ -91,7 +111,10 @@ def _option_policy(state: State) -> _Option: return option return utils.option_policy_to_policy( - _option_policy, max_option_steps=CFG.max_num_steps_option_rollout) + _option_policy, + max_option_steps=CFG.max_num_steps_option_rollout, + abstract_function=lambda s: utils.abstract( + s, self._get_current_predicates())) def _load_scripted_option_plan(self, task: Task) -> Sequence[_Option]: """Load and parse a scripted option plan from a file. @@ -159,7 +182,7 @@ def prompt_user_for_option(self, state: State, for atom in sorted(current_atoms, key=str): print(f" {atom}") - if CFG.human_interaction_approach_use_all_options: + if CFG.human_option_control_approach_use_all_options: return self._prompt_user_for_option_from_all(state, goal) return self._prompt_user_for_option_from_processes( diff --git a/predicators/settings.py b/predicators/settings.py index 248b8c63e..479d3612f 100644 --- a/predicators/settings.py +++ b/predicators/settings.py @@ -590,9 +590,9 @@ class GlobalSettings: vlm_open_loop_use_training_demos = False vlm_open_loop_no_image = False # Use object-centric state - # parameters for the human_interaction_approach - human_interaction_approach_use_scripted_option = False - human_interaction_approach_use_all_options = False + # parameters for the human_option_control_approach + human_option_control_approach_use_scripted_option = False + human_option_control_approach_use_all_options = False scripted_option_dir = "scripted_options" script_option_file_name = "scripted_plan.txt" diff --git a/scripts/configs/predicatorv3/oracle.yaml b/scripts/configs/predicatorv3/oracle.yaml index 45abe8371..c2c20e658 100644 --- a/scripts/configs/predicatorv3/oracle.yaml +++ b/scripts/configs/predicatorv3/oracle.yaml @@ -11,11 +11,11 @@ APPROACHES: demonstrator: "oracle_process_planning" terminate_on_goal_reached_and_option_terminated: True bilevel_plan_without_sim: True - # human_interaction: - # NAME: "human_interaction" + # human_option_control: + # NAME: "human_option_control" # FLAGS: - # human_interaction_approach_use_scripted_option: True - # human_interaction_approach_use_all_options: True + # human_option_control_approach_use_scripted_option: True + # human_option_control_approach_use_all_options: True # scripted_option_dir: "scripted_option_policies" # skill_phase_use_motion_planning: True # terminate_on_goal_reached_and_option_terminated: True diff --git a/scripts/configs/predicatorv3/predicator_v3.yaml b/scripts/configs/predicatorv3/predicator_v3.yaml index 9678225af..479248aec 100644 --- a/scripts/configs/predicatorv3/predicator_v3.yaml +++ b/scripts/configs/predicatorv3/predicator_v3.yaml @@ -2,11 +2,11 @@ # Usage: python scripts/local/launch_simp.py -c predicatorv3/predicator_v3.yaml --- APPROACHES: - # human_interaction: - # NAME: "human_interaction" + # human_option_control: + # NAME: "human_option_control" # FLAGS: - # human_interaction_approach_use_scripted_option: True - # human_interaction_approach_use_all_options: True + # human_option_control_approach_use_scripted_option: True + # human_option_control_approach_use_all_options: True # scripted_option_dir: "scripted_option_policies" # skill_phase_use_motion_planning: True oracle: diff --git a/tests/test_skill_factories_integration.py b/tests/test_skill_factories_integration.py index 54f56cde9..459795838 100644 --- a/tests/test_skill_factories_integration.py +++ b/tests/test_skill_factories_integration.py @@ -1480,8 +1480,8 @@ def test_coffee_place_no_button_press(): f"PlaceJugInMachine — robot arm likely triggered the button.") -def test_human_interaction_scripted_domino_solves_task(): - """Full pipeline: human_interaction approach with scripted option plan +def test_human_option_control_scripted_domino_solves_task(): + """Full pipeline: human_option_control approach with scripted option plan (domino2.txt) solves the 1st test task in pybullet_domino.""" try: from predicators.envs.pybullet_domino import PyBulletDominoEnv @@ -1495,7 +1495,7 @@ def test_human_interaction_scripted_domino_solves_task(): utils.reset_config({ "env": "pybullet_domino", - "approach": "human_interaction", + "approach": "human_option_control", "seed": 0, "use_gui": False, "pybullet_control_mode": "position", @@ -1514,8 +1514,8 @@ def test_human_interaction_scripted_domino_solves_task(): "domino_has_glued_dominos": False, "keep_failed_demos": True, "skill_phase_use_motion_planning": True, - "human_interaction_approach_use_scripted_option": True, - "human_interaction_approach_use_all_options": True, + "human_option_control_approach_use_scripted_option": True, + "human_option_control_approach_use_all_options": True, "scripted_option_dir": "scripted_option_policies", "script_option_file_name": "domino2.txt", }) @@ -1528,7 +1528,7 @@ def test_human_interaction_scripted_domino_solves_task(): options = get_gt_options(env.get_name()) approach = create_approach( - "human_interaction", + "human_option_control", env.predicates, options, env.types,