# actuators.py — Controle de LEDs (PWM) e buzzer
from machine import Pin, PWM
import time
import config
class TrafficLight:
# Semaforo veicular: 3 LEDs com PWM
def __init__(self, pin_green, pin_yellow, pin_red, label):
self.label = label
self._pwm_g = PWM(Pin(pin_green), freq=1000, duty=0)
self._pwm_y = PWM(Pin(pin_yellow), freq=1000, duty=0)
self._pwm_r = PWM(Pin(pin_red), freq=1000, duty=0)
self._duty = 1023
self._state = "red"
self._pwm_r.duty(self._duty)
def set_green(self):
self._pwm_g.duty(self._duty)
self._pwm_y.duty(0)
self._pwm_r.duty(0)
self._state = "green"
def set_yellow(self):
self._pwm_g.duty(0)
self._pwm_y.duty(self._duty)
self._pwm_r.duty(0)
self._state = "yellow"
def set_red(self):
self._pwm_g.duty(0)
self._pwm_y.duty(0)
self._pwm_r.duty(self._duty)
self._state = "red"
def set_all_off(self):
self._pwm_g.duty(0)
self._pwm_y.duty(0)
self._pwm_r.duty(0)
self._state = "off"
def blink_green(self, on):
self._pwm_y.duty(0)
self._pwm_r.duty(0)
self._pwm_g.duty(self._duty if on else 0)
def blink_yellow(self, on):
self._pwm_g.duty(0)
self._pwm_r.duty(0)
self._pwm_y.duty(self._duty if on else 0)
def set_brightness(self, percent):
self._duty = (percent * 1023) // 100
if self._state == "green":
self.set_green()
elif self._state == "yellow":
self.set_yellow()
elif self._state == "red":
self.set_red()
def get_state(self):
return self._state
class PedestrianLight:
# Semaforo de pedestre: 2 LEDs com PWM
def __init__(self, pin_green, pin_red, label):
self.label = label
self._pwm_g = PWM(Pin(pin_green), freq=1000, duty=0)
self._pwm_r = PWM(Pin(pin_red), freq=1000, duty=0)
self._duty = 1023
self._state = "red"
self._pwm_r.duty(self._duty)
def set_green(self):
self._pwm_g.duty(self._duty)
self._pwm_r.duty(0)
self._state = "green"
def set_red(self):
self._pwm_g.duty(0)
self._pwm_r.duty(self._duty)
self._state = "red"
def blink_green(self, on):
self._pwm_r.duty(0)
self._pwm_g.duty(self._duty if on else 0)
def set_brightness(self, percent):
self._duty = (percent * 1023) // 100
if self._state == "green":
self.set_green()
elif self._state == "red":
self.set_red()
def get_state(self):
return self._state
class Buzzer:
# Buzzer com padroes sonoros programaveis
PATTERNS = {
'ped_walk': (2000, [(125, True), (125, False)]),
'ped_ending': (1500, [(500, True), (500, False)]),
'ped_extended': (2000, [(100, True), (50, False), (100, True), (750, False)]),
'emergency': (800, [(1000, True)]),
'intermittent': (1000, [(200, True), (1800, False)]),
}
def __init__(self, pin):
self._pwm = PWM(Pin(pin), freq=1000, duty=0)
self._name = None
self._steps = None
self._freq = 0
self._idx = 0
self._start = 0
def start_pattern(self, name):
if name not in self.PATTERNS or name == self._name:
return # FIX A4: nao reiniciar se mesmo padrao
self._name = name
self._freq, self._steps = self.PATTERNS[name]
self._idx = 0
self._start = time.ticks_ms()
self._apply()
def stop(self):
self._pwm.duty(0)
self._name = None
self._steps = None
def tick(self, now_ms):
if self._steps is None:
return
dur, _ = self._steps[self._idx]
if time.ticks_diff(now_ms, self._start) >= dur:
self._idx = (self._idx + 1) % len(self._steps)
self._start = now_ms
self._apply()
def _apply(self):
_, is_on = self._steps[self._idx]
if is_on:
self._pwm.freq(self._freq)
self._pwm.duty(512)
else:
self._pwm.duty(0)
def is_active(self):
return self._name is not None
class ActuatorHub:
# Fachada que agrega todos os atuadores
def __init__(self):
self.tl_vp = TrafficLight(
config.PINS_VP_LEDS['green'],
config.PINS_VP_LEDS['yellow'],
config.PINS_VP_LEDS['red'], "VP")
self.tl_vs = TrafficLight(
config.PINS_VS_LEDS['green'],
config.PINS_VS_LEDS['yellow'],
config.PINS_VS_LEDS['red'], "VS")
self.ped_vp = PedestrianLight(
config.PINS_PED_VP_LEDS['green'],
config.PINS_PED_VP_LEDS['red'], "PedVP")
self.ped_vs = PedestrianLight(
config.PINS_PED_VS_LEDS['green'],
config.PINS_PED_VS_LEDS['red'], "PedVS")
self.buzzer = Buzzer(config.PIN_BUZZER)
self._brightness = 100
def apply_phase(self, phase_id):
# Configura LEDs conforme a fase (tabela da Logica 2.2)
if phase_id == "F0":
self.tl_vp.set_green()
self.tl_vs.set_red()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.stop()
elif phase_id == "F1":
self.tl_vp.set_yellow()
self.tl_vs.set_red()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.stop()
elif phase_id == "F2":
self.tl_vp.set_red()
self.tl_vs.set_green()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.stop()
elif phase_id == "F3":
self.tl_vp.set_red()
self.tl_vs.set_red()
self.ped_vp.set_green()
self.ped_vs.set_red()
elif phase_id == "F4":
self.tl_vp.set_red()
self.tl_vs.set_yellow()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.stop()
elif phase_id == "F5":
self.tl_vp.set_red()
self.tl_vs.set_red()
self.ped_vp.set_red()
self.ped_vs.set_green()
elif phase_id == "ALL_RED":
self.tl_vp.set_red()
self.tl_vs.set_red()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.stop()
elif phase_id == "EMERGENCY_VP":
self.tl_vp.set_green()
self.tl_vs.set_red()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.start_pattern('emergency')
elif phase_id == "EMERGENCY_VS":
self.tl_vp.set_red()
self.tl_vs.set_green()
self.ped_vp.set_red()
self.ped_vs.set_red()
self.buzzer.start_pattern('emergency')
def set_all_red(self):
self.apply_phase("ALL_RED")
def set_intermittent(self, on):
self.tl_vp.blink_yellow(on)
self.tl_vs.blink_yellow(on)
self.ped_vp.set_red()
self.ped_vs.set_red()
# FIX A4: nao reiniciar buzzer (start_pattern ja faz guarda)
if on:
self.buzzer.start_pattern('intermittent')
def set_brightness(self, percent):
# FIX A3: so atualizar se mudou
if percent == self._brightness:
return
self._brightness = percent
self.tl_vp.set_brightness(percent)
self.tl_vs.set_brightness(percent)
self.ped_vp.set_brightness(percent)
self.ped_vs.set_brightness(percent)
def tick(self, now_ms):
self.buzzer.tick(now_ms)