from machine import Pin, PWM, ADC, I2C
import time
# =========================================================
# LCD1602 I2C DRIVER
# =========================================================
class LCD1602:
def __init__(self, i2c, addr=0x27):
self.i2c = i2c
self.addr = addr
self.backlight = 0x08
self.init_lcd()
def write_byte(self, data):
self.i2c.writeto(self.addr, bytes([data | self.backlight]))
def pulse_enable(self, data):
self.write_byte(data | 0x04)
time.sleep_us(1)
self.write_byte(data & ~0x04)
time.sleep_us(50)
def write4bits(self, data):
self.write_byte(data)
self.pulse_enable(data)
def send(self, value, mode=0):
high = value & 0xF0
low = (value << 4) & 0xF0
self.write4bits(high | mode)
self.write4bits(low | mode)
def command(self, cmd):
self.send(cmd, 0)
def write_char(self, char):
self.send(ord(char), 1)
def init_lcd(self):
time.sleep_ms(50)
self.write4bits(0x30)
time.sleep_ms(5)
self.write4bits(0x30)
time.sleep_us(150)
self.write4bits(0x30)
self.write4bits(0x20)
self.command(0x28)
self.command(0x0C)
self.command(0x06)
self.clear()
def clear(self):
self.command(0x01)
time.sleep_ms(2)
def move_to(self, col, row):
row_offsets = [0x00, 0x40]
self.command(0x80 | (col + row_offsets[row]))
def putstr(self, text):
for char in text:
self.write_char(char)
# =========================================================
# PINS - MATCHES YOUR FIXED DIAGRAM
# =========================================================
SERVO_PINS = [4, 5, 6, 7, 15, 16]
BTN_RUN_PIN = 17
BTN_MODE_PIN = 3
BUZZER_PIN = 19
POT_PIN = 2
LCD_SDA = 8
LCD_SCL = 9
LED_RED_PIN = 10
LED_GREEN_PIN = 11
LED_BLUE_PIN = 12
# Biaxial stepper motor used as vibration motor
MOTOR_A_PLUS_PIN = 13
MOTOR_A_MINUS_PIN = 14
MOTOR_B_PLUS_PIN = 18
MOTOR_B_MINUS_PIN = 21
# =========================================================
# SETUP SERVOS
# =========================================================
servos = []
for pin in SERVO_PINS:
pwm = PWM(Pin(pin))
pwm.freq(50)
pwm.duty_u16(0)
servos.append(pwm)
# =========================================================
# SETUP BUTTONS
# =========================================================
btn_run = Pin(BTN_RUN_PIN, Pin.IN, Pin.PULL_UP)
btn_mode = Pin(BTN_MODE_PIN, Pin.IN, Pin.PULL_UP)
# =========================================================
# SETUP LEDS
# =========================================================
led_red = Pin(LED_RED_PIN, Pin.OUT)
led_green = Pin(LED_GREEN_PIN, Pin.OUT)
led_blue = Pin(LED_BLUE_PIN, Pin.OUT)
# =========================================================
# SETUP BUZZER
# =========================================================
buzzer = PWM(Pin(BUZZER_PIN))
buzzer.freq(1000)
buzzer.duty_u16(0)
# =========================================================
# SETUP POTENTIOMETER / MIC LEVEL
# =========================================================
pot = ADC(Pin(POT_PIN))
try:
pot.atten(ADC.ATTN_11DB)
except:
print("ADC atten not supported")
# =========================================================
# SETUP BIAXIAL STEPPER MOTOR
# =========================================================
motor_a_plus = Pin(MOTOR_A_PLUS_PIN, Pin.OUT)
motor_a_minus = Pin(MOTOR_A_MINUS_PIN, Pin.OUT)
motor_b_plus = Pin(MOTOR_B_PLUS_PIN, Pin.OUT)
motor_b_minus = Pin(MOTOR_B_MINUS_PIN, Pin.OUT)
# =========================================================
# SETUP LCD
# =========================================================
i2c = I2C(0, scl=Pin(LCD_SCL), sda=Pin(LCD_SDA), freq=400000)
devices = i2c.scan()
print("I2C devices:", devices)
lcd = None
lcd_ok = False
if 0x27 in devices:
lcd = LCD1602(i2c, 0x27)
lcd_ok = True
elif 0x3F in devices:
lcd = LCD1602(i2c, 0x3F)
lcd_ok = True
else:
print("LCD not found. Check SDA/SCL/VCC/GND wiring.")
# =========================================================
# DISPLAY
# =========================================================
def show_screen(line1="", line2=""):
line1 = str(line1)[:16]
line2 = str(line2)[:16]
if lcd_ok:
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr(line1)
lcd.move_to(0, 1)
lcd.putstr(line2)
else:
print(line1, line2)
# =========================================================
# LED STATUS
# =========================================================
def leds_off():
led_red.value(0)
led_green.value(0)
led_blue.value(0)
def status_ready():
leds_off()
led_green.value(1)
def status_working():
leds_off()
led_blue.value(1)
def status_error():
leds_off()
led_red.value(1)
# =========================================================
# BUZZER
# =========================================================
def beep(duration=0.15, freq=1000):
buzzer.freq(freq)
buzzer.duty_u16(30000)
time.sleep(duration)
buzzer.duty_u16(0)
def start_beep():
beep(0.1, 900)
time.sleep(0.05)
beep(0.1, 1200)
time.sleep(0.05)
beep(0.1, 1500)
def success_beep():
beep(0.12, 1000)
time.sleep(0.05)
beep(0.12, 1400)
def error_beep():
beep(0.35, 400)
# =========================================================
# BIAXIAL STEPPER AS VIBRATION MOTOR
# =========================================================
def motor_off():
motor_a_plus.value(0)
motor_a_minus.value(0)
motor_b_plus.value(0)
motor_b_minus.value(0)
def motor_step(step):
motor_off()
if step == 0:
motor_a_plus.value(1)
elif step == 1:
motor_b_plus.value(1)
elif step == 2:
motor_a_minus.value(1)
elif step == 3:
motor_b_minus.value(1)
def vibrate(duration=0.4):
print("VIBRATION ON")
end_time = time.ticks_add(time.ticks_ms(), int(duration * 1000))
step = 0
while time.ticks_diff(end_time, time.ticks_ms()) > 0:
motor_step(step)
step += 1
if step > 3:
step = 0
time.sleep(0.03)
motor_off()
print("VIBRATION OFF")
# =========================================================
# SERVO / BRAILLE
# =========================================================
def set_servo_angle(servo, angle):
if angle < 0:
angle = 0
if angle > 180:
angle = 180
min_us = 500
max_us = 2400
us = min_us + (angle / 180) * (max_us - min_us)
duty = int((us / 20000) * 65535)
servo.duty_u16(duty)
def all_down():
for servo in servos:
set_servo_angle(servo, 0)
def all_up():
for servo in servos:
set_servo_angle(servo, 90)
def set_braille(dots):
"""
Braille dot order:
1 4
2 5
3 6
dots = [dot1, dot2, dot3, dot4, dot5, dot6]
1 = up
0 = down
"""
for i in range(6):
if dots[i] == 1:
set_servo_angle(servos[i], 90)
else:
set_servo_angle(servos[i], 0)
# =========================================================
# ADC / MIC LEVEL
# =========================================================
def read_pot():
try:
return pot.read()
except:
return pot.read_u16() // 16
# =========================================================
# BRAILLE WORDS
# =========================================================
BRAILLE_WORDS = [
("HELLO", [1, 0, 0, 0, 1, 1]),
("YES", [1, 0, 1, 0, 1, 0]),
("NO", [1, 1, 0, 0, 0, 0]),
("HELP", [1, 1, 1, 0, 1, 0]),
("WATER", [1, 0, 0, 1, 1, 0]),
("DANGER", [1, 1, 1, 1, 0, 0])
]
word_index = 0
mode = 0
# mode 0 = sign demo
# mode 1 = mic demo
# =========================================================
# ACTIONS
# =========================================================
def run_sign_demo():
global word_index
word, dots = BRAILLE_WORDS[word_index]
status_working()
show_screen("SIGN MODE", "Word: " + word)
start_beep()
vibrate(0.4)
set_braille(dots)
time.sleep(1.5)
all_down()
success_beep()
vibrate(0.4)
status_ready()
show_screen("SMART GLASSES", "Ready")
word_index += 1
if word_index >= len(BRAILLE_WORDS):
word_index = 0
def run_mic_demo():
status_working()
show_screen("MIC DETECTED", "Text -> Braille")
beep(0.12, 1500)
vibrate(0.4)
# Demo word: HELP
set_braille([1, 1, 1, 0, 1, 0])
time.sleep(1.5)
all_down()
success_beep()
vibrate(0.4)
status_ready()
show_screen("SMART GLASSES", "Ready")
def change_mode():
global mode
mode += 1
if mode > 1:
mode = 0
if mode == 0:
show_screen("MODE", "Sign Demo")
beep(0.1, 900)
else:
show_screen("MODE", "Mic Demo")
beep(0.1, 1300)
vibrate(0.3)
time.sleep(0.5)
show_screen("SMART GLASSES", "Ready")
# =========================================================
# START
# =========================================================
all_down()
leds_off()
motor_off()
show_screen("SMART GLASSES", "Starting...")
start_beep()
vibrate(0.5)
status_ready()
show_screen("SMART GLASSES", "Ready")
print("Smart Sign Braille Glasses Started")
# =========================================================
# MAIN LOOP
# =========================================================
last_run_state = 1
last_mode_state = 1
last_run_time = 0
last_mode_time = 0
mic_triggered = False
while True:
current_run = btn_run.value()
current_mode = btn_mode.value()
# RUN button
if last_run_state == 1 and current_run == 0:
now = time.ticks_ms()
if time.ticks_diff(now, last_run_time) > 500:
last_run_time = now
if mode == 0:
run_sign_demo()
else:
run_mic_demo()
# MODE button
if last_mode_state == 1 and current_mode == 0:
now = time.ticks_ms()
if time.ticks_diff(now, last_mode_time) > 500:
last_mode_time = now
change_mode()
last_run_state = current_run
last_mode_state = current_mode
# Potentiometer / fake microphone
pot_value = read_pot()
print("Mic Level:", pot_value)
if mode == 1:
if pot_value > 3000 and not mic_triggered:
mic_triggered = True
run_mic_demo()
if pot_value < 1500:
mic_triggered = False
time.sleep(0.1)