isar 1.33.6__tar.gz → 1.33.7__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.33.6 → isar-1.33.7}/PKG-INFO +1 -1
- isar-1.33.7/docs/full_state_machine_diagram.png +0 -0
- isar-1.33.7/docs/mission_state_machine_diagram.png +0 -0
- isar-1.33.7/docs/robot_status_state_machine_diagram.png +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/settings.py +4 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/models/events.py +2 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/robot/robot.py +18 -1
- isar-1.33.6/src/isar/robot/robot_status.py → isar-1.33.7/src/isar/robot/robot_battery.py +17 -15
- isar-1.33.7/src/isar/robot/robot_status.py +71 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/blocked_protective_stop.py +9 -9
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/home.py +21 -13
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/offline.py +9 -10
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/robot_status.py +15 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/return_home.py +9 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/utils/common_event_handlers.py +5 -2
- {isar-1.33.6 → isar-1.33.7}/src/isar.egg-info/PKG-INFO +1 -1
- {isar-1.33.6 → isar-1.33.7}/src/isar.egg-info/SOURCES.txt +1 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/state_machine/test_state_machine.py +22 -4
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/robot_interface.py +38 -1
- isar-1.33.6/docs/full_state_machine_diagram.png +0 -0
- isar-1.33.6/docs/mission_state_machine_diagram.png +0 -0
- isar-1.33.6/docs/robot_status_state_machine_diagram.png +0 -0
- {isar-1.33.6 → isar-1.33.7}/.dockerignore +0 -0
- {isar-1.33.6 → isar-1.33.7}/.env.test +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/ISSUE_TEMPLATE/improvement.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/release.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/workflows/compile_requirements.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/workflows/project_automations.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/workflows/pythonpackage.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/workflows/pythonpublish.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/.github/workflows/stale.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/.gitignore +0 -0
- {isar-1.33.6 → isar-1.33.7}/.pre-commit-config.yaml +0 -0
- {isar-1.33.6 → isar-1.33.7}/LICENSE +0 -0
- {isar-1.33.6 → isar-1.33.7}/README.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/SECURITY.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/Makefile +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/make.bat +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/rst_processing.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/source/conf.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/source/index.rst +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/source/readme_link.md +0 -0
- {isar-1.33.6 → isar-1.33.7}/docs/update_state_diagram.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/main.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/pyproject.toml +0 -0
- {isar-1.33.6 → isar-1.33.7}/radixconfig.yml +0 -0
- {isar-1.33.6 → isar-1.33.7}/requirements.txt +0 -0
- {isar-1.33.6 → isar-1.33.7}/setup.cfg +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/api.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/models/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/models/models.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/models/start_mission_definition.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/robot_control/robot_controller.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/schedule/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/schedule/scheduling_controller.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/security/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/apis/security/authentication.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/certs/ca-cert.pem +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/configuration_error.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/keyvault/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/keyvault/keyvault_error.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/keyvault/keyvault_service.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/log.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/logging.conf +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/JSP1_intermediate_deck.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/JSP1_weather_deck.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/default_map.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/klab_b.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/klab_compressor.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/klab_turtlebot.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/maps/turtleworld.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/open_telemetry.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_mission_definition/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_mission_definition/default_exr.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_mission_definition/default_mission.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_mission_definition/default_turtlebot.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_missions/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_missions/default.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/config/predefined_missions/default_turtlebot.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/eventhandlers/eventhandler.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/mission_planner/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/mission_planner/local_planner.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/mission_planner/mission_planner_interface.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/mission_planner/sequential_task_selector.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/mission_planner/task_selector_interface.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/models/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/modules.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/robot/robot_pause_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/robot/robot_start_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/robot/robot_stop_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/robot/robot_task_status.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/script.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/auth/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/auth/azure_credentials.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/service_connections/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/service_connections/mqtt/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/service_connections/mqtt/mqtt_client.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/service_connections/mqtt/robot_info_publisher.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/service_connections/request_handler.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/utilities/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/utilities/robot_utilities.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/utilities/scheduling_utilities.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/services/utilities/threaded_request.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/state_machine.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/await_next_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/going_to_lockdown.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/intervention_needed.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/lockdown.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/monitor.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/paused.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/pausing.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/pausing_return_home.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/recharging.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/return_home_paused.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/returning_home.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/stopping.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/stopping_go_to_lockdown.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/stopping_return_home.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states/unknown_status.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/states_enum.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/fail_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/finish_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/pause.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/resume.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/return_home.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/start_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/stop.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/functions/utils.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/state_machine/transitions/robot_status.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/storage/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/storage/blob_storage.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/storage/local_storage.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/storage/storage_interface.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/storage/uploader.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar/storage/utilities.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar.egg-info/dependency_links.txt +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar.egg-info/entry_points.txt +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar.egg-info/requires.txt +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/isar.egg-info/top_level.txt +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/exceptions/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/exceptions/robot_exceptions.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/initialize/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/inspection/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/inspection/inspection.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/mission/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/mission/mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/mission/status.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/mission/task.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/robots/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/robots/battery_state.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/robots/media.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/models/robots/robot_model.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/robot_interface.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/telemetry/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/telemetry/mqtt_client.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/telemetry/payloads.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/test_robot_interface.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/utilities/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/utilities/json_service.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/src/robot_interface/utilities/uuid_string_factory.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/conftest.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/config/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/config/maps/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/config/maps/turtleworld.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/config/missions/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/config/missions/default.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/integration/turtlebot/test_successful_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/models/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/models/example_mission_definition.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/models/test_start_mission_definition.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/scheduler/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/scheduler/test_scheduler_router.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/security/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/apis/security/test_authentication.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/mission/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/mission/test_mission.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/models/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/models/communication/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/models/communication/test_events.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/readers/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/readers/test_mission_reader.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/service_connections/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/service_connections/echo/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/service_connections/test_base_request_handler.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/utilities/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/utilities/test_queue_utilities.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/services/utilities/test_scheduling_utilities.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/state_machine/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/state_machine/states/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/state_machine/states/test_monitor.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/storage/test_blob_storage.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/isar/storage/test_uploader.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_data/test_map_config/test_map_config.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_data/test_mission_not_working.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_data/test_mission_working.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_data/test_mission_working_no_tasks.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_data/test_thermal_image_mission.json +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/__init__.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/blob_storage.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/mission_definition.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/mqtt_client.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/pose.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/request.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/status.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/task.py +0 -0
- {isar-1.33.6 → isar-1.33.7}/tests/test_double/token.py +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -59,6 +59,9 @@ class Settings(BaseSettings):
|
|
|
59
59
|
# issues
|
|
60
60
|
REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY: float = Field(default=10)
|
|
61
61
|
|
|
62
|
+
# Time allowed to clear the robot status before giving up
|
|
63
|
+
CLEAR_ROBOT_STATUS_TIMEOUT: int = Field(default=3)
|
|
64
|
+
|
|
62
65
|
# Number of attempts for state transitions resume and pause if failed
|
|
63
66
|
STATE_TRANSITION_NUM_RETIRES: int = Field(default=10)
|
|
64
67
|
|
|
@@ -78,6 +81,7 @@ class Settings(BaseSettings):
|
|
|
78
81
|
ROBOT_STATUS_PUBLISH_INTERVAL: float = Field(default=1)
|
|
79
82
|
ROBOT_HEARTBEAT_PUBLISH_INTERVAL: float = Field(default=1)
|
|
80
83
|
ROBOT_INFO_PUBLISH_INTERVAL: float = Field(default=5)
|
|
84
|
+
ROBOT_API_BATTERY_POLL_INTERVAL: float = Field(default=5)
|
|
81
85
|
ROBOT_API_STATUS_POLL_INTERVAL: float = Field(default=5)
|
|
82
86
|
THREAD_CHECK_INTERVAL: float = Field(default=0.01)
|
|
83
87
|
|
|
@@ -123,6 +123,7 @@ class StateMachineEvents:
|
|
|
123
123
|
self.stop_mission: Event[bool] = Event("stop_mission")
|
|
124
124
|
self.pause_mission: Event[bool] = Event("pause_mission")
|
|
125
125
|
self.task_status_request: Event[str] = Event("task_status_request")
|
|
126
|
+
self.clear_robot_status: Event[bool] = Event("clear_robot_status")
|
|
126
127
|
|
|
127
128
|
|
|
128
129
|
class RobotServiceEvents:
|
|
@@ -132,6 +133,7 @@ class RobotServiceEvents:
|
|
|
132
133
|
self.mission_started: Event[bool] = Event("mission_started")
|
|
133
134
|
self.mission_failed: Event[ErrorMessage] = Event("mission_failed")
|
|
134
135
|
self.robot_status_changed: Event[bool] = Event("robot_status_changed")
|
|
136
|
+
self.robot_status_cleared: Event[bool] = Event("robot_status_cleared")
|
|
135
137
|
self.mission_failed_to_stop: Event[ErrorMessage] = Event(
|
|
136
138
|
"mission_failed_to_stop"
|
|
137
139
|
)
|
|
@@ -9,6 +9,7 @@ from isar.models.events import (
|
|
|
9
9
|
SharedState,
|
|
10
10
|
StateMachineEvents,
|
|
11
11
|
)
|
|
12
|
+
from isar.robot.robot_battery import RobotBatteryThread
|
|
12
13
|
from isar.robot.robot_pause_mission import RobotPauseMissionThread
|
|
13
14
|
from isar.robot.robot_start_mission import RobotStartMissionThread
|
|
14
15
|
from isar.robot.robot_status import RobotStatusThread
|
|
@@ -29,6 +30,7 @@ class Robot(object):
|
|
|
29
30
|
self.shared_state: SharedState = shared_state
|
|
30
31
|
self.robot: RobotInterface = robot
|
|
31
32
|
self.start_mission_thread: Optional[RobotStartMissionThread] = None
|
|
33
|
+
self.robot_battery_thread: Optional[RobotBatteryThread] = None
|
|
32
34
|
self.robot_status_thread: Optional[RobotStatusThread] = None
|
|
33
35
|
self.robot_task_status_thread: Optional[RobotTaskStatusThread] = None
|
|
34
36
|
self.stop_mission_thread: Optional[RobotStopMissionThread] = None
|
|
@@ -39,6 +41,11 @@ class Robot(object):
|
|
|
39
41
|
self.signal_thread_quitting.set()
|
|
40
42
|
if self.robot_status_thread is not None and self.robot_status_thread.is_alive():
|
|
41
43
|
self.robot_status_thread.join()
|
|
44
|
+
if (
|
|
45
|
+
self.robot_battery_thread is not None
|
|
46
|
+
and self.robot_battery_thread.is_alive()
|
|
47
|
+
):
|
|
48
|
+
self.robot_battery_thread.join()
|
|
42
49
|
if (
|
|
43
50
|
self.robot_task_status_thread is not None
|
|
44
51
|
and self.robot_task_status_thread.is_alive()
|
|
@@ -52,6 +59,7 @@ class Robot(object):
|
|
|
52
59
|
if self.stop_mission_thread is not None and self.stop_mission_thread.is_alive():
|
|
53
60
|
self.stop_mission_thread.join()
|
|
54
61
|
self.robot_status_thread = None
|
|
62
|
+
self.robot_battery_thread = None
|
|
55
63
|
self.robot_task_status_thread = None
|
|
56
64
|
self.start_mission_thread = None
|
|
57
65
|
|
|
@@ -143,10 +151,19 @@ class Robot(object):
|
|
|
143
151
|
|
|
144
152
|
def run(self) -> None:
|
|
145
153
|
self.robot_status_thread = RobotStatusThread(
|
|
146
|
-
self.robot,
|
|
154
|
+
robot=self.robot,
|
|
155
|
+
signal_thread_quitting=self.signal_thread_quitting,
|
|
156
|
+
shared_state=self.shared_state,
|
|
157
|
+
state_machine_events=self.state_machine_events,
|
|
158
|
+
robot_service_events=self.robot_service_events,
|
|
147
159
|
)
|
|
148
160
|
self.robot_status_thread.start()
|
|
149
161
|
|
|
162
|
+
self.robot_battery_thread = RobotBatteryThread(
|
|
163
|
+
self.robot, self.signal_thread_quitting, self.shared_state
|
|
164
|
+
)
|
|
165
|
+
self.robot_battery_thread.start()
|
|
166
|
+
|
|
150
167
|
while not self.signal_thread_quitting.wait(0):
|
|
151
168
|
self._start_mission_event_handler(self.state_machine_events.start_mission)
|
|
152
169
|
|
|
@@ -8,7 +8,7 @@ from robot_interface.models.exceptions.robot_exceptions import RobotException
|
|
|
8
8
|
from robot_interface.robot_interface import RobotInterface
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class
|
|
11
|
+
class RobotBatteryThread(Thread):
|
|
12
12
|
def __init__(
|
|
13
13
|
self,
|
|
14
14
|
robot: RobotInterface,
|
|
@@ -19,20 +19,24 @@ class RobotStatusThread(Thread):
|
|
|
19
19
|
self.shared_state: SharedState = shared_state
|
|
20
20
|
self.robot: RobotInterface = robot
|
|
21
21
|
self.signal_thread_quitting: Event = signal_thread_quitting
|
|
22
|
-
self.
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
Thread.__init__(self, name="Robot status thread")
|
|
22
|
+
self.last_robot_battery_poll_time: float = time.time()
|
|
23
|
+
self.force_battery_poll_next_iteration: bool = True
|
|
24
|
+
Thread.__init__(self, name="Robot battery thread")
|
|
26
25
|
|
|
27
26
|
def stop(self) -> None:
|
|
28
27
|
return
|
|
29
28
|
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
def _is_ready_to_poll_for_battery(self) -> bool:
|
|
30
|
+
if self.force_battery_poll_next_iteration:
|
|
31
|
+
self.force_battery_poll_next_iteration = False
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
time_since_last_robot_battery_poll = (
|
|
35
|
+
time.time() - self.last_robot_battery_poll_time
|
|
33
36
|
)
|
|
34
37
|
return (
|
|
35
|
-
|
|
38
|
+
time_since_last_robot_battery_poll
|
|
39
|
+
> settings.ROBOT_API_BATTERY_POLL_INTERVAL
|
|
36
40
|
)
|
|
37
41
|
|
|
38
42
|
def run(self):
|
|
@@ -42,17 +46,15 @@ class RobotStatusThread(Thread):
|
|
|
42
46
|
thread_check_interval = settings.THREAD_CHECK_INTERVAL
|
|
43
47
|
|
|
44
48
|
while not self.signal_thread_quitting.wait(thread_check_interval):
|
|
45
|
-
if not self.
|
|
49
|
+
if not self._is_ready_to_poll_for_battery():
|
|
46
50
|
continue
|
|
47
51
|
try:
|
|
48
|
-
self.
|
|
52
|
+
self.last_robot_battery_poll_time = time.time()
|
|
49
53
|
|
|
50
|
-
robot_status = self.robot.robot_status()
|
|
51
54
|
robot_battery_level = self.robot.get_battery_level()
|
|
52
55
|
|
|
53
|
-
self.shared_state.robot_status.update(robot_status)
|
|
54
56
|
self.shared_state.robot_battery_level.update(robot_battery_level)
|
|
55
57
|
except RobotException as e:
|
|
56
|
-
self.logger.error(f"Failed to retrieve robot
|
|
58
|
+
self.logger.error(f"Failed to retrieve robot battery level: {e}")
|
|
57
59
|
continue
|
|
58
|
-
self.logger.info("Exiting robot
|
|
60
|
+
self.logger.info("Exiting robot battery thread")
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from threading import Event, Thread
|
|
4
|
+
|
|
5
|
+
from isar.config.settings import settings
|
|
6
|
+
from isar.models.events import RobotServiceEvents, SharedState, StateMachineEvents
|
|
7
|
+
from robot_interface.models.exceptions.robot_exceptions import RobotException
|
|
8
|
+
from robot_interface.robot_interface import RobotInterface
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RobotStatusThread(Thread):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
robot: RobotInterface,
|
|
15
|
+
signal_thread_quitting: Event,
|
|
16
|
+
shared_state: SharedState,
|
|
17
|
+
robot_service_events: RobotServiceEvents,
|
|
18
|
+
state_machine_events: StateMachineEvents,
|
|
19
|
+
):
|
|
20
|
+
self.logger = logging.getLogger("robot")
|
|
21
|
+
self.shared_state: SharedState = shared_state
|
|
22
|
+
self.robot_service_events: RobotServiceEvents = robot_service_events
|
|
23
|
+
self.state_machine_events: StateMachineEvents = state_machine_events
|
|
24
|
+
self.robot: RobotInterface = robot
|
|
25
|
+
self.signal_thread_quitting: Event = signal_thread_quitting
|
|
26
|
+
self.robot_status_poll_interval: float = settings.ROBOT_API_STATUS_POLL_INTERVAL
|
|
27
|
+
self.last_robot_status_poll_time: float = time.time()
|
|
28
|
+
self.force_status_poll_next_iteration: bool = True
|
|
29
|
+
Thread.__init__(self, name="Robot status thread")
|
|
30
|
+
|
|
31
|
+
def stop(self) -> None:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
def _is_ready_to_poll_for_status(self) -> bool:
|
|
35
|
+
if self.force_status_poll_next_iteration:
|
|
36
|
+
self.force_status_poll_next_iteration = False
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
time_since_last_robot_status_poll = (
|
|
40
|
+
time.time() - self.last_robot_status_poll_time
|
|
41
|
+
)
|
|
42
|
+
return time_since_last_robot_status_poll > self.robot_status_poll_interval
|
|
43
|
+
|
|
44
|
+
def run(self):
|
|
45
|
+
if self.signal_thread_quitting.is_set():
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
thread_check_interval = settings.THREAD_CHECK_INTERVAL
|
|
49
|
+
|
|
50
|
+
while not self.signal_thread_quitting.wait(thread_check_interval):
|
|
51
|
+
if self.state_machine_events.clear_robot_status.consume_event() is not None:
|
|
52
|
+
self.shared_state.robot_status.clear_event()
|
|
53
|
+
self.robot_service_events.robot_status_changed.clear_event()
|
|
54
|
+
self.robot_service_events.robot_status_cleared.trigger_event(True)
|
|
55
|
+
self.force_status_poll_next_iteration = True
|
|
56
|
+
|
|
57
|
+
if not self._is_ready_to_poll_for_status():
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
self.last_robot_status_poll_time = time.time()
|
|
62
|
+
|
|
63
|
+
robot_status = self.robot.robot_status()
|
|
64
|
+
|
|
65
|
+
if robot_status is not self.shared_state.robot_status.check():
|
|
66
|
+
self.shared_state.robot_status.update(robot_status)
|
|
67
|
+
self.robot_service_events.robot_status_changed.trigger_event(True)
|
|
68
|
+
except RobotException as e:
|
|
69
|
+
self.logger.error(f"Failed to retrieve robot status: {e}")
|
|
70
|
+
continue
|
|
71
|
+
self.logger.info("Exiting robot status thread")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
3
|
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
-
from isar.
|
|
4
|
+
from isar.state_machine.utils.common_event_handlers import robot_status_event_handler
|
|
5
5
|
from robot_interface.models.mission.status import RobotStatus
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
@@ -11,19 +11,19 @@ if TYPE_CHECKING:
|
|
|
11
11
|
class BlockedProtectiveStop(EventHandlerBase):
|
|
12
12
|
|
|
13
13
|
def __init__(self, state_machine: "StateMachine"):
|
|
14
|
+
events = state_machine.events
|
|
14
15
|
shared_state = state_machine.shared_state
|
|
15
16
|
|
|
16
|
-
def _robot_status_event_handler(event: Event[RobotStatus]):
|
|
17
|
-
robot_status: RobotStatus = event.check()
|
|
18
|
-
if robot_status != RobotStatus.BlockedProtectiveStop:
|
|
19
|
-
return state_machine.robot_status_changed # type: ignore
|
|
20
|
-
return None
|
|
21
|
-
|
|
22
17
|
event_handlers: List[EventHandlerMapping] = [
|
|
23
18
|
EventHandlerMapping(
|
|
24
19
|
name="robot_status_event",
|
|
25
|
-
event=
|
|
26
|
-
handler=
|
|
20
|
+
event=events.robot_service_events.robot_status_changed,
|
|
21
|
+
handler=lambda event: robot_status_event_handler(
|
|
22
|
+
state_machine=state_machine,
|
|
23
|
+
expected_status=RobotStatus.BlockedProtectiveStop,
|
|
24
|
+
status_changed_event=event,
|
|
25
|
+
status_event=shared_state.robot_status,
|
|
26
|
+
),
|
|
27
27
|
),
|
|
28
28
|
]
|
|
29
29
|
super().__init__(
|
|
@@ -20,17 +20,6 @@ class Home(EventHandlerBase):
|
|
|
20
20
|
events = state_machine.events
|
|
21
21
|
shared_state = state_machine.shared_state
|
|
22
22
|
|
|
23
|
-
def _robot_status_event_handler(
|
|
24
|
-
event: Event[RobotStatus],
|
|
25
|
-
) -> Optional[Callable]:
|
|
26
|
-
robot_status: RobotStatus = event.check()
|
|
27
|
-
if not (
|
|
28
|
-
robot_status == RobotStatus.Available
|
|
29
|
-
or robot_status == RobotStatus.Home
|
|
30
|
-
):
|
|
31
|
-
return state_machine.robot_status_changed # type: ignore
|
|
32
|
-
return None
|
|
33
|
-
|
|
34
23
|
def _send_to_lockdown_event_handler(event: Event[bool]):
|
|
35
24
|
should_send_robot_home: bool = event.consume_event()
|
|
36
25
|
if should_send_robot_home:
|
|
@@ -40,6 +29,21 @@ class Home(EventHandlerBase):
|
|
|
40
29
|
return state_machine.reached_lockdown # type: ignore
|
|
41
30
|
return None
|
|
42
31
|
|
|
32
|
+
def _robot_status_event_handler(
|
|
33
|
+
state_machine: "StateMachine",
|
|
34
|
+
status_changed_event: Event[bool],
|
|
35
|
+
status_event: Event[RobotStatus],
|
|
36
|
+
) -> Optional[Callable]:
|
|
37
|
+
if not status_changed_event.consume_event():
|
|
38
|
+
return None
|
|
39
|
+
robot_status: Optional[RobotStatus] = status_event.check()
|
|
40
|
+
if not (
|
|
41
|
+
robot_status == RobotStatus.Available
|
|
42
|
+
or robot_status == RobotStatus.Home
|
|
43
|
+
):
|
|
44
|
+
return state_machine.robot_status_changed # type: ignore
|
|
45
|
+
return None
|
|
46
|
+
|
|
43
47
|
event_handlers: List[EventHandlerMapping] = [
|
|
44
48
|
EventHandlerMapping(
|
|
45
49
|
name="start_mission_event",
|
|
@@ -60,8 +64,12 @@ class Home(EventHandlerBase):
|
|
|
60
64
|
),
|
|
61
65
|
EventHandlerMapping(
|
|
62
66
|
name="robot_status_event",
|
|
63
|
-
event=
|
|
64
|
-
handler=_robot_status_event_handler
|
|
67
|
+
event=events.robot_service_events.robot_status_changed,
|
|
68
|
+
handler=lambda event: _robot_status_event_handler(
|
|
69
|
+
state_machine=state_machine,
|
|
70
|
+
status_changed_event=event,
|
|
71
|
+
status_event=shared_state.robot_status,
|
|
72
|
+
),
|
|
65
73
|
),
|
|
66
74
|
EventHandlerMapping(
|
|
67
75
|
name="send_to_lockdown_event",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
3
|
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
-
from isar.
|
|
4
|
+
from isar.state_machine.utils.common_event_handlers import robot_status_event_handler
|
|
5
5
|
from robot_interface.models.mission.status import RobotStatus
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
@@ -11,20 +11,19 @@ if TYPE_CHECKING:
|
|
|
11
11
|
class Offline(EventHandlerBase):
|
|
12
12
|
|
|
13
13
|
def __init__(self, state_machine: "StateMachine"):
|
|
14
|
-
|
|
14
|
+
events = state_machine.events
|
|
15
15
|
shared_state = state_machine.shared_state
|
|
16
16
|
|
|
17
|
-
def _robot_status_event_handler(event: Event[RobotStatus]):
|
|
18
|
-
robot_status: RobotStatus = event.check()
|
|
19
|
-
if robot_status != RobotStatus.Offline:
|
|
20
|
-
return state_machine.robot_status_changed # type: ignore
|
|
21
|
-
return None
|
|
22
|
-
|
|
23
17
|
event_handlers: List[EventHandlerMapping] = [
|
|
24
18
|
EventHandlerMapping(
|
|
25
19
|
name="robot_status_event",
|
|
26
|
-
event=
|
|
27
|
-
handler=
|
|
20
|
+
event=events.robot_service_events.robot_status_changed,
|
|
21
|
+
handler=lambda event: robot_status_event_handler(
|
|
22
|
+
state_machine=state_machine,
|
|
23
|
+
expected_status=RobotStatus.Offline,
|
|
24
|
+
status_changed_event=event,
|
|
25
|
+
status_event=shared_state.robot_status,
|
|
26
|
+
),
|
|
28
27
|
),
|
|
29
28
|
]
|
|
30
29
|
super().__init__(
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import time
|
|
1
2
|
from typing import TYPE_CHECKING
|
|
2
3
|
|
|
4
|
+
from isar.config.settings import settings
|
|
3
5
|
from robot_interface.models.mission.status import RobotStatus
|
|
4
6
|
|
|
5
7
|
if TYPE_CHECKING:
|
|
@@ -19,3 +21,16 @@ def is_available_or_home(state_machine: "StateMachine") -> bool:
|
|
|
19
21
|
def is_blocked_protective_stop(state_machine: "StateMachine") -> bool:
|
|
20
22
|
robot_status = state_machine.shared_state.robot_status.check()
|
|
21
23
|
return robot_status == RobotStatus.BlockedProtectiveStop
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def clear_robot_status(state_machine: "StateMachine") -> bool:
|
|
27
|
+
state_machine.events.state_machine_events.clear_robot_status.trigger_event(True)
|
|
28
|
+
start_time: float = time.time()
|
|
29
|
+
while time.time() - start_time < settings.CLEAR_ROBOT_STATUS_TIMEOUT:
|
|
30
|
+
if (
|
|
31
|
+
state_machine.events.robot_service_events.robot_status_cleared.consume_event()
|
|
32
|
+
):
|
|
33
|
+
return True
|
|
34
|
+
time.sleep(settings.FSM_SLEEP_TIME)
|
|
35
|
+
state_machine.logger.error("Timed out waiting for robot status to be cleared")
|
|
36
|
+
return False
|
|
@@ -12,6 +12,7 @@ from isar.state_machine.transitions.functions.return_home import (
|
|
|
12
12
|
should_retry_return_home,
|
|
13
13
|
start_return_home_mission,
|
|
14
14
|
)
|
|
15
|
+
from isar.state_machine.transitions.functions.robot_status import clear_robot_status
|
|
15
16
|
from isar.state_machine.transitions.functions.start_mission import (
|
|
16
17
|
initialize_robot,
|
|
17
18
|
trigger_start_mission_event,
|
|
@@ -58,11 +59,19 @@ def get_return_home_transitions(state_machine: "StateMachine") -> List[dict]:
|
|
|
58
59
|
"trigger": "returned_home",
|
|
59
60
|
"source": state_machine.returning_home_state,
|
|
60
61
|
"dest": state_machine.home_state,
|
|
62
|
+
"conditions": [
|
|
63
|
+
def_transition(state_machine, clear_robot_status),
|
|
64
|
+
],
|
|
61
65
|
"before": [
|
|
62
66
|
def_transition(state_machine, reset_return_home_failure_counter),
|
|
63
67
|
def_transition(state_machine, return_home_finished),
|
|
64
68
|
],
|
|
65
69
|
},
|
|
70
|
+
{
|
|
71
|
+
"trigger": "returned_home",
|
|
72
|
+
"source": state_machine.returning_home_state,
|
|
73
|
+
"dest": state_machine.intervention_needed_state,
|
|
74
|
+
},
|
|
66
75
|
{
|
|
67
76
|
"trigger": "starting_recharging",
|
|
68
77
|
"source": state_machine.returning_home_state,
|
|
@@ -43,9 +43,12 @@ def return_home_event_handler(
|
|
|
43
43
|
def robot_status_event_handler(
|
|
44
44
|
state_machine: "StateMachine",
|
|
45
45
|
expected_status: RobotStatus,
|
|
46
|
-
|
|
46
|
+
status_changed_event: Event[bool],
|
|
47
|
+
status_event: Event[RobotStatus],
|
|
47
48
|
) -> Optional[Callable]:
|
|
48
|
-
|
|
49
|
+
if not status_changed_event.consume_event():
|
|
50
|
+
return None
|
|
51
|
+
robot_status: Optional[RobotStatus] = status_event.check()
|
|
49
52
|
if robot_status != expected_status:
|
|
50
53
|
return state_machine.robot_status_changed # type: ignore
|
|
51
54
|
return None
|
|
@@ -81,6 +81,7 @@ src/isar/mission_planner/task_selector_interface.py
|
|
|
81
81
|
src/isar/models/__init__.py
|
|
82
82
|
src/isar/models/events.py
|
|
83
83
|
src/isar/robot/robot.py
|
|
84
|
+
src/isar/robot/robot_battery.py
|
|
84
85
|
src/isar/robot/robot_pause_mission.py
|
|
85
86
|
src/isar/robot/robot_start_mission.py
|
|
86
87
|
src/isar/robot/robot_status.py
|
|
@@ -37,6 +37,7 @@ from tests.test_double.robot_interface import (
|
|
|
37
37
|
StubRobot,
|
|
38
38
|
StubRobotBlockedProtectiveStopToHomeTest,
|
|
39
39
|
StubRobotOfflineToHomeTest,
|
|
40
|
+
StubRobotRobotStatusBusyIfNotHomeOrUnknownStatus,
|
|
40
41
|
)
|
|
41
42
|
from tests.test_double.task import StubTask
|
|
42
43
|
|
|
@@ -95,21 +96,34 @@ def test_state_machine_transitions_when_running_full_mission(
|
|
|
95
96
|
container: ApplicationContainer,
|
|
96
97
|
state_machine_thread: StateMachineThreadMock,
|
|
97
98
|
robot_service_thread: RobotServiceThreadMock,
|
|
98
|
-
mocker,
|
|
99
99
|
) -> None:
|
|
100
100
|
state_machine_thread.state_machine.await_next_mission_state.timers[
|
|
101
101
|
0
|
|
102
102
|
].timeout_in_seconds = 0.01
|
|
103
|
+
|
|
104
|
+
robot_service_thread.robot_service.robot = (
|
|
105
|
+
StubRobotRobotStatusBusyIfNotHomeOrUnknownStatus(
|
|
106
|
+
current_state=robot_service_thread.robot_service.shared_state.state,
|
|
107
|
+
initiate_mission_delay=1,
|
|
108
|
+
)
|
|
109
|
+
)
|
|
103
110
|
state_machine_thread.start()
|
|
104
|
-
mocker.patch.object(StubRobot, "robot_status", return_value=RobotStatus.Home)
|
|
105
111
|
robot_service_thread.start()
|
|
112
|
+
|
|
113
|
+
# Setting the poll interval to a lower value to ensure that the robot status is
|
|
114
|
+
# updated during the mission. This value needs to be set after the robot service
|
|
115
|
+
# thread has been started.
|
|
116
|
+
robot_service_thread.robot_service.robot_status_thread.robot_status_poll_interval = (
|
|
117
|
+
0.5
|
|
118
|
+
)
|
|
119
|
+
|
|
106
120
|
task_1: Task = TakeImage(
|
|
107
121
|
target=DummyPose.default_pose().position, robot_pose=DummyPose.default_pose()
|
|
108
122
|
)
|
|
109
123
|
task_2: Task = TakeImage(
|
|
110
124
|
target=DummyPose.default_pose().position, robot_pose=DummyPose.default_pose()
|
|
111
125
|
)
|
|
112
|
-
mission: Mission = Mission(name="Dummy
|
|
126
|
+
mission: Mission = Mission(name="Dummy mission", tasks=[task_1, task_2])
|
|
113
127
|
|
|
114
128
|
scheduling_utilities: SchedulingUtilities = container.scheduling_utilities()
|
|
115
129
|
scheduling_utilities.start_mission(mission=mission)
|
|
@@ -965,7 +979,11 @@ def test_state_machine_with_return_home_failure_successful_retries(
|
|
|
965
979
|
].timeout_in_seconds = 0.01
|
|
966
980
|
scheduling_utilities: SchedulingUtilities = container.scheduling_utilities()
|
|
967
981
|
state_machine_thread.start()
|
|
968
|
-
mocker.patch.object(
|
|
982
|
+
mocker.patch.object(
|
|
983
|
+
StubRobot,
|
|
984
|
+
"robot_status",
|
|
985
|
+
side_effect=[RobotStatus.Available, RobotStatus.Home],
|
|
986
|
+
)
|
|
969
987
|
mocker.patch.object(
|
|
970
988
|
StubRobot, "task_status", side_effect=[TaskStatus.Failed, TaskStatus.Successful]
|
|
971
989
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import time
|
|
1
2
|
from datetime import datetime
|
|
2
3
|
from queue import Queue
|
|
3
4
|
from threading import Thread
|
|
4
|
-
from typing import Callable, List
|
|
5
|
+
from typing import Callable, List, Optional
|
|
5
6
|
|
|
6
7
|
from alitra import Frame, Orientation, Pose, Position
|
|
7
8
|
|
|
@@ -33,14 +34,19 @@ class StubRobot(RobotInterface):
|
|
|
33
34
|
frame=Frame("robot"),
|
|
34
35
|
),
|
|
35
36
|
robot_status: RobotStatus = RobotStatus.Available,
|
|
37
|
+
initiate_mission_delay: float = 0.0,
|
|
36
38
|
):
|
|
37
39
|
self.mission_status_return_value: MissionStatus = mission_status
|
|
38
40
|
self.task_status_return_value: TaskStatus = task_status
|
|
39
41
|
self.stop_return_value: bool = stop
|
|
40
42
|
self.robot_pose_return_value: Pose = pose
|
|
41
43
|
self.robot_status_return_value: RobotStatus = robot_status
|
|
44
|
+
self.initiate_mission_delay: float = initiate_mission_delay
|
|
45
|
+
self.mission: Optional[Mission] = None
|
|
42
46
|
|
|
43
47
|
def initiate_mission(self, mission: Mission) -> None:
|
|
48
|
+
time.sleep(self.initiate_mission_delay)
|
|
49
|
+
self.mission = mission
|
|
44
50
|
return
|
|
45
51
|
|
|
46
52
|
def task_status(self, task_id: str) -> TaskStatus:
|
|
@@ -153,3 +159,34 @@ class StubRobotOfflineToHomeTest(StubRobot):
|
|
|
153
159
|
if not self.entered_offline:
|
|
154
160
|
return RobotStatus.Offline
|
|
155
161
|
return RobotStatus.Home
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class StubRobotRobotStatusBusyIfNotHomeOrUnknownStatus(StubRobot):
|
|
165
|
+
def __init__(
|
|
166
|
+
self,
|
|
167
|
+
current_state: Event,
|
|
168
|
+
initiate_mission_delay: float = 0.0,
|
|
169
|
+
):
|
|
170
|
+
super().__init__()
|
|
171
|
+
self.current_state = current_state
|
|
172
|
+
self.initiate_mission_delay: float = initiate_mission_delay
|
|
173
|
+
self.return_home_mission_just_finished_successfully = False
|
|
174
|
+
|
|
175
|
+
def task_status(self, task_id: str) -> TaskStatus:
|
|
176
|
+
if self.mission._is_return_to_home_mission():
|
|
177
|
+
if self.task_status_return_value == TaskStatus.Successful:
|
|
178
|
+
self.return_home_mission_just_finished_successfully = True
|
|
179
|
+
return self.task_status_return_value
|
|
180
|
+
|
|
181
|
+
def robot_status(self) -> RobotStatus:
|
|
182
|
+
current_state = self.current_state.check()
|
|
183
|
+
if current_state is None:
|
|
184
|
+
raise RobotCommunicationException("Could not read state machine state")
|
|
185
|
+
if current_state == "home":
|
|
186
|
+
return RobotStatus.Home
|
|
187
|
+
elif current_state == "unknown_status":
|
|
188
|
+
return RobotStatus.Home
|
|
189
|
+
elif self.return_home_mission_just_finished_successfully:
|
|
190
|
+
return RobotStatus.Home
|
|
191
|
+
|
|
192
|
+
return RobotStatus.Busy
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|