|
Visual Studio CodeMicrosofe
|
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
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")
FNAF Head control board for raspberry pi pico WH
Project images are for reference only. Actual production is based on the manufacturing files on the project page.
Please review the designer's notes (e.g., PCB thickness) and select the appropriate options.
PCBWay is not responsible
for issues caused by unsuitable parameter selections.
For more important ordering information, please refer to
Read More
Raspberry Pi 5 7 Inch Touch Screen IPS 1024x600 HD LCD HDMI-compatible Display for RPI 4B 3B+ OPI 5 AIDA64 PC Secondary Screen(Without Speaker)
BUY NOW- Comments(0)
- Likes(0)
- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by Sl33py Dev
-
Programmable Mist Maker - XIAO / QT PY Extension
1067 2 1 -
RadioHAT - Raspberry Pi radio development platform
883 0 2 -
QWIIC-VL53L4CD Time-of-Flight Distance Sensor Module
1093 0 1 -
-
-
-
ARPS-2 – Arduino-Compatible Robot Project Shield for Arduino UNO
3332 0 6 -
-
A Compact Charging Breakout Board For Waveshare ESP32-C3
3941 3 8 -
AI-driven LoRa & LLM-enabled Kiosk & Food Delivery System
4327 2 2







