# Alarm Keamanan Anak/Hewan — PIR -> Servo 0° ke 90° + LED + Buzzer
# Untuk Raspberry Pi Pico (MicroPython)
from machine import Pin, PWM
import time
# --- Konfigurasi pin ---
PIR_PIN = 2 # GP2
LED_PIN = 15 # GP15
BUZZER_PIN = 14 # GP14 (PWM untuk buzzer pasif / aktif)
SERVO_PIN = 16 # GP16
# --- Parameter servo (pulse dalam ms) ---
SERVO_FREQ = 50 # 50 Hz -> periode 20 ms
PULSE_MIN_MS = 0.5 # pulse utk 0°
PULSE_MAX_MS = 2.5 # pulse utk 180°
PERIOD_MS = 1000 / SERVO_FREQ # 20.0 ms
# Hitung duty_u16 konstanta
U16_MAX = 65535
d_min = int((PULSE_MIN_MS / PERIOD_MS) * U16_MAX) # ~1638
d_max = int((PULSE_MAX_MS / PERIOD_MS) * U16_MAX) # ~8192
# --- Inisialisasi hardware ---
pir = Pin(PIR_PIN, Pin.IN)
led = Pin(LED_PIN, Pin.OUT)
buzzer = PWM(Pin(BUZZER_PIN))
# default: matikan buzzer
buzzer.duty_u16(0)
servo = PWM(Pin(SERVO_PIN))
servo.freq(SERVO_FREQ)
# --- Pengaturan perilaku ---
DEBOUNCE_MS = 80 # butuh PIR HIGH selama ini untuk dianggap valid
COOLDOWN_S = 5 # setelah trigger, tunggu cooldown detik
SWEEP_STEP = 3 # derajat per langkah saat bergerak halus
SWEEP_DELAY = 0.02 # delay (s) antar langkah untuk pergerakan halus
ALARM_BEEPS = 3
BEEP_DURATION = 0.15 # detik bunyi per beep
BEEP_GAP = 0.12
# track sudut saat ini (mulai di 0°)
current_angle = 0
def angle_to_duty_u16(angle):
"""Map angle (0..180) ke duty_u16 antara d_min..d_max"""
if angle < 0: angle = 0
if angle > 180: angle = 180
return int(d_min + (angle / 180.0) * (d_max - d_min))
def set_servo(angle):
"""Gerakkan servo ke sudut 'angle' (0..180) langsung via duty"""
duty = angle_to_duty_u16(angle)
servo.duty_u16(duty)
def smooth_move(from_angle, to_angle, step=SWEEP_STEP, delay=SWEEP_DELAY):
"""Gerakkan servo halus dari from_angle ke to_angle"""
if from_angle == to_angle:
set_servo(to_angle)
return
step = abs(step)
if to_angle > from_angle:
a = from_angle
while a < to_angle:
a = min(to_angle, a + step)
set_servo(a)
time.sleep(delay)
else:
a = from_angle
while a > to_angle:
a = max(to_angle, a - step)
set_servo(a)
time.sleep(delay)
# pastikan posisi akhir presisi
set_servo(to_angle)
def beep(duration=BEEP_DURATION, freq=2000, duty_pct=0.5):
"""Bunyi buzzer (untuk buzzer pasif set freq, untuk aktif cukup duty_on)"""
buzzer.freq(freq)
buzzer.duty_u16(int(U16_MAX * duty_pct))
time.sleep(duration)
buzzer.duty_u16(0)
# set posisi awal servo ke 0°
smooth_move(current_angle, 0)
current_angle = 0
print("Sistem Alarm Siap. Menunggu gerakan...")
last_trigger_time = 0
while True:
# simple debounce: harus tetap HIGH selama DEBOUNCE_MS
if pir.value() == 1:
t0 = time.ticks_ms()
# tunggu singkat untuk verifikasi
while time.ticks_diff(time.ticks_ms(), t0) < DEBOUNCE_MS:
if pir.value() == 0:
break
time.sleep_ms(5)
else:
# valid trigger detected
now = time.time()
if now - last_trigger_time >= COOLDOWN_S:
print(">>> Gerakan terdeteksi! Triggering alarm.")
last_trigger_time = now
# LED ON
led.on()
# Move servo 0 -> 90 smoothly
target = 90
smooth_move(current_angle, target)
current_angle = target
# Bunyi alarm beberapa kali
for i in range(ALARM_BEEPS):
beep()
time.sleep(BEEP_GAP)
# tunggu sebentar (misal untuk monitoring atau agar servo tetap terbuka)
time.sleep(1.5)
# Kembali ke posisi 0° halus
smooth_move(current_angle, 0)
current_angle = 0
# LED OFF
led.off()
else:
# masih cooldown, abaikan
# bisa beri indikator singkat kalau diinginkan
pass
else:
# idle state: pastikan LED & buzzer mati
led.off()
buzzer.duty_u16(0)
# tetap di posisi standby (jika servo ter-reset, ulangi set)
#set_servo(0)
time.sleep(0.05)