Skip to content

Commit

Permalink
feat(robot-server): Robot server command namespaces (#6098)
Browse files Browse the repository at this point in the history
* adding namespaces

* refactor after rebase

* create multiple command definition enumerations.

* allow backwards compatility for pre-namespaced command names

* rename exit to exitSession

* run app uses namespaced calibration check commands

* Update robot-server/robot_server/service/session/models.py

Co-authored-by: Brian Arthur Cooper <[email protected]>

* Removed unused -TIP_LENGTH_TRANSITIONS dict

* clean up naming

* flow errors

* fix js test

Co-authored-by: Brian Arthur Cooper <[email protected]>

closes #6089
  • Loading branch information
amitlissack authored Jul 10, 2020
1 parent 83d7c7d commit 73152e3
Show file tree
Hide file tree
Showing 17 changed files with 210 additions and 155 deletions.
4 changes: 2 additions & 2 deletions app/src/sessions/__fixtures__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ export const mockSession: Types.Session = {
}

export const mockSessionCommand: Types.SessionCommandAttributes = {
command: 'jog',
command: 'calibration.jog',
data: { someData: 32 },
}

export const mockSessionCommandAttributes: Types.SessionCommandAttributes = {
command: 'preparePipette',
command: 'calibration.preparePipette',
status: 'accepted',
data: {},
}
Expand Down
21 changes: 12 additions & 9 deletions app/src/sessions/calibration-check/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,18 @@ export const CHECK_STEP_BAD_ROBOT_CALIBRATION: 'badCalibrationData' =
export const CHECK_STEP_NO_PIPETTES_ATTACHED: 'noPipettesAttached' =
'noPipettesAttached'

const LOAD_LABWARE: 'loadLabware' = 'loadLabware'
const PREPARE_PIPETTE: 'preparePipette' = 'preparePipette'
const JOG: 'jog' = 'jog'
const PICK_UP_TIP: 'pickUpTip' = 'pickUpTip'
const CONFIRM_TIP: 'confirmTip' = 'confirmTip'
const INVALIDATE_TIP: 'invalidateTip' = 'invalidateTip'
const COMPARE_POINT: 'comparePoint' = 'comparePoint'
const GO_TO_NEXT_CHECK: 'goToNextCheck' = 'goToNextCheck'
const EXIT: 'exitSession' = 'exitSession'
const LOAD_LABWARE: 'calibration.loadLabware' = 'calibration.loadLabware'
const PREPARE_PIPETTE: 'calibration.preparePipette' =
'calibration.preparePipette'
const JOG: 'calibration.jog' = 'calibration.jog'
const PICK_UP_TIP: 'calibration.pickUpTip' = 'calibration.pickUpTip'
const CONFIRM_TIP: 'calibration.confirmTip' = 'calibration.confirmTip'
const INVALIDATE_TIP: 'calibration.invalidateTip' = 'calibration.invalidateTip'
const COMPARE_POINT: 'calibration.check.comparePoint' =
'calibration.check.comparePoint'
const GO_TO_NEXT_CHECK: 'calibration.check.goToNextCheck' =
'calibration.check.goToNextCheck'
const EXIT: 'calibration.exitSession' = 'calibration.exitSession'

export const checkCommands = {
LOAD_LABWARE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('createSessionCommandEpic', () => {
data: {
type: 'Command',
attributes: {
command: 'jog',
command: 'calibration.jog',
data: {
someData: 32,
},
Expand Down
23 changes: 12 additions & 11 deletions robot-server/robot_server/robot/calibration/check/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from robot_server.robot.calibration.helper_classes import (
CheckMove, DeckCalibrationError, PipetteRank, PipetteInfo, PipetteStatus
)
from robot_server.service.session.models import OffsetVector
from robot_server.service.session.models import OffsetVector,\
CalibrationCommand, CalibrationCheckCommand
from opentrons.hardware_control import ThreadManager
from opentrons.protocol_api import labware

Expand Down Expand Up @@ -57,16 +58,16 @@ class CalibrationCheckState(str, Enum):


class CalibrationCheckTrigger(str, Enum):
load_labware = "loadLabware"
prepare_pipette = "preparePipette"
jog = "jog"
pick_up_tip = "pickUpTip"
confirm_tip_attached = "confirmTip"
invalidate_tip = "invalidateTip"
compare_point = "comparePoint"
go_to_next_check = "goToNextCheck"
exit = "exitSession"
reject_calibration = "rejectCalibration"
load_labware = CalibrationCommand.load_labware.value
prepare_pipette = CalibrationCommand.prepare_pipette.value
jog = CalibrationCommand.jog.value
pick_up_tip = CalibrationCommand.pick_up_tip.value
confirm_tip_attached = CalibrationCommand.confirm_tip_attached.value
invalidate_tip = CalibrationCommand.invalidate_tip.value
compare_point = CalibrationCheckCommand.compare_point.value
go_to_next_check = CalibrationCheckCommand.go_to_next_check.value
exit = CalibrationCommand.exit.value
reject_calibration = CalibrationCheckCommand.reject_calibration.value


CHECK_TRANSITIONS: typing.List[typing.Dict[str, typing.Any]] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Dict
from robot_server.service.session.models import CommandName
from robot_server.service.session.models import CommandDefinition, \
TipLengthCalibrationCommand, CalibrationCommand
from robot_server.robot.calibration.tip_length.util import (
SimpleStateMachine,
TipCalibrationError as Error
Expand All @@ -9,41 +10,41 @@
)


TIP_LENGTH_TRANSITIONS: Dict[State, Dict[CommandName, State]] = {
TIP_LENGTH_TRANSITIONS: Dict[State, Dict[CommandDefinition, State]] = {
State.sessionStarted: {
CommandName.load_labware: State.labwareLoaded
CalibrationCommand.load_labware: State.labwareLoaded
},
State.labwareLoaded: {
CommandName.move_to_reference_point: State.measuringNozzleOffset
TipLengthCalibrationCommand.move_to_reference_point: State.measuringNozzleOffset # noqa: e501
},
State.measuringNozzleOffset: {
CommandName.save_offset: State.preparingPipette,
CommandName.jog: State.measuringNozzleOffset
CalibrationCommand.save_offset: State.preparingPipette,
CalibrationCommand.jog: State.measuringNozzleOffset
},
State.preparingPipette: {
CommandName.jog: State.preparingPipette,
CommandName.pick_up_tip: State.preparingPipette,
CommandName.invalidate_tip: State.preparingPipette,
CommandName.move_to_reference_point: State.measuringTipOffset
CalibrationCommand.jog: State.preparingPipette,
CalibrationCommand.pick_up_tip: State.preparingPipette,
CalibrationCommand.invalidate_tip: State.preparingPipette,
TipLengthCalibrationCommand.move_to_reference_point: State.measuringTipOffset # noqa: e501
},
State.measuringTipOffset: {
CommandName.save_offset: State.calibrationComplete,
CommandName.jog: State.measuringTipOffset
CalibrationCommand.save_offset: State.calibrationComplete,
CalibrationCommand.jog: State.measuringTipOffset
},
State.WILDCARD: {
CommandName.exit: State.sessionExited
CalibrationCommand.exit: State.sessionExited
}
}


class TipCalibrationStateMachine():
class TipCalibrationStateMachine:
def __init__(self):
self._state_machine = SimpleStateMachine(
states=set(s for s in State),
transitions=TIP_LENGTH_TRANSITIONS
)

def get_next_state(self, from_state: State, command: CommandName):
def get_next_state(self, from_state: State, command: CommandDefinition):
next_state = self._state_machine.get_next_state(from_state, command)
if next_state:
return next_state
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Dict, Awaitable, Callable, Any
from opentrons.types import Mount, Point
from opentrons.hardware_control import ThreadManager
from robot_server.service.session.models import CommandName
from robot_server.service.session.models import CalibrationCommand, \
TipLengthCalibrationCommand
from robot_server.robot.calibration.tip_length.state_machine import (
TipCalibrationStateMachine
)
Expand All @@ -19,32 +20,6 @@
unique (by serial number) physical pipette.
"""

TIP_LENGTH_TRANSITIONS: Dict[State, Dict[CommandName, State]] = {
State.sessionStarted: {
CommandName.load_labware: State.labwareLoaded
},
State.labwareLoaded: {
CommandName.move_to_reference_point: State.measuringNozzleOffset
},
State.measuringNozzleOffset: {
CommandName.save_offset: State.preparingPipette,
CommandName.jog: State.measuringNozzleOffset
},
State.preparingPipette: {
CommandName.jog: State.preparingPipette,
CommandName.pick_up_tip: State.preparingPipette,
CommandName.invalidate_tip: State.preparingPipette,
CommandName.move_to_reference_point: State.measuringTipOffset
},
State.measuringTipOffset: {
CommandName.save_offset: State.calibrationComplete,
CommandName.jog: State.measuringTipOffset
},
State.WILDCARD: {
CommandName.exit: State.sessionExited
}
}

# TODO: BC 2020-07-08: type all command logic here with actual Model type
COMMAND_HANDLER = Callable[..., Awaitable]

Expand All @@ -68,13 +43,13 @@ def __init__(self,
'cannot run tip length calibration')

self._command_map: COMMAND_MAP = {
CommandName.load_labware: self.load_labware,
CommandName.jog: self.jog,
CommandName.pick_up_tip: self.pick_up_tip,
CommandName.invalidate_tip: self.invalidate_tip,
CommandName.save_offset: self.save_offset,
CommandName.move_to_reference_point: self.move_to_reference_point,
CommandName.exit: self.exit_session,
CalibrationCommand.load_labware: self.load_labware,
CalibrationCommand.jog: self.jog,
CalibrationCommand.pick_up_tip: self.pick_up_tip,
CalibrationCommand.invalidate_tip: self.invalidate_tip,
CalibrationCommand.save_offset: self.save_offset,
TipLengthCalibrationCommand.move_to_reference_point: self.move_to_reference_point, # noqa: E501
CalibrationCommand.exit: self.exit_session,
}

def _set_current_state(self, to_state: State):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .base_command_queue import CommandQueue # noqa(W0611)
from .base_executor import CommandExecutor # noqa(W0611)
from .command import Command, CompletedCommand, create_command # noqa(W0611)
from .command import Command, CompletedCommand, create_command, CommandResult # noqa(W0611)
from .callable_executor import CallableExecutor # noqa(W0611)
from .hardware_executor import HardwareExecutor, DefaultHardwareExecutor # noqa(W0611)
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from dataclasses import dataclass, field

from robot_server.service.session.models import IdentifierType, \
create_identifier, CommandName, CommandDataType, CommandStatus
create_identifier, CommandDefinition, CommandDataType, CommandStatus


@dataclass(frozen=True)
class CommandContent:
name: CommandName
name: CommandDefinition
data: CommandDataType


Expand Down Expand Up @@ -37,7 +37,7 @@ class CompletedCommand:
result: CommandResult


def create_command(name: CommandName, data: CommandDataType) -> Command:
def create_command(name: CommandDefinition, data: CommandDataType) -> Command:
"""Create a command object"""
return Command(
content=CommandContent(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import typing
from opentrons.hardware_control import ThreadManager

from . import Command, CompletedCommand
from . import Command, CompletedCommand, CommandResult
from . base_executor import CommandExecutor
from .command import CommandResult
from ..errors import UnsupportedCommandException
from ..models import CommandDataType, CommandName
from ..models import CommandDataType, RobotCommand, CommandDefinition
from robot_server.util import duration


Expand All @@ -25,14 +24,14 @@ async def toggle_lights(hardware: ThreadManager, *args):
class HardwareExecutor(CommandExecutor):
"""A command executor that executes direct hardware commands"""

COMMAND_TO_FUNC: typing.Dict[CommandName, COMMAND_HANDLER] = {
CommandName.home_all_motors: home_all_motors,
CommandName.toggle_lights: toggle_lights
COMMAND_TO_FUNC: typing.Dict[CommandDefinition, COMMAND_HANDLER] = {
RobotCommand.home_all_motors: home_all_motors,
RobotCommand.toggle_lights: toggle_lights
}

def __init__(self,
hardware: ThreadManager,
command_filter: typing.Optional[typing.Set[CommandName]]):
command_filter: typing.Optional[typing.Set[RobotCommand]]):
"""
Constructor
Expand All @@ -59,7 +58,7 @@ async def execute(self, command: Command) -> CompletedCommand:
completed_at=timed.end)
)

def get_handler(self, command_name: CommandName) \
def get_handler(self, command_name: CommandDefinition) \
-> typing.Optional[COMMAND_HANDLER]:
"""Get the handler for the command type"""
if self._command_filter is not None:
Expand All @@ -71,6 +70,6 @@ def get_handler(self, command_name: CommandName) \
class DefaultHardwareExecutor(HardwareExecutor):
"""The default command executor"""
def __init__(self, hardware: ThreadManager):
super().__init__(hardware, {CommandName.home_all_motors,
CommandName.home_pipette,
CommandName.toggle_lights})
super().__init__(hardware, {RobotCommand.home_all_motors,
RobotCommand.home_pipette,
RobotCommand.toggle_lights})
Loading

0 comments on commit 73152e3

Please sign in to comment.