a scrappy gimbal that insults you in shakespearean english

feat: add code to use the serial console in interactive form

+111 -32
+111 -32
code.py
··· 1 + import sys 1 2 import board 2 3 import time 3 4 import digitalio 5 + import supervisor 4 6 5 7 # Define pins for stepper motors 6 - motor1_step = digitalio.DigitalInOut(board.GP10) 8 + motor1_step = digitalio.DigitalInOut(board.GP11) 7 9 motor1_step.direction = digitalio.Direction.OUTPUT 8 - motor1_dir = digitalio.DigitalInOut(board.GP9) 10 + motor1_dir = digitalio.DigitalInOut(board.GP10) 9 11 motor1_dir.direction = digitalio.Direction.OUTPUT 10 12 motor2_step = digitalio.DigitalInOut(board.GP8) 11 13 motor2_step.direction = digitalio.Direction.OUTPUT 12 14 motor2_dir = digitalio.DigitalInOut(board.GP7) 13 15 motor2_dir.direction = digitalio.Direction.OUTPUT 14 - enable = digitalio.DigitalInOut(board.GP1) 16 + enable = digitalio.DigitalInOut(board.GP9) 15 17 enable.direction = digitalio.Direction.OUTPUT 16 18 19 + command_buffer = "" 20 + last_serial_check = time.monotonic() 21 + SERIAL_CHECK_INTERVAL = 0.1 # Check serial every 1ms 22 + 17 23 # Enable motors 18 24 enable.value = False 19 25 print("Motors enabled") 20 26 21 - # Function to step motor 22 - def step(step_pin): 23 - step_pin.value = True 24 - time.sleep(0.000001) # 1 microsecond 25 - step_pin.value = False 26 - time.sleep(0.000001) # 1 microsecond 27 + STEPS_PER_REVOLUTION = 200 # For a typical 1.8° stepper motor 28 + 29 + # Motor state tracking 30 + class MotorState: 31 + def __init__(self): 32 + self.running = False 33 + self.direction = True # True for forward 34 + self.speed = 1.0 35 + self.last_step_time = 0 36 + 37 + motor1 = MotorState() 38 + motor2 = MotorState() 39 + 40 + def calculate_step_delay(speed): 41 + return 1 / (STEPS_PER_REVOLUTION * speed) 42 + 43 + def handle_command(command): 44 + parts = command.split() 45 + speed = 1 # Default speed 46 + if len(parts) > 1: 47 + try: 48 + speed = float(parts[1]) 49 + except ValueError: 50 + print("Invalid speed value") 51 + return 52 + command = parts[0] 53 + 54 + if command == "forward1": 55 + motor1.running = True 56 + motor1.direction = True 57 + motor1.speed = speed 58 + motor1_dir.value = True 59 + print(f"Moving motor 1 forward at {speed} rotations per second...") 60 + 61 + elif command == "forward2": 62 + motor2.running = True 63 + motor2.direction = True 64 + motor2.speed = speed 65 + motor2_dir.value = True 66 + print(f"Moving motor 2 forward at {speed} rotations per second...") 67 + 68 + elif command == "reverse1": 69 + motor1.running = True 70 + motor1.direction = False 71 + motor1.speed = speed 72 + motor1_dir.value = False 73 + print(f"Moving motor 1 in reverse at {speed} rotations per second...") 74 + 75 + elif command == "reverse2": 76 + motor2.running = True 77 + motor2.direction = False 78 + motor2.speed = speed 79 + motor2_dir.value = False 80 + print(f"Moving motor 2 in reverse at {speed} rotations per second...") 81 + 82 + elif command == "stop1": 83 + motor1.running = False 84 + print("Motor 1 stopped") 85 + 86 + elif command == "stop2": 87 + motor2.running = False 88 + print("Motor 2 stopped") 27 89 28 - while True: 29 - # Set direction forward 30 - motor1_dir.value = True 31 - motor2_dir.value = True 32 - print("Moving motors forward...") 90 + elif command == "stop": 91 + motor1.running = False 92 + motor2.running = False 93 + enable.value = True 94 + print("All motors stopped") 33 95 34 - # Run motors forward for 1 second 35 - start = time.time() 36 - while time.time() - start < 1: 37 - step(motor1_step) 38 - step(motor2_step) 39 - time.sleep(0.001) 96 + else: 97 + print("Unknown command. Use 'forward1/2 [speed]', 'reverse1/2 [speed]' or 'stop1/2'") 98 + 99 + def step_motor(motor_state, step_pin): 100 + if not motor_state.running: 101 + return 102 + 103 + current_time = time.monotonic() 104 + step_delay = calculate_step_delay(motor_state.speed) 105 + 106 + if (current_time - motor_state.last_step_time) >= step_delay: 107 + step_pin.value = not step_pin.value # Toggle the pin 108 + motor_state.last_step_time = current_time 40 109 41 - print("Forward movement complete") 110 + while True: 111 + current_time = time.monotonic() 42 112 43 - # Set direction reverse 44 - motor1_dir.value = False 45 - motor2_dir.value = False 46 - print("Moving motors in reverse...") 113 + # Check serial input less frequently 114 + if current_time - last_serial_check >= SERIAL_CHECK_INTERVAL: 115 + if supervisor.runtime.serial_bytes_available: 116 + byte = sys.stdin.read(1) 47 117 48 - # Run motors reverse for 1 second 49 - start = time.time() 50 - while time.time() - start < 1: 51 - step(motor1_step) 52 - step(motor2_step) 53 - time.sleep(0.001) 118 + if byte in ('\x08', '\x7f'): 119 + if command_buffer: 120 + command_buffer = command_buffer[:-1] 121 + print('\x08 \x08', end='') 122 + elif byte == '\n' or byte == '\r': 123 + print() 124 + if command_buffer: 125 + handle_command(command_buffer.strip().lower()) 126 + command_buffer = "" 127 + else: 128 + command_buffer += byte 129 + print(byte, end='') 130 + last_serial_check = current_time 54 131 55 - print("Reverse movement complete") 132 + # Handle motor stepping 133 + step_motor(motor1, motor1_step) 134 + step_motor(motor2, motor2_step)