isar 1.33.5__tar.gz → 1.33.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {isar-1.33.5 → isar-1.33.6}/PKG-INFO +1 -1
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/api.py +34 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/models/models.py +5 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/schedule/scheduling_controller.py +34 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/models/events.py +17 -1
- {isar-1.33.5 → isar-1.33.6}/src/isar/robot/robot.py +32 -0
- isar-1.33.6/src/isar/robot/robot_pause_mission.py +63 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/robot/robot_stop_mission.py +1 -1
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/utilities/scheduling_utilities.py +50 -4
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/state_machine.py +27 -7
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/await_next_mission.py +19 -1
- isar-1.33.6/src/isar/state_machine/states/going_to_lockdown.py +80 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/home.py +15 -0
- isar-1.33.6/src/isar/state_machine/states/lockdown.py +37 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/monitor.py +16 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/paused.py +19 -1
- isar-1.33.6/src/isar/state_machine/states/pausing.py +74 -0
- isar-1.33.6/src/isar/state_machine/states/pausing_return_home.py +74 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/recharging.py +16 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/return_home_paused.py +17 -1
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/returning_home.py +18 -2
- isar-1.33.6/src/isar/state_machine/states/stopping_go_to_lockdown.py +79 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states_enum.py +5 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/fail_mission.py +7 -0
- isar-1.33.6/src/isar/state_machine/transitions/functions/pause.py +31 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/mission.py +55 -10
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/return_home.py +53 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar.egg-info/PKG-INFO +1 -1
- {isar-1.33.5 → isar-1.33.6}/src/isar.egg-info/SOURCES.txt +6 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/mission/status.py +2 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/state_machine/test_state_machine.py +456 -0
- isar-1.33.5/src/isar/state_machine/transitions/functions/pause.py +0 -91
- {isar-1.33.5 → isar-1.33.6}/.dockerignore +0 -0
- {isar-1.33.5 → isar-1.33.6}/.env.test +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/ISSUE_TEMPLATE/improvement.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/release.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/workflows/compile_requirements.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/workflows/project_automations.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/workflows/pythonpackage.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/workflows/pythonpublish.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/.github/workflows/stale.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/.gitignore +0 -0
- {isar-1.33.5 → isar-1.33.6}/.pre-commit-config.yaml +0 -0
- {isar-1.33.5 → isar-1.33.6}/LICENSE +0 -0
- {isar-1.33.5 → isar-1.33.6}/README.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/SECURITY.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/Makefile +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/full_state_machine_diagram.png +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/make.bat +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/mission_state_machine_diagram.png +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/robot_status_state_machine_diagram.png +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/rst_processing.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/source/conf.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/source/index.rst +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/source/readme_link.md +0 -0
- {isar-1.33.5 → isar-1.33.6}/docs/update_state_diagram.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/main.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/pyproject.toml +0 -0
- {isar-1.33.5 → isar-1.33.6}/radixconfig.yml +0 -0
- {isar-1.33.5 → isar-1.33.6}/requirements.txt +0 -0
- {isar-1.33.5 → isar-1.33.6}/setup.cfg +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/models/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/models/start_mission_definition.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/robot_control/robot_controller.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/schedule/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/security/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/apis/security/authentication.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/certs/ca-cert.pem +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/configuration_error.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/keyvault/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/keyvault/keyvault_error.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/keyvault/keyvault_service.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/log.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/logging.conf +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/JSP1_intermediate_deck.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/JSP1_weather_deck.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/default_map.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/klab_b.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/klab_compressor.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/klab_turtlebot.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/maps/turtleworld.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/open_telemetry.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_mission_definition/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_mission_definition/default_exr.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_mission_definition/default_mission.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_mission_definition/default_turtlebot.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_missions/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_missions/default.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/predefined_missions/default_turtlebot.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/config/settings.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/eventhandlers/eventhandler.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/mission_planner/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/mission_planner/local_planner.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/mission_planner/mission_planner_interface.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/mission_planner/sequential_task_selector.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/mission_planner/task_selector_interface.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/models/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/modules.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/robot/robot_start_mission.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/robot/robot_status.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/robot/robot_task_status.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/script.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/auth/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/auth/azure_credentials.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/service_connections/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/service_connections/mqtt/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/service_connections/mqtt/mqtt_client.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/service_connections/mqtt/robot_info_publisher.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/service_connections/request_handler.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/utilities/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/utilities/robot_utilities.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/services/utilities/threaded_request.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/blocked_protective_stop.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/intervention_needed.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/offline.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/stopping.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/stopping_return_home.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/states/unknown_status.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/finish_mission.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/resume.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/return_home.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/robot_status.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/start_mission.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/stop.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/functions/utils.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/transitions/robot_status.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/state_machine/utils/common_event_handlers.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/storage/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/storage/blob_storage.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/storage/local_storage.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/storage/storage_interface.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/storage/uploader.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar/storage/utilities.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar.egg-info/dependency_links.txt +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar.egg-info/entry_points.txt +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar.egg-info/requires.txt +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/isar.egg-info/top_level.txt +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/exceptions/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/exceptions/robot_exceptions.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/initialize/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/inspection/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/inspection/inspection.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/mission/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/mission/mission.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/mission/task.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/robots/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/robots/battery_state.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/robots/media.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/models/robots/robot_model.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/robot_interface.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/telemetry/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/telemetry/mqtt_client.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/telemetry/payloads.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/test_robot_interface.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/utilities/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/utilities/json_service.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/src/robot_interface/utilities/uuid_string_factory.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/conftest.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/config/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/config/maps/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/config/maps/turtleworld.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/config/missions/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/config/missions/default.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/integration/turtlebot/test_successful_mission.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/models/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/models/example_mission_definition.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/models/test_start_mission_definition.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/scheduler/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/scheduler/test_scheduler_router.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/security/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/apis/security/test_authentication.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/mission/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/mission/test_mission.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/models/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/models/communication/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/models/communication/test_events.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/readers/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/readers/test_mission_reader.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/service_connections/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/service_connections/echo/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/service_connections/test_base_request_handler.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/utilities/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/utilities/test_queue_utilities.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/services/utilities/test_scheduling_utilities.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/state_machine/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/state_machine/states/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/state_machine/states/test_monitor.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/storage/test_blob_storage.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/isar/storage/test_uploader.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_data/test_map_config/test_map_config.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_data/test_mission_not_working.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_data/test_mission_working.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_data/test_mission_working_no_tasks.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_data/test_thermal_image_mission.json +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/__init__.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/blob_storage.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/mission_definition.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/mqtt_client.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/pose.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/request.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/robot_interface.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/status.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/task.py +0 -0
- {isar-1.33.5 → isar-1.33.6}/tests/test_double/token.py +0 -0
|
@@ -245,6 +245,40 @@ class API:
|
|
|
245
245
|
},
|
|
246
246
|
},
|
|
247
247
|
)
|
|
248
|
+
router.add_api_route(
|
|
249
|
+
path="/schedule/lockdown",
|
|
250
|
+
endpoint=self.scheduling_controller.lockdown,
|
|
251
|
+
methods=["POST"],
|
|
252
|
+
dependencies=[authentication_dependency],
|
|
253
|
+
summary="Send the robot to dock and ensure that it stays there",
|
|
254
|
+
responses={
|
|
255
|
+
HTTPStatus.OK.value: {"description": "Robot going to dock"},
|
|
256
|
+
HTTPStatus.CONFLICT.value: {
|
|
257
|
+
"description": "Conflict - Invalid command in the current state"
|
|
258
|
+
},
|
|
259
|
+
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
260
|
+
"description": "Internal Server Error - Current state of state machine unknown"
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
router.add_api_route(
|
|
265
|
+
path="/schedule/release-lockdown",
|
|
266
|
+
endpoint=self.scheduling_controller.release_lockdown,
|
|
267
|
+
methods=["POST"],
|
|
268
|
+
dependencies=[authentication_dependency],
|
|
269
|
+
summary="Allow the robot to start missions again",
|
|
270
|
+
responses={
|
|
271
|
+
HTTPStatus.OK.value: {
|
|
272
|
+
"description": "Robot is able to receive missions again"
|
|
273
|
+
},
|
|
274
|
+
HTTPStatus.CONFLICT.value: {
|
|
275
|
+
"description": "Conflict - Invalid command in the current state"
|
|
276
|
+
},
|
|
277
|
+
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
278
|
+
"description": "Internal Server Error - Current state of state machine unknown"
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
)
|
|
248
282
|
router.add_api_route(
|
|
249
283
|
path="/schedule/release-intervention-needed",
|
|
250
284
|
endpoint=self.scheduling_controller.release_intervention_needed,
|
|
@@ -32,6 +32,11 @@ class MissionStartResponse(BaseModel):
|
|
|
32
32
|
mission_not_started_reason: Optional[str] = None
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
class LockdownResponse(BaseModel):
|
|
36
|
+
lockdown_started: bool
|
|
37
|
+
failure_reason: Optional[str] = None
|
|
38
|
+
|
|
39
|
+
|
|
35
40
|
class RobotInfoResponse(BaseModel):
|
|
36
41
|
robot_package: str
|
|
37
42
|
isar_id: str
|
|
@@ -254,6 +254,40 @@ class SchedulingController:
|
|
|
254
254
|
self.scheduling_utilities.release_intervention_needed()
|
|
255
255
|
self.logger.info("Released intervention needed state successfully")
|
|
256
256
|
|
|
257
|
+
@tracer.start_as_current_span("lockdown")
|
|
258
|
+
def lockdown(self) -> None:
|
|
259
|
+
self.logger.info("Received request to lockdown robot")
|
|
260
|
+
|
|
261
|
+
state: States = self.scheduling_utilities.get_state()
|
|
262
|
+
|
|
263
|
+
if state == States.Lockdown:
|
|
264
|
+
error_message = "Conflict - Lockdown command received in lockdown state"
|
|
265
|
+
self.logger.warning(error_message)
|
|
266
|
+
raise HTTPException(
|
|
267
|
+
status_code=HTTPStatus.CONFLICT,
|
|
268
|
+
detail=error_message,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
self.scheduling_utilities.lock_down_robot()
|
|
272
|
+
self.logger.info("Lockdown started successfully")
|
|
273
|
+
|
|
274
|
+
@tracer.start_as_current_span("release_lockdown")
|
|
275
|
+
def release_lockdown(self) -> None:
|
|
276
|
+
self.logger.info("Received request to release robot lockdown")
|
|
277
|
+
|
|
278
|
+
state: States = self.scheduling_utilities.get_state()
|
|
279
|
+
|
|
280
|
+
if state != States.Lockdown:
|
|
281
|
+
error_message = f"Conflict - Release lockdown command received in invalid state - State: {state}"
|
|
282
|
+
self.logger.warning(error_message)
|
|
283
|
+
raise HTTPException(
|
|
284
|
+
status_code=HTTPStatus.CONFLICT,
|
|
285
|
+
detail=error_message,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
self.scheduling_utilities.release_robot_lockdown()
|
|
289
|
+
self.logger.info("Released lockdown successfully")
|
|
290
|
+
|
|
257
291
|
def _api_response(self, mission: Mission) -> StartMissionResponse:
|
|
258
292
|
return StartMissionResponse(
|
|
259
293
|
id=mission.id,
|
|
@@ -4,7 +4,11 @@ from typing import Generic, Optional, TypeVar
|
|
|
4
4
|
|
|
5
5
|
from transitions import State
|
|
6
6
|
|
|
7
|
-
from isar.apis.models.models import
|
|
7
|
+
from isar.apis.models.models import (
|
|
8
|
+
ControlMissionResponse,
|
|
9
|
+
LockdownResponse,
|
|
10
|
+
MissionStartResponse,
|
|
11
|
+
)
|
|
8
12
|
from isar.config.settings import settings
|
|
9
13
|
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
|
|
10
14
|
from robot_interface.models.mission.mission import Mission
|
|
@@ -105,6 +109,12 @@ class APIRequests:
|
|
|
105
109
|
self.release_intervention_needed: APIEvent[bool, bool] = APIEvent(
|
|
106
110
|
"release_intervention_needed"
|
|
107
111
|
)
|
|
112
|
+
self.send_to_lockdown: APIEvent[bool, LockdownResponse] = APIEvent(
|
|
113
|
+
"send_to_lockdown"
|
|
114
|
+
)
|
|
115
|
+
self.release_from_lockdown: APIEvent[bool, bool] = APIEvent(
|
|
116
|
+
"release_from_lockdown"
|
|
117
|
+
)
|
|
108
118
|
|
|
109
119
|
|
|
110
120
|
class StateMachineEvents:
|
|
@@ -128,6 +138,12 @@ class RobotServiceEvents:
|
|
|
128
138
|
self.mission_successfully_stopped: Event[bool] = Event(
|
|
129
139
|
"mission_successfully_stopped"
|
|
130
140
|
)
|
|
141
|
+
self.mission_failed_to_pause: Event[ErrorMessage] = Event(
|
|
142
|
+
"mission_failed_to_pause"
|
|
143
|
+
)
|
|
144
|
+
self.mission_successfully_paused: Event[bool] = Event(
|
|
145
|
+
"mission_successfully_paused"
|
|
146
|
+
)
|
|
131
147
|
|
|
132
148
|
|
|
133
149
|
class SharedState:
|
|
@@ -9,6 +9,7 @@ from isar.models.events import (
|
|
|
9
9
|
SharedState,
|
|
10
10
|
StateMachineEvents,
|
|
11
11
|
)
|
|
12
|
+
from isar.robot.robot_pause_mission import RobotPauseMissionThread
|
|
12
13
|
from isar.robot.robot_start_mission import RobotStartMissionThread
|
|
13
14
|
from isar.robot.robot_status import RobotStatusThread
|
|
14
15
|
from isar.robot.robot_stop_mission import RobotStopMissionThread
|
|
@@ -31,6 +32,7 @@ class Robot(object):
|
|
|
31
32
|
self.robot_status_thread: Optional[RobotStatusThread] = None
|
|
32
33
|
self.robot_task_status_thread: Optional[RobotTaskStatusThread] = None
|
|
33
34
|
self.stop_mission_thread: Optional[RobotStopMissionThread] = None
|
|
35
|
+
self.pause_mission_thread: Optional[RobotPauseMissionThread] = None
|
|
34
36
|
self.signal_thread_quitting: ThreadEvent = ThreadEvent()
|
|
35
37
|
|
|
36
38
|
def stop(self) -> None:
|
|
@@ -111,6 +113,34 @@ class Robot(object):
|
|
|
111
113
|
)
|
|
112
114
|
self.stop_mission_thread.start()
|
|
113
115
|
|
|
116
|
+
def _pause_mission_request_handler(self, event: Event[bool]) -> None:
|
|
117
|
+
if event.consume_event():
|
|
118
|
+
if (
|
|
119
|
+
self.pause_mission_thread is not None
|
|
120
|
+
and self.pause_mission_thread.is_alive()
|
|
121
|
+
):
|
|
122
|
+
self.logger.warning(
|
|
123
|
+
"Received pause mission event while trying to pause a mission. Aborting pause attempt."
|
|
124
|
+
)
|
|
125
|
+
return
|
|
126
|
+
if (
|
|
127
|
+
self.start_mission_thread is not None
|
|
128
|
+
and self.start_mission_thread.is_alive()
|
|
129
|
+
):
|
|
130
|
+
error_description = "Received pause mission event while trying to start a mission. Aborting pause attempt."
|
|
131
|
+
error_message = ErrorMessage(
|
|
132
|
+
error_reason=ErrorReason.RobotStillStartingMissionException,
|
|
133
|
+
error_description=error_description,
|
|
134
|
+
)
|
|
135
|
+
self.robot_service_events.mission_failed_to_stop.trigger_event(
|
|
136
|
+
error_message
|
|
137
|
+
)
|
|
138
|
+
return
|
|
139
|
+
self.pause_mission_thread = RobotPauseMissionThread(
|
|
140
|
+
self.robot_service_events, self.robot, self.signal_thread_quitting
|
|
141
|
+
)
|
|
142
|
+
self.pause_mission_thread.start()
|
|
143
|
+
|
|
114
144
|
def run(self) -> None:
|
|
115
145
|
self.robot_status_thread = RobotStatusThread(
|
|
116
146
|
self.robot, self.signal_thread_quitting, self.shared_state
|
|
@@ -124,6 +154,8 @@ class Robot(object):
|
|
|
124
154
|
self.state_machine_events.task_status_request
|
|
125
155
|
)
|
|
126
156
|
|
|
157
|
+
self._pause_mission_request_handler(self.state_machine_events.pause_mission)
|
|
158
|
+
|
|
127
159
|
self._stop_mission_request_handler(self.state_machine_events.stop_mission)
|
|
128
160
|
|
|
129
161
|
self.logger.info("Exiting robot service main thread")
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from threading import Event, Thread
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from isar.config.settings import settings
|
|
7
|
+
from isar.models.events import RobotServiceEvents
|
|
8
|
+
from robot_interface.models.exceptions.robot_exceptions import (
|
|
9
|
+
ErrorMessage,
|
|
10
|
+
RobotActionException,
|
|
11
|
+
RobotException,
|
|
12
|
+
)
|
|
13
|
+
from robot_interface.robot_interface import RobotInterface
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RobotPauseMissionThread(Thread):
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
robot_service_events: RobotServiceEvents,
|
|
20
|
+
robot: RobotInterface,
|
|
21
|
+
signal_thread_quitting: Event,
|
|
22
|
+
):
|
|
23
|
+
self.logger = logging.getLogger("robot")
|
|
24
|
+
self.robot_service_events: RobotServiceEvents = robot_service_events
|
|
25
|
+
self.robot: RobotInterface = robot
|
|
26
|
+
self.signal_thread_quitting: Event = signal_thread_quitting
|
|
27
|
+
Thread.__init__(self, name="Robot pause mission thread")
|
|
28
|
+
|
|
29
|
+
def run(self) -> None:
|
|
30
|
+
retries = 0
|
|
31
|
+
error: Optional[ErrorMessage] = None
|
|
32
|
+
while retries < settings.STATE_TRANSITION_NUM_RETIRES:
|
|
33
|
+
if self.signal_thread_quitting.wait(0):
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
self.robot.pause()
|
|
38
|
+
except (RobotActionException, RobotException) as e:
|
|
39
|
+
self.logger.warning(
|
|
40
|
+
f"\nFailed to pause robot because: {e.error_description}"
|
|
41
|
+
f"\nAttempting to pause the robot again"
|
|
42
|
+
)
|
|
43
|
+
retries += 1
|
|
44
|
+
error = ErrorMessage(
|
|
45
|
+
error_reason=e.error_reason, error_description=e.error_description
|
|
46
|
+
)
|
|
47
|
+
time.sleep(settings.FSM_SLEEP_TIME)
|
|
48
|
+
continue
|
|
49
|
+
self.robot_service_events.mission_successfully_paused.trigger_event(True)
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
error_description = (
|
|
53
|
+
f"\nFailed to pause the robot after {retries} attempts because: "
|
|
54
|
+
f"{error.error_description}"
|
|
55
|
+
f"\nBe aware that the robot may still be moving even though a pause has "
|
|
56
|
+
"been attempted"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
error_message = ErrorMessage(
|
|
60
|
+
error_reason=error.error_reason,
|
|
61
|
+
error_description=error_description,
|
|
62
|
+
)
|
|
63
|
+
self.robot_service_events.mission_failed_to_pause.trigger_event(error_message)
|
|
@@ -24,7 +24,7 @@ class RobotStopMissionThread(Thread):
|
|
|
24
24
|
self.robot_service_events: RobotServiceEvents = robot_service_events
|
|
25
25
|
self.robot: RobotInterface = robot
|
|
26
26
|
self.signal_thread_quitting: Event = signal_thread_quitting
|
|
27
|
-
Thread.__init__(self, name="Robot
|
|
27
|
+
Thread.__init__(self, name="Robot stop mission thread")
|
|
28
28
|
|
|
29
29
|
def run(self) -> None:
|
|
30
30
|
retries = 0
|
|
@@ -322,14 +322,60 @@ class SchedulingUtilities:
|
|
|
322
322
|
try:
|
|
323
323
|
self._send_command(True, self.api_events.release_intervention_needed)
|
|
324
324
|
self.logger.info("OK - Intervention needed state released")
|
|
325
|
+
except EventConflictError:
|
|
326
|
+
error_message = (
|
|
327
|
+
"Previous release intervention needed request is still being processed"
|
|
328
|
+
)
|
|
329
|
+
self.logger.warning(error_message)
|
|
330
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
325
331
|
except EventTimeoutError:
|
|
332
|
+
error_message = "Cannot release intervention needed as it is not in intervention needed state"
|
|
333
|
+
self.logger.warning(error_message)
|
|
334
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
335
|
+
|
|
336
|
+
def lock_down_robot(self) -> None:
|
|
337
|
+
"""Lock down robot
|
|
338
|
+
|
|
339
|
+
Raises
|
|
340
|
+
------
|
|
341
|
+
HTTPException 500 Internal Server Error
|
|
342
|
+
If the robot could not be locked down
|
|
343
|
+
"""
|
|
344
|
+
try:
|
|
345
|
+
self._send_command(True, self.api_events.send_to_lockdown)
|
|
346
|
+
self.logger.info("OK - Robot sent into lockdown")
|
|
347
|
+
except EventConflictError:
|
|
348
|
+
error_message = "Previous lockdown request is still being processed"
|
|
349
|
+
self.logger.warning(error_message)
|
|
350
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
351
|
+
except EventTimeoutError:
|
|
352
|
+
error_message = "Cannot send robot to lockdown as it is already in lockdown"
|
|
353
|
+
self.logger.warning(error_message)
|
|
354
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
355
|
+
|
|
356
|
+
def release_robot_lockdown(self) -> None:
|
|
357
|
+
"""Release robot from lockdown
|
|
358
|
+
|
|
359
|
+
Raises
|
|
360
|
+
------
|
|
361
|
+
HTTPException 500 Internal Server Error
|
|
362
|
+
If the robot could not be released from lockdown
|
|
363
|
+
"""
|
|
364
|
+
try:
|
|
365
|
+
self._send_command(True, self.api_events.release_from_lockdown)
|
|
366
|
+
self.logger.info("OK - Robot released form lockdown")
|
|
367
|
+
except EventConflictError:
|
|
326
368
|
error_message = (
|
|
327
|
-
"
|
|
369
|
+
"Previous release robot from lockdown request is still being processed"
|
|
328
370
|
)
|
|
329
|
-
self.logger.
|
|
330
|
-
raise HTTPException(
|
|
331
|
-
|
|
371
|
+
self.logger.warning(error_message)
|
|
372
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
373
|
+
except EventTimeoutError:
|
|
374
|
+
error_message = (
|
|
375
|
+
"Cannot release robot from lockdown as it is not in lockdown"
|
|
332
376
|
)
|
|
377
|
+
self.logger.warning(error_message)
|
|
378
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
333
379
|
|
|
334
380
|
def _send_command(self, input: T1, api_event: APIEvent[T1, T2]) -> T2:
|
|
335
381
|
if api_event.request.has_event():
|
|
@@ -18,15 +18,20 @@ from isar.models.events import Events, SharedState
|
|
|
18
18
|
from isar.services.service_connections.mqtt.mqtt_client import props_expiry
|
|
19
19
|
from isar.state_machine.states.await_next_mission import AwaitNextMission
|
|
20
20
|
from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
|
|
21
|
+
from isar.state_machine.states.going_to_lockdown import GoingToLockdown
|
|
21
22
|
from isar.state_machine.states.home import Home
|
|
22
23
|
from isar.state_machine.states.intervention_needed import InterventionNeeded
|
|
24
|
+
from isar.state_machine.states.lockdown import Lockdown
|
|
23
25
|
from isar.state_machine.states.monitor import Monitor
|
|
24
26
|
from isar.state_machine.states.offline import Offline
|
|
25
27
|
from isar.state_machine.states.paused import Paused
|
|
28
|
+
from isar.state_machine.states.pausing import Pausing
|
|
29
|
+
from isar.state_machine.states.pausing_return_home import PausingReturnHome
|
|
26
30
|
from isar.state_machine.states.recharging import Recharging
|
|
27
31
|
from isar.state_machine.states.return_home_paused import ReturnHomePaused
|
|
28
32
|
from isar.state_machine.states.returning_home import ReturningHome
|
|
29
33
|
from isar.state_machine.states.stopping import Stopping
|
|
34
|
+
from isar.state_machine.states.stopping_go_to_lockdown import StoppingGoToLockdown
|
|
30
35
|
from isar.state_machine.states.stopping_return_home import StoppingReturnHome
|
|
31
36
|
from isar.state_machine.states.unknown_status import UnknownStatus
|
|
32
37
|
from isar.state_machine.states_enum import States
|
|
@@ -102,8 +107,12 @@ class StateMachine(object):
|
|
|
102
107
|
self.returning_home_state: State = ReturningHome(self)
|
|
103
108
|
self.stopping_state: State = Stopping(self)
|
|
104
109
|
self.paused_state: State = Paused(self)
|
|
110
|
+
self.pausing_state: State = Pausing(self)
|
|
105
111
|
self.return_home_paused_state: State = ReturnHomePaused(self)
|
|
106
112
|
self.stopping_return_home_state: State = StoppingReturnHome(self)
|
|
113
|
+
self.pausing_return_home_state: State = PausingReturnHome(self)
|
|
114
|
+
self.stopping_go_to_lockdown_state: State = StoppingGoToLockdown(self)
|
|
115
|
+
self.going_to_lockdown_state: State = GoingToLockdown(self)
|
|
107
116
|
|
|
108
117
|
# States Waiting for mission
|
|
109
118
|
self.await_next_mission_state: State = AwaitNextMission(self)
|
|
@@ -114,6 +123,7 @@ class StateMachine(object):
|
|
|
114
123
|
self.offline_state: State = Offline(self)
|
|
115
124
|
self.blocked_protective_stopping_state: State = BlockedProtectiveStop(self)
|
|
116
125
|
self.recharging_state: State = Recharging(self)
|
|
126
|
+
self.lockdown_state: State = Lockdown(self)
|
|
117
127
|
|
|
118
128
|
# Error and special status states
|
|
119
129
|
self.unknown_status_state: State = UnknownStatus(self)
|
|
@@ -123,7 +133,9 @@ class StateMachine(object):
|
|
|
123
133
|
self.returning_home_state,
|
|
124
134
|
self.stopping_state,
|
|
125
135
|
self.stopping_return_home_state,
|
|
136
|
+
self.pausing_return_home_state,
|
|
126
137
|
self.paused_state,
|
|
138
|
+
self.pausing_state,
|
|
127
139
|
self.return_home_paused_state,
|
|
128
140
|
self.await_next_mission_state,
|
|
129
141
|
self.home_state,
|
|
@@ -132,6 +144,9 @@ class StateMachine(object):
|
|
|
132
144
|
self.unknown_status_state,
|
|
133
145
|
self.intervention_needed_state,
|
|
134
146
|
self.recharging_state,
|
|
147
|
+
self.stopping_go_to_lockdown_state,
|
|
148
|
+
self.going_to_lockdown_state,
|
|
149
|
+
self.lockdown_state,
|
|
135
150
|
]
|
|
136
151
|
|
|
137
152
|
self.machine = Machine(
|
|
@@ -288,13 +303,14 @@ class StateMachine(object):
|
|
|
288
303
|
timestamp=datetime.now(timezone.utc),
|
|
289
304
|
)
|
|
290
305
|
|
|
291
|
-
self.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
306
|
+
if self.current_mission:
|
|
307
|
+
self.mqtt_publisher.publish(
|
|
308
|
+
topic=settings.TOPIC_ISAR_MISSION + f"/{self.current_mission.id}",
|
|
309
|
+
payload=json.dumps(payload, cls=EnhancedJSONEncoder),
|
|
310
|
+
qos=1,
|
|
311
|
+
retain=True,
|
|
312
|
+
properties=props_expiry(settings.MQTT_MISSION_AND_TASK_EXPIRY),
|
|
313
|
+
)
|
|
298
314
|
|
|
299
315
|
def publish_task_status(self, task: TASKS) -> None:
|
|
300
316
|
"""Publishes the task status to the MQTT Broker"""
|
|
@@ -384,6 +400,10 @@ class StateMachine(object):
|
|
|
384
400
|
return RobotStatus.InterventionNeeded
|
|
385
401
|
elif self.current_state == States.Recharging:
|
|
386
402
|
return RobotStatus.Recharging
|
|
403
|
+
elif self.current_state == States.Lockdown:
|
|
404
|
+
return RobotStatus.Lockdown
|
|
405
|
+
elif self.current_state == States.GoingToLockdown:
|
|
406
|
+
return RobotStatus.GoingToLockdown
|
|
387
407
|
else:
|
|
388
408
|
return RobotStatus.Busy
|
|
389
409
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, List
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
2
2
|
|
|
3
|
+
from isar.apis.models.models import LockdownResponse
|
|
3
4
|
from isar.config.settings import settings
|
|
4
5
|
from isar.eventhandlers.eventhandler import (
|
|
5
6
|
EventHandlerBase,
|
|
6
7
|
EventHandlerMapping,
|
|
7
8
|
TimeoutHandlerMapping,
|
|
8
9
|
)
|
|
10
|
+
from isar.models.events import Event
|
|
9
11
|
from isar.state_machine.utils.common_event_handlers import (
|
|
10
12
|
return_home_event_handler,
|
|
11
13
|
start_mission_event_handler,
|
|
@@ -21,6 +23,17 @@ class AwaitNextMission(EventHandlerBase):
|
|
|
21
23
|
def __init__(self, state_machine: "StateMachine"):
|
|
22
24
|
events = state_machine.events
|
|
23
25
|
|
|
26
|
+
def _send_to_lockdown_event_handler(
|
|
27
|
+
event: Event[bool],
|
|
28
|
+
) -> Optional[Callable]:
|
|
29
|
+
should_lockdown: bool = event.consume_event()
|
|
30
|
+
if should_lockdown:
|
|
31
|
+
events.api_requests.send_to_lockdown.response.trigger_event(
|
|
32
|
+
LockdownResponse(lockdown_started=True)
|
|
33
|
+
)
|
|
34
|
+
return state_machine.request_lockdown_mission # type: ignore
|
|
35
|
+
return None
|
|
36
|
+
|
|
24
37
|
event_handlers: List[EventHandlerMapping] = [
|
|
25
38
|
EventHandlerMapping(
|
|
26
39
|
name="start_mission_event",
|
|
@@ -39,6 +52,11 @@ class AwaitNextMission(EventHandlerBase):
|
|
|
39
52
|
event=events.api_requests.return_home.request,
|
|
40
53
|
handler=lambda event: stop_mission_event_handler(state_machine, event),
|
|
41
54
|
),
|
|
55
|
+
EventHandlerMapping(
|
|
56
|
+
name="send_to_lockdown_event",
|
|
57
|
+
event=events.api_requests.send_to_lockdown.request,
|
|
58
|
+
handler=_send_to_lockdown_event_handler,
|
|
59
|
+
),
|
|
42
60
|
]
|
|
43
61
|
|
|
44
62
|
timers: List[TimeoutHandlerMapping] = [
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
2
|
+
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
from isar.state_machine.utils.common_event_handlers import (
|
|
6
|
+
mission_started_event_handler,
|
|
7
|
+
task_status_event_handler,
|
|
8
|
+
task_status_failed_event_handler,
|
|
9
|
+
)
|
|
10
|
+
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage, ErrorReason
|
|
11
|
+
from robot_interface.models.mission.status import TaskStatus
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from isar.state_machine.state_machine import StateMachine
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GoingToLockdown(EventHandlerBase):
|
|
18
|
+
|
|
19
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
20
|
+
events = state_machine.events
|
|
21
|
+
|
|
22
|
+
def _handle_task_completed(status: TaskStatus):
|
|
23
|
+
if status != TaskStatus.Successful:
|
|
24
|
+
state_machine.current_mission.error_message = ErrorMessage(
|
|
25
|
+
error_reason=ErrorReason.RobotActionException,
|
|
26
|
+
error_description="Lock down mission failed.",
|
|
27
|
+
)
|
|
28
|
+
return state_machine.lockdown_mission_failed # type: ignore
|
|
29
|
+
return state_machine.reached_lockdown # type: ignore
|
|
30
|
+
|
|
31
|
+
def _mission_failed_event_handler(
|
|
32
|
+
event: Event[Optional[ErrorMessage]],
|
|
33
|
+
) -> Optional[Callable]:
|
|
34
|
+
mission_failed: Optional[ErrorMessage] = event.consume_event()
|
|
35
|
+
if mission_failed is not None:
|
|
36
|
+
state_machine.logger.warning(
|
|
37
|
+
f"Failed to initiate mission "
|
|
38
|
+
f"{str(state_machine.current_mission.id)[:8]} because: "
|
|
39
|
+
f"{mission_failed.error_description}"
|
|
40
|
+
)
|
|
41
|
+
state_machine.current_mission.error_message = ErrorMessage(
|
|
42
|
+
error_reason=mission_failed.error_reason,
|
|
43
|
+
error_description=mission_failed.error_description,
|
|
44
|
+
)
|
|
45
|
+
return state_machine.lockdown_mission_failed # type: ignore
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
49
|
+
EventHandlerMapping(
|
|
50
|
+
name="mission_started_event",
|
|
51
|
+
event=events.robot_service_events.mission_started,
|
|
52
|
+
handler=lambda event: mission_started_event_handler(
|
|
53
|
+
state_machine, event
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
EventHandlerMapping(
|
|
57
|
+
name="mission_failed_event",
|
|
58
|
+
event=events.robot_service_events.mission_failed,
|
|
59
|
+
handler=_mission_failed_event_handler,
|
|
60
|
+
),
|
|
61
|
+
EventHandlerMapping(
|
|
62
|
+
name="task_status_failed_event",
|
|
63
|
+
event=events.robot_service_events.task_status_failed,
|
|
64
|
+
handler=lambda event: task_status_failed_event_handler(
|
|
65
|
+
state_machine, _handle_task_completed, event
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
EventHandlerMapping(
|
|
69
|
+
name="task_status_event",
|
|
70
|
+
event=events.robot_service_events.task_status_updated,
|
|
71
|
+
handler=lambda event: task_status_event_handler(
|
|
72
|
+
state_machine, _handle_task_completed, event
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
]
|
|
76
|
+
super().__init__(
|
|
77
|
+
state_name="going_to_lockdown",
|
|
78
|
+
state_machine=state_machine,
|
|
79
|
+
event_handler_mappings=event_handlers,
|
|
80
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
2
2
|
|
|
3
|
+
from isar.apis.models.models import LockdownResponse
|
|
3
4
|
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
5
|
from isar.models.events import Event
|
|
5
6
|
from isar.state_machine.utils.common_event_handlers import (
|
|
@@ -30,6 +31,15 @@ class Home(EventHandlerBase):
|
|
|
30
31
|
return state_machine.robot_status_changed # type: ignore
|
|
31
32
|
return None
|
|
32
33
|
|
|
34
|
+
def _send_to_lockdown_event_handler(event: Event[bool]):
|
|
35
|
+
should_send_robot_home: bool = event.consume_event()
|
|
36
|
+
if should_send_robot_home:
|
|
37
|
+
events.api_requests.send_to_lockdown.response.trigger_event(
|
|
38
|
+
LockdownResponse(lockdown_started=True)
|
|
39
|
+
)
|
|
40
|
+
return state_machine.reached_lockdown # type: ignore
|
|
41
|
+
return None
|
|
42
|
+
|
|
33
43
|
event_handlers: List[EventHandlerMapping] = [
|
|
34
44
|
EventHandlerMapping(
|
|
35
45
|
name="start_mission_event",
|
|
@@ -53,6 +63,11 @@ class Home(EventHandlerBase):
|
|
|
53
63
|
event=shared_state.robot_status,
|
|
54
64
|
handler=_robot_status_event_handler,
|
|
55
65
|
),
|
|
66
|
+
EventHandlerMapping(
|
|
67
|
+
name="send_to_lockdown_event",
|
|
68
|
+
event=events.api_requests.send_to_lockdown.request,
|
|
69
|
+
handler=_send_to_lockdown_event_handler,
|
|
70
|
+
),
|
|
56
71
|
]
|
|
57
72
|
super().__init__(
|
|
58
73
|
state_name="home",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
|
+
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from isar.state_machine.state_machine import StateMachine
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Lockdown(EventHandlerBase):
|
|
11
|
+
|
|
12
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
13
|
+
events = state_machine.events
|
|
14
|
+
|
|
15
|
+
def _release_from_lockdown_handler(event: Event[bool]):
|
|
16
|
+
should_release_from_lockdown: bool = event.consume_event()
|
|
17
|
+
if should_release_from_lockdown:
|
|
18
|
+
events.api_requests.release_from_lockdown.response.trigger_event(True)
|
|
19
|
+
if state_machine.battery_level_is_above_mission_start_threshold():
|
|
20
|
+
return state_machine.release_from_lockdown # type: ignore
|
|
21
|
+
else:
|
|
22
|
+
return state_machine.starting_recharging # type: ignore
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
26
|
+
EventHandlerMapping(
|
|
27
|
+
name="release_from_lockdown",
|
|
28
|
+
event=events.api_requests.release_from_lockdown.request,
|
|
29
|
+
handler=_release_from_lockdown_handler,
|
|
30
|
+
),
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
super().__init__(
|
|
34
|
+
state_name="lockdown",
|
|
35
|
+
state_machine=state_machine,
|
|
36
|
+
event_handler_mappings=event_handlers,
|
|
37
|
+
)
|
|
@@ -63,6 +63,17 @@ class Monitor(EventHandlerBase):
|
|
|
63
63
|
return state_machine.stop # type: ignore
|
|
64
64
|
return None
|
|
65
65
|
|
|
66
|
+
def _send_to_lockdown_event_handler(
|
|
67
|
+
event: Event[bool],
|
|
68
|
+
) -> Optional[Callable]:
|
|
69
|
+
should_lockdown: bool = event.consume_event()
|
|
70
|
+
if should_lockdown:
|
|
71
|
+
state_machine.logger.warning(
|
|
72
|
+
"Cancelling current mission due to robot going to lockdown"
|
|
73
|
+
)
|
|
74
|
+
return state_machine.stop_go_to_lockdown # type: ignore
|
|
75
|
+
return None
|
|
76
|
+
|
|
66
77
|
event_handlers: List[EventHandlerMapping] = [
|
|
67
78
|
EventHandlerMapping(
|
|
68
79
|
name="stop_mission_event",
|
|
@@ -107,6 +118,11 @@ class Monitor(EventHandlerBase):
|
|
|
107
118
|
event=shared_state.robot_battery_level,
|
|
108
119
|
handler=_robot_battery_level_updated_handler,
|
|
109
120
|
),
|
|
121
|
+
EventHandlerMapping(
|
|
122
|
+
name="send_to_lockdown_event",
|
|
123
|
+
event=events.api_requests.send_to_lockdown.request,
|
|
124
|
+
handler=_send_to_lockdown_event_handler,
|
|
125
|
+
),
|
|
110
126
|
]
|
|
111
127
|
super().__init__(
|
|
112
128
|
state_name="monitor",
|