#!/usr/bin/env python3 """ Genera una ilustración técnica de alta resolución del pinout del módulo GPS (U-blox NEO-6M / NEO-7M / N32+) y su correspondencia con la placa ESP32 CYD. """ from PIL import Image, ImageDraw, ImageFont import os W, H = 1000, 680 im = Image.new("RGB", (W, H), (11, 15, 25)) # Sleek dark navy draw = ImageDraw.Draw(im) # Load fonts try: font_title = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 18) font_subtitle = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12) font_sec = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 14) font_bold = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 12) font_reg = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11) font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 10) font_tiny = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 9) font_chip = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 10) except Exception: font_title = font_subtitle = font_sec = font_bold = font_reg = font_small = font_tiny = font_chip = ImageFont.load_default() def draw_card(box, fill, outline, radius=6, width=1): draw.rounded_rectangle(box, radius=radius, fill=fill, outline=outline, width=width) # Palette C_CARD = (18, 24, 38) C_CARD_BORDER = (45, 58, 88) C_TEXT_WHITE = (245, 248, 252) C_TEXT_MUTED = (145, 158, 180) C_TEXT_CYAN = (0, 210, 255) COLOR_VCC = (255, 60, 60) COLOR_RX = (255, 145, 0) COLOR_TX = (40, 215, 125) COLOR_GND = (45, 135, 255) COLOR_PPS = (190, 100, 255) # ------------------------------------------------------------- # 1. HEADER # ------------------------------------------------------------- draw.text((40, 20), "PINOUT Y GUIA DE CONEXION: MODULO GPS U-BLOX / N32+", fill=C_TEXT_WHITE, font=font_title) draw.text((40, 46), "Chipsets NEO-6M / NEO-7M / NEO-8M / N32+ con Antena Cerámica y Puerto Serial UART", fill=C_TEXT_CYAN, font=font_subtitle) draw.line([(40, 70), (W - 40, 70)], fill=(35, 46, 72), width=1) # ------------------------------------------------------------- # 2. CUADRO PRINCIPAL DEL MODULO GPS (ILUSTRACION DE PLACA) # ------------------------------------------------------------- board_panel = [40, 85, 480, 480] draw_card(board_panel, (14, 18, 30), C_CARD_BORDER, radius=8) draw.text((55, 95), "VISTA SUPERIOR DEL MODULO GPS", fill=C_TEXT_CYAN, font=font_sec) # PCB del GPS (Azul industrial estilo U-blox) pcb_box = [80, 130, 440, 440] draw_card(pcb_box, (15, 50, 105), (35, 80, 155), radius=10, width=2) # Orificios de montaje en las 4 esquinas (con arandela dorada) for hx, hy in [(95, 145), (425, 145), (95, 425), (425, 425)]: draw.ellipse([hx-7, hy-7, hx+7, hy+7], fill=(190, 160, 60), outline=(140, 110, 30)) draw.ellipse([hx-4, hy-4, hx+4, hy+4], fill=(11, 15, 25)) # Antena Cerámica Cuadrada (Parche cerámico color marrón dorado) ant_box = [115, 165, 260, 310] draw_card(ant_box, (185, 145, 65), (130, 95, 35), radius=6, width=2) # Superficie metalizada superior de la antena draw_card([125, 175, 250, 300], (210, 175, 95), (150, 115, 50), radius=4, width=1) # Punto central de soldadura / alimentación RF draw.ellipse([182, 232, 194, 244], fill=(245, 245, 245), outline=(120, 120, 120), width=1) draw.text((135, 315), "ANTENA CERAMICA GPS", fill=(210, 185, 130), font=font_small) # Blindaje Metálico U-blox (Shield Can) shield_box = [280, 165, 415, 285] draw_card(shield_box, (190, 198, 210), (140, 148, 160), radius=4, width=2) draw.rectangle([282, 167, 413, 172], fill=(220, 228, 238)) # Reflejo de luz draw.text((295, 178), "u-blox", fill=(190, 30, 30), font=font_sec) draw.text((295, 202), "NEO-7M-0-001", fill=(30, 35, 45), font=font_chip) draw.text((295, 218), "GPS / GLONASS", fill=(60, 70, 85), font=font_tiny) # Mini QR / DataMatrix decorativo draw_card([370, 235, 405, 270], (240, 240, 240), (80, 80, 80), radius=2) draw.rectangle([374, 239, 380, 245], fill=(30, 30, 30)) draw.rectangle([395, 239, 401, 245], fill=(30, 30, 30)) draw.rectangle([374, 260, 380, 266], fill=(30, 30, 30)) draw.rectangle([386, 248, 392, 254], fill=(30, 30, 30)) # Pila de botón de respaldo (RTC / Ephemeris Backup Battery) batt_x, batt_y = 305, 325 draw.ellipse([batt_x-16, batt_y-16, batt_x+16, batt_y+16], fill=(195, 202, 212), outline=(130, 135, 145), width=2) draw.text((batt_x-10, batt_y-5), "3V", fill=(50, 55, 65), font=font_tiny) draw.text((280, 345), "Pila RTC Backup", fill=C_TEXT_MUTED, font=font_tiny) # LED de Estado PPS (Fix Indicator) led_x, led_y = 380, 325 draw.ellipse([led_x-7, led_y-7, led_x+7, led_y+7], fill=(50, 220, 110), outline=(20, 140, 60), width=1) draw.ellipse([led_x-3, led_y-3, led_x+3, led_y+3], fill=(200, 255, 220)) # brillo central draw.text((358, 345), "LED PPS (Fix)", fill=(80, 235, 130), font=font_tiny) # Silkscreen del modelo draw.text((120, 350), "N32+ GPS MODULE", fill=(220, 230, 245), font=font_bold) draw.text((120, 368), "UART: 9600 bps 8N1", fill=(160, 190, 230), font=font_small) # Tira de pines (Header) en la parte inferior del PCB # 5 pines: VCC, RX, TX, GND, PPS header_box = [130, 395, 390, 430] draw_card(header_box, (20, 20, 20), (50, 50, 50), radius=3) pin_defs = [ ("VCC", COLOR_VCC, 160), ("RX", COLOR_RX, 215), ("TX", COLOR_TX, 270), ("GND", COLOR_GND, 325), ("PPS", COLOR_PPS, 370) ] for name, col, px in pin_defs: # Pin cuadrado dorado con orificio draw.rectangle([px-8, 400, px+8, 420], fill=(220, 185, 55), outline=(150, 120, 30)) draw.ellipse([px-4, 406, px+4, 414], fill=(20, 20, 20)) # Texto de serigrafia en PCB draw.text((px-9, 380), name, fill=col, font=font_chip) # ------------------------------------------------------------- # 3. DETALLE DE CADA PIN Y CONEXION A LA CYD (COLUMNA DERECHA) # ------------------------------------------------------------- pins_panel = [500, 85, 960, 480] draw_card(pins_panel, (14, 18, 30), C_CARD_BORDER, radius=8) draw.text((515, 95), "DESCRIPCION DE PINES Y DESTINO EN PLACA CYD", fill=C_TEXT_WHITE, font=font_sec) # Tarjeta Pin 1: VCC p1_card = [515, 125, 945, 185] draw_card(p1_card, (26, 32, 48), (200, 50, 50), radius=6) draw.rectangle([515, 125, 523, 185], fill=COLOR_VCC) draw.text((535, 132), "PIN 1: VCC (Alimentacion 3.3V a 5.0V DC)", fill=COLOR_VCC, font=font_bold) draw.text((535, 149), "Entrada de corriente con regulador LDO integrado en la placa GPS.", fill=C_TEXT_MUTED, font=font_small) draw.text((535, 165), "--> CONECTAR A: Pin 1 del conector P1 de la CYD (Vin 5V USB)", fill=C_TEXT_WHITE, font=font_reg) # Tarjeta Pin 2: RX p2_card = [515, 195, 945, 255] draw_card(p2_card, (26, 32, 48), (200, 120, 20), radius=6) draw.rectangle([515, 195, 523, 255], fill=COLOR_RX) draw.text((535, 202), "PIN 2: RX (Entrada Serial UART del GPS - Nivel 3.3V)", fill=COLOR_RX, font=font_bold) draw.text((535, 219), "Recibe comandos UBX de reposo (Sleep) y despertar (Wake) desde el ESP32.", fill=C_TEXT_MUTED, font=font_small) draw.text((535, 235), "--> CONECTAR A: Pin 2 del conector P1 de la CYD (GPIO 1 / TX0)", fill=C_TEXT_WHITE, font=font_reg) # Tarjeta Pin 3: TX p3_card = [515, 265, 945, 325] draw_card(p3_card, (26, 32, 48), (30, 160, 90), radius=6) draw.rectangle([515, 265, 523, 325], fill=COLOR_TX) draw.text((535, 272), "PIN 3: TX (Salida Serial UART del GPS - Nivel 3.3V)", fill=COLOR_TX, font=font_bold) draw.text((535, 289), "Transmite sentencias NMEA ($GPRMC, $GPGGA, velocidad, hora satelital).", fill=C_TEXT_MUTED, font=font_small) draw.text((535, 305), "--> CONECTAR A: Pin 3 del conector P3 de la CYD (GPIO 35 / RX1)", fill=C_TEXT_WHITE, font=font_reg) # Tarjeta Pin 4: GND p4_card = [515, 335, 945, 395] draw_card(p4_card, (26, 32, 48), (30, 90, 180), radius=6) draw.rectangle([515, 335, 523, 395], fill=COLOR_GND) draw.text((535, 342), "PIN 4: GND (Masa / Retorno comun)", fill=COLOR_GND, font=font_bold) draw.text((535, 359), "Retorno de corriente y referencia de nivel logico serial.", fill=C_TEXT_MUTED, font=font_small) draw.text((535, 375), "--> CONECTAR A: Pin 4 del conector P1 de la CYD (GND)", fill=C_TEXT_WHITE, font=font_reg) # Tarjeta Pin 5: PPS (Opcional) p5_card = [515, 405, 945, 465] draw_card(p5_card, (22, 28, 42), (120, 60, 180), radius=6) draw.rectangle([515, 405, 523, 465], fill=COLOR_PPS) draw.text((535, 412), "PIN 5: PPS (Pulse Per Second - Pulso 1 Hz)", fill=COLOR_PPS, font=font_bold) draw.text((535, 429), "Pulso de sincronismo atómico cada 1 segundo exacto cuando hay fix 3D.", fill=C_TEXT_MUTED, font=font_small) draw.text((535, 445), "--> NO REQUERIDO: Queda libre / no conectar (sincronismo por NMEA)", fill=(160, 170, 185), font=font_small) # ------------------------------------------------------------- # 4. ESPECIFICACIONES TECNICAS Y TIPS DE INSTALACION (INFERIOR) # ------------------------------------------------------------- info_box = [40, 500, 960, 655] draw_card(info_box, (15, 20, 32), (45, 58, 88), radius=8) draw.text((55, 510), "ESPECIFICACIONES TECNICAS Y RECOMENDACIONES DE INSTALACION:", fill=C_TEXT_WHITE, font=font_bold) col1_x = 55 val1_x = 180 draw.text((col1_x, 532), "• Chipset:", fill=C_TEXT_CYAN, font=font_bold) draw.text((val1_x, 532), "U-blox 7 / NEO-7M (o NEO-6M / N32+) 56 canales.", fill=C_TEXT_WHITE, font=font_small) draw.text((col1_x, 552), "• Protocolo:", fill=C_TEXT_CYAN, font=font_bold) draw.text((val1_x, 552), "NMEA 0183 a 9600 bps (8N1 - 8 bits, no paridad, 1 stop).", fill=C_TEXT_WHITE, font=font_small) draw.text((col1_x, 572), "• Consumo:", fill=C_TEXT_CYAN, font=font_bold) draw.text((val1_x, 572), "Activo: ~45 mA | Modo Sleep (UBX-RXM-PMREQ): < 0.5 mA.", fill=C_TEXT_WHITE, font=font_small) draw.text((col1_x, 592), "• Nivel Logico:", fill=C_TEXT_CYAN, font=font_bold) draw.text((val1_x, 592), "3.3V TTL (compatible directo con pines GPIO del ESP32).", fill=C_TEXT_WHITE, font=font_small) col2_x = 525 val2_x = 705 draw.text((col2_x, 532), "• Posición de Antena:", fill=(255, 215, 60), font=font_bold) draw.text((val2_x, 532), "Cara cerámica orientada al cielo.", fill=C_TEXT_WHITE, font=font_small) draw.text((col2_x, 552), " (En el tablero del vehículo, libre de chapas metálicas o tintes metalizados).", fill=C_TEXT_MUTED, font=font_small) draw.text((col2_x, 575), "• LED Verde (Fix/PPS):", fill=(80, 235, 130), font=font_bold) draw.text((val2_x, 575), "Apagado: buscando satélites.", fill=C_TEXT_WHITE, font=font_small) draw.text((col2_x, 595), " (Destella 1 vez por segundo cuando la señal satelital 3D está fijada).", fill=C_TEXT_MUTED, font=font_small) draw.text((col1_x, 625), "NOTA: Al programar el ESP32 por USB, si el pin RX del GPS esta conectado a GPIO 1 (P1), desconectar temporalmente el cable amarillo para evitar colisiones.", fill=(255, 180, 80), font=font_small) # Guardar imagen en hardware/ y en raíz out_path_1 = "hardware/pinout_gps.png" out_path_2 = "hardware/gps_pinout.png" out_path_3 = "pinout_gps.png" im.save(out_path_1, "PNG") im.save(out_path_2, "PNG") im.save(out_path_3, "PNG") print("Pinout GPS generado exitosamente en:", out_path_1, out_path_2, out_path_3)