with AutoLISP
Elektrotechnik Trahe GmbH
Unterneukirchen, Bayern · 1991
How we automated CAD drawing
and saved weeks of work
My brother's electrical company needed hundreds of Schaltpläne (circuit diagrams).
Each drawing: Schütz, Motor, Sicherung, Motorschutzschalter, Klemmen...
Professional CAD work? Unbezahlbar.
Drawing each by hand = 5 hours per plan
100 drawings = 500 hours = 12 weeks
AutoCAD Release 10 on a 486 DX-50
Special boot disk (B:) for memory optimization
HIMEM.SYS + EMM386.EXE → 605KB conventional RAM
The secret weapon: AutoLISP
A programming language built into AutoCAD
1. Export component list from dBase III → CSV file
2. CSV format: START;TEMPLATE;NAME + component lines + STOP
3. AutoLISP reads CSV, loads TPL (template)
4. Template draws the Schaltplan, inserts symbols
5. Save as DWG, send to Druckwarteschlange
Print queue written in Turbo Pascal
HP LaserJet III kept printing while AutoCAD kept drawing
99.5%
time saved
100 drawings: 12 weeks → <1 hour
(prepare CSV, run script, go for Kaffee)
In 1991, LISP was synonymous with Artificial Intelligence
MIT AI Lab, Symbolics LISP Machines, Expert Systems...
The language that could manipulate its own code
And here I was, using it to draw Schaltpläne
; Define a function that draws a Schütz (contactor) (defun DRAW-SCHUETZ (pos name) (command "CIRCLE" pos 5) (command "TEXT" (list (+ (car pos) 10) (cadr pos)) 3 0 name) (princ (strcat "\nSchütz " name " inserted")) ) ; Call it (DRAW-SCHUETZ '(50 150) "K1")
Functions that create drawing entities
; Process each component recursively (defun PROCESS-COMPONENTS (lst y) (if (null lst) (princ "\nDone!") (progn (DRAW-COMPONENT (car lst) y) (PROCESS-COMPONENTS (cdr lst) (- y 25)) ; next position ) ) )
The function calls itself - classic LISP recursion
; Inserting a Schütz TRIGGERS other Bauteile (defun INSERT-SCHUETZ (name pos) (DRAW-SCHUETZ-SYMBOL pos) ; The Schütz needs a coil in control circuit! (setq *CONTROL-CIRCUIT* (append *CONTROL-CIRCUIT* (list (list 'COIL name *NEXT-CTRL-Y*)))) ; It also needs auxiliary contacts (if (= *SCHUETZ-COUNT* 1) (setq *CONTROL-CIRCUIT* (append *CONTROL-CIRCUIT* '((SELF-HOLD K1))))) ; add self-holding contact )
Inserting K1 automatically generates coil + self-holding contact
; Motorschutz symbol SIZE depends on Ampere value (defun DRAW-MOTORSCHUTZ (pos ampere) (setq size (cond ((< ampere 10) 8) ; small ((< ampere 25) 12) ; medium (t 16))) ; large (DRAW-THERMAL-ELEMENT pos size) ; Large motors need additional thermal protection (if (> ampere 20) (progn (INSERT-PTC-SENSOR) ; auto-add PTC (ADD-TO-CONTROL 'TEMP-RELAY))) )
The symbol adapts - and triggers more components
; STERN-DREIECK template BUILDS its own control circuit (defun STERN-DR-CONTROL () (setq ctrl-code '()) ; Add timer relay - it will control K2/K3 switching (setq ctrl-code (append ctrl-code '((TIMER K4 *UMSCHALT-ZEIT*)))) ; K2 (Stern) and K3 (Dreieck) are interlocked! (setq ctrl-code (append ctrl-code '((INTERLOCK K2 K3)))) ; generate interlock logic ; NOW EXECUTE the generated code (foreach cmd ctrl-code (eval cmd)) )
The template BUILDS code, then EXECUTES it - code writes code
This was Artificial Intelligence in 1991:
• Insert Schütz → auto-generate coil + contacts
• Read Ampere value → adapt symbol size
• Detect Stern-Dreieck → build interlock logic
• Template → generates more template
The code understood the domain.
It made decisions. It wrote itself.
Not neural networks. Rules, recursion, self-modification.
33 years later, I rebuilt the engine in Rust
Compiled to WebAssembly
Same workflow: CSV → TPL → Drawing
Same LISP: defun, setq, car, cdr, recursion
Same speed: <1 second for 50+ drawings
Next slide: Try it yourself →
Click "Verarbeiten" to generate drawings from CSV
Drawing Commands:
(command "LINE" '(x1 y1) '(x2 y2) "")(command "CIRCLE" '(cx cy) radius)(command "TEXT" '(x y) height rot "text")Math:
(+ - * / 1+ 1-)(sin cos sqrt abs)Lists:
(car lst) → first(cdr lst) → rest(list a b c)(nth n lst)Control:
(if cond then else)(cond (c1 r1) (c2 r2))(while cond body)(foreach x lst body)Functions:
(defun name (args) body)(setq var value)(princ "text")