#!/usr/bin/env python3 """ Generate KiCad 7 schematic and project files for Baby Mobile Audio Board. Design: ATmega328P + W25Q128 SPI Flash + PAM8302A Class-D Amp + MOSFET motor driver Power: 2x AA batteries (1.8V-3.3V), optimized for long runtime Audio: 30+ min at 8kHz/8-bit mono via 16MB SPI flash """ import uuid import json import os def uid(): return str(uuid.uuid4()) # ============================================================ # SCHEMATIC GENERATION # ============================================================ def generate_schematic(): """Generate the complete .kicad_sch file.""" # We use net labels for connections instead of routing every wire. # This keeps the schematic clean and KiCad resolves connectivity by label name. sch = [] sch.append(f"""(kicad_sch (version 20230121) (generator "custom_generator") (uuid "{uid()}") (paper "A3") (title_block (title "Baby Mobile Audio Board") (date "2026-03-08") (rev "1.0") (comment 1 "ATmega328P + W25Q128 + PAM8302A") (comment 2 "2xAA Battery Powered - Long Runtime Design") (comment 3 "8-ohm 0.25W Speaker, DC Motor, 8 Buttons") (comment 4 "Arduino Compatible (8MHz Internal Osc)") ) """) # ---- LIB_SYMBOLS ---- sch.append(" (lib_symbols") sch.append(_sym_atmega328p()) sch.append(_sym_w25q128()) sch.append(_sym_pam8302a()) sch.append(_sym_nmos()) sch.append(_sym_capacitor()) sch.append(_sym_resistor()) sch.append(_sym_diode_schottky()) sch.append(_sym_inductor()) sch.append(_sym_switch()) sch.append(_sym_conn2()) sch.append(_sym_conn3()) sch.append(_sym_conn6()) sch.append(_sym_led()) sch.append(_sym_pwr_flag()) sch.append(" )") # end lib_symbols # ---- COMPONENT INSTANCES ---- # Layout regions (KiCad uses mm, origin top-left): # Power supply section: x=30, y=30 # MCU (ATmega328P): x=130, y=90 # SPI Flash (W25Q128): x=230, y=60 # Audio section (PAM8302A): x=230, y=140 # Motor driver: x=130, y=190 # Buttons (8x): x=30, y=80-180 # ISP Header: x=230, y=200 # Serial Header: x=30, y=200 # ---- POWER SUPPLY SECTION ---- # Battery connector J1 sch.append(_instance("baby_mobile:Conn_2Pin", "J1", "BATTERY", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", 25, 35, 0)) # Main decoupling C1: 100uF electrolytic sch.append(_instance("baby_mobile:Capacitor", "C1", "100uF", "Capacitor_THT:CP_Radial_D5.0mm_P2.00mm", 55, 35, 0)) # Decoupling C2: 100nF ceramic near MCU VCC sch.append(_instance("baby_mobile:Capacitor", "C2", "100nF", "Capacitor_SMD:C_0805_2012Metric", 100, 30, 0)) # Decoupling C3: 100nF ceramic near MCU AVCC sch.append(_instance("baby_mobile:Capacitor", "C3", "100nF", "Capacitor_SMD:C_0805_2012Metric", 115, 30, 0)) # Power switch SW_PWR sch.append(_instance("baby_mobile:Switch", "SW9", "PWR", "Button_Switch_THT:SW_SPDT_CK-JS102011SAQN", 40, 25, 0)) # ---- MCU: ATmega328P-AU ---- sch.append(_instance("baby_mobile:ATmega328P-AU", "U1", "ATmega328P-AU", "Package_QFP:TQFP-32_7x7mm_P0.8mm", 130, 90, 0)) # Reset pullup R_RST: 10K sch.append(_instance("baby_mobile:Resistor", "R1", "10K", "Resistor_SMD:R_0805_2012Metric", 95, 55, 0)) # Reset capacitor C_RST: 100nF sch.append(_instance("baby_mobile:Capacitor", "C4", "100nF", "Capacitor_SMD:C_0805_2012Metric", 95, 65, 0)) # ---- SPI FLASH: W25Q128JVSIQ ---- sch.append(_instance("baby_mobile:W25Q128", "U2", "W25Q128JVSIQ", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm", 230, 60, 0)) # Flash decoupling C5: 100nF sch.append(_instance("baby_mobile:Capacitor", "C5", "100nF", "Capacitor_SMD:C_0805_2012Metric", 255, 50, 0)) # ---- AUDIO AMP: PAM8302A ---- sch.append(_instance("baby_mobile:PAM8302A", "U3", "PAM8302A", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm", 230, 140, 0)) # Input coupling cap C6: 1uF sch.append(_instance("baby_mobile:Capacitor", "C6", "1uF", "Capacitor_SMD:C_0805_2012Metric", 200, 135, 0)) # RC low-pass filter on PWM: R_LPF + C_LPF # f_c = 1/(2*pi*R*C) ~ 3.4kHz with 4.7K + 10nF sch.append(_instance("baby_mobile:Resistor", "R2", "4.7K", "Resistor_SMD:R_0805_2012Metric", 185, 135, 0)) sch.append(_instance("baby_mobile:Capacitor", "C7", "10nF", "Capacitor_SMD:C_0805_2012Metric", 192, 145, 0)) # Amp supply bypass C8: 10uF sch.append(_instance("baby_mobile:Capacitor", "C8", "10uF", "Capacitor_SMD:C_0805_2012Metric", 255, 130, 0)) # Speaker connector J2 sch.append(_instance("baby_mobile:Conn_2Pin", "J2", "SPEAKER", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", 265, 145, 0)) # Shutdown pulldown R_SD: 100K (default ON, MCU can shut down) sch.append(_instance("baby_mobile:Resistor", "R3", "100K", "Resistor_SMD:R_0805_2012Metric", 210, 150, 0)) # ---- MOTOR DRIVER ---- # N-ch MOSFET Q1 sch.append(_instance("baby_mobile:NMOS", "Q1", "AO3400A", "Package_TO_SOT_SMD:SOT-23", 140, 190, 0)) # Gate resistor R_GATE: 100 ohm sch.append(_instance("baby_mobile:Resistor", "R4", "100R", "Resistor_SMD:R_0805_2012Metric", 120, 190, 0)) # Gate pulldown R_GPD: 100K sch.append(_instance("baby_mobile:Resistor", "R5", "100K", "Resistor_SMD:R_0805_2012Metric", 130, 200, 0)) # Flyback diode D1 sch.append(_instance("baby_mobile:Diode_Schottky", "D1", "SS14", "Diode_SMD:D_SMA", 155, 180, 90)) # Motor connector J3 sch.append(_instance("baby_mobile:Conn_2Pin", "J3", "MOTOR", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", 160, 170, 0)) # ---- 8 BUTTONS ---- button_pins = ["BTN1", "BTN2", "BTN3", "BTN4", "BTN5", "BTN6", "BTN7", "BTN8"] for i, name in enumerate(button_pins): y = 75 + i * 15 sch.append(_instance("baby_mobile:Switch", f"SW{i+1}", name, "Button_Switch_SMD:SW_SPST_TL3342", 30, y, 0)) # ---- STATUS LED ---- sch.append(_instance("baby_mobile:LED", "D2", "LED", "LED_SMD:LED_0805_2012Metric", 85, 190, 0)) sch.append(_instance("baby_mobile:Resistor", "R6", "1K", "Resistor_SMD:R_0805_2012Metric", 75, 190, 0)) # ---- ISP HEADER (2x3) ---- sch.append(_instance("baby_mobile:Conn_6Pin", "J4", "ISP", "Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Vertical", 250, 200, 0)) # ---- SERIAL HEADER (3-pin: GND, TX, RX) ---- sch.append(_instance("baby_mobile:Conn_3Pin", "J5", "SERIAL", "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical", 30, 210, 0)) # ---- NET LABELS ---- # Power nets net_labels = [ # Power distribution ("VCC", 55, 25), ("VCC", 100, 25), ("VCC", 115, 25), ("VCC", 130, 50), ("VCC", 255, 45), ("VCC", 255, 125), ("VCC", 95, 50), ("VCC", 160, 165), ("GND", 55, 45), ("GND", 100, 40), ("GND", 115, 40), ("GND", 130, 130), ("GND", 255, 70), ("GND", 255, 155), ("GND", 95, 70), ("GND", 140, 205), ("GND", 192, 155), # SPI bus ("SPI_MOSI", 165, 85), ("SPI_MOSI", 215, 55), ("SPI_MISO", 165, 90), ("SPI_MISO", 215, 60), ("SPI_SCK", 165, 95), ("SPI_SCK", 215, 65), ("FLASH_CS", 165, 80), ("FLASH_CS", 215, 50), # Audio ("AUDIO_PWM", 165, 100), ("AUDIO_PWM", 175, 135), ("AMP_SD", 165, 105), ("AMP_SD", 210, 145), # Motor ("MOTOR_PWM", 165, 110), ("MOTOR_PWM", 110, 190), # Buttons (directly named for MCU pins mapping) ("BTN1", 45, 75), ("BTN1", 95, 85), ("BTN2", 45, 90), ("BTN2", 95, 90), ("BTN3", 45, 105), ("BTN3", 95, 95), ("BTN4", 45, 120), ("BTN4", 95, 100), ("BTN5", 45, 135), ("BTN5", 95, 105), ("BTN6", 45, 150), ("BTN6", 95, 110), ("BTN7", 45, 165), ("BTN7", 95, 115), ("BTN8", 45, 180), ("BTN8", 95, 120), # ISP ("SPI_MOSI", 240, 195), ("SPI_MISO", 240, 200), ("SPI_SCK", 240, 205), ("RESET", 240, 210), ("RESET", 95, 60), # Serial ("TXD", 40, 210), ("RXD", 40, 215), ("TXD", 95, 75), ("RXD", 95, 80), # LED ("LED_OUT", 65, 190), ("LED_OUT", 95, 125), ] for name, x, y in net_labels: sch.append(f""" (label "{name}" (at {x} {y} 0) (effects (font (size 1.27 1.27))) (uuid "{uid()}"))""") # ---- TEXT NOTES ---- notes = [ (15, 15, "POWER: 2xAA (1.8V-3.3V) → Long runtime design"), (15, 18, "MCU: ATmega328P-AU @ 8MHz internal osc, Arduino compatible"), (200, 15, "FLASH: W25Q128 16MB = ~33 min @ 8kHz 8-bit PCM"), (200, 18, "AMP: PAM8302A Class-D, 90% efficient, Vmin=2.0V"), (15, 220, "BUTTONS: Internal pull-ups, active LOW, PCINT wake-from-sleep"), (120, 220, "MOTOR: AO3400A logic-level N-MOSFET, PWM speed control"), (15, 225, "ESTIMATED RUNTIME: Audio+Motor ~23h, Audio only ~200h, Sleep ~years"), ] for x, y, text in notes: sch.append(f""" (text "{text}" (at {x} {y} 0) (effects (font (size 1.5 1.5)) (justify left)) (uuid "{uid()}") )""") sch.append(")") # end kicad_sch return "\n".join(sch) # ============================================================ # SYMBOL DEFINITIONS # ============================================================ def _sym_atmega328p(): return f""" (symbol "baby_mobile:ATmega328P-AU" (in_bom yes) (on_board yes) (property "Reference" "U" (at 0 26 0) (effects (font (size 1.27 1.27)))) (property "Value" "ATmega328P-AU" (at 0 24 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "Package_QFP:TQFP-32_7x7mm_P0.8mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:ATmega328P-AU_0_1" (rectangle (start -17 23) (end 17 -23) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:ATmega328P-AU_1_1" (pin power_in line (at -7 -26 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) (pin power_in line (at -5 -26 90) (length 3) (name "GND2" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) (pin power_in line (at -3 26 270) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) (pin power_in line (at -1 26 270) (length 3) (name "AVCC" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) (pin passive line (at 1 26 270) (length 3) (name "AREF" (effects (font (size 1 1)))) (number "21" (effects (font (size 1 1))))) (pin bidirectional line (at -20 15 0) (length 3) (name "PD0/RXD" (effects (font (size 1 1)))) (number "30" (effects (font (size 1 1))))) (pin bidirectional line (at -20 12.5 0) (length 3) (name "PD1/TXD" (effects (font (size 1 1)))) (number "31" (effects (font (size 1 1))))) (pin bidirectional line (at -20 10 0) (length 3) (name "PD2/INT0" (effects (font (size 1 1)))) (number "32" (effects (font (size 1 1))))) (pin bidirectional line (at -20 7.5 0) (length 3) (name "PD3/INT1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin bidirectional line (at -20 5 0) (length 3) (name "PD4" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) (pin bidirectional line (at -20 2.5 0) (length 3) (name "PD5/OC0B" (effects (font (size 1 1)))) (number "9" (effects (font (size 1 1))))) (pin bidirectional line (at -20 0 0) (length 3) (name "PD6/OC0A" (effects (font (size 1 1)))) (number "10" (effects (font (size 1 1))))) (pin bidirectional line (at -20 -2.5 0) (length 3) (name "PD7" (effects (font (size 1 1)))) (number "11" (effects (font (size 1 1))))) (pin bidirectional line (at 20 15 180) (length 3) (name "PB0" (effects (font (size 1 1)))) (number "12" (effects (font (size 1 1))))) (pin bidirectional line (at 20 12.5 180) (length 3) (name "PB1/OC1A" (effects (font (size 1 1)))) (number "13" (effects (font (size 1 1))))) (pin bidirectional line (at 20 10 180) (length 3) (name "PB2/SS" (effects (font (size 1 1)))) (number "14" (effects (font (size 1 1))))) (pin bidirectional line (at 20 7.5 180) (length 3) (name "PB3/MOSI" (effects (font (size 1 1)))) (number "15" (effects (font (size 1 1))))) (pin bidirectional line (at 20 5 180) (length 3) (name "PB4/MISO" (effects (font (size 1 1)))) (number "16" (effects (font (size 1 1))))) (pin bidirectional line (at 20 2.5 180) (length 3) (name "PB5/SCK" (effects (font (size 1 1)))) (number "17" (effects (font (size 1 1))))) (pin bidirectional line (at 20 -2.5 180) (length 3) (name "PC0/ADC0" (effects (font (size 1 1)))) (number "23" (effects (font (size 1 1))))) (pin bidirectional line (at 20 -5 180) (length 3) (name "PC1/ADC1" (effects (font (size 1 1)))) (number "24" (effects (font (size 1 1))))) (pin bidirectional line (at 20 -7.5 180) (length 3) (name "PC2/ADC2" (effects (font (size 1 1)))) (number "25" (effects (font (size 1 1))))) (pin bidirectional line (at 20 -10 180) (length 3) (name "PC3/ADC3" (effects (font (size 1 1)))) (number "26" (effects (font (size 1 1))))) (pin bidirectional line (at 20 -12.5 180) (length 3) (name "PC4/SDA" (effects (font (size 1 1)))) (number "27" (effects (font (size 1 1))))) (pin bidirectional line (at 20 -15 180) (length 3) (name "PC5/SCL" (effects (font (size 1 1)))) (number "28" (effects (font (size 1 1))))) (pin input line (at -20 -10 0) (length 3) (name "~{{RESET}}" (effects (font (size 1 1)))) (number "29" (effects (font (size 1 1))))) (pin input line (at -20 -15 0) (length 3) (name "XTAL1" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) (pin output line (at -20 -17.5 0) (length 3) (name "XTAL2" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) ) )""" def _sym_w25q128(): return f""" (symbol "baby_mobile:W25Q128" (in_bom yes) (on_board yes) (property "Reference" "U" (at 0 9 0) (effects (font (size 1.27 1.27)))) (property "Value" "W25Q128JVSIQ" (at 0 7 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:W25Q128_0_1" (rectangle (start -7 6) (end 7 -6) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:W25Q128_1_1" (pin input line (at -10 4 0) (length 3) (name "~{{CS}}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin output line (at -10 1.5 0) (length 3) (name "DO/IO1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) (pin input line (at -10 -1.5 0) (length 3) (name "~{{WP}}/IO2" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) (pin power_in line (at -10 -4 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) (pin input line (at 10 -4 180) (length 3) (name "DI/IO0" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) (pin input line (at 10 -1.5 180) (length 3) (name "CLK" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) (pin input line (at 10 1.5 180) (length 3) (name "~{{HOLD}}/IO3" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) (pin power_in line (at 10 4 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) ) )""" def _sym_pam8302a(): return f""" (symbol "baby_mobile:PAM8302A" (in_bom yes) (on_board yes) (property "Reference" "U" (at 0 11 0) (effects (font (size 1.27 1.27)))) (property "Value" "PAM8302A" (at 0 9 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:PAM8302A_0_1" (rectangle (start -8 8) (end 8 -8) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:PAM8302A_1_1" (pin input line (at -11 5 0) (length 3) (name "~{{SD}}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin power_in line (at -11 2 0) (length 3) (name "VDD" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) (pin power_in line (at -11 -1 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) (pin input line (at -11 -4 0) (length 3) (name "A+" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) (pin input line (at -11 -7 0) (length 3) (name "A-" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) (pin output line (at 11 2 180) (length 3) (name "VO+" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) (pin output line (at 11 -1 180) (length 3) (name "VO-" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) (pin power_in line (at 11 -4 180) (length 3) (name "PAD" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) ) )""" def _sym_nmos(): return f""" (symbol "baby_mobile:NMOS" (in_bom yes) (on_board yes) (property "Reference" "Q" (at 3 0 0) (effects (font (size 1.27 1.27)))) (property "Value" "AO3400A" (at 5 -2.5 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:NMOS_0_1" (polyline (pts (xy -0.5 0.5) (xy -0.5 -0.5)) (stroke (width 0.33) (type default)) (fill (type none))) (polyline (pts (xy -0.5 -2) (xy -0.5 2)) (stroke (width 0.254) (type default)) (fill (type none))) (polyline (pts (xy 0 -2.5) (xy 0 -1.5)) (stroke (width 0) (type default)) (fill (type none))) (polyline (pts (xy 0 1.5) (xy 0 2.5)) (stroke (width 0) (type default)) (fill (type none))) (polyline (pts (xy 0 0) (xy -1.5 0)) (stroke (width 0) (type default)) (fill (type none))) ) (symbol "baby_mobile:NMOS_1_1" (pin passive line (at 0 5 270) (length 2.5) (name "D" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) (pin input line (at -4 0 0) (length 2.5) (name "G" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 0 -5 90) (length 2.5) (name "S" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_capacitor(): return f""" (symbol "baby_mobile:Capacitor" (in_bom yes) (on_board yes) (property "Reference" "C" (at 2 0 0) (effects (font (size 1.27 1.27)))) (property "Value" "C" (at 2 -2 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Capacitor_0_1" (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) ) (symbol "baby_mobile:Capacitor_1_1" (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_resistor(): return f""" (symbol "baby_mobile:Resistor" (in_bom yes) (on_board yes) (property "Reference" "R" (at 2 0 0) (effects (font (size 1.27 1.27)))) (property "Value" "R" (at 2 -2 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Resistor_0_1" (rectangle (start -1 2.5) (end 1 -2.5) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:Resistor_1_1" (pin passive line (at 0 5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_diode_schottky(): return f""" (symbol "baby_mobile:Diode_Schottky" (in_bom yes) (on_board yes) (property "Reference" "D" (at 2 0 0) (effects (font (size 1.27 1.27)))) (property "Value" "SS14" (at 2 -2 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "Diode_SMD:D_SMA" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Diode_Schottky_0_1" (polyline (pts (xy -1.5 1) (xy 0 -1) (xy 1.5 1) (xy -1.5 1)) (stroke (width 0.2) (type default)) (fill (type none))) (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.3) (type default)) (fill (type none))) ) (symbol "baby_mobile:Diode_Schottky_1_1" (pin passive line (at 0 3.5 270) (length 2.5) (name "A" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 0 -3.5 90) (length 2.5) (name "K" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_inductor(): return f""" (symbol "baby_mobile:Inductor" (in_bom yes) (on_board yes) (property "Reference" "L" (at 2 0 0) (effects (font (size 1.27 1.27)))) (property "Value" "L" (at 2 -2 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Inductor_0_1" (arc (start 0 2.5) (mid 0.75 1.875) (end 0 1.25) (stroke (width 0.254) (type default)) (fill (type none))) (arc (start 0 1.25) (mid 0.75 0.625) (end 0 0) (stroke (width 0.254) (type default)) (fill (type none))) (arc (start 0 0) (mid 0.75 -0.625) (end 0 -1.25) (stroke (width 0.254) (type default)) (fill (type none))) (arc (start 0 -1.25) (mid 0.75 -1.875) (end 0 -2.5) (stroke (width 0.254) (type default)) (fill (type none))) ) (symbol "baby_mobile:Inductor_1_1" (pin passive line (at 0 5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_switch(): return f""" (symbol "baby_mobile:Switch" (in_bom yes) (on_board yes) (property "Reference" "SW" (at 0 3 0) (effects (font (size 1.27 1.27)))) (property "Value" "SW" (at 0 -3 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Switch_0_1" (circle (center -2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) (circle (center 2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) (polyline (pts (xy -1.6 0) (xy 1.6 1)) (stroke (width 0.254) (type default)) (fill (type none))) ) (symbol "baby_mobile:Switch_1_1" (pin passive line (at -5 0 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 5 0 180) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_conn2(): return f""" (symbol "baby_mobile:Conn_2Pin" (in_bom yes) (on_board yes) (property "Reference" "J" (at 0 4 0) (effects (font (size 1.27 1.27)))) (property "Value" "Conn_2" (at 0 -4 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Conn_2Pin_0_1" (rectangle (start -2 3) (end 2 -3) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:Conn_2Pin_1_1" (pin passive line (at -5 1.5 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at -5 -1.5 0) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_conn3(): return f""" (symbol "baby_mobile:Conn_3Pin" (in_bom yes) (on_board yes) (property "Reference" "J" (at 0 5.5 0) (effects (font (size 1.27 1.27)))) (property "Value" "Conn_3" (at 0 -5.5 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Conn_3Pin_0_1" (rectangle (start -2 4) (end 2 -4) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:Conn_3Pin_1_1" (pin passive line (at -5 2.5 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at -5 0 0) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) (pin passive line (at -5 -2.5 0) (length 3) (name "3" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) ) )""" def _sym_conn6(): return f""" (symbol "baby_mobile:Conn_6Pin" (in_bom yes) (on_board yes) (property "Reference" "J" (at 0 9 0) (effects (font (size 1.27 1.27)))) (property "Value" "ISP_2x3" (at 0 -9 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:Conn_6Pin_0_1" (rectangle (start -3 8) (end 3 -8) (stroke (width 0.254) (type default)) (fill (type background))) ) (symbol "baby_mobile:Conn_6Pin_1_1" (pin passive line (at -6 5 0) (length 3) (name "MISO" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 6 5 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) (pin passive line (at -6 0 0) (length 3) (name "SCK" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) (pin passive line (at 6 0 180) (length 3) (name "MOSI" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) (pin passive line (at -6 -5 0) (length 3) (name "~{{RST}}" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) (pin passive line (at 6 -5 180) (length 3) (name "GND" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) ) )""" def _sym_led(): return f""" (symbol "baby_mobile:LED" (in_bom yes) (on_board yes) (property "Reference" "D" (at 2 0 0) (effects (font (size 1.27 1.27)))) (property "Value" "LED" (at 2 -2 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:LED_0_1" (polyline (pts (xy -1.5 1) (xy 0 -1) (xy 1.5 1) (xy -1.5 1)) (stroke (width 0.2) (type default)) (fill (type none))) (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.3) (type default)) (fill (type none))) ) (symbol "baby_mobile:LED_1_1" (pin passive line (at 0 3.5 270) (length 2.5) (name "A" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) (pin passive line (at 0 -3.5 90) (length 2.5) (name "K" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" def _sym_pwr_flag(): return f""" (symbol "baby_mobile:PWR_FLAG" (power) (in_bom no) (on_board no) (property "Reference" "#FLG" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Value" "PWR_FLAG" (at 0 3 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) (symbol "baby_mobile:PWR_FLAG_0_1" (polyline (pts (xy 0 0) (xy 0 1.5)) (stroke (width 0) (type default)) (fill (type none))) (polyline (pts (xy -1 1.5) (xy 0 3) (xy 1 1.5) (xy -1 1.5)) (stroke (width 0) (type default)) (fill (type none))) ) (symbol "baby_mobile:PWR_FLAG_1_1" (pin power_out line (at 0 0 90) (length 0) (name "pwr" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) ) )""" def _instance(lib_id, ref, value, footprint, x, y, angle): """Generate a component instance.""" return f""" (symbol (lib_id "{lib_id}") (at {x} {y} {angle}) (unit 1) (in_bom yes) (on_board yes) (dnp no) (uuid "{uid()}") (property "Reference" "{ref}" (at {x} {y-3} 0) (effects (font (size 1.27 1.27)))) (property "Value" "{value}" (at {x} {y+3} 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "{footprint}" (at {x} {y} 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at {x} {y} 0) (effects (font (size 1.27 1.27)) hide)) )""" # ============================================================ # PROJECT FILE # ============================================================ def generate_project(): return json.dumps({ "meta": { "filename": "baby-mobile.kicad_pro", "version": 1 }, "board": { "design_settings": { "defaults": { "board_outline_line_width": 0.1, "copper_line_width": 0.2, "copper_text_size_h": 1.5, "copper_text_size_v": 1.5, "other_line_width": 0.15 }, "rules": { "min_copper_edge_clearance": 0.3, "min_hole_clearance": 0.25, "min_track_width": 0.2, "min_via_annular_width": 0.13, "min_via_diameter": 0.6, "solder_mask_to_copper_clearance": 0 } }, "layer_presets": [] }, "libraries": { "pinned_footprint_libs": [], "pinned_symbol_libs": [] }, "net_settings": { "classes": [{ "bus_width": 12, "clearance": 0.2, "diff_pair_gap": 0.25, "diff_pair_via_gap": 0.25, "diff_pair_width": 0.2, "line_style": 0, "microvia_diameter": 0.3, "microvia_drill": 0.1, "name": "Default", "pcb_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)", "track_width": 0.3, "via_diameter": 0.6, "via_drill": 0.3, "wire_width": 6 }] }, "schematic": { "legacy_lib_dir": "", "legacy_lib_list": [] }, "sheets": [["", ""]] }, indent=2) # ============================================================ # MAIN # ============================================================ if __name__ == "__main__": outdir = "/home/claude/baby-mobile-pcb" # Generate schematic sch = generate_schematic() with open(os.path.join(outdir, "baby-mobile.kicad_sch"), "w") as f: f.write(sch) print(f"Written: baby-mobile.kicad_sch ({len(sch)} bytes)") # Generate project file proj = generate_project() with open(os.path.join(outdir, "baby-mobile.kicad_pro"), "w") as f: f.write(proj) print(f"Written: baby-mobile.kicad_pro ({len(proj)} bytes)") print("Done! Open baby-mobile.kicad_pro in KiCad 7+")