Source code for brace.example.zaber.ZaberControlLogic
from collections import deque
from typing import NamedTuple, override
from brace.example.zaber.ZaberMeasurementList import ZaberMeasurementLists
from brace.Server.Core.ControlLogic import IControlLogic
import numpy as np
[docs]
class ZaberData(NamedTuple):
position: float
loadcell: float
t: float #time vector
[docs]
class ControlLogic:
ZaberController = 0
[docs]
class ZaberControlLogic(IControlLogic):
DataClass = ZaberData
def __init__(self, index: int):
"""
:param index: The count of the respective robot that is running.
:type index: int
"""
super().__init__(index)
self.positionMin = 0
self.positionMax = 30
self.loadcellMin = 0 # in g
self.loadcellMax = 100 # in g
[docs]
@override
def setup(self, **kwargs) -> None:
"""
Initializes anything prior to running.
:param kwargs: Keyword arguments
:type kwargs: dict[str, All]
:return: None
:rtype: None
"""
pass
[docs]
@override
def setParameters(self, parameters: dict[str, float]) -> None:
"""
Sets the parameters that are in the dictionary to
the instance variables of this object.
:param parameters: The dictionary of configuration values from a remote procedure call.
:type parameters: dict[str, float]
:return: None
:rtype: Nones
"""
# To enable changing of the parameters.
for parameterName, parameterValues in parameters.items():
self.__setattr__(parameterName, parameterValues)
[docs]
@override
def getConfigurationParameters(self, formatForConfiguration: bool) -> dict[str, float | dict]:
"""
Gets the current configuration parameters that were defined for this controller.
:param formatForConfiguration: Whether or not this should be formatted for file saving.
:type formatForConfiguration: bool
:return: Dictionary of parameters in this object.
:rtype: dict[str, float]
"""
controllerParameters = {
"positionMin": self.positionMin, # mm
"positionMax": self.positionMax, # mm
"loadcellMin": self.loadcellMin, # g
"loadcellMax": self.loadcellMax # g
}
return controllerParameters
[docs]
@override
def getDesiredOutputValues(self, enable: bool, timeData: deque[float], deltaTime: float, currentCycleMeasurementLists: list[ZaberMeasurementLists]) -> list[float]:
"""
Transforms the output values through a proportional response. Increased load cell
response leads to increased actuation.
:param enable: Whether or not device is active and running.
:type enable: bool
:param timeData: The time data for the the last set of cycles (the time values in s).
:type timeData: deque[float]
:param deltaTime: The amount of time between this iteration and the last iteration.
:type deltaTime: float
:param currentCycleMeasurementLists: The set of ZaberMeasurementList that can be accessed to determine the output response.
:type currentCycleMeasurementLists: list[ZaberMeasurementLists]
:return: The list of output responses that should be run against the actuators.
:rtype: list[float]
"""
posDes = 0.0
if enable:
measurementLists: ZaberMeasurementLists = self.getRespectiveMeasurementList(currentCycleMeasurementLists)
loadcellG = measurementLists.getLoadCellMeasurements()[-1]
if loadcellG <= self.loadcellMin:
posDes = self.positionMin
elif loadcellG >= self.loadcellMax:
posDes = self.positionMax
else:
# Calculate the proportional torque within the bounds
posDes = self.positionMin + (self.positionMax - self.positionMin) * (loadcellG - self.loadcellMin) / (self.loadcellMax - self.loadcellMin)
return [posDes]
[docs]
@override
def exportMeasurementData(self, measurementLists: ZaberMeasurementLists, index: int, isActive: bool) -> dict[str, float | int]:
"""
Exports the MeasurementData for this cycle.
:param measurementLists: The measurement lists for this robot whose data should be exported.
:type measurementLists: ZaberMeasurementLists
:param index: The current index of this robot.
:type index: int
:param isActive: Whether or not this robot is active (or enabled). If disabled, should return NaN maps.
:type isActive: bool
:return: A mapping of the attributes and the values for this current iteration.
:rtype: dict[str, float | int]
"""
fieldMapping = {
"position": measurementLists.getPosMeasurements()[-1] if isActive else np.nan,
'loadcell': measurementLists.getLoadCellMeasurements()[-1] if isActive else np.nan,
}
toReturn = fieldMapping
return toReturn