Fixed SangaDeltaStage type annotations

This commit is contained in:
Joel Collins 2020-12-07 12:44:34 +00:00
parent c75a7c5401
commit 9659c45bb4

View file

@ -12,6 +12,19 @@ from openflexure_microscope.stage.base import BaseStage
from openflexure_microscope.utilities import axes_to_array
def _displacement_to_array(
displacement: int, axis: Literal["x", "y", "z"]
) -> np.ndarray:
# Create the displacement array
return np.array(
[
displacement if axis == "x" else 0,
displacement if axis == "y" else 0,
displacement if axis == "z" else 0,
]
)
class SangaStage(BaseStage):
"""
Sangaboard v0.2 and v0.3 powered Stage object
@ -55,7 +68,7 @@ class SangaStage(BaseStage):
return 3
@property
def position(self):
def position(self) -> Tuple[int, int, int]:
return self.board.position
@property
@ -120,7 +133,7 @@ class SangaStage(BaseStage):
def move_rel(
self,
displacement: Union[int, Tuple[int, int, int]],
displacement: Union[int, Tuple[int, int, int], np.ndarray],
axis: Optional[Literal["x", "y", "z"]] = None,
backlash: bool = True,
):
@ -141,10 +154,6 @@ class SangaStage(BaseStage):
"""
with self.lock:
logging.debug("Moving sangaboard by %s", displacement)
if not backlash or self.backlash is None:
return self.board.move_rel(displacement, axis=axis)
# If we specify an axis name and a displacement int, convert to a displacement tuple
if axis:
# Displacement MUST be an integer if axis name is specified
@ -155,16 +164,10 @@ class SangaStage(BaseStage):
# Axis name MUST be x, y, or z
if axis not in ("x", "y", "z"):
raise ValueError("axis must be one of x, y, or z")
# Create the displacement array
displacement_array: np.ndarray = np.array(
[
displacement if axis == "x" else 0,
displacement if axis == "y" else 0,
displacement if axis == "z" else 0,
]
# Calculate displacement array
displacement_array: np.ndarray = _displacement_to_array(
displacement, axis
)
elif isinstance(displacement, np.ndarray):
displacement_array = displacement
elif isinstance(displacement, (list, tuple, GeneratorType)):
@ -173,6 +176,11 @@ class SangaStage(BaseStage):
else:
raise TypeError(f"Unsupported displacement type {type(displacement)}")
# Handle simple case, no backlash
if not backlash or self.backlash is None:
return self.board.move_rel(displacement_array)
# Handle move with backlash correction
# Calculate main movement
initial_move: np.ndarray = displacement_array
initial_move -= np.where(
@ -191,7 +199,7 @@ class SangaStage(BaseStage):
# can just take over before settling
time.sleep(self.settle_time)
def move_abs(self, final: Tuple[int, int, int], **kwargs):
def move_abs(self, final: Union[Tuple[int, int, int], np.ndarray], **kwargs):
"""Make an absolute move to a position
"""
with self.lock:
@ -244,15 +252,21 @@ class SangaStage(BaseStage):
class SangaDeltaStage(SangaStage):
def __init__(
self, port=None, flex_h=80, flex_a=50, flex_b=50, camera_angle=0, **kwargs
self,
port: Optional[str] = None,
flex_h: int = 80,
flex_a: int = 50,
flex_b: int = 50,
camera_angle: float = 0,
**kwargs,
):
self.flex_h = flex_h
self.flex_a = flex_a
self.flex_b = flex_b
self.flex_h: int = flex_h
self.flex_a: int = flex_a
self.flex_b: int = flex_b
# Set up camera rotation relative to stage
camera_theta = (camera_angle / 180) * np.pi
self.R_camera = np.array(
camera_theta: float = (camera_angle / 180) * np.pi
self.R_camera: np.ndarray = np.array(
[
[np.cos(camera_theta), -np.sin(camera_theta), 0],
[np.sin(camera_theta), np.cos(camera_theta), 0],
@ -263,13 +277,15 @@ class SangaDeltaStage(SangaStage):
logging.debug(self.R_camera)
# Transformation matrix converting delta into cartesian
x_fac = -1 * np.multiply(
x_fac: np.float = -1 * np.multiply(
np.divide(2, np.sqrt(3)), np.divide(self.flex_b, self.flex_h)
)
y_fac = -1 * np.divide(self.flex_b, self.flex_h)
z_fac = np.multiply(np.divide(1, 3), np.divide(self.flex_b, self.flex_a))
y_fac: np.float = -1 * np.divide(self.flex_b, self.flex_h)
z_fac: np.float = np.multiply(
np.divide(1, 3), np.divide(self.flex_b, self.flex_a)
)
self.Tvd = np.array(
self.Tvd: np.ndarray = np.array(
[
[-x_fac, x_fac, 0],
[0.5 * y_fac, 0.5 * y_fac, -y_fac],
@ -278,40 +294,76 @@ class SangaDeltaStage(SangaStage):
)
logging.debug(self.Tvd)
self.Tdv = np.linalg.inv(self.Tvd)
self.Tdv: np.ndarray = np.linalg.inv(self.Tvd)
logging.debug(self.Tdv)
SangaStage.__init__(self, port=port, **kwargs)
@property
def raw_position(self) -> Tuple[int, int, int]:
return self.board.position
@property
def position(self):
# TODO: Account for camera rotation
position = np.dot(self.Tvd, self.board.position)
position: np.ndarray = np.dot(self.Tvd, self.raw_position)
position = np.dot(np.linalg.inv(self.R_camera), position)
position: np.ndarray = np.dot(np.linalg.inv(self.R_camera), position)
return [int(p) for p in position]
def move_rel(self, displacement, axis=None, backlash=True):
def move_rel(
self,
displacement: Union[int, Tuple[int, int, int], np.ndarray],
axis: Optional[Literal["x", "y", "z"]] = None,
backlash: bool = True,
):
# If we specify an axis name and a displacement int, convert to a displacement tuple
if axis:
# Displacement MUST be an integer if axis name is specified
if not isinstance(displacement, int):
raise TypeError(
"Displacement must be an integer when axis is specified"
)
# Axis name MUST be x, y, or z
if axis not in ("x", "y", "z"):
raise ValueError("axis must be one of x, y, or z")
# Calculate displacement array
cartesian_displacement_array: np.ndarray = _displacement_to_array(
displacement, axis
)
elif isinstance(displacement, np.ndarray):
cartesian_displacement_array = displacement
elif isinstance(displacement, (list, tuple, GeneratorType)):
# Convert our displacement tuple/generator into a numpy array
cartesian_displacement_array = np.array(list(displacement))
else:
raise TypeError(f"Unsupported displacement type {type(displacement)}")
# Transform into camera coordinates
displacement = np.dot(self.R_camera, displacement)
camera_displacement_array: np.ndarray = np.dot(
self.R_camera, cartesian_displacement_array
)
# Transform into delta coordinates
displacement = np.dot(self.Tdv, displacement)
delta_displacement_array: np.ndarray = np.dot(
self.Tdv, camera_displacement_array
)
logging.debug("Delta displacement: %s", (displacement))
logging.debug("Delta displacement: %s", (delta_displacement_array))
# Do the move
SangaStage.move_rel(self, displacement, axis=None, backlash=backlash)
SangaStage.move_rel(
self, delta_displacement_array, axis=None, backlash=backlash
)
def move_abs(self, final, **kwargs):
def move_abs(self, final: Union[Tuple[int, int, int], np.ndarray], **kwargs):
# Transform into camera coordinates
final = np.dot(self.R_camera, final)
camera_final_array: np.ndarray = np.dot(self.R_camera, final)
# Transform into delta coordinates
final = np.dot(self.Tdv, final)
delta_final_array: np.ndarray = np.dot(self.Tdv, camera_final_array)
logging.debug("Delta final: %s", (final))
# Do the move
SangaStage.move_abs(self, final, **kwargs)
SangaStage.move_abs(self, delta_final_array, **kwargs)