Add z-direction calibration action to sangaboard

This commit is contained in:
Julian Stirling 2026-07-07 15:11:30 +01:00
parent f68515b17d
commit 274f698fab
4 changed files with 74 additions and 27 deletions

View file

@ -166,8 +166,14 @@ class BaseStage(lt.Thing):
) )
"""Used to convert coordinates between the program frame and the hardware frame.""" """Used to convert coordinates between the program frame and the hardware frame."""
calibration_required: bool = lt.setting(default=False) @lt.property
"""Whether calibration of the stage z axis is required.""" def calibration_required(self) -> bool:
"""Whether the stage requires calibration.
Currently the only calibration method for the stage is the z-gear rotation
direction in the sangaboard stage.
"""
return False
def update_position(self) -> None: def update_position(self) -> None:
"""Update the position property from the stage.""" """Update the position property from the stage."""
@ -538,8 +544,3 @@ class BaseStage(lt.Thing):
This method provides the interface expected by the camera_stage_mapping. This method provides the interface expected by the camera_stage_mapping.
""" """
self.move_absolute(x=xyz_pos[0], y=xyz_pos[1], z=xyz_pos[2]) self.move_absolute(x=xyz_pos[0], y=xyz_pos[1], z=xyz_pos[2])
@lt.action
def mark_calibration_complete(self) -> None:
"""Mark stage calibration as complete."""
self.calibration_required = False

View file

@ -80,6 +80,37 @@ class SangaboardThing(BaseStage):
) )
"""Used to convert coordinates between the program frame and the hardware frame.""" """Used to convert coordinates between the program frame and the hardware frame."""
z_axis_calibrated: bool = lt.setting(default=False, readonly=True)
@lt.property
def calibration_required(self) -> bool:
"""Whether the stage requires calibration.
Return False only if z-direction has been calibrated.
"""
return not self.z_axis_calibrated
@lt.action
def calibrate_z_direction(
self, positive_motion: Literal["clockwise", "anti-clockwise"]
) -> None:
"""Calibrate the z motor direction based on the gear rotation direction.
Positive z motion should turn the exposed gear anti-clockwise. Calling this
action marks the z motor as calibrated.
:param positive_motion: The direction the gear moved during pisitive z motion.
"""
if positive_motion == "clockwise":
# Wrong direction, mark as such.
self.invert_axis_direction(axis="z")
elif positive_motion != "anti-clockwise":
raise ValueError(
"Motion should be reported as either 'clockwise' or 'anti-clockwise'."
)
# Set z_axis_calibrated to true once this function is called.
self.z_axis_calibrated = True
def _hardware_update_position(self) -> None: def _hardware_update_position(self) -> None:
"""Read position from the stage and set internal attribute _hardware_position. """Read position from the stage and set internal attribute _hardware_position.
@ -236,6 +267,3 @@ class SangaboardThing(BaseStage):
self._sangaboard.query(f"{led_command} {on_brightness}") self._sangaboard.query(f"{led_command} {on_brightness}")
else: else:
self._sangaboard.query(f"{led_command} 0") self._sangaboard.query(f"{led_command} 0")
calibration_required: bool = lt.setting(default=True)
"""By default, Sangaboard stage will require calibration of z direction."""

View file

@ -21,13 +21,13 @@
src="/direction_AC.png" src="/direction_AC.png"
alt="Anti-clockwise" alt="Anti-clockwise"
class="dir-image clickable" class="dir-image clickable"
@click="selectDir" @click="reportDirection('anti-clockwise')"
/> />
<button <button
class="uk-button uk-button-default uk-width-1-1 uk-button-primary" class="uk-button uk-button-default uk-width-1-1 uk-button-primary"
type="button" type="button"
@click="selectDir" @click="reportDirection('anti-clockwise')"
> >
Anti-clockwise Anti-clockwise
</button> </button>
@ -39,13 +39,13 @@
src="/direction_CW.png" src="/direction_CW.png"
alt="Clockwise" alt="Clockwise"
class="dir-image clickable" class="dir-image clickable"
@click="triggerClockwise" @click="reportDirection('clockwise')"
/> />
<button <button
class="uk-button uk-button-default uk-width-1-1 uk-button-primary" class="uk-button uk-button-default uk-width-1-1 uk-button-primary"
type="button" type="button"
@click="triggerClockwise" @click="reportDirection('clockwise')"
> >
Clockwise Clockwise
</button> </button>
@ -68,7 +68,7 @@ export default {
}; };
}, },
mounted() { async mounted() {
this.checkCalibrationState(); this.checkCalibrationState();
}, },
@ -92,20 +92,25 @@ export default {
} }
this.invokeAction("stage", "jog", { stop: true }); this.invokeAction("stage", "jog", { stop: true });
}, },
// Once a direction is selected, advance /**
selectDir() { * Report the direction to the microscope then advance to next pane in wizard.
this.invokeAction("stage", "mark_calibration_complete").then(() => { */
this.$emit("advance"); async reportDirection(direction) {
}); await this.invokeAction("stage", "calibrate_z_direction", { positive_motion: direction });
}, this.$emit("advance");
// If motor moves clockwise, invert z direction, then progress to next step
triggerClockwise() {
this.invokeAction("stage", "invert_axis_direction", { axis: "z" }).then(() => {
this.selectDir();
});
}, },
async checkCalibrationState() { async checkCalibrationState() {
const needsCal = await this.readThingProperty("stage", "calibration_required"); let needsCal = await this.readThingProperty("stage", "calibration_required");
if (needsCal) {
// If it needs calibration check the relevant calibration action exists.
const actions = this.thingDescription("stage").actions;
if (!("calibrate_z_direction" in actions)) {
console.error(
"Stage is requesting calibration but has no 'calibrate_z_direction' action",
);
needsCal = false;
}
}
this.$emit("awaiting-user", needsCal); this.$emit("awaiting-user", needsCal);
}, },
}, },

View file

@ -133,4 +133,17 @@ export const componentOverrides = {
"cameraCalibrationSettings.vue": { "cameraCalibrationSettings.vue": {
props: { cameraUri: "" }, props: { cameraUri: "" },
}, },
"zMotorDirectionStep.vue": {
mocks: {
thingDescription: () => ({
properties: {
test_property_1: {},
test_property_2: {},
},
actions: {
calibrate_z_direction: {},
},
}),
},
},
}; };