# /// script # dependencies = ["pyserial>=3.5"] # /// import serial from enum import Flag, auto class StatusByte(Flag): """ The Status Byte returned by the RDSBYTE (RB) command. The value parameter should be an 8-bit int, 0-255. 00000001 <- Bit 0 is 1, commanded move in progress. """ COMMANDED_MOVE = auto() AXIS_ENABLED = auto() MOTOR_ACTIVE = auto() JS_KNOB_ENABLED = auto() MOTOR_RAMPING = auto() MOTOR_RAMPING_UP = auto() AT_UPPER_LIMIT = auto() AT_LOWER_LIMIT = auto() def main() -> None: # use an empty string for MS2000 (card_address = "") card_address = "1" # which axes to query (for a single axis use: axes = ["X"]) # axes_byte_len is the number of bytes that need to be read for RDSBYTE axes = ["X", "Y"] axes_str = " ".join(axes) axes_byte_len = len(axes) + 3 # 3 bytes for ':', '\r', and '\n' with serial.Serial("COM5", 115200, timeout=1) as serial_port: # query the controller for the status byte of each axis command = f"{card_address}RB {axes_str}\r" serial_port.write(bytes(command, encoding="ascii")) response = serial_port.read(axes_byte_len) # report and check for errors print(f"Send: \"{command[:-1]}\"") print(f"Recv: \"{response}\" (interpreted as ASCII)") print(f"Number of bytes to read: {axes_byte_len}\n") if b"N" in response: print("Error in response...") return # view as bytes response_bytes = [byte for byte in response] print(f"{response_bytes = } (raw bytes)\n") # get the status byte for each axis and skip the first byte (':') status_bytes = [response[i] for i in range(1, len(axes) + 1)] print(f"{status_bytes = } (decimal)") # create a dictionary that maps uppercase axis names to status bytes status_bytes_dict = {axis.upper(): StatusByte(status_byte) for (axis, status_byte) in zip(axes, status_bytes, strict=True)} print(f"{status_bytes_dict = }\n") # check the status of each axis for axis in axes: status_byte = status_bytes_dict.get(axis.upper()) # check a single flag is_at_upper_limit = StatusByte.AT_UPPER_LIMIT in status_byte # check multiple flags is_js_and_axis_enabled = StatusByte.JS_KNOB_ENABLED | StatusByte.AXIS_ENABLED in status_byte # check if one flag is True and the other is False is_motor_on_and_not_cmd_move = StatusByte.MOTOR_ACTIVE in status_byte and StatusByte.COMMANDED_MOVE not in status_byte print(f"{axis} Axis Status: {status_byte.value:08b}") # print the status_byte in binary print(f"{status_byte = }") print(f"{is_at_upper_limit = }") print(f"{is_js_and_axis_enabled = }") print(f"{is_motor_on_and_not_cmd_move = }\n") if __name__ == "__main__": main()