Início›Projetos›Caixote Inteligente
⬤ Projeto Integrado · LCD + Servo + Motor DC · Cenário LED

🗑️ Caixote do Lixo Inteligente — Versão Avançada

⏱️ 60–70 min 🧩 Servo · Motor DC · LCD 20×4 · Sensor obstáculos · Chars custom · Cenário LED oficial

Nesta página

🎯 Objetivo e Resultado

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.

BEM-VINDO! Tampa: ABERTA t:2s Utilizacoes: 42>>> Obrigado! <<< <<

🏗️ Arquitetura do Sistema

SubsistemaComponenteFunção
DeteçãoSensor IR obstáculos (#37)Deteta mão a <15cm — activa abertura
TampaServo SG90 (D9)0° = fechado · 90° = aberto
CompactaçãoMotor DC (M1)Liga 2s a cada 5 utilizações
DisplayLCD 20×4 (I2C)Contagem, estado, mensagem animada
IndicaçãoChars custom CGRAMÍcone de lixo, seta, check

🔌 Ligações

ComponentePino ArduinoNota
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 placaAF_DCMotor motor(1)
ℹ️
O sensor de obstáculos IR tem alcance regulável por potenciómetro. Ajusta para detetar a mão a ~10–15cm — nem demasiado sensível (abre com qualquer movimento) nem insensível (não abre ao aproximar).

🔨 Fases de Montagem

Fase 1 — Servo e sensor

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°.

Fase 2 — LCD com chars custom

Regista 4 chars: lixo (slot 0), seta (slot 1), check (slot 2), bloco (slot 3). Exibe dashboard básico com estado da tampa.

Fase 3 — Lógica de abertura com timeout

Implementa timeout de 3s sem mão para fechar. Usa millis() — não delay(). Cada abertura incrementa o contador.

Fase 4 — Motor de compactação

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.

Fase 5 — Mensagem animada e polish

Adiciona scroll de 'Obrigado!' na linha 3. Anima o ícone de tampa no LCD. Afina todos os timings para comportamento natural.

💻 Código Completo

proj_caixote_inteligente.ino
#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;
  }
}

🚀 Como Expandir

🏆 Para ir mais longe

PR.FT9_5 · LCD 20×4 · L293D Motor Driver · Arduino UNO Rev3 · Início · led.dge.medu.pt