Versão avançada do cenário LED oficial de eco-caixote. O sensor IR deteta aproximação da mão → o servo abre a tampa → o LCD exibe contagem de utilizações, tempo de abertura e mensagem animada → após 3s sem mão o servo fecha. Um motor DC simula compressor de compactação ativado em cada 5 utilizações.
| Subsistema | Componente | Função |
|---|---|---|
| Deteção | Sensor IR obstáculos (#37) | Deteta mão a <15cm — activa abertura |
| Tampa | Servo SG90 (D9) | 0° = fechado · 90° = aberto |
| Compactação | Motor DC (M1) | Liga 2s a cada 5 utilizações |
| Display | LCD 20×4 (I2C) | Contagem, estado, mensagem animada |
| Indicação | Chars custom CGRAM | Ícone de lixo, seta, check |
| Componente | Pino Arduino | Nota |
|---|---|---|
| LCD 20×4 (I2C) | A4 (SDA) / A5 (SCL) | Endereço 0x27 |
| Sensor obstáculos IR (#37) | D5 (INPUT) | LOW = mão detectada |
| Servo (tampa) | D9 (PWM 50 Hz) | SG90 — 0°=fechado, 90°=aberto |
| Motor DC (compactação) | Canal M1 da placa | AF_DCMotor motor(1) |
Liga servo ao D9 (90°=tampa aberta). Liga sensor ao D5. Testa isoladamente: ao tapar o sensor o servo vai a 90°, ao descobrir volta a 0°.
Regista 4 chars: lixo (slot 0), seta (slot 1), check (slot 2), bloco (slot 3). Exibe dashboard básico com estado da tampa.
Implementa timeout de 3s sem mão para fechar. Usa millis() — não delay(). Cada abertura incrementa o contador.
A cada 5 utilizações, após fechar a tampa, activa o motor DC por 2s a 200/255. Exibe 'A COMPACTAR...' no LCD durante esse tempo.
Adiciona scroll de 'Obrigado!' na linha 3. Anima o ícone de tampa no LCD. Afina todos os timings para comportamento natural.
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <AFMotor.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo tampa;
AF_DCMotor compactador(1);
#define SENSOR_PIN 5
#define ANG_ABERTO 90
#define ANG_FECHADO 0
#define TIMEOUT_MS 3000 // 3s sem mão → fechar
#define COMPACT_N 5 // compactar a cada 5 utilizações
// ── Chars custom ─────────────────────────────────────────────
byte ic_lixo[8] = {0b01110,0b11111,0b01010,0b01010,0b01010,0b01010,0b01110,0b00000}; // 🗑
byte ic_seta[8] = {0b00000,0b00100,0b00110,0b11111,0b11111,0b00110,0b00100,0b00000}; // →
byte ic_check[8] = {0b00000,0b00001,0b00011,0b10110,0b11100,0b01000,0b00000,0b00000}; // ✓
byte ic_bloco[8] = {0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111}; // █
// ── Estado ────────────────────────────────────────────────────
bool aberta = false;
int utilizacoes = 0;
unsigned long tUltimaMAO = 0; // quando a mão foi detetada pela última vez
unsigned long tAbertura = 0; // quando a tampa abriu
int posScroll = 0;
unsigned long tScroll = 0;
String msgScroll;
// ── Abrir tampa ───────────────────────────────────────────────
void abrirTampa() {
if (aberta) return;
tampa.write(ANG_ABERTO);
aberta = true;
tAbertura = millis();
utilizacoes++;
lcd.setCursor(0,1); lcd.print("Tampa: ABERTA ");
lcd.setCursor(0,2);
lcd.print("Utilizacoes: "); lcd.print(utilizacoes); lcd.print(" ");
// Prepara mensagem scroll para linha 3
msgScroll = String(" Obrigado pela utilizacao! ");
posScroll = 0;
}
// ── Fechar tampa ──────────────────────────────────────────────
void fecharTampa() {
if (!aberta) return;
tampa.write(ANG_FECHADO);
aberta = false;
lcd.setCursor(0,1); lcd.print("Tampa: FECHADA ");
// Compactar a cada COMPACT_N utilizações
if (utilizacoes % COMPACT_N == 0 && utilizacoes > 0) {
lcd.setCursor(0,1); lcd.print("A COMPACTAR... ");
compactador.setSpeed(200); compactador.run(FORWARD);
delay(2000);
compactador.run(RELEASE);
lcd.setCursor(0,1); lcd.print("Compactado! OK ");
delay(500);
lcd.setCursor(0,1); lcd.print("Tampa: FECHADA ");
}
}
void setup() {
lcd.createChar(0, ic_lixo); lcd.createChar(1, ic_seta);
lcd.createChar(2, ic_check); lcd.createChar(3, ic_bloco);
lcd.init(); lcd.backlight();
tampa.attach(9); tampa.write(ANG_FECHADO);
pinMode(SENSOR_PIN, INPUT);
// Ecrã inicial
lcd.setCursor(0,0); lcd.write(0); lcd.print(" Caixote Intelig. ");
lcd.setCursor(0,1); lcd.print("Tampa: FECHADA ");
lcd.setCursor(0,2); lcd.print("Utilizacoes: 0 ");
lcd.setCursor(0,3); lcd.print("PR.FT9_5 LED 2025 ");
msgScroll = " Aproxime a mao para abrir! ";
}
void loop() {
bool mao = (digitalRead(SENSOR_PIN) == LOW);
unsigned long agora = millis();
// Deteção de mão → abre
if (mao) { tUltimaMAO = agora; abrirTampa(); }
// Timeout sem mão → fecha
if (aberta && (agora - tUltimaMAO > TIMEOUT_MS)) fecharTampa();
// Tempo aberta na linha 1
if (aberta) {
int seg = (int)((agora - tAbertura) / 1000);
lcd.setCursor(14, 1); lcd.print("t:"); lcd.print(seg); lcd.print("s ");
}
// Scroll mensagem linha 3
if (agora - tScroll > 280 && msgScroll.length() > 0) {
lcd.setCursor(0, 3);
lcd.print(msgScroll.substring(posScroll, posScroll + 20));
posScroll++;
if(posScroll > (int)msgScroll.length() - 20) posScroll = 0;
tScroll = agora;
}
}