diff --git a/README.md b/README.md index 39abe969..087a332c 100644 --- a/README.md +++ b/README.md @@ -214,8 +214,8 @@ In general the states ``` States.Off, States.Initialize, -States.InitiateStep, -States.StopStep, +States.Initiate, +States.Stop, States.Monitor, States.Paused, ``` diff --git a/src/isar/apis/schedule/scheduling_controller.py b/src/isar/apis/schedule/scheduling_controller.py index 51ddc9a1..9e9883c6 100644 --- a/src/isar/apis/schedule/scheduling_controller.py +++ b/src/isar/apis/schedule/scheduling_controller.py @@ -153,7 +153,7 @@ def pause_mission(self) -> ControlMissionResponse: if state not in [ States.Monitor, - States.InitiateStep, + States.Initiate, ]: error_message = ( f"Conflict - Pause command received in invalid state - State: {state}" diff --git a/src/isar/config/settings.py b/src/isar/config/settings.py index 66c40290..6fa557f6 100644 --- a/src/isar/config/settings.py +++ b/src/isar/config/settings.py @@ -44,8 +44,8 @@ class Settings(BaseSettings): # Determines the number of state transitions that are kept in the log STATE_TRANSITIONS_LOG_LENGTH: int = Field(default=20) - # Number of attempts to initiate a step before cancelling - INITIATE_STEP_FAILURE_COUNTER_LIMIT: int = Field(default=10) + # Number of attempts to initiate a step or mission before cancelling + INITIATE_FAILURE_COUNTER_LIMIT: int = Field(default=10) # Number of attempts to stop the robot before giving up STOP_ROBOT_ATTEMPTS_LIMIT: int = Field(default=10) diff --git a/src/isar/state_machine/state_machine.py b/src/isar/state_machine/state_machine.py index 5627731f..6a393c6d 100644 --- a/src/isar/state_machine/state_machine.py +++ b/src/isar/state_machine/state_machine.py @@ -23,11 +23,11 @@ from isar.state_machine.states import ( Idle, Initialize, - InitiateStep, + Initiate, Monitor, Off, Paused, - StopStep, + Stop, ) from isar.state_machine.states_enum import States from robot_interface.models.initialize.initialize_params import InitializeParams @@ -82,21 +82,21 @@ def __init__( self.stepwise_mission: bool = stepwise_mission # List of states - self.stop_step_state: State = StopStep(self) + self.stop_state: State = Stop(self) self.paused_state: State = Paused(self) self.idle_state: State = Idle(self) self.initialize_state: State = Initialize(self) self.monitor_state: State = Monitor(self) - self.initiate_step_state: State = InitiateStep(self) + self.initiate_state: State = Initiate(self) self.off_state: State = Off(self) self.states: List[State] = [ self.off_state, self.idle_state, self.initialize_state, - self.initiate_step_state, + self.initiate_state, self.monitor_state, - self.stop_step_state, + self.stop_state, self.paused_state, ] @@ -110,27 +110,27 @@ def __init__( "before": self._off, }, { - "trigger": "step_initiated", - "source": self.initiate_step_state, + "trigger": "initiated", + "source": self.initiate_state, "dest": self.monitor_state, - "before": self._step_initiated, + "before": self._initiated, }, { "trigger": "pause", - "source": [self.initiate_step_state, self.monitor_state], - "dest": self.stop_step_state, + "source": [self.initiate_state, self.monitor_state], + "dest": self.stop_state, "before": self._pause, }, { "trigger": "stop", - "source": [self.initiate_step_state, self.monitor_state], - "dest": self.stop_step_state, + "source": [self.initiate_state, self.monitor_state], + "dest": self.stop_state, "before": self._stop, }, { "trigger": "mission_finished", "source": [ - self.initiate_step_state, + self.initiate_state, ], "dest": self.idle_state, "before": self._mission_finished, @@ -144,7 +144,7 @@ def __init__( { "trigger": "initialization_successful", "source": self.initialize_state, - "dest": self.initiate_step_state, + "dest": self.initiate_state, "before": self._initialization_successful, }, { @@ -156,36 +156,36 @@ def __init__( { "trigger": "resume", "source": self.paused_state, - "dest": self.initiate_step_state, + "dest": self.initiate_state, "before": self._resume, }, { "trigger": "step_finished", "source": self.monitor_state, - "dest": self.initiate_step_state, + "dest": self.initiate_state, "before": self._step_finished, }, { "trigger": "mission_paused", - "source": self.stop_step_state, + "source": self.stop_state, "dest": self.paused_state, "before": self._mission_paused, }, { - "trigger": "step_infeasible", - "source": self.initiate_step_state, - "dest": self.initiate_step_state, - "before": self._step_infeasible, + "trigger": "initiate_infeasible", + "source": self.initiate_state, + "dest": self.initiate_state, + "before": self._initiate_infeasible, }, { - "trigger": "initiate_step_failed", - "source": self.initiate_step_state, + "trigger": "initiate_failed", + "source": self.initiate_state, "dest": self.idle_state, - "before": self._initiate_step_failed, + "before": self._initiate_failed, }, { "trigger": "mission_stopped", - "source": [self.stop_step_state, self.paused_state], + "source": [self.stop_state, self.paused_state], "dest": self.idle_state, "before": self._mission_stopped, }, @@ -235,7 +235,7 @@ def _initialization_failed(self) -> None: self.queues.start_mission.output.put(False) self._finalize() - def _step_initiated(self) -> None: + def _initiated(self) -> None: self.current_step.status = StepStatus.InProgress self.publish_step_status() self.logger.info( @@ -309,7 +309,7 @@ def _mission_paused(self) -> None: def _stop(self) -> None: self.stopped = True - def _initiate_step_failed(self) -> None: + def _initiate_failed(self) -> None: self.current_step.status = StepStatus.Failed self.current_task.update_task_status() self.current_mission.status = MissionStatus.Failed @@ -317,7 +317,7 @@ def _initiate_step_failed(self) -> None: self.publish_task_status() self._finalize() - def _step_infeasible(self) -> None: + def _initiate_infeasible(self) -> None: self.current_step.status = StepStatus.Failed self.publish_step_status() self.update_current_task() diff --git a/src/isar/state_machine/states/__init__.py b/src/isar/state_machine/states/__init__.py index 23459eb4..ec766345 100644 --- a/src/isar/state_machine/states/__init__.py +++ b/src/isar/state_machine/states/__init__.py @@ -1,7 +1,7 @@ from .idle import Idle from .initialize import Initialize -from .initiate_step import InitiateStep +from .initiate import Initiate from .monitor import Monitor from .off import Off from .paused import Paused -from .stop_step import StopStep +from .stop import Stop diff --git a/src/isar/state_machine/states/initiate_step.py b/src/isar/state_machine/states/initiate.py similarity index 65% rename from src/isar/state_machine/states/initiate_step.py rename to src/isar/state_machine/states/initiate.py index ba245495..83c52d86 100644 --- a/src/isar/state_machine/states/initiate_step.py +++ b/src/isar/state_machine/states/initiate.py @@ -1,6 +1,6 @@ import logging import time -from typing import Callable, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable, Optional from transitions import State @@ -15,32 +15,31 @@ RobotLowBatteryException, ) - if TYPE_CHECKING: from isar.state_machine.state_machine import StateMachine -class InitiateStep(State): +class Initiate(State): def __init__(self, state_machine: "StateMachine") -> None: - super().__init__(name="initiate_step", on_enter=self.start, on_exit=self.stop) + super().__init__(name="initiate", on_enter=self.start, on_exit=self.stop) self.state_machine: "StateMachine" = state_machine - self.initiate_step_failure_counter: int = 0 - self.initiate_step_failure_counter_limit: int = ( - settings.INITIATE_STEP_FAILURE_COUNTER_LIMIT + self.initiate_failure_counter: int = 0 + self.initiate_failure_counter_limit: int = ( + settings.INITIATE_FAILURE_COUNTER_LIMIT ) self.logger = logging.getLogger("state_machine") - self.initiate_step_thread: Optional[ThreadedRequest] = None + self.initiate_thread: Optional[ThreadedRequest] = None def start(self) -> None: self.state_machine.update_state() self._run() def stop(self) -> None: - self.initiate_step_failure_counter = 0 - if self.initiate_step_thread: - self.initiate_step_thread.wait_for_thread() - self.initiate_step_thread = None + self.initiate_failure_counter = 0 + if self.initiate_thread: + self.initiate_thread.wait_for_thread() + self.initiate_thread = None def _run(self) -> None: transition: Callable @@ -60,18 +59,18 @@ def _run(self) -> None: transition = self.state_machine.mission_finished # type: ignore break - if not self.initiate_step_thread: - self.initiate_step_thread = ThreadedRequest( + if not self.initiate_thread: + self.initiate_thread = ThreadedRequest( self.state_machine.robot.initiate_step ) - self.initiate_step_thread.start_thread( + self.initiate_thread.start_thread( self.state_machine.current_step, name="State Machine Initiate Step", ) try: - self.initiate_step_thread.get_output() - transition = self.state_machine.step_initiated # type: ignore + self.initiate_thread.get_output() + transition = self.state_machine.initiated # type: ignore break except ThreadedRequestNotFinishedError: time.sleep(self.state_machine.sleep_time) @@ -82,7 +81,7 @@ def _run(self) -> None: f"{type(self.state_machine.current_step).__name__}" f"Invalid step: {str(self.state_machine.current_step.id)[:8]}" ) - transition = self.state_machine.step_infeasible # type: ignore + transition = self.state_machine.initiate_infeasible # type: ignore break except RobotLowBatteryException as e: @@ -91,27 +90,24 @@ def _run(self) -> None: f"{type(self.state_machine.current_step).__name__}" f"Current Battery Level: {str(e.battery_level)}" ) - transition = self.state_machine.initiate_step_failed # type: ignore + transition = self.state_machine.initiate__failed # type: ignore break except RobotException as e: - self.initiate_step_thread = None - self.initiate_step_failure_counter += 1 + self.initiate_thread = None + self.initiate_failure_counter += 1 self.logger.warning( f"Initiating step failed #: " - f"{str(self.initiate_step_failure_counter)}" + f"{str(self.initiate_failure_counter)}" f"{e}" ) - if ( - self.initiate_step_failure_counter - >= self.initiate_step_failure_counter_limit - ): + if self.initiate_failure_counter >= self.initiate_failure_counter_limit: self.logger.error( f"Failed to initiate step after " - f"{self.initiate_step_failure_counter_limit} attempts. " + f"{self.initiate_failure_counter_limit} attempts. " f"Cancelling mission." ) - transition = self.state_machine.initiate_step_failed # type: ignore + transition = self.state_machine.initiate_failed # type: ignore break time.sleep(self.state_machine.sleep_time) diff --git a/src/isar/state_machine/states/stop_step.py b/src/isar/state_machine/states/stop.py similarity index 94% rename from src/isar/state_machine/states/stop_step.py rename to src/isar/state_machine/states/stop.py index c8707991..6ed0edb5 100644 --- a/src/isar/state_machine/states/stop_step.py +++ b/src/isar/state_machine/states/stop.py @@ -1,6 +1,6 @@ import logging import time -from typing import Callable, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable, Optional from transitions import State @@ -14,9 +14,9 @@ from isar.state_machine.state_machine import StateMachine -class StopStep(State): +class Stop(State): def __init__(self, state_machine: "StateMachine") -> None: - super().__init__(name="stop_step", on_enter=self.start, on_exit=self.stop) + super().__init__(name="stop", on_enter=self.start, on_exit=self.stop) self.state_machine: "StateMachine" = state_machine self.logger = logging.getLogger("state_machine") self.stop_thread: Optional[ThreadedRequest] = None diff --git a/src/isar/state_machine/states_enum.py b/src/isar/state_machine/states_enum.py index 4fa8980d..55ccae83 100644 --- a/src/isar/state_machine/states_enum.py +++ b/src/isar/state_machine/states_enum.py @@ -4,11 +4,11 @@ class States(str, Enum): Off = "off" Idle = "idle" - InitiateStep = "initiate_step" + Initiate = "initiate" Initialize = "initialize" Monitor = "monitor" Paused = "paused" - StopStep = "stop_step" + Stop = "stop" def __repr__(self): return self.value diff --git a/state_machine_diagram.png b/state_machine_diagram.png new file mode 100644 index 00000000..9875d49d Binary files /dev/null and b/state_machine_diagram.png differ diff --git a/tests/conftest.py b/tests/conftest.py index 17489450..8818ccd6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,7 +23,7 @@ from isar.services.service_connections.stid.stid_service import StidService from isar.services.utilities.scheduling_utilities import SchedulingUtilities from isar.state_machine.state_machine import StateMachine -from isar.state_machine.states import Idle, InitiateStep, Monitor +from isar.state_machine.states import Idle, Initiate, Monitor from robot_interface.telemetry.mqtt_client import MqttClientInterface from tests.mocks.robot_interface import MockRobot from tests.test_modules import ( @@ -129,8 +129,8 @@ def idle_state(state_machine): @pytest.fixture() -def initiate_step(state_machine): - return InitiateStep(state_machine) +def initiate(state_machine): + return Initiate(state_machine) @pytest.fixture() diff --git a/tests/isar/apis/scheduler/test_scheduler_router.py b/tests/isar/apis/scheduler/test_scheduler_router.py index 8ea9143b..467e091a 100644 --- a/tests/isar/apis/scheduler/test_scheduler_router.py +++ b/tests/isar/apis/scheduler/test_scheduler_router.py @@ -308,11 +308,11 @@ def test_resume_mission_timeout(self, client: TestClient): class TestStopMission: schedule_stop_mission_path = "/schedule/stop-mission" valid_states = [ - States.InitiateStep, + States.Initiate, States.Initialize, States.Monitor, States.Paused, - States.StopStep, + States.Stop, ] @pytest.mark.parametrize("state", valid_states) diff --git a/tests/isar/state_machine/test_state_machine.py b/tests/isar/state_machine/test_state_machine.py index d4fe1731..65d6afa4 100644 --- a/tests/isar/state_machine/test_state_machine.py +++ b/tests/isar/state_machine/test_state_machine.py @@ -103,9 +103,9 @@ def test_state_machine_transitions(injector, state_machine_thread) -> None: [ States.Idle, States.Initialize, - States.InitiateStep, + States.Initiate, States.Monitor, - States.InitiateStep, + States.Initiate, States.Idle, ] ) @@ -134,9 +134,9 @@ def test_state_machine_failed_dependency( [ States.Idle, States.Initialize, - States.InitiateStep, + States.Initiate, States.Monitor, - States.InitiateStep, + States.Initiate, States.Idle, ] ) @@ -163,9 +163,9 @@ def test_state_machine_with_successful_collection( [ States.Idle, States.Initialize, - States.InitiateStep, + States.Initiate, States.Monitor, - States.InitiateStep, + States.Initiate, States.Idle, ] ) @@ -196,9 +196,9 @@ def test_state_machine_with_unsuccessful_collection( [ States.Idle, States.Initialize, - States.InitiateStep, + States.Initiate, States.Monitor, - States.InitiateStep, + States.Initiate, States.Idle, ] ) @@ -227,8 +227,8 @@ def test_state_machine_with_successful_mission_stop( [ States.Idle, States.Initialize, - States.InitiateStep, - States.StopStep, + States.Initiate, + States.Stop, States.Idle, ] ) @@ -260,8 +260,8 @@ def test_state_machine_with_unsuccsessful_mission_stop( [ States.Idle, States.Initialize, - States.InitiateStep, - States.StopStep, + States.Initiate, + States.Stop, States.Idle, ] )