Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ typedef struct
int target_tolerance;
int pid_tolerance;

int ramp_mode;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we don't initialize this in tmc4361A_init, which means I think we default it to 0. To preserve the original behavior it'd be good to set tmc4361a->ramp_mode = TMC4361_RAMP_SSHAP in the init.

I know we set the ramp mode in our .py implementation, but you generally don't want to assume other pieces of code will do the right thing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I agree with you.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@veerwang can you implement the suggested change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I would do it.

} TMC4361ATypeDef;

typedef void (*tmc4361A_callback)(TMC4361ATypeDef*, ConfigState);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ void tmc4361A_moveToExtreme(TMC4361ATypeDef *tmc4361A, int32_t vel, int8_t dir)
-----------------------------------------------------------------------------
*/
void tmc4361A_sRampInit(TMC4361ATypeDef *tmc4361A) {
tmc4361A_setBits(tmc4361A, TMC4361A_RAMPMODE, TMC4361A_RAMP_POSITION | TMC4361A_RAMP_SSHAPE); // positioning mode, s-shaped ramp
tmc4361A_setBits(tmc4361A, TMC4361A_RAMPMODE, TMC4361A_RAMP_POSITION | tmc4361A->ramp_mode); // positioning mode
tmc4361A_rstBits(tmc4361A, TMC4361A_GENERAL_CONF, TMC4361A_USE_ASTART_AND_VSTART_MASK); // keep astart, vstart = 0
tmc4361A_writeInt(tmc4361A, TMC4361A_BOW1, tmc4361A->rampParam[BOW1_IDX]); // determines the value which increases the absolute acceleration value.
tmc4361A_writeInt(tmc4361A, TMC4361A_BOW2, tmc4361A->rampParam[BOW2_IDX]); // determines the value which decreases the absolute acceleration value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
// byte[2]: how many micro steps - upper 8 bits
// byte[3]: how many micro steps - lower 8 bits

static const int CMD_LENGTH = 8;
static const int CMD_LENGTH = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out why this needs to go up to 24 instead of 10 (we need 2 extra bytes for the MOVE*_XY, but I don't see why we need 11-24).

It's probably okay, but it does mean we send 14 more bytes per command than we absolutely need to. I think that's only ~8 us more per command at 2 MHz, but if we don't need it we might as well not waste the time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't thought much about it; I'm just leaving room for future situations. OK, I would change to 10.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command length must be adjusted in multiples of 4 bytes. @ianohara

static const int MSG_LENGTH = 24;
byte buffer_rx[512];
byte buffer_tx[MSG_LENGTH];
Expand Down Expand Up @@ -67,6 +67,9 @@ static const int SET_PID_ARGUMENTS = 29;
static const int SEND_HARDWARE_TRIGGER = 30;
static const int SET_STROBE_DELAY = 31;
static const int SET_AXIS_DISABLE_ENABLE = 32;
static const int MOVE_XY = 33;
static const int MOVETO_XY = 34;
static const int SET_SRAMP_MOD = 36;
static const int SET_PIN_LEVEL = 41;
static const int INITFILTERWHEEL = 253;
static const int INITIALIZE = 254;
Expand Down Expand Up @@ -301,12 +304,11 @@ uint16_t home_safety_margin[4] = {4, 4, 4, 4};
// IntervalTimer does not work on teensy with SPI, the below lines are to be removed
static const int TIMER_PERIOD = 500; // in us
volatile int counter_send_pos_update = 0;
volatile bool flag_send_pos_update = false;

static const int interval_send_pos_update = 10000; // in us
elapsedMicros us_since_last_pos_update;

static const int interval_check_position = 10000; // in us
static const int interval_check_position = 5000; // in us
elapsedMicros us_since_last_check_position;

static const int interval_send_joystick_update = 30000; // in us
Expand Down Expand Up @@ -356,7 +358,7 @@ void onJoystickPacketReceived(const uint8_t* buffer, size_t size)
}
else
{
focusPosition = focusPosition + (int32_t(uint32_t(buffer[0]) << 24 | uint32_t(buffer[1]) << 16 | uint32_t(buffer[2]) << 8 | uint32_t(buffer[3])) - focuswheel_pos);
focusPosition = focusPosition - (int32_t(uint32_t(buffer[0]) << 24 | uint32_t(buffer[1]) << 16 | uint32_t(buffer[2]) << 8 | uint32_t(buffer[3])) - focuswheel_pos);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out why we switched the sign here. Can you help me understand how this is related to scanning performance, and what the sign switch does?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The knob is designed to increase with clockwise rotation and decrease with counterclockwise rotation. This modification aims to align with conventional intuition.

focuswheel_pos = int32_t(uint32_t(buffer[0]) << 24 | uint32_t(buffer[1]) << 16 | uint32_t(buffer[2]) << 8 | uint32_t(buffer[3]));
}

Expand Down Expand Up @@ -911,6 +913,21 @@ void loop() {
}
break;
}
case MOVETO_XY:
{
long x_absolute_position = int32_t(uint32_t(buffer_rx[2]) << 24 | uint32_t(buffer_rx[3]) << 16 | uint32_t(buffer_rx[4]) << 8 | uint32_t(buffer_rx[5]));
X_direction = sgn(x_absolute_position - tmc4361A_currentPosition(&tmc4361[x]));
X_commanded_target_position = x_absolute_position;
if (tmc4361A_moveTo(&tmc4361[x], X_commanded_target_position) == 0)
X_commanded_movement_in_progress = true;
long y_absolute_position = int32_t(uint32_t(buffer_rx[6]) << 24 | uint32_t(buffer_rx[7]) << 16 | uint32_t(buffer_rx[8]) << 8 | uint32_t(buffer_rx[9]));
Y_direction = sgn(y_absolute_position - tmc4361A_currentPosition(&tmc4361[y]));
Y_commanded_target_position = y_absolute_position;
if (tmc4361A_moveTo(&tmc4361[y], Y_commanded_target_position) == 0)
Y_commanded_movement_in_progress = true;
mcu_cmd_execution_in_progress = true;
break;
}
case MOVETO_Z:
{
long absolute_position = int32_t(uint32_t(buffer_rx[2]) << 24 | uint32_t(buffer_rx[3]) << 16 | uint32_t(buffer_rx[4]) << 8 | uint32_t(buffer_rx[5]));
Expand Down Expand Up @@ -938,6 +955,21 @@ void loop() {
}
break;
}
case SET_SRAMP_MOD:
{
uint8_t axis = buffer_rx[2];
uint8_t mode = buffer_rx[3];
// map to w axis, in the host w axis index is 5
if (axis == 5)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on the comment above? What code is the host code in this case?

Also, we have AXIS_W defined - can you use that?

And I don't understand why we map AXIS_W to AXIS_THETA here. Can you explain that?

In general - try to avoid using bare numbers like this. Instead, use constants with clear names. This helps make the code more clear, and helps in refactoring later (For instance, if we need to change the axis number for AXIS_W in the future, it's easy to change the AXIS_W define but hard to go and figure out which inline 5 are AXIS_W or some other use of the number 5). Bare numbers are only sortof okay if they are true universal constants (as in, they never change throughout the entire universe).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the python axes match the defines here, so I'm really not sure what the "map to w axis, in host w axis is 5" comment means.

Here are the firmware defines:

static const int AXIS_X = 0;
static const int AXIS_Y = 1;
static const int AXIS_Z = 2;
static const int AXIS_THETA = 3;
static const int AXES_XY = 4;
static const int AXIS_W = 5;

Here are the python defines:

class AXIS:
    X = 0
    Y = 1
    Z = 2
    THETA = 3
    XY = 4
    W = 5

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I would change the code to easy to understand.

axis = 3;

// guard code
if (axis > STAGE_AXES)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it only okay to change the ramp mode for X, Y, and Z? It isn't okay to change them for THETA and W?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For safety reasons, I’ve only tested along the X, Y, and Z axes so far, so I’m keeping it in safe mode for now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just fails silently, though. If someone tries to use this command with axis > STAGE_AXES, how do they know that they didn't actually set ramp mode on the axis?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we let all other commands fail silently, so I guess we can keep this.

We really need to introduce a mechanism for communicating command failures, though. Failing silently shouldn't be an option!

return;

tmc4361[axis].ramp_mode = mode;
break;
}
case SET_LIM:
{
switch (buffer_rx[2])
Expand Down Expand Up @@ -2181,9 +2213,9 @@ void loop() {
buffer_tx[18] &= ~ (1 << BIT_POS_JOYSTICK_BUTTON); // clear the joystick button bit
buffer_tx[18] = buffer_tx[18] | joystick_button_pressed << BIT_POS_JOYSTICK_BUTTON;

// Calculate and fill out the checksum. NOTE: This must be after all other buffer_tx modifications are done!
uint8_t checksum = crc8ccitt(buffer_tx, MSG_LENGTH - 1);
buffer_tx[MSG_LENGTH - 1] = checksum;
// Calculate and fill out the checksum. NOTE: This must be after all other buffer_tx modifications are done!
uint8_t checksum = crc8ccitt(buffer_tx, MSG_LENGTH - 1);
buffer_tx[MSG_LENGTH - 1] = checksum;

if(!DEBUG_MODE)
SerialUSB.write(buffer_tx,MSG_LENGTH);
Expand All @@ -2201,8 +2233,6 @@ void loop() {
SerialUSB.print(", PG:");
SerialUSB.println(digitalRead(pin_PG));
}
flag_send_pos_update = false;

}

// keep checking position process at suitable frequence
Expand All @@ -2213,22 +2243,26 @@ void loop() {
{
X_commanded_movement_in_progress = false;
mcu_cmd_execution_in_progress = false || Y_commanded_movement_in_progress || Z_commanded_movement_in_progress || W_commanded_movement_in_progress;
us_since_last_check_position = interval_check_position + 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment here to explain this might be helpful. Something like "// It's important that we check positions next time around because <explain why ...>, so force the elapsed time to be larger than our interval."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

}
if (Y_commanded_movement_in_progress && tmc4361A_currentPosition(&tmc4361[y]) == Y_commanded_target_position && !is_homing_Y && !tmc4361A_isRunning(&tmc4361[y], stage_PID_enabled[y]))
{
Y_commanded_movement_in_progress = false;
mcu_cmd_execution_in_progress = false || X_commanded_movement_in_progress || Z_commanded_movement_in_progress || W_commanded_movement_in_progress;
us_since_last_check_position = interval_check_position + 1;
}
if (Z_commanded_movement_in_progress && tmc4361A_currentPosition(&tmc4361[z]) == Z_commanded_target_position && !is_homing_Z && !tmc4361A_isRunning(&tmc4361[z], stage_PID_enabled[z]))
{
Z_commanded_movement_in_progress = false;
mcu_cmd_execution_in_progress = false || X_commanded_movement_in_progress || Y_commanded_movement_in_progress || W_commanded_movement_in_progress;
us_since_last_check_position = interval_check_position + 1;
}
if (enable_filterwheel == true) {
if (W_commanded_movement_in_progress && tmc4361A_currentPosition(&tmc4361[w]) == W_commanded_target_position && !is_homing_W && !tmc4361A_isRunning(&tmc4361[w], stage_PID_enabled[w]))
{
W_commanded_movement_in_progress = false;
mcu_cmd_execution_in_progress = false || X_commanded_movement_in_progress || Y_commanded_movement_in_progress || Z_commanded_movement_in_progress;
us_since_last_check_position = interval_check_position + 1;
}
}
}
Expand Down Expand Up @@ -2270,28 +2304,6 @@ void loop() {
}
}

/***************************************************

timer interrupt

***************************************************/

// timer interrupt
/*
// IntervalTimer stops working after SPI.begin()
void timer_interruptHandler()
{
SerialUSB.println("timer event");
counter_send_pos_update = counter_send_pos_update + 1;
if(counter_send_pos_update==interval_send_pos_update/TIMER_PERIOD)
{
flag_send_pos_update = true;
counter_send_pos_update = 0;
SerialUSB.println("send pos update");
}
}
*/

/***************************************************************************************************/
/********************************************* utils *********************************************/
/***************************************************************************************************/
Expand Down
13 changes: 12 additions & 1 deletion software/control/_def.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class PosUpdate:

class MicrocontrollerDef:
MSG_LENGTH = 24
CMD_LENGTH = 8
CMD_LENGTH = 24
N_BYTES_POS = 4


Expand Down Expand Up @@ -145,6 +145,9 @@ class CMD_SET:
SEND_HARDWARE_TRIGGER = 30
SET_STROBE_DELAY = 31
SET_AXIS_DISABLE_ENABLE = 32
MOVE_XY = 33
MOVETO_XY = 34
SET_SRAMP_MOD = 36
SET_PIN_LEVEL = 41
INITFILTERWHEEL = 253
INITIALIZE = 254
Expand Down Expand Up @@ -426,6 +429,14 @@ def convert_to_enum(option: Union[str, "FocusMeasureOperator"]) -> "FocusMeasure
DEFAULT_SAVING_PATH = str(Path.home()) + "/Downloads"
FILE_ID_PADDING = 0

# 0: RAMP_HOLD
# 1: RAMP_TRAPEZ
# 2: RAMP_SSHAPE
X_AXIS_SRAMP_MODE = 2
Y_AXIS_SRAMP_MODE = 2
Z_AXIS_SRAMP_MODE = 2
W_AXIS_SRAMP_MODE = 2


class PLATE_READER:
NUMBER_OF_ROWS = 8
Expand Down
9 changes: 3 additions & 6 deletions software/control/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,8 +1172,7 @@ def gen_focus_map(self, coord1, coord2, coord3):

for coord in [coord1, coord2, coord3]:
print(f"Navigating to coordinates ({coord[0]},{coord[1]}) to sample for focus map")
self.stage.move_x_to(coord[0])
self.stage.move_y_to(coord[1])
self.stage.move_xy_to(coord[0], coord[1])

print("Autofocusing")
self.autofocus(True)
Expand Down Expand Up @@ -2369,8 +2368,7 @@ def run_acquisition(self, acquire_current_fov=False):
self.autofocusController.set_focus_map_use(True)

# Return to center position
self.stage.move_x_to(x_center)
self.stage.move_y_to(y_center)
self.stage.move_xy_to(x_center, y_center)

except ValueError:
self._log.exception("Invalid coordinates for autofocus plane, aborting.")
Expand Down Expand Up @@ -2447,8 +2445,7 @@ def _on_acquisition_completed(self):
if "current" in self.scanCoordinates.region_centers:
region_center = self.scanCoordinates.region_centers["current"]
try:
self.stage.move_x_to(region_center[0])
self.stage.move_y_to(region_center[1])
self.stage.move_xy_to(region_center[0], region_center[1])
self.stage.move_z_to(region_center[2])
except:
self._log.error("Failed to move to center of current region")
Expand Down
21 changes: 12 additions & 9 deletions software/control/core/multi_point_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,19 +329,24 @@ def update_coordinates_dataframe(self, region_id, z_level, pos: squid.abc.Pos, f

def move_to_coordinate(self, coordinate_mm):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe there's a reason I'm missing here, but this refactor duplicates code. Instead, I probably would do:

def move_to_coordinate(self, coordinate_mm):
    x_mm = coordinate_mm[0]
    y_mm = coordinate_mm[1]
    have_z = len(coordinate_mm) >= 3
    self.stage.move_xy_to(x_mm, y_mm, blocking=not have_z)

    if have_z >= 3:
        self.move_to_z_level(z_mm)
    
    self._sleep(SCAN_STABILIZATION_TIME_MS / 1000)

This:

  1. Does not duplicate the x_mm, y_mm code.
  2. Doesn't have two move_xy_to calls

Also, since SCAN_STABILIZATION_TIME_MS_Y is no longer used for just Y in your code, we should re-name it. This is to follow the "principle of least surprise" - it'd be really surprising to someone in the future to change SCAN_STABILIZATION_TIME_MS_Y and see that all the axis move stabilization times change (not just Y).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I would copy the code.

print("moving to coordinate", coordinate_mm)
x_mm = coordinate_mm[0]
self.stage.move_x_to(x_mm)
self._sleep(SCAN_STABILIZATION_TIME_MS_X / 1000)

y_mm = coordinate_mm[1]
self.stage.move_y_to(y_mm)
self._sleep(SCAN_STABILIZATION_TIME_MS_Y / 1000)

# check if z is included in the coordinate
if len(coordinate_mm) == 3:
x_mm = coordinate_mm[0]
y_mm = coordinate_mm[1]
z_mm = coordinate_mm[2]

self.stage.move_xy_to(x_mm, y_mm, blocking=False)
self.move_to_z_level(z_mm)

time.sleep(SCAN_STABILIZATION_TIME_MS_Y / 1000)
else:
x_mm = coordinate_mm[0]
y_mm = coordinate_mm[1]

self.stage.move_xy_to(x_mm, y_mm)
time.sleep(SCAN_STABILIZATION_TIME_MS_Y / 1000)

def move_to_z_level(self, z_mm):
print("moving z")
self.stage.move_z_to(z_mm)
Expand Down Expand Up @@ -546,7 +551,6 @@ def acquire_camera_image(
camera_illumination_time = self.camera.get_exposure_time()
if self.liveController.trigger_mode == TriggerMode.SOFTWARE:
self.liveController.turn_on_illumination()
self.wait_till_operation_is_completed()
camera_illumination_time = None
elif self.liveController.trigger_mode == TriggerMode.HARDWARE:
if "Fluorescence" in config.name and ENABLE_NL5 and NL5_USE_DOUT:
Expand Down Expand Up @@ -614,7 +618,6 @@ def acquire_rgb_image(self, config, file_ID, current_path, current_round_images,
if self.liveController.trigger_mode == TriggerMode.SOFTWARE:
# TODO(imo): use illum controller
self.liveController.turn_on_illumination()
self.wait_till_operation_is_completed()

# read camera frame
self.camera.send_trigger(illumination_time=self.camera.get_exposure_time())
Expand Down
43 changes: 43 additions & 0 deletions software/control/microcontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,10 @@ def __init__(self, serial_device: AbstractCephlaMicroSerial, reset_and_initializ
self.log.debug("Resetting and initializing microcontroller.")
self.reset()
time.sleep(0.5)

# Need set the parameter before initialization
self.initizlize_sramp_of_axes()

if USE_SQUID_FILTERWHEEL:
self.init_filter_wheel()
time.sleep(0.5)
Expand Down Expand Up @@ -561,6 +565,17 @@ def reset(self):
# here.
self._cmd_id = 0

def initizlize_sramp_of_axes(self):
# initialize axes sramp mode
self.set_sramp_mode(AXIS.X, X_AXIS_SRAMP_MODE)
self.wait_till_operation_is_completed()
self.set_sramp_mode(AXIS.Y, Y_AXIS_SRAMP_MODE)
self.wait_till_operation_is_completed()
self.set_sramp_mode(AXIS.Z, Z_AXIS_SRAMP_MODE)
self.wait_till_operation_is_completed()
self.set_sramp_mode(AXIS.W, W_AXIS_SRAMP_MODE)
self.wait_till_operation_is_completed()

def initialize_drivers(self):
self._cmd_id = 0
cmd = bytearray(self.tx_buffer_length)
Expand Down Expand Up @@ -684,6 +699,24 @@ def move_y_to_usteps(self, usteps):
cmd[5] = payload & 0xFF
self.send_command(cmd)

def move_xy_to_usteps(self, xusteps, yusteps):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we also added a MOVE_XY - we should add that here so users of the Microcontroller know it exists. Or remove it from the firmware.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I will temporarily remove MOVE_XY from the firmware.

xpayload = self._int_to_payload(xusteps, 4)
ypayload = self._int_to_payload(yusteps, 4)

cmd = bytearray(self.tx_buffer_length)
cmd[1] = CMD_SET.MOVETO_XY
cmd[2] = xpayload >> 24
cmd[3] = (xpayload >> 16) & 0xFF
cmd[4] = (xpayload >> 8) & 0xFF
cmd[5] = xpayload & 0xFF

cmd[6] = ypayload >> 24
cmd[7] = (ypayload >> 16) & 0xFF
cmd[8] = (ypayload >> 8) & 0xFF
cmd[9] = ypayload & 0xFF

self.send_command(cmd)

def move_z_usteps(self, usteps):
self._move_axis_usteps(usteps, CMD_SET.MOVE_Z)

Expand Down Expand Up @@ -961,6 +994,9 @@ def configure_squidfilter(self):
self.wait_till_operation_is_completed()
self.set_max_velocity_acceleration(AXIS.W, MAX_VELOCITY_W_mm, MAX_ACCELERATION_W_mm)
self.wait_till_operation_is_completed()
# initialize axes sramp mode
self.set_sramp_mode(AXIS.W, W_AXIS_SRAMP_MODE)
self.wait_till_operation_is_completed()

def ack_joystick_button_pressed(self):
cmd = bytearray(self.tx_buffer_length)
Expand Down Expand Up @@ -994,6 +1030,13 @@ def set_pin_level(self, pin, level):
cmd[3] = level
self.send_command(cmd)

def set_sramp_mode(self, axis, mode):
cmd = bytearray(self.tx_buffer_length)
cmd[1] = CMD_SET.SET_SRAMP_MOD
cmd[2] = axis
cmd[3] = mode
self.send_command(cmd)

def turn_on_AF_laser(self):
self.set_pin_level(MCU_PINS.AF_LASER, 1)

Expand Down
12 changes: 12 additions & 0 deletions software/squid/stage/cephla.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ def move_y_to(self, abs_mm: float, blocking: bool = True):
self._calc_move_timeout(abs_mm - self.get_pos().y_mm, self.get_config().Y_AXIS.MAX_SPEED)
)

def move_xy_to(self, x_abs_mm: float, y_abs_mm: float, blocking: bool = True):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an AbstractStage interface now. This means the codebase outside of squid/stage can only use methods on the AbstractStage class, and any class that implements AbstractStage must implement all the @abstractmethod on it. As is, this breaks the PriorStage and the AbstractStage interface.

To do this change properly, we should:

  1. Add an @abstractmethod called move_xy_to to AbstractStage.
  2. Implement move_xy_to on all the stage implementations in squid/stage (right now, just the cephla and prior stages).

Test, or find someone that can help you test, the new code on all the stages we support.

We should not merge this before doing all of the above since it will break some customers!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I would add an @AbstractMethod called move_xy_to to AbstractStage. Would you please ask somebody do the implementation of move_xy_to in to prior_stages? @hongquanli

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I just add an empty function in prior_stages?

self._microcontroller.move_xy_to_usteps(
self._config.X_AXIS.convert_real_units_to_ustep(x_abs_mm),
self._config.Y_AXIS.convert_real_units_to_ustep(y_abs_mm),
)

if blocking:
x_timeout = self._calc_move_timeout(x_abs_mm - self.get_pos().x_mm, self.get_config().X_AXIS.MAX_SPEED)
y_timeout = self._calc_move_timeout(y_abs_mm - self.get_pos().y_mm, self.get_config().Y_AXIS.MAX_SPEED)

self._microcontroller.wait_till_operation_is_completed(max(x_timeout, y_timeout))

def move_z_to(self, abs_mm: float, blocking: bool = True):
# From Hongquan, we want the z axis to rest on the "up" (wrt gravity) direction of gravity. So if we
# are moving in the negative (down) z direction, we need to move past our mark a bit then
Expand Down