from machine import Pin, UART import struct import time import sys import select # ============================================================ # ESP32 + IMU + USB binary bridge # # Wiring: # IMU TX yellow -> ESP32 GPIO16 / RX2 # IMU RX green -> ESP32 GPIO17 / TX2 # IMU GND -> ESP32 GND # # UART2: IMU # USB stdout/stdin: PC # # Important: # - Output uses sys.stdout, because this is the stable path. # - Command input uses sys.stdin, ASCII only: o / c / s. # - First test with USE_REAL_DOUT = False. # ============================================================ # ---------------- PIN CONFIG ---------------- IMU_RX_PIN = 16 IMU_TX_PIN = 17 DIN_PINS = (25, 26, 27, 32) DOUT_PINS = (18, 19) digital_inputs = [Pin(pin, Pin.IN, Pin.PULL_UP) for pin in DIN_PINS] # Low-level trigger relay: # GPIO HIGH = relay OFF # GPIO LOW = relay ON digital_outputs = [Pin(pin, Pin.OUT, value=1) for pin in DOUT_PINS] # ---------------- SERIAL CONFIG ---------------- # PC side uses MicroPython stdout/stdin. # PC reader should use: # python3 pc_reader.py /dev/ttyUSB0 --baud 115200 PC_BAUD_NOTE = 115200 # IMU side confirmed working. IMU_BAUD = 921600 SEND_PERIOD_MS = 20 # 50 Hz STARTUP_DELAY_MS = 3000 # quiet window after reset # ---------------- IMU FRAME CONFIG ---------------- FRAME_LEN = 11 HEADER = 0x55 TYPE_ACC = 0x51 TYPE_GYRO = 0x52 TYPE_ANGLE = 0x53 # raw_values: # acc x y z, gyro x y z, angle x y z, temperature raw_values = [0] * 10 # ---------------- DOUT TEST MODE ---------------- # False: # Only update software DOUT state in outgoing packet. # GPIO18/GPIO19 will NOT really change. # # True: # Actually drive GPIO18/GPIO19. # # Start with False. If o/c/s changes DOUT in pc_reader output, # then set it to True and test real hardware. USE_REAL_DOUT = True # bit0 = DOUT0 / GPIO18 # bit1 = DOUT1 / GPIO19 dout_shadow = 0 # ---------------- BUFFERS ---------------- rx_buffer = bytearray(2048) write_idx = 0 read_idx = 0 # ---------------- USB STDOUT / STDIN ---------------- try: usb_out = sys.stdout.buffer except AttributeError: usb_out = sys.stdout poller = select.poll() poller.register(sys.stdin, select.POLLIN) # ============================================================ # DOUT / gripper # ============================================================ def clear_douts(): global dout_shadow # Logical DOUT state reported to PC. # 0 means no gripper command active. dout_shadow = 0 # Low-level trigger relay: # HIGH = relay OFF # LOW = relay ON for pin in digital_outputs: pin.value(1) def set_gripper(mode): global dout_shadow # mode: # 0 = STOP # 1 = OPEN # 2 = CLOSE # # DOUT[0] = GPIO18 -> relay IN1 # DOUT[1] = GPIO19 -> relay IN2 # # Low-level trigger relay: # GPIO HIGH = relay OFF # GPIO LOW = relay ON # # Tested hardware behavior: # IN1 = LOW, IN2 = HIGH -> CLOSE # IN1 = HIGH, IN2 = LOW -> OPEN if mode == 1: # OPEN -> logical DOUT=[0, 1] dout_shadow = 0b10 elif mode == 2: # CLOSE -> logical DOUT=[1, 0] dout_shadow = 0b01 else: # STOP -> logical DOUT=[0, 0] dout_shadow = 0b00 # Shadow test mode: do not touch real GPIO pins. if not USE_REAL_DOUT: return # First turn both relays OFF. digital_outputs[0].value(1) # GPIO18 / IN1 OFF digital_outputs[1].value(1) # GPIO19 / IN2 OFF time.sleep_ms(20) if mode == 1: # OPEN -> trigger IN2 / GPIO19 digital_outputs[1].value(0) elif mode == 2: # CLOSE -> trigger IN1 / GPIO18 digital_outputs[0].value(0) # mode 0 keeps both HIGH/OFF # ============================================================ # IMU UART # ============================================================ def open_imu_uart(): uart = UART( 2, baudrate=IMU_BAUD, bits=8, parity=None, stop=1, rx=IMU_RX_PIN, tx=IMU_TX_PIN, timeout=0, rxbuf=4096, ) time.sleep_ms(300) # Flush startup junk. while uart.any(): uart.read() return uart # ============================================================ # IMU parser # ============================================================ def update_raw_values(frame): frame_type = frame[1] x, y, z, extra = struct.unpack_from("= SEND_PERIOD_MS: usb_write(make_packet()) last_send_ms = now time.sleep_ms(0)