isar 1.26.4__tar.gz → 1.27.1__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.
Potentially problematic release.
This version of isar might be problematic. Click here for more details.
- {isar-1.26.4 → isar-1.27.1}/PKG-INFO +14 -7
- {isar-1.26.4 → isar-1.27.1}/README.md +13 -6
- isar-1.27.1/docs/full_state_machine_diagram.png +0 -0
- isar-1.27.1/docs/mission_state_machine_diagram.png +0 -0
- isar-1.27.1/docs/robot_status_state_machine_diagram.png +0 -0
- isar-1.27.1/docs/update_state_diagram.py +58 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/api.py +25 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/models/start_mission_definition.py +1 -7
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/schedule/scheduling_controller.py +17 -1
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/settings.py +4 -1
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/queues/events.py +1 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/queues/queue_utils.py +6 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/modules.py +13 -6
- {isar-1.26.4 → isar-1.27.1}/src/isar/robot/robot.py +10 -1
- {isar-1.26.4 → isar-1.27.1}/src/isar/robot/robot_status.py +11 -5
- {isar-1.26.4 → isar-1.27.1}/src/isar/robot/robot_task_status.py +3 -3
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/utilities/scheduling_utilities.py +60 -7
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/state_machine.py +51 -121
- isar-1.27.1/src/isar/state_machine/states/await_next_mission.py +92 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/states/blocked_protective_stop.py +2 -5
- isar-1.27.1/src/isar/state_machine/states/home.py +87 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/states/monitor.py +8 -3
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/states/offline.py +3 -5
- isar-1.27.1/src/isar/state_machine/states/returning_home.py +186 -0
- isar-1.26.4/src/isar/state_machine/states/idle.py → isar-1.27.1/src/isar/state_machine/states/robot_standing_still.py +20 -8
- isar-1.26.4/src/isar/state_machine/states/stop.py → isar-1.27.1/src/isar/state_machine/states/stopping.py +16 -4
- isar-1.27.1/src/isar/state_machine/states/unknown_status.py +74 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/states_enum.py +6 -3
- isar-1.27.1/src/isar/state_machine/transitions/functions/return_home.py +38 -0
- isar-1.27.1/src/isar/state_machine/transitions/functions/robot_status.py +27 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/start_mission.py +1 -1
- isar-1.27.1/src/isar/state_machine/transitions/mission.py +119 -0
- isar-1.27.1/src/isar/state_machine/transitions/return_home.py +69 -0
- isar-1.27.1/src/isar/state_machine/transitions/robot_status.py +73 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar.egg-info/PKG-INFO +14 -7
- {isar-1.26.4 → isar-1.27.1}/src/isar.egg-info/SOURCES.txt +22 -11
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/exceptions/robot_exceptions.py +14 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/mission/mission.py +8 -1
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/mission/status.py +2 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/mission/task.py +0 -1
- {isar-1.26.4 → isar-1.27.1}/tests/conftest.py +4 -4
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/test_successful_mission.py +1 -1
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/scheduler/test_scheduler_router.py +56 -17
- {isar-1.26.4 → isar-1.27.1}/tests/isar/mission/test_mission.py +1 -7
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/readers/test_mission_reader.py +9 -20
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/utilities/test_scheduling_utilities.py +10 -1
- {isar-1.26.4 → isar-1.27.1}/tests/isar/state_machine/states/test_monitor.py +2 -2
- {isar-1.26.4 → isar-1.27.1}/tests/isar/state_machine/test_state_machine.py +152 -43
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/mission_definition.py +1 -8
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/robot_interface.py +46 -9
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/status.py +1 -1
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/task.py +1 -6
- {isar-1.26.4 → isar-1.27.1}/tests/test_data/test_mission_working.json +0 -38
- isar-1.26.4/docs/state_machine_diagram.png +0 -0
- isar-1.26.4/src/isar/state_machine/states/off.py +0 -18
- {isar-1.26.4 → isar-1.27.1}/.dockerignore +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/ISSUE_TEMPLATE/improvement.md +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/release.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/workflows/compile_requirements.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/workflows/project_automations.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/workflows/pythonpackage.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/workflows/pythonpublish.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/.github/workflows/stale.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/.gitignore +0 -0
- {isar-1.26.4 → isar-1.27.1}/.pre-commit-config.yaml +0 -0
- {isar-1.26.4 → isar-1.27.1}/LICENSE +0 -0
- {isar-1.26.4 → isar-1.27.1}/SECURITY.md +0 -0
- {isar-1.26.4 → isar-1.27.1}/docs/Makefile +0 -0
- {isar-1.26.4 → isar-1.27.1}/docs/make.bat +0 -0
- {isar-1.26.4 → isar-1.27.1}/docs/rst_processing.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/docs/source/conf.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/docs/source/index.rst +0 -0
- {isar-1.26.4 → isar-1.27.1}/docs/source/readme_link.md +0 -0
- {isar-1.26.4 → isar-1.27.1}/main.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/pyproject.toml +0 -0
- {isar-1.26.4 → isar-1.27.1}/radixconfig.yml +0 -0
- {isar-1.26.4 → isar-1.27.1}/requirements.txt +0 -0
- {isar-1.26.4 → isar-1.27.1}/setup.cfg +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/models/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/models/models.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/robot_control/robot_controller.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/schedule/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/security/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/apis/security/authentication.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/certs/ca-cert.pem +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/configuration_error.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/keyvault/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/keyvault/keyvault_error.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/keyvault/keyvault_service.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/log.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/logging.conf +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/JSP1_intermediate_deck.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/JSP1_weather_deck.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/default_map.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/klab_b.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/klab_compressor.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/klab_turtlebot.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/maps/turtleworld.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_mission_definition/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_mission_definition/default_exr.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_mission_definition/default_mission.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_mission_definition/default_turtlebot.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_missions/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_missions/default.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/predefined_missions/default_turtlebot.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/config/settings.env +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/mission_planner/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/mission_planner/local_planner.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/mission_planner/mission_planner_interface.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/mission_planner/sequential_task_selector.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/mission_planner/task_selector_interface.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/message.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/queues/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/queues/queue_io.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/queues/queue_timeout_error.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/communication/queues/status_queue.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/models/mission_metadata/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/robot/robot_start_mission.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/robot/robot_stop_mission.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/script.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/auth/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/auth/azure_credentials.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/mqtt/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/mqtt/mqtt_client.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/mqtt/robot_info_publisher.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/request_handler.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/service_connections/stid/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/utilities/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/utilities/queue_utilities.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/utilities/robot_utilities.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/services/utilities/threaded_request.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/states/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/state_machine/states/paused.py +0 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/fail_mission.py +0 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/finish_mission.py +0 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/pause.py +0 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/resume.py +0 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/stop.py +0 -0
- {isar-1.26.4/src/isar/state_machine/transitions → isar-1.27.1/src/isar/state_machine/transitions/functions}/utils.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/blob_storage.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/local_storage.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/slimm_storage.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/storage_interface.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/uploader.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar/storage/utilities.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar.egg-info/dependency_links.txt +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar.egg-info/entry_points.txt +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar.egg-info/requires.txt +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/isar.egg-info/top_level.txt +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/exceptions/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/initialize/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/inspection/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/inspection/inspection.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/mission/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/robots/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/robots/battery_state.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/robots/media.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/models/robots/robot_model.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/robot_interface.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/telemetry/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/telemetry/mqtt_client.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/telemetry/payloads.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/test_robot_interface.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/utilities/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/utilities/json_service.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/src/robot_interface/utilities/uuid_string_factory.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/config/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/config/maps/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/config/maps/turtleworld.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/config/missions/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/integration/turtlebot/config/missions/default.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/models/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/models/example_mission_definition.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/models/test_start_mission_definition.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/scheduler/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/security/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/apis/security/test_authentication.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/mission/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/models/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/models/communication/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/models/communication/test_queues.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/readers/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/service_connections/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/service_connections/echo/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/service_connections/test_base_request_handler.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/utilities/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/services/utilities/test_queue_utilities.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/state_machine/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/state_machine/states/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/storage/test_blob_storage.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/isar/storage/test_uploader.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/__init__.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/blob_storage.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/mqtt_client.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/pose.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/request.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/mocks/token.py +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/test_data/test_map_config/test_map_config.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/test_data/test_mission_not_working.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/test_data/test_mission_working_no_tasks.json +0 -0
- {isar-1.26.4 → isar-1.27.1}/tests/test_data/test_thermal_image_mission.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: isar
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.27.1
|
|
4
4
|
Summary: Integration and Supervisory control of Autonomous Robots
|
|
5
5
|
Author-email: Equinor ASA <fg_robots_dev@equinor.com>
|
|
6
6
|
License: Eclipse Public License version 2.0
|
|
@@ -331,22 +331,29 @@ The system consists of two main components.
|
|
|
331
331
|
The state machine handles interaction with the robots API and monitors the execution of missions. It also enables
|
|
332
332
|
interacting with the robot before, during and after missions.
|
|
333
333
|
|
|
334
|
-
The state machine is based on the [transitions](https://github.com/pytransitions/transitions) package for Python.
|
|
335
|
-
|
|
334
|
+
The state machine is based on the [transitions](https://github.com/pytransitions/transitions) package for Python. The following are some visualizations of the state machine:
|
|
335
|
+
|
|
336
|
+
Mission behavior without the robot status changed transition that enable the resting states to transition between each other if the robot status changes:
|
|
337
|
+

|
|
338
|
+
|
|
339
|
+
Robot status changed transition:
|
|
340
|
+

|
|
341
|
+
|
|
342
|
+
Full state machine:
|
|
343
|
+

|
|
336
344
|
|
|
337
345
|
In general the states
|
|
338
346
|
|
|
339
347
|
```
|
|
340
|
-
States.
|
|
341
|
-
States.Stop,
|
|
348
|
+
States.Stopping,
|
|
342
349
|
States.Monitor,
|
|
343
350
|
States.Paused,
|
|
344
351
|
```
|
|
345
352
|
|
|
346
|
-
indicates that the state machine is already running. For running a mission the state machine need to be in the
|
|
353
|
+
indicates that the state machine is already running. For running a mission the state machine need to be in the states
|
|
347
354
|
|
|
348
355
|
```
|
|
349
|
-
States.
|
|
356
|
+
States.Home, States.RobotStandingStill, States.AwaitNextMission or States.ReturningHome
|
|
350
357
|
```
|
|
351
358
|
|
|
352
359
|
### FastAPI
|
|
@@ -189,22 +189,29 @@ The system consists of two main components.
|
|
|
189
189
|
The state machine handles interaction with the robots API and monitors the execution of missions. It also enables
|
|
190
190
|
interacting with the robot before, during and after missions.
|
|
191
191
|
|
|
192
|
-
The state machine is based on the [transitions](https://github.com/pytransitions/transitions) package for Python.
|
|
193
|
-
|
|
192
|
+
The state machine is based on the [transitions](https://github.com/pytransitions/transitions) package for Python. The following are some visualizations of the state machine:
|
|
193
|
+
|
|
194
|
+
Mission behavior without the robot status changed transition that enable the resting states to transition between each other if the robot status changes:
|
|
195
|
+

|
|
196
|
+
|
|
197
|
+
Robot status changed transition:
|
|
198
|
+

|
|
199
|
+
|
|
200
|
+
Full state machine:
|
|
201
|
+

|
|
194
202
|
|
|
195
203
|
In general the states
|
|
196
204
|
|
|
197
205
|
```
|
|
198
|
-
States.
|
|
199
|
-
States.Stop,
|
|
206
|
+
States.Stopping,
|
|
200
207
|
States.Monitor,
|
|
201
208
|
States.Paused,
|
|
202
209
|
```
|
|
203
210
|
|
|
204
|
-
indicates that the state machine is already running. For running a mission the state machine need to be in the
|
|
211
|
+
indicates that the state machine is already running. For running a mission the state machine need to be in the states
|
|
205
212
|
|
|
206
213
|
```
|
|
207
|
-
States.
|
|
214
|
+
States.Home, States.RobotStandingStill, States.AwaitNextMission or States.ReturningHome
|
|
208
215
|
```
|
|
209
216
|
|
|
210
217
|
### FastAPI
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from injector import Injector
|
|
6
|
+
from transitions import State
|
|
7
|
+
from transitions.extensions import GraphMachine
|
|
8
|
+
|
|
9
|
+
from isar.modules import get_injector
|
|
10
|
+
from isar.state_machine.state_machine import StateMachine
|
|
11
|
+
from isar.state_machine.transitions.mission import get_mission_transitions
|
|
12
|
+
from isar.state_machine.transitions.return_home import get_return_home_transitions
|
|
13
|
+
from isar.state_machine.transitions.robot_status import get_robot_status_transitions
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def draw_diagram(states: List[State], transitions: List[dict], name: str):
|
|
17
|
+
machine = GraphMachine(states=states, initial="unknown_status", queued=True)
|
|
18
|
+
machine.add_transitions(transitions)
|
|
19
|
+
gp = machine.get_combined_graph()
|
|
20
|
+
|
|
21
|
+
state_machine_diagram_file = (
|
|
22
|
+
Path(__file__).parent.resolve().joinpath(Path(f"{name}.png"))
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if os.path.isfile(state_machine_diagram_file):
|
|
26
|
+
os.remove(state_machine_diagram_file)
|
|
27
|
+
|
|
28
|
+
gp.draw(state_machine_diagram_file, prog="dot")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
injector: Injector = get_injector()
|
|
33
|
+
state_machine: StateMachine = injector.get(StateMachine)
|
|
34
|
+
|
|
35
|
+
mission_extended_transitions: List[dict] = []
|
|
36
|
+
for transition in get_mission_transitions(state_machine):
|
|
37
|
+
mission_extended_transitions.append(transition)
|
|
38
|
+
|
|
39
|
+
for transition in get_return_home_transitions(state_machine):
|
|
40
|
+
mission_extended_transitions.append(transition)
|
|
41
|
+
|
|
42
|
+
draw_diagram(
|
|
43
|
+
states=state_machine.states,
|
|
44
|
+
transitions=mission_extended_transitions,
|
|
45
|
+
name="mission_state_machine_diagram",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
draw_diagram(
|
|
49
|
+
states=state_machine.states,
|
|
50
|
+
transitions=get_robot_status_transitions(state_machine),
|
|
51
|
+
name="robot_status_state_machine_diagram",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
draw_diagram(
|
|
55
|
+
states=state_machine.states,
|
|
56
|
+
transitions=state_machine.transitions,
|
|
57
|
+
name="full_state_machine_diagram",
|
|
58
|
+
)
|
|
@@ -150,6 +150,31 @@ class API:
|
|
|
150
150
|
HTTPStatus.CONFLICT.value: {
|
|
151
151
|
"description": "Conflict - Invalid command in the current state",
|
|
152
152
|
},
|
|
153
|
+
HTTPStatus.BAD_REQUEST.value: {
|
|
154
|
+
"description": "Bad request - Robot does not have the capabilities to perform the mission",
|
|
155
|
+
},
|
|
156
|
+
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
157
|
+
"description": "Internal Server Error - Current state of state machine unknown",
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
router.add_api_route(
|
|
162
|
+
path="/schedule/return-home",
|
|
163
|
+
endpoint=self.scheduling_controller.return_home,
|
|
164
|
+
methods=["POST"],
|
|
165
|
+
dependencies=[authentication_dependency],
|
|
166
|
+
summary="Start return home mission",
|
|
167
|
+
responses={
|
|
168
|
+
HTTPStatus.OK.value: {
|
|
169
|
+
"description": "Return home mission succesfully started",
|
|
170
|
+
"model": StartMissionResponse,
|
|
171
|
+
},
|
|
172
|
+
HTTPStatus.UNPROCESSABLE_ENTITY.value: {
|
|
173
|
+
"description": "Invalid body - The JSON is incorrect",
|
|
174
|
+
},
|
|
175
|
+
HTTPStatus.CONFLICT.value: {
|
|
176
|
+
"description": "Conflict - Invalid command in the current state",
|
|
177
|
+
},
|
|
153
178
|
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
154
179
|
"description": "Internal Server Error - Current state of state machine unknown",
|
|
155
180
|
},
|
|
@@ -92,7 +92,7 @@ def to_isar_task(task_definition: StartMissionTaskDefinition) -> TASKS:
|
|
|
92
92
|
if task_definition.type == TaskType.Inspection:
|
|
93
93
|
return to_inspection_task(task_definition)
|
|
94
94
|
elif task_definition.type == TaskType.ReturnToHome:
|
|
95
|
-
return
|
|
95
|
+
return ReturnToHome()
|
|
96
96
|
else:
|
|
97
97
|
raise MissionPlannerError(
|
|
98
98
|
f"Failed to create task: '{task_definition.type}' is not a valid"
|
|
@@ -162,11 +162,5 @@ def to_inspection_task(task_definition: StartMissionTaskDefinition) -> TASKS:
|
|
|
162
162
|
)
|
|
163
163
|
|
|
164
164
|
|
|
165
|
-
def create_return_to_home_task(
|
|
166
|
-
task_definition: StartMissionTaskDefinition,
|
|
167
|
-
) -> ReturnToHome:
|
|
168
|
-
return ReturnToHome(pose=task_definition.pose.to_alitra_pose())
|
|
169
|
-
|
|
170
|
-
|
|
171
165
|
def _build_mission_name() -> str:
|
|
172
166
|
return f"{settings.PLANT_SHORT_NAME}{settings.ROBOT_NAME}{int(time.time())}"
|
|
@@ -98,6 +98,16 @@ class SchedulingController:
|
|
|
98
98
|
self.scheduling_utilities.start_mission(mission=mission)
|
|
99
99
|
return self._api_response(mission)
|
|
100
100
|
|
|
101
|
+
def return_home(self) -> None:
|
|
102
|
+
self.logger.info("Received request to return home")
|
|
103
|
+
|
|
104
|
+
state: States = self.scheduling_utilities.get_state()
|
|
105
|
+
self.scheduling_utilities.verify_state_machine_ready_to_receive_return_home_mission(
|
|
106
|
+
state
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
self.scheduling_utilities.return_home()
|
|
110
|
+
|
|
101
111
|
def pause_mission(self) -> ControlMissionResponse:
|
|
102
112
|
self.logger.info("Received request to pause current mission")
|
|
103
113
|
|
|
@@ -142,7 +152,13 @@ class SchedulingController:
|
|
|
142
152
|
|
|
143
153
|
state: States = self.scheduling_utilities.get_state()
|
|
144
154
|
|
|
145
|
-
if
|
|
155
|
+
if (
|
|
156
|
+
state == States.UnknownStatus
|
|
157
|
+
or state == States.Stopping
|
|
158
|
+
or state == States.BlockedProtectiveStop
|
|
159
|
+
or state == States.Offline
|
|
160
|
+
or state == States.Home
|
|
161
|
+
):
|
|
146
162
|
error_message = (
|
|
147
163
|
f"Conflict - Stop command received in invalid state - State: {state}"
|
|
148
164
|
)
|
|
@@ -82,6 +82,9 @@ class Settings(BaseSettings):
|
|
|
82
82
|
# FastAPI port
|
|
83
83
|
API_PORT: int = Field(default=3000)
|
|
84
84
|
|
|
85
|
+
# Determines how long delay time should be allowed before returning home
|
|
86
|
+
RETURN_HOME_DELAY: int = Field(default=10)
|
|
87
|
+
|
|
85
88
|
# Determines which mission planner module is used by ISAR
|
|
86
89
|
MISSION_PLANNER: str = Field(default="local")
|
|
87
90
|
|
|
@@ -311,7 +314,7 @@ class RobotSettings(BaseSettings):
|
|
|
311
314
|
|
|
312
315
|
# ISAR steps the robot is capable of performing
|
|
313
316
|
# This should be set in the robot package settings.env file
|
|
314
|
-
CAPABILITIES: List[str] = Field(default=["
|
|
317
|
+
CAPABILITIES: List[str] = Field(default=["take_image"])
|
|
315
318
|
|
|
316
319
|
# Model of the robot which ISAR is connected to
|
|
317
320
|
# This should be set in the robot package settings.env file
|
|
@@ -29,6 +29,7 @@ class APIRequests:
|
|
|
29
29
|
self.stop_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
30
30
|
self.pause_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
31
31
|
self.resume_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
32
|
+
self.return_home: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class StateMachineEvents:
|
|
@@ -30,3 +30,9 @@ def check_for_event(queue: Queue[T]) -> Optional[T]:
|
|
|
30
30
|
return queue.get(block=False)
|
|
31
31
|
except Empty:
|
|
32
32
|
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def check_for_event_without_consumption(queue: Queue[T]) -> bool:
|
|
36
|
+
return (
|
|
37
|
+
queue.qsize() != 0
|
|
38
|
+
) # Queue size is not reliable, but should be sufficient for this case
|
|
@@ -70,12 +70,19 @@ class ApplicationContainer(containers.DeclarativeContainer):
|
|
|
70
70
|
)
|
|
71
71
|
|
|
72
72
|
# Storage
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
storage_handlers_temp = []
|
|
74
|
+
if settings.STORAGE_LOCAL_ENABLED:
|
|
75
|
+
local_storage = providers.Singleton(LocalStorage)
|
|
76
|
+
storage_handlers_temp.append(local_storage)
|
|
77
|
+
if settings.STORAGE_BLOB_ENABLED:
|
|
78
|
+
blob_storage = providers.Singleton(BlobStorage, keyvault=keyvault)
|
|
79
|
+
storage_handlers_temp.append(blob_storage)
|
|
80
|
+
if settings.STORAGE_SLIMM_ENABLED:
|
|
81
|
+
slimm_storage = providers.Singleton(
|
|
82
|
+
SlimmStorage, request_handler=providers.Singleton(RequestHandler)
|
|
83
|
+
)
|
|
84
|
+
storage_handlers_temp.append(slimm_storage)
|
|
85
|
+
storage_handlers = providers.List(*storage_handlers_temp)
|
|
79
86
|
|
|
80
87
|
# Mqtt client
|
|
81
88
|
mqtt_client = (
|
|
@@ -11,11 +11,12 @@ from isar.models.communication.queues.events import (
|
|
|
11
11
|
SharedState,
|
|
12
12
|
StateMachineEvents,
|
|
13
13
|
)
|
|
14
|
-
from isar.models.communication.queues.queue_utils import check_for_event
|
|
14
|
+
from isar.models.communication.queues.queue_utils import check_for_event, trigger_event
|
|
15
15
|
from isar.robot.robot_start_mission import RobotStartMissionThread
|
|
16
16
|
from isar.robot.robot_status import RobotStatusThread
|
|
17
17
|
from isar.robot.robot_stop_mission import RobotStopMissionThread
|
|
18
18
|
from isar.robot.robot_task_status import RobotTaskStatusThread
|
|
19
|
+
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage, ErrorReason
|
|
19
20
|
from robot_interface.robot_interface import RobotInterface
|
|
20
21
|
|
|
21
22
|
|
|
@@ -94,6 +95,14 @@ class Robot(object):
|
|
|
94
95
|
self.stop_mission_thread_thread is not None
|
|
95
96
|
and self.start_mission_thread.is_alive()
|
|
96
97
|
):
|
|
98
|
+
error_description = "Received stop mission event while trying to start a mission. Aborting stop attempt."
|
|
99
|
+
error_message = ErrorMessage(
|
|
100
|
+
error_reason=ErrorReason.RobotStillStartingMissionException,
|
|
101
|
+
error_description=error_description,
|
|
102
|
+
)
|
|
103
|
+
trigger_event(
|
|
104
|
+
self.robot_service_events.mission_failed_to_stop, error_message
|
|
105
|
+
)
|
|
97
106
|
return
|
|
98
107
|
self.stop_mission_thread_thread = RobotStopMissionThread(
|
|
99
108
|
self.robot_service_events, self.robot, self.signal_thread_quitting
|
|
@@ -5,6 +5,7 @@ from threading import Event, Thread
|
|
|
5
5
|
from isar.config.settings import settings
|
|
6
6
|
from isar.models.communication.queues.events import SharedState
|
|
7
7
|
from isar.models.communication.queues.queue_utils import update_shared_state
|
|
8
|
+
from robot_interface.models.exceptions.robot_exceptions import RobotException
|
|
8
9
|
from robot_interface.robot_interface import RobotInterface
|
|
9
10
|
|
|
10
11
|
|
|
@@ -19,7 +20,9 @@ class RobotStatusThread(Thread):
|
|
|
19
20
|
self.shared_state: SharedState = shared_state
|
|
20
21
|
self.robot: RobotInterface = robot
|
|
21
22
|
self.signal_thread_quitting: Event = signal_thread_quitting
|
|
22
|
-
self.last_robot_status_poll_time: float =
|
|
23
|
+
self.last_robot_status_poll_time: float = (
|
|
24
|
+
time.time() - settings.ROBOT_API_STATUS_POLL_INTERVAL
|
|
25
|
+
)
|
|
23
26
|
Thread.__init__(self, name="Robot status thread")
|
|
24
27
|
|
|
25
28
|
def stop(self) -> None:
|
|
@@ -40,9 +43,12 @@ class RobotStatusThread(Thread):
|
|
|
40
43
|
while not self.signal_thread_quitting.wait(0.001):
|
|
41
44
|
if not self._is_ready_to_poll_for_status():
|
|
42
45
|
continue
|
|
46
|
+
try:
|
|
47
|
+
robot_status = self.robot.robot_status()
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
update_shared_state(self.shared_state.robot_status, robot_status)
|
|
50
|
+
self.last_robot_status_poll_time = time.time()
|
|
51
|
+
except RobotException as e:
|
|
52
|
+
self.logger.error(f"Failed to retrieve robot status: {e}")
|
|
53
|
+
continue
|
|
48
54
|
self.logger.info("Exiting robot status thread")
|
|
@@ -50,15 +50,15 @@ class RobotTaskStatusThread(Thread):
|
|
|
50
50
|
|
|
51
51
|
try:
|
|
52
52
|
task_status = self.robot.task_status(self.task_id)
|
|
53
|
-
|
|
53
|
+
request_status_failure_counter = 0
|
|
54
54
|
except (
|
|
55
55
|
RobotCommunicationTimeoutException,
|
|
56
56
|
RobotCommunicationException,
|
|
57
57
|
) as e:
|
|
58
|
-
|
|
58
|
+
request_status_failure_counter += 1
|
|
59
59
|
self.logger.error(
|
|
60
60
|
f"Failed to get task status "
|
|
61
|
-
f"{
|
|
61
|
+
f"{request_status_failure_counter} times because: "
|
|
62
62
|
f"{e.error_description}"
|
|
63
63
|
)
|
|
64
64
|
|
|
@@ -119,19 +119,47 @@ class SchedulingUtilities:
|
|
|
119
119
|
return True
|
|
120
120
|
|
|
121
121
|
def verify_state_machine_ready_to_receive_mission(self, state: States) -> bool:
|
|
122
|
-
"""Verify that the state machine is
|
|
122
|
+
"""Verify that the state machine is ready to receive a mission
|
|
123
123
|
|
|
124
124
|
Raises
|
|
125
125
|
------
|
|
126
126
|
HTTPException 409 Conflict
|
|
127
|
-
If state machine is not
|
|
127
|
+
If state machine is not home, robot standing still, awaiting next mission
|
|
128
|
+
or returning home and therefore cannot start a new mission
|
|
128
129
|
"""
|
|
129
|
-
if
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
if (
|
|
131
|
+
state == States.RobotStandingStill
|
|
132
|
+
or state == States.Home
|
|
133
|
+
or state == States.AwaitNextMission
|
|
134
|
+
or state == States.ReturningHome
|
|
135
|
+
):
|
|
136
|
+
return True
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
error_message = f"Conflict - Robot is not home, robot standing still, awaiting next mission or returning home - State: {state}"
|
|
139
|
+
self.logger.warning(error_message)
|
|
140
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
141
|
+
|
|
142
|
+
def verify_state_machine_ready_to_receive_return_home_mission(
|
|
143
|
+
self, state: States
|
|
144
|
+
) -> bool:
|
|
145
|
+
"""Verify that the state machine is ready to receive a return home mission
|
|
146
|
+
|
|
147
|
+
Raises
|
|
148
|
+
------
|
|
149
|
+
HTTPException 409 Conflict
|
|
150
|
+
If state machine is not home, robot standing still or awaiting next mission
|
|
151
|
+
and therefore cannot start a new return home mission
|
|
152
|
+
"""
|
|
153
|
+
if (
|
|
154
|
+
state == States.RobotStandingStill
|
|
155
|
+
or state == States.Home
|
|
156
|
+
or state == States.AwaitNextMission
|
|
157
|
+
):
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
error_message = f"Conflict - Robot is not home, robot standing still or awaiting next mission - State: {state}"
|
|
161
|
+
self.logger.warning(error_message)
|
|
162
|
+
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
|
|
135
163
|
|
|
136
164
|
def start_mission(
|
|
137
165
|
self,
|
|
@@ -157,6 +185,31 @@ class SchedulingUtilities:
|
|
|
157
185
|
)
|
|
158
186
|
self.logger.info("OK - Mission started in ISAR")
|
|
159
187
|
|
|
188
|
+
def return_home(
|
|
189
|
+
self,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Start return home mission
|
|
192
|
+
|
|
193
|
+
Raises
|
|
194
|
+
------
|
|
195
|
+
HTTTPException 408 Request timeout
|
|
196
|
+
If there is a timeout while communicating with the state machine
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
self._send_command(
|
|
200
|
+
True,
|
|
201
|
+
self.api_events.return_home,
|
|
202
|
+
)
|
|
203
|
+
except QueueTimeoutError:
|
|
204
|
+
error_message = (
|
|
205
|
+
"Internal Server Error - Failed to start return home mission in ISAR"
|
|
206
|
+
)
|
|
207
|
+
self.logger.error(error_message)
|
|
208
|
+
raise HTTPException(
|
|
209
|
+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=error_message
|
|
210
|
+
)
|
|
211
|
+
self.logger.info("OK - Return home mission started in ISAR")
|
|
212
|
+
|
|
160
213
|
def pause_mission(self) -> ControlMissionResponse:
|
|
161
214
|
"""Pause mission
|
|
162
215
|
|