- import ast
- import copy
- import csv
-
-
- class Move:
- moveType = None # i.e spin, extension, delay etc
- index = None # stores the index on which the move acts on
- # (in this case the side of the machine or the index of the LED)
- position = None # which position to goto (angle or retraction since I've reused the variable)
- delay = None # only used for delay moves
- colour = None # colour set to LEDs during the move
-
- # Validation dicts. Used to check weather the data that is given is valid
- _validMoves = {'spin', 'extension', 'delay', 'stop', 'led', 'photo'}
- _validSides = {'b': 0, 'r': 1, 'f': 2, 'l': 3, 0: 0, 1: 1, 2: 2, 3: 3}
- _validAngles = {0, 1, 2, 3}
- _validPositions = {'f', 'e', 'r'}
-
- def __init__(self, _move_type, _index=None, _position=None, _colour=None, _delay=0.0):
- if _move_type in self._validMoves:
- self.moveType = _move_type
- else:
- raise ValueError("Invalid Move Type")
-
- if _move_type == 'spin':
- try:
- self.index = self._validSides.get(_index)
- except KeyError:
- raise ValueError("Invalid Side Num")
-
- if int(_position) in range(4):
- self.position = int(_position)
- else:
- raise ValueError("Invalid position num")
-
- elif _move_type == 'extension':
- try:
- self.index = self._validSides.get(_index)
- except KeyError:
- raise ValueError("Invalid Side Num")
- if _position in self._validPositions:
- self.position = _position
- else:
- raise ValueError("Position must be either f, e or r")
-
- elif _move_type == 'delay':
- self.delay = _delay
- elif _move_type == 'stop': # stops the servos 'pushing' when they are not being activated anymore
- self.index = _index
- elif _move_type == 'led':
- if _index in range(-1, 8):
- self.index = _index # in this case, index is the index of the LED
- else:
- raise ValueError("Invalid LED Index")
- # todo error checking
- self.colour = _colour
-
- def execute(self, _machine):
- if self.moveType == 'spin':
- _machine.goto(self.index, self.position)
-
- elif self.moveType == 'extension':
- if self.position == 'e':
- _machine.extend(self.index)
- elif self.position == 'r':
- _machine.retract(self.index)
- elif self.position == 'f':
- _machine.full_extend(self.index)
-
- elif self.moveType == 'delay':
- return {'type': 'delay', 'content': self.delay}
-
- elif self.moveType == 'stop':
- # todo check if this works
- _machine.set_angle(self.index, None)
- _machine.set_angle(self.index + 4, None)
-
- elif self.moveType == 'led':
- _machine.set_leds(self.index, self.colour)
-
- elif self.moveType == 'photo':
- _machine.take_photo()
- return {'type': 'none'}
-
-
- class MoveList:
- moves: list[Move] = []
- moves2 = None
- counter = 1
- machine = None
- waitSeconds = 0
- _running = False
-
- def __init__(self, _machine, _moves: list[Move] = None, csv_path=None):
- self.machine = _machine
- if _moves is None:
- self.read_from_csv(csv_path)
- else:
- self.moves = _moves
-
- def read_from_csv(self, csv_path):
- with open(csv_path, newline='') as csvfile:
- csv_reader = csv.DictReader(csvfile, delimiter=',', quotechar='|')
- for row in csv_reader:
- row_d = dict(row)
- # bit of a mess here to ensure all values are cast correctly
- move_type = row_d['move_type']
- if not move_type:
- raise ValueError("move_type passed empty")
- index = None
- if row_d['index']:
- index = int(row_d['index'])
- position = None
- if row_d['position']:
- try:
- position = int(row_d['position'])
- except ValueError:
- position = row_d['position']
- colour = None
- if row_d['colour'] is not None:
- colour = row_d['colour']
- delay = 0
- if row_d['delay']:
- delay = float(row_d['delay'])
-
- self.moves.append(Move(
- move_type, index, position, colour, delay)
- )
-
- def add_move(self, _move_type, _index=None, _position=None, _colour=None, _delay=0.0):
- self.moves.append(Move(_move_type, _index, _position, _colour, _delay))
-
- def send_list_request(self):
- self.machine.execute_move_list(self.moves)
-
- def execute(self):
- # dynamically executes the moves each time tick() is called
- self.moves2 = copy.copy(self.moves)
- self._running = True
-
- def tick(self):
- if self._running:
- self.waitSeconds -= .05
- if self.waitSeconds <= 0:
- while True:
- move_delay = 0
- try:
- move_response = self.moves2[0].execute(self.machine)
- except IndexError:
- self._running = False
- self.counter -= 1
- if self.counter != 0:
- self.execute()
- break
- self.moves2.pop(0)
- if move_response['type'] == 'delay':
- move_delay = move_response['value']
- self.waitSeconds = move_delay
- elif move_response['type'] == 'camera':
- # hand down the response to be further handled
- return move_response