Git Product home page Git Product logo

isar's Introduction

ISAR

Python package Code style: black License

ISAR - Integration and Supervisory control of Autonomous Robots - is a tool for integrating robot applications into operator systems. Through the ISAR API you can send commands to a robot to do missions and collect results from the missions.

Getting started

Steps:

  • Install
  • Integrate a robot
  • Run the ISAR server
  • Run a robot mission

Install

For local development, please fork the repository. Then, clone and install in the repository root folder:

git clone https://github.com/<path_to_parent>/isar
cd isar
pip install -e .[dev]

For zsh you might have to type ".[dev]"

Verify that you can run the tests:

pytest .

The repository contains a configuration file for installing pre-commit hooks. Currently, black and a mirror of mypy are configured hooks. Install with:

pre-commit install

Verify that pre-commit runs:

pre-commit

pre-commit will now run the installed hooks before code is commited to git. To turn pre-commit off, run:

pre-commit uninstall

Robot integration

To connect the state machine to a robot in a separate repository, it is required that the separate repository implements the robot interface. The separate repository should also have a settings.env file in a config folder where CAPABILITIES and ROBOT_MODEL are set. A mocked robot can be found in this repository. Install the repo, i.e:

pip install isar-robot

NB: isar-robot has not been published to PyPi for some time, and needs to be downloaded directly from git to work.

Then, ensure the ISAR_ROBOT_PACKAGE variable in settings.env is set to the name of the package you installed. isar_robot is set by default. See the section for configuration for overwriting configuration.

If you have the robot repository locally, you can simply install through

pip install -e /path/to/robot/repo/

Running ISAR with a robot simulator

A simulator based on the open source robot Turtlebot3 has been implemented for use with ISAR and may be found here. Follow the installation instructions for the simulator and install isar-turtlebot in the same manner as given in the robot integration section. Overwrite the following configuration variables:

ISAR_ROBOT_PACKAGE = isar_turtlebot
ISAR_DEFAULT_MAP = turtleworld

Run ISAR server

To run ISAR:

python main.py

Note, running the full system requires that an implementation of a robot has been installed. See this section for installing a mocked robot or a Turtlebot3 simulator.

Running a robot mission

Once the application has been started the swagger site may be accessed at

http://localhost:3000/docs

Execute the /schedule/start-mission endpoint with mission_id=1 to run a mission.

In this folder there are predefined default missions, for example the mission corresponding to mission_id=1. A new mission may be added by adding a new json-file with a mission description. Note, the mission IDs must be unique.

Running with docker-compose

ISAR may be started with an instance of the isar-robot package by

docker-compose up --build

Provided that the simulator from isar-turtlebot is running ISAR may be started with the turtlebot by

docker-compose -f docker-compose-turtlebot.yml up --build

Configuration

The system consists of many configuration variables which may alter the functionality. As an example, it is possible to change mission planners or add multiple storage handlers as described in the mission planner and storage sections.

There are two methods of specifying configuration.

  1. Override the default value by setting an environment variable.

    Every configuration variable is defined in settings.py, and they may all be overwritten by specifying the variables in the environment instead. Note that the configuration variable must be prefixed with ISAR_ when specified in the environment. So for the ROBOT_PACKAGEconfiguration variable:

    export ISAR_ROBOT_PACKAGE=isar_turtlebot

    This means ISAR will connect to isar_turtlebot robot package.

  2. Adding environment variables through settings.env.

    By adding environment variables with the prefix ISAR_ to the settings.env file the configuration variables will be overwritten by the values in this file.

Running tests

After following the steps in Development, you can run the tests:

pytest .

To create an interface test in your robot repository, use the function interface_test from robot_interface. The argument should be an interface object from your robot specific implementation. See isar-robot for example.

Integration tests

Integration tests can be found here and have been created with a simulator in mind. The integration tests will not run as part of pytest . or as part of the CI/CD pipeline. To run the integration tests please follow the instructions in this section for setting up the isar-turtlebot implementation with simulator and run the following command once the simulation has been launched.

pytest tests/integration

Note that these tests will run towards the actual simulation (you may monitor it through Gazebo and RVIZ) and it will take a long time.

Documentation

To build the project documentation, run the following commands:

cd docs
make docs

The documentation can now be viewed at docs/build/html/index.html.

Components

The system consists of two main components.

  1. State machine
  2. FastAPI

State machine

The state machine handles interaction with the robots API and monitors the execution of missions. It also enables interacting with the robot before, during and after missions.

The state machine is based on the transitions package for Python. An visualization of the state machine can be seen below: State Machine

In general the states

States.Off,
States.Initialize,
States.Initiate,
States.Stop,
States.Monitor,
States.Paused,

