Sl33py Dev
UNITED STATES OF AMERICA • + Follow
Edit Project
Components
Tools, APP Software Used etc.
|
Visual Studio CodeMicrosofe
|
Description
FNAF Head control board for raspberry pi pico WH
I use it for a FNAF Foxy head it has 2 sockets for LED Common(-) RGB LED's which are tied to operate together and 2 sockets for 2 Servo motors and its compatible with the raspberry pi pico board and it has a AUX socket for things like a fan or a speaker for inside the head of your cosplay
Code
Python
import network
import socket
import time
import random
import machine
import json
import gc
from machine import Pin, PWM, ADC
# ==========================================
# FAZBEAR OS v1.9.8.3 CONFIG
# ==========================================
SSID = "FAZBEAR_NET_83" # Hidden Network Name
PASSWORD = "_its_me_" # Network Password
SERVO_1_PIN = 0 # Eyes Left/Right
SERVO_2_PIN = 1 # Eyelids Open/Close
PIN_RED = 13 # RGB Red
PIN_GREEN = 14 # RGB Green
PIN_BLUE = 15 # RGB Blue
BTN_PIN = 16 # Soft Reboot/Park Button
# ==========================================
# --- HARDWARE INITIALIZATION ---
status_led = Pin("LED", Pin.OUT)
btn_soft = Pin(BTN_PIN, Pin.IN, Pin.PULL_UP)
temp_sensor = ADC(4)
# Servos (50Hz)
s1 = PWM(Pin(SERVO_1_PIN)); s1.freq(50)
s2 = PWM(Pin(SERVO_2_PIN)); s2.freq(50)
# LEDs (1000Hz for smooth dimming)
eye_r = PWM(Pin(PIN_RED)); eye_g = PWM(Pin(PIN_GREEN)); eye_b = PWM(Pin(PIN_BLUE))
eye_r.freq(1000); eye_g.freq(1000); eye_b.freq(1000)
# --- SYSTEM LOGGING (Circular Buffer) ---
MAX_LOGS = 25
system_logs = []
def log(msg):
"""Adds timestamped message to memory log"""
t = int(time.ticks_ms()/1000)
entry = f"[{t}s] {msg}"
print(entry)
system_logs.insert(0, entry)
if len(system_logs) > MAX_LOGS: system_logs.pop()
# --- STATE MANAGEMENT ---
# Default State
state = {
"auto_eyes": False,
"auto_lids": False,
"auto_leds": False,
"r": 255, "g": 0, "b": 0 # Default Purple
}
next_eye_move = 0
next_lid_move = 0
next_led_flicker = 0
def save_state():
try:
with open('config.json', 'w') as f: json.dump(state, f)
except: pass
def load_state():
try:
with open('config.json', 'r') as f:
state.update(json.load(f))
log("CONFIG LOADED")
except:
log("USING DEFAULTS")
# --- HARDWARE HELPERS ---
def set_servo(s, angle):
"""Safe servo movement (0-180)"""
angle = max(0, min(180, angle))
# Map 0-180 to 1500-8200 duty cycle (Standard MG90S range)
s.duty_u16(int(1500 + (angle/180)*(8200-1500)))
def set_color(r, g, b):
"""Sets RGB color (0-255 input)"""
# Map 0-255 to 0-65535
eye_r.duty_u16(r*257)
eye_g.duty_u16(g*257)
eye_b.duty_u16(b*257)
def get_temp():
"""Reads internal CPU temperature"""
reading = temp_sensor.read_u16() * (3.3 / 65535)
return int(27 - (reading - 0.706)/0.001721)
def park_servos():
"""Safety shutdown sequence"""
log("PARKING SYSTEM...")
state["auto_eyes"]=False; state["auto_lids"]=False; state["auto_leds"]=False
set_servo(s1, 90) # Center Eyes
set_servo(s2, 140) # Close Lids (Adjust if needed)
set_color(0, 0, 0) # Lights Out
save_state()
time.sleep(1.0) # Wait for motors
log("SYSTEM SAFE TO UNPLUG")
# --- ANIMATION SEQUENCER ---
def run_sequence(name):
log(f"SEQ START: {name}")
# Temporarily disable auto
state["auto_eyes"]=False; state["auto_lids"]=False; state["auto_leds"]=False
if name == "jumpscare":
set_color(255, 0, 0) # RED
set_servo(s2, 10) # EYES WIDE
for _ in range(12): # VIOLENT SHAKE
set_servo(s1, random.randint(30, 150))
time.sleep(0.06)
set_servo(s1, 90) # RE-CENTER
elif name == "suspicious":
set_color(80, 0, 120)# DIM PURPLE
set_servo(s2, 110) # SQUINT
for pos in [60, 70, 80, 90, 100, 110, 120]: # SLOW SCAN
set_servo(s1, pos)
time.sleep(0.2)
elif name == "glitch":
for _ in range(20): # CHAOS MODE
set_color(random.randint(0,255), random.randint(0,255), random.randint(0,255))
set_servo(s1, random.randint(20, 160))
set_servo(s2, random.randint(20, 160))
time.sleep(0.05)
# Restore original color
set_color(state["r"], state["g"], state["b"])
log("SEQ END")
# ==========================================
# BOOT SEQUENCE
# ==========================================
log("BOOTING FAZ-OS...")
# 1. Load Settings
load_state()
set_color(state["r"], state["g"], state["b"])
# 2. Safety Delay (5 Seconds)
# PRESS STOP IN VS CODE NOW IF YOU NEED TO EDIT!
log("SAFETY DELAY (5s)...")
for i in range(10):
status_led.toggle()
time.sleep(0.5)
status_led.off()
# 3. Wi-Fi Setup (Stealth Mode)
log("STARTING RADIO...")
ap = network.WLAN(network.AP_IF)
ap.config(essid=SSID, password=PASSWORD, channel=6)
ap.active(True)
while not ap.active():
time.sleep(0.1)
log(f"NETWORK READY: {SSID} (OPEN)")
status_led.on() # Solid LED = Ready
# --- WEB SERVER GENERATOR ---
def get_html():
# Prepare checkbox states
chk_eyes = "checked" if state["auto_eyes"] else ""
chk_lids = "checked" if state["auto_lids"] else ""
chk_leds = "checked" if state["auto_leds"] else ""
hex_col = "#{:02x}{:02x}{:02x}".format(state["r"], state["g"], state["b"])
# Telemetry
temp = get_temp()
ram = gc.mem_free()
logs_txt = "\\n".join(system_logs)
return f"""<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>FAZ-OS TERMINAL</title>
<style>
body {{ background: #000; color: #33ff00; font-family: monospace; text-align: center; margin: 0; }}
.header {{ border-bottom: 2px solid #33ff00; padding: 10px; background: #051000; }}
.panel {{ border: 1px solid #224400; background: #0a0f00; padding: 10px; margin: 10px; border-radius: 4px; }}
h2 {{ font-size: 1rem; border-bottom: 1px solid #335500; margin-top: 0; }}
.stats {{ display: flex; justify-content: space-around; font-size: 0.8rem; color: #ccffcc; }}
input[type=range] {{ width: 100%; height: 40px; accent-color: #33ff00; }}
input[type=color] {{ width: 100%; height: 40px; border: none; background: none; }}
button {{ background: #113300; color: #33ff00; border: 1px solid #33ff00; padding: 10px; width: 30%; font-weight: bold; margin: 2px; }}
button:active {{ background: #33ff00; color: #000; }}
.danger {{ border-color: red; color: red; background: #330000; width: 100%; margin-top: 5px; }}
.toggle-row {{ display: flex; justify-content: space-between; margin: 10px 0; border-bottom: 1px dashed #224400; }}
#logs {{ width: 95%; height: 100px; background: #000; color: #00ff00; border: 1px solid #335500; font-size: 0.7rem; }}
#login-overlay {{ position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; z-index: 99; display: flex; flex-direction: column; justify-content: center; }}
#main-ui {{ display: none; }}
</style>
</head>
<body>
<div id="login-overlay">
<div class="panel">
<p>FAZBEAR ENT. TERMINAL</p>
<input type="password" id="pin" placeholder="PIN:" style="background:#000; color:#0f0; padding:10px; text-align:center;">
<br><br><button onclick="login()" style="width:50%">ACCESS</button>
</div>
</div>
<div id="main-ui">
<div class="header">
<h1>FAZ-OS v1.9</h1>
<div class="stats">
<span>TEMP: {temp}C</span>
<span>RAM: {ram}b</span>
</div>
</div>
<div class="panel">
<h2>> SEQUENCER</h2>
<button onclick="seq('jumpscare')">! JUMP !</button>
<button onclick="seq('suspicious')">SUSPECT</button>
<button onclick="seq('glitch')">GLITCH</button>
</div>
<div class="panel">
<h2>> AUTOMATION</h2>
<div class="toggle-row"><span>AUTO-EYES</span><input type="checkbox" {chk_eyes} onchange="tog('auto_eyes', this.checked)"></div>
<div class="toggle-row"><span>AUTO-LIDS</span><input type="checkbox" {chk_lids} onchange="tog('auto_lids', this.checked)"></div>
<div class="toggle-row"><span>VOLT-FLICKER</span><input type="checkbox" {chk_leds} onchange="tog('auto_leds', this.checked)"></div>
</div>
<div class="panel">
<h2>> MANUAL OVERRIDE</h2>
<input type="range" min="0" max="180" oninput="srv(1, this.value)">
<input type="range" min="0" max="180" oninput="srv(2, this.value)">
<input type="color" value="{hex_col}" oninput="col(this.value)">
</div>
<div class="panel">
<h2>> SYSTEM LOGS</h2>
<textarea id="logs" readonly>{logs_txt}</textarea>
<button onclick="location.reload()" style="width:100%">REFRESH DATA</button>
<button class="danger" onclick="park()">PARK & SLEEP</button>
<button class="danger" onclick="reboot()">⚠ REBOOT ⚠</button>
</div>
</div>
<script>
function login() {{ if(document.getElementById('pin').value=='1983') {{ document.getElementById('login-overlay').style.display='none'; document.getElementById('main-ui').style.display='block'; }} }}
let last=0;
function send(u) {{ if(Date.now()-last>50) {{ last=Date.now(); fetch(u); }} }}
function srv(i,v) {{ send('/set?id='+i+'&v='+v); }}
function col(h) {{ let r=parseInt(h.substr(1,2),16), g=parseInt(h.substr(3,2),16), b=parseInt(h.substr(5,2),16); send('/col?r='+r+'&g='+g+'&b='+b); }}
function tog(m,s) {{ fetch('/tog?m='+m+'&s='+(s?1:0)); }}
function seq(n) {{ fetch('/seq?n='+n); }}
function park() {{ fetch('/park'); alert('SYSTEM PARKED. SAFE TO UNPLUG.'); }}
function reboot() {{ if(confirm('CONFIRM REBOOT?')) fetch('/reboot'); }}
</script>
</body>
</html>
"""
# --- SERVER SETUP ---
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(1)
s.setblocking(False) # NON-BLOCKING SERVER
log("SERVER LISTENING...")
# ==========================================
# MAIN LOOP
# ==========================================
try:
while True:
now = time.ticks_ms()
# 1. HARDWARE BUTTON CHECK (Soft Reboot/Park)
if btn_soft.value() == 0:
log("MANUAL BUTTON PRESSED")
status_led.on()
park_servos()
log("REBOOTING...")
time.sleep(0.5)
machine.reset()
# 2. AUTOMATION LOGIC
if state["auto_eyes"] and now > next_eye_move:
set_servo(s1, random.randint(30, 150))
next_eye_move = now + random.randint(500, 3000)
if state["auto_lids"] and now > next_lid_move:
set_servo(s2, 140) # Close
time.sleep(0.15)
set_servo(s2, 40) # Open
next_lid_move = now + random.randint(2000, 8000)
if state["auto_leds"] and now > next_led_flicker:
f = random.uniform(0.1, 1.0)
set_color(int(state["r"]*f), int(state["g"]*f), int(state["b"]*f))
next_led_flicker = now + random.randint(50, 200)
elif not state["auto_leds"]:
# Ensure steady color if flicker is OFF
set_color(state["r"], state["g"], state["b"])
# 3. NETWORK HANDLING (Non-Blocking)
try:
cl, addr = s.accept()
cl.settimeout(0.1) # Fast timeout
try:
r = str(cl.recv(1024))
# --- API ENDPOINTS ---
if "GET /set" in r:
# Parse /set?id=1&v=90
p = r.split('?')[1].split(' ')[0].split('&')
i=int(p[0].split('=')[1]); v=int(p[1].split('=')[1])
if i==1: set_servo(s1,v); state["auto_eyes"]=False
if i==2: set_servo(s2,v); state["auto_lids"]=False
save_state(); cl.send('HTTP/1.0 200 OK\r\n\r\n')
elif "GET /col" in r:
# Parse /col?r=255&g=0&b=255
p = r.split('?')[1].split(' ')[0].split('&')
state["r"]=int(p[0].split('=')[1]); state["g"]=int(p[1].split('=')[1]); state["b"]=int(p[2].split('=')[1])
save_state(); cl.send('HTTP/1.0 200 OK\r\n\r\n')
elif "GET /tog" in r:
# Parse /tog?m=auto_eyes&s=1
p = r.split('?')[1].split(' ')[0].split('&')
state[p[0].split('=')[1]] = bool(int(p[1].split('=')[1]))
save_state(); cl.send('HTTP/1.0 200 OK\r\n\r\n')
elif "GET /seq" in r:
# Parse /seq?n=jumpscare
n = r.split('?')[1].split(' ')[0].split('=')[1]
run_sequence(n)
cl.send('HTTP/1.0 200 OK\r\n\r\n')
elif "GET /park" in r:
park_servos(); cl.send('HTTP/1.0 200 OK\r\n\r\n')
elif "GET /reboot" in r:
cl.send('HTTP/1.0 200 OK\r\n\r\n'); cl.close()
time.sleep(1); machine.reset()
else:
# Serve Webpage
cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
cl.send(get_html())
except Exception as e:
pass
cl.close()
except OSError:
pass # No client connected
except KeyboardInterrupt:
s.close()
log("SHUTDOWN")
Dec 13,2025
10 views
FNAF Head control board for raspberry pi pico WH
10
0
0
Published: Dec 13,2025
Standard PCB
Download Gerber file 0
BOM(Bill of materials)
Purchase
Donation Received ($)
PCBWay Donate 10% cost To Author
Only PCB
PCB+Assembly
*PCBWay community is a sharing platform. We are not responsible for any design issues and parameter issues (board thickness, surface finish, etc.) you choose.
Copy this HTML into your page to embed a link to order this shared project
Copy
Under the
Attribution-ShareAlike (CC BY-SA)
License.
- Comments(0)
- Likes(0)
Upload photo
You can only upload 5 files in total. Each file cannot exceed 2MB. Supports JPG, JPEG, GIF, PNG, BMP
0 / 10000
It looks like you have not written anything. Please add a comment and try again.
You can upload up to 5 images!
Image size should not exceed 2MB!
File format not supported!
View More
View More
VOTING
0 votes
- 0 USER VOTES
0.00
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Design
1/4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Usability
2/4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Creativity
3/4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Content
4/4
More by Sl33py Dev
You may also like
-
-
AEL-2011 Power Supply Module
503 0 2 -
AEL-2011 50W Power Amplifier
457 0 2 -
-
-
Custom Mechanical Keyboard
678 0 0 -
Tester for Touch Screen Digitizer without using microcontroller
314 2 2 -
Audio reactive glow LED wristband/bracelet with NFC / RFID-Tags
301 0 1 -
-
-