indicates that the state machine is already running. For running a mission the state machine need to be in the state

States.Idle

FastAPI

The FastAPI establishes an interface to the state machine for the user. As the API and state machine are separate threads, they communicate through python queues. FastAPI runs on an ASGI-server, specifically uvicorn. The FastAPI-framework is split into routers where the endpoint operations are defined.

Mission planner

The mission planner that is currently in use is a local mission planner, where missions are specified in a json file. You can create your own mission planner by implementing the mission planner interface and adding your planner to the selection here. Note that you must add your module as an option in the dictionary.

Storage

The storage modules that are used is defined by the ISAR_STORAGE configuration variable. This can be changed by overriding the configuration through an environment variable. It accepts a json encoded list and will use each element in the list to retrieve the corresponding handler. The current options are

ISAR_STORAGE = '["local", "blob", "slimm"]'

Note that the blob and slimm options require special configuration to authenticate to these endpoints.

Implement your own storage module

You can create your own storage module by implementing the storage interface and adding your storage module to the selection here. Note that you must add your module as an option in the dictionary.

Task selection

The tasks of a mission are selected based on a task selector module, defined by the TASK_SELECTOR configuration variable. The default task selector is sequential. When using the default module, tasks are executed in sequential order defined by the current input mission.

Implement you own task selector module

Custom task selector modules may be added by implementing additional versions of the task selector interface.

For every custom module, the interface function next_task() must be implemented. All interface implementations by default have access to the list of tasks in the current mission through the member self.tasks, however additional variables may be supplied by adding arguments to next_task(). To comply with the interface definition, the function should return the next task upon every call, and raise the TaskSelectorStop exception when all tasks in the current mission have been completed:

class CustomTaskSelector(TaskSelectorInterface):
    ...
    def next_task(...) -> Task:

        # Add code here
        ...

        # Raise `TaskSelectorStop` when all tasks have been completed
        ...

Optionally, the initialize() function may be extended by supplementing the parameter list or function body:

class CustomTaskSelector(TaskSelectorInterface):
    ...
    def initialize(self, tasks: List[Task], ...) -> None:
        super.initialize(tasks=tasks)

        # Add supplementary code here
        ...

A custom task selector may be made available during module selection by adding it to the series of options in the dictionary of injector modules. It can then be activated by overriding the task selector configuration variable:

# Add custom task selector module to `modules.py`

class CustomTaskSelectorModule(Module):
    @provider
    @singleton
    def provide_task_selector(self) -> TaskSelectorInterface:
        return CustomTaskSelector()

...

# Make it available to select during injector instantiation

modules: dict[str, tuple[Module, Union[str, bool]]] = {
    ...
    "task_selector": (
        {
            "sequential": SequentialTaskSelectorModule,
            "custom": CustomTaskSelectorModule
        }
        ...
    )
    ...
}

API authentication

The API has an option to include user authentication. This can be enabled by setting the environment variable

ISAR_AUTHENTICATION_ENABLED = true

By default, the local storage module is used and API authentication is disabled. If using Azure Blob Storage a set of environment variables must be available which gives access to an app registration that may use the storage account. Enabling API authentication also requires the same environment variables. The required variables are

AZURE_CLIENT_ID
AZURE_TENANT_ID
AZURE_CLIENT_SECRET

MQTT communication

ISAR is able to publish parts of its internal state to topics on an MQTT broker whenever they change. This is by default turned off but may be activated by setting the environment variable

ISAR_MQTT_ENABLED = true

The connection to the broker will be determined by the following configuration values in settings.py

ISAR_MQTT_USERNAME
ISAR_MQTT_HOST
ISAR_MQTT_PORT

The default values of these are overwritten by the environment in settings.env.

To specify broker password, add the following environment variable to a .env file in the root of the repository:

ISAR_MQTT_PASSWORD

If not specified the password will default to an empty string.

Running several ISAR instances locally

To run several ISAR instances in parallel locally:

  1. Generate a guid: https://www.guidgenerator.com/
  2. Open a new terminal in the isar folder
  3. Run the following command before running main.py:
export ISAR_API_PORT=port_name_higher_than_1024 ISAR_ISAR_ID=guid ISAR_ROBOT_NAME=random_robot_name

Dependencies

The dependencies used for this package are listed in pyproject.toml and pinned in requirements.txt. This ensures our builds are predictable and deterministic. This project uses pip-compile (from pip-tools) for this:

pip-compile --output-file=requirements.txt pyproject.toml

To update the requirements to the latest versions, run the same command with the --upgrade flag:

pip-compile --output-file=requirements.txt pyproject.toml --upgrade

Contributions

Equinor welcomes all kinds of contributions, including code, bug reports, issues, feature requests, and documentation Please initiate your contribution by creating an issue or by forking the project and making a pull requests. Commit messages shall be written according to this guide.

isar's People

Contributors

aeshub avatar afonso-2403 avatar andchiind avatar anetteu avatar christdej avatar eddasol avatar einarueland avatar eivindsjovold avatar godvenn avatar haakonsf avatar knord94 avatar mrica-equinor avatar muhammadusama-afk-equinor avatar nicholasdalhaug avatar oledrange avatar oysand avatar phhuseboe avatar pramod74 avatar prasm313 avatar snyk-bot avatar sondreo avatar thorvaldj avatar tsundvoll avatar vetlek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

isar's Issues

Upload to blob fails when using local planner

The local planner passes the inspections as Inspection, whereas the get_sensor_sub_folder_name expects types AudioReference, ImageReference, ThermalImageReference, VideoReference

Add unique IDs to every step

Add a unique ID to every step in a mission. The ID can then be used to manage inspections within isar-robot such that ISAR itself only has to manage the step ID.

This will remove the need for vendor_mission_id where this is present.

Use while loops instead of self transitions in state machine

The state machine has previously used self transitions to simulate the effects of a while loop. This has made it difficult to perform cleanup once the state is actually left and a new state is attained.

The new solution should use while loops within the state instead such that the state machine maintains its state continuously until a new state should be attained.

Add option to instantiate Orientation object from Euler angles

Describe the improvement you would like to see
The Orientation object is currently instantiated directly only, which can sometimes be a hassle as quaternions are more confusing to the human mind than Euler angles. The suggestion is to add a function from_euler to the Orientation dataclass which takes in three angles (roll, pitch, yaw) and outputs the corresponding Orientation object with quaternions. Note that the ZYX intrinsic rotations for Euler may be assumed as standard.

Note that the euler_to_quaternion function from alitra may be used.

class Orientation:
"""
This class represents an orientation using quaternions. The quaternion is used throughout the project.
Methods that utilize Euler angles will all follow the yaw, pitch, roll convention which rotates around the ZYX axis
with intrinsic rotations.
"""
x: float
y: float
z: float
w: float
frame: Frame

How will this change existing functionality?
Simplify creation of Orientation objects where the angles are known but not the quaternions.

How will this improvement affect the current Threat Model?
No effect on the current threat model.

Move Joints-class out of ISAR

The Joints class was made to hold the joint values for a robot specific implementation. However, ISAR should be robot independent and as such it should be moved into the specific package for that robot.

The joint values are used for a few things.

  • Storage of joint values as metadata.
  • Computation of desired joints the robot should achieve to point the camera at an object specified by Echo.

Note that the second usage implies that the joint values are computed and passed around in the system. In the scheduler interface the function schedule_step returns joints. This should not be the case for the general implementation of the interface.

Reset counter for send failures when transitioning to a new state

When ISAR fails to send a mission to the robot the strategy is to retry. Currently, retry is often done ten times based on a counter in the send state. The counter is not being reset correctly once the 10 times have been attempted or a successful send has been achieved. This results in the counter being at the limit already when a new mission is scheduled. Thus, the mission will never be sent to the robot.

After a mission is successfully sent to the robot, or when we have retried the amount of times specified by the configuration, the send retry counter should be reset to zero.

Add robot configuration class

ISAR should have a concept of what configuration the robot it is controlling has. This should contain the sensors that are available which indicates which steps the robot supports performing.

This is a way to ensure missions will not be scheduled for robots that are unable to perform all relevant steps in that mission.

Add open source robot simulator to use for testing

An effort should be made to establish an open source simulator which ISAR can implement an interface towards. The simulator would then be used to verify and test the functionality of ISAR in a "simulated real" environment.

Tests sometime fails for test_data_offload

The data offload test fails now and then. This test is timing dependent as there are two threads running in parallel.

It can be that the test calls some functions which we believe are mocked but after recent changes are not mocked anymore. Thus it could take more time to finish the test.

Make a test for Monitor state

The monitor state test, with misleading name, was removed since it did not work, see #68

The test was in tests/integration/state_machine/test_state_machine.py

Supply injector with modules based on configuration

The injector object is currently created in __init__.py in the create_app function. This should be moved to the top level main.py where the injector is created based on configuration. For example for storage there will be two modules LocalStorageModule and BlobStorageModule which are chosen prior to the creation of the injector based on the configuration.

Add option to log to a database

There should be an option for ISAR to send logs to a database rather than only log to a local file.

The default behavior should be to log locally. Remote logging can be activated optionally.

Rewrite API to use FastAPI instead of Flask

Flask was chosen as it was the known option at the time, but now a decision has been made to try out FastAPI as a solution instead. The current API controllers should be rewritten to use FastAPI insead of Flask.

Ingest inspection results to SLIMM directly through their API

Currently all the inspections results are uploaded on the end of the mission when we enter cancel. This can be problematic if the mission is very long and we want the results as fast as possible (no need to get all inspections at the same time). If the state machine crashes due to internal or external issues, the inspection results are potentially lost. A potential fix is to upload the results in the collect state.

Incorporate unique ID into filename of results

The filename of a result is now created as follows:

return f"{mission_id}_{sensor_sub_folder_name}_{inspection.id}.{inspection.metadata.file_type}"

The inspection.id that is provided comes from the robot specific implementation and it's currently not guaranteed that this is unique. For example, the mock isar-robot always returns an id=1 which means there can be duplicate filenames within one inspection.

#96 aims to add unique IDs for all steps and could be a solution to a unique ID which can be included in the filename.

Toggle coordinate transformation

The coordinate transformation is currently executed all the time where the default transformation is the unity transform using the default map. However, it would be better to perform no transformation if the unity transform should be used. Thus, an option to toggle the transformation on or off should be added.

Implement stop functionality in robot interface

Stop the execution of the current task and not schedule any new task.

If possible, stop the robot physically. Whether this is possible or not might differ from robot to robot.

The robot should end in a safe state.

Add support for autonomous docking

A robot could potentially support docking as a functionality in itself. The robot will then know where the docking station is located and should be told that it is time to go back to the dock. To support this, ISAR should contain a docking step which may be specified as part of the mission list. Typically, this step will be the final step in the mission when the robot goes back to the docking station after having completed the mission.

Add a step which supports autonomous docking for a robot.

Add default mission for isar-turtlebot

Currently there are no suitable missions for isar-turtlebot in the list of predefined missions. A mission that is suitable for testing the isar-turtlebot implementation in the standard turtlebot-house should be added.

Add default map implementation

The current default map implementation uses a very particular map that will not make sense to new users. Suggestion is to add a default map where the robot and asset frame have the same base coordinate system. Thus there will be a simple default implementation.

A new map must be added to this folder.

The default map configuration variable here should be changed to use the new map.

Move create_app() function out of isar __init__.py

Move the function create_app() from isar/__init__.py to a file which are to be called from main startup file. Per now the function will be called when something wants to import from ISAR which can cause issues with circular dependencies upon import.

Instead, the function should be imported to the main function where the application is started.

Timeout in robot interface functions that can potentially block

Robot interface functions like schedule_step can potentially hang and never return. This will block the progress of the state machine. There should be some sort of requirement on the functions that they have a timeout and tests for testing that the interface actually have implemented a timeout within a given period.

Consolidate mission ID across mission planners

The mission ID which is created when a mission is created should be an ID according to a specification. The ID is created here.

However, a mission from the local planner from a local file uses the mission ID that is defined as an int in the json file. An example can be seen here.

Whenever a mission is created, if it comes from the local planner, the echo planner or some other future planner the mission ID that is created should be unique and according to the aforementioned specifications. Note that rerunning missions from the local planner will currently overwrite the results from the previous mission as the mission ID is not unique.

The creation of a mission id happens here:

def __post_init__(self) -> None:
if self.mission_id is None:
plant_short_name: str = config.get("metadata", "plant_short_name")
robot_id: str = config.get("metadata", "eqrobot_robot_id")
now: datetime = datetime.utcnow()
self.mission_id = f"{plant_short_name.upper()}{robot_id.upper()}{now.strftime('%d%m%Y%H%M')}"
if self.mission_metadata is None:
self.mission_metadata = MissionMetadata(mission_id=self.mission_id)

Implement MQTT as ISAR communication broker

ISAR currently uses python queues to communicate between the state machine and API implementations. The system should be split in two where the API and the state machine runs in two docker containers. The containers should communicate through an MQTT Broker which runs in a third docker container.

  • Any status messages from the state machine will be pushed to the broker and then spread to anyone subscribing to the broker.
  • New missions and commands from the API should be supplied through the MQTT broker for the state machine to subscribe to.

Create a pretty-print function to log the current step

The current step is logged when the state machine is looping with the Monitor state. The step is logged here.

The Step type can be any of the low-level steps defined in here.

Currently the step object is logged as is without any formatting. This means the logged line can be very long and will go outside the terminal window.

The task is to create a log function which takes any of the defined steps as input and logs it in a neatly formatted way such that it is easily readable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.