Simulação de semáforos para tráfego e peões
Um projeto engraçado para quem tem alguns LEDs de sobra é simular uma passagem de peões/pedestres, controlada por dois semáforos: um para os peões e outro para os carros. Para fazer este mini projeto, vamos usar o Arduino. O objetivo final é criar um semáforo que mude automaticamente de 10 em 10 segundos, ou manualmente, ao carregar num botão.
Material necessário
- Arduino (Duemillanove, Uno ou Leonardo)
- 5 LEDs (2 vermelhos, 2 verdes e 1 laranja/amarelo) + 5 resistências 330 Ω
- 1 botão + 1 resitência 1 kΩ
- 1 Buzzer + 1 resistência 330 Ω (opcionais)
- Breadboard e fios de ligação qb.
Esquema de ligação
Montagem
- Colocar os LEDs na breadboard, assim como as respetivas resistências (todas de 330 Ω). Assegurem-se que ligam os LEDs na posição correta, e fazem a ligação da perna do negativo à resistência, e das resistências ao negativo/ground. Nas pernas positivas do LED iremos ligar os fios às portas digitais no Arduino (mais tarde).
- Se tiverem um buzzer, liguem-no após o semáforo dos carros. Liguem a resistência de 300 Ω na perna negativa do buzzer, e liguem essa resistência ao negativo, tal como nos LEDs.
- Coloquem agora os semáforos dos peões (vermelho e verde), tal como foi feito para o semáforo dos carros (colocação dos LEDs e resistências)
- Temos agora, da esquerda para a direita: 3 LEDs, vermelho, amarelo e verde para os carros, um buzzer (opcional) e 2 LEDs vermelho e verde, para os peões. Depois do semáforo dos peões coloquem o botão e, numa das pernas, liguem a resistência de 1 kΩ, que por sua vez liga ao negativo. Liguem a outra perna diagonalmente oposta ao positivo (5V) da breadboard.
Vamos agora proceder à ligação dos fios que controlam as luzes dos semáforos às portas digitais do Arduino. Vamos fazer a ligação da esquerda para a direita.
- No positivo do LED vermelho do semáforo dos peões, liguem um fio à porta digital 10.
- No positivo do LED amarelo, liguem um fio à porta digital 9.
- No positivo do LED verde, liguem um fio à porta digital 8.
- Se usarem o buzzer, liguem um fio ao positivo do buzzer à porta digital 6.
- Liguem um fio do numa das pernas do botão (entre a resistência), e liguem a outra extremidade à porta digital 5
- Agora, para o LED vermelho dos peões, no positivo, liguem um fio à porta digital 3
- Por fim, para o LED verde, liguem um fio da perna do lado positivo à porta digital 2
Terminámos as ligações de componentes. Resta agora ligar o positivo da breadboard à porta de 5V do Arduino, e o negativo da breadboard a uma das portas GND (ground/negativo) do Arduino. Agora na parte de software, basta fazer upload do seguinte código:
// variáveis para controlar o ciclo de troca automática
long ciclo = 10 * 1000l; // 10 segundos
long ultimo_ciclo = 0;
// variáveis para controlar o botão
int debounce_delay = 800;
int pedido_peao = 0;
int pedido_estado = 0;
// portas de ligação ao arduino
const byte PEAO_GREEN = 2;
const byte PEAO_RED = 3;
const byte BUTTON = 5;
const byte BELL = 6;
const byte CAR_GREEN = 8;
const byte CAR_YELLOW = 9;
const byte CAR_RED = 10;
// som de aviso para peões/pedestres
const byte NOTE_A6 = 1760; // experimentem mudar para sons diferentes
/**
* Rotinas de configuração inicial
*/
void setup(){
// semaforo peoes
pinMode(PEAO_GREEN, OUTPUT);
digitalWrite(PEAO_GREEN, LOW);
pinMode(PEAO_RED, OUTPUT);
digitalWrite(PEAO_RED, HIGH);
// semaforo transito
pinMode(CAR_GREEN, OUTPUT);
digitalWrite(CAR_GREEN, HIGH);
pinMode(CAR_YELLOW, OUTPUT);
digitalWrite(CAR_YELLOW, LOW);
pinMode(CAR_RED, OUTPUT);
digitalWrite(CAR_RED, LOW);
// botao peoes
pinMode(BUTTON, INPUT);
// definir o ultimo ciclo
ultimo_ciclo = millis();
Serial.begin(9600);
}
/**
* Programa para gerir o semáforo
*/
void loop(){
// detetar botao pressionado, com proteção debounce
// http://arduino.cc/it/Tutorial/Debounce
long ms = millis();
byte pedido = digitalRead(BUTTON);
if( ultimo_ciclo + ciclo < ms ){
// esta na hora de trocar para peoes (ciclo automático)
Serial.print("Prioridade aos peoes (automatico)\n");
pararCarros();
peoes();
arrancarCarros();
pedido_estado = 1;
ultimo_ciclo = millis();
} else if( pedido == 1 && (ms - debounce_delay) > pedido_peao ){
// um peao/pedestre pediu para parar o trânsito
Serial.print("Prioridade aos peoes (manual)\n");
pararCarros();
peoes();
arrancarCarros();
pedido_estado = 1;
ultimo_ciclo = millis(); // repor o contador automatico para nao acionar logo de seguida
} else if( pedido != pedido_estado ){
// protecao de debounce
pedido_peao = ms;
}
pedido_estado = pedido;
}
/**
* Função para ativar a transição do semáforo dos veículos para vermelho,
* de forma sequencial (verde, amarelo, vermelho) com 1 segundo de intervalo
*/
void pararCarros(){
delay(1000);
digitalWrite(CAR_GREEN, LOW);
digitalWrite(CAR_YELLOW, HIGH);
delay(1000);
digitalWrite(CAR_YELLOW, LOW);
digitalWrite(CAR_RED, HIGH);
delay(1500);
}
/**
* Função para dar luz verde a veículos
* (de imediato, sem intervalo)
*/
void arrancarCarros(){
digitalWrite(CAR_RED, LOW);
digitalWrite(CAR_YELLOW, LOW);
digitalWrite(CAR_GREEN, HIGH);
}
/**
* Função para ativar o sinal verde para peões/pedestres.
* O semáfoto ativa o sinal verde por 5 segundos, e depois
* dá 5 beeps indicativos que o sinal vai fechar
*/
void peoes(){
digitalWrite(PEAO_RED, LOW);
digitalWrite(PEAO_GREEN, HIGH);
delay(5000);
piscaLuz(PEAO_GREEN, 5, 400);
digitalWrite(PEAO_GREEN, LOW);
digitalWrite(PEAO_RED, HIGH);
delay(2000);
}
/**
* Faz piscar uma determinada luz, um certo número de vezes
* @param luz Porta onde está ligada a luz que se pretende fazer piscar
* @param vezes Número de vezes para fazer piscar a luz
* @param tempo Tempo durante o qual a luz fica acesa
*/
void piscaLuz(byte luz, byte vezes, int tempo){
for( byte i = 0; i < vezes; i++ ){
digitalWrite(luz, LOW);
tone(BELL, NOTE_A6, 1000/2);
delay(tempo);
digitalWrite(luz, HIGH);
delay(tempo);
noTone(BELL);
}
}
Após fazerem upload, o semáforo dos veículos deve estar com a luz verde acesa, enquanto o semáforo dos peões está vermelho. Experimentem carregar no botão ou esperar 10 segundos, e vejam a sequência que é desencadeada pelo código: o semáforo dos veículos passa por amarelo, e fica vermelho; após 1,5 segundos, acende o verde dos peões; passados 5 segundos, o semáforo verde dos peões pisca, enquanto é emitido um som a indicar que o semáforo vai ser encerrado; o semáforo dos peões fica vermelho, e acende-se novamente o verde para os veículos.
Notas
Se repararem, a leitura o botão é feita de forma ligeiramente diferente da que se vê em tutoriais para iniciados. Como a porta digital do Arduino é bastante sensível, um toque rápido no botão, um toque ligeiro na resistência ou um toque nos fios pode levar a uma alteração de corrente, sendo incorretamente interpretada como um toque no botão pelo Arduino. Para resolver este problema, é necessário usar uma técnica chamada Debounce.
O objetivo do Debounce é verificar se o estado do botão é constante durante
um período de tempo (neste caso, o código verifica durante 800 ms). Assim,
uma alteração de estado de poucos milissegundos não irá ativar por acidente
o semáforo. Uma implicação deste sistema é que necessitamos de carregar
no botão por 800 ms para ser considerada a mudança de estado no sistema.
Este período de tempo pode ser ajustado na variável debounce_delay
.
Mais informações: https://www.arduino.cc/en/Tutorial/Debounce
Este tutorial foi melhorado na sequência de uma dúvida que recebi por email sobre como colocar o semáforo automático. Na versão antiga, o semáforo apenas mudava quando o botão era pressionado. Nesta nova versão, o semáforo muda automaticamente passados 10 segundos sem o botão ser pressionado. O download em baixo incluí as duas versões: a antiga (semaforos-antigo.ino) e a mais recente (semaforos2.ino). O esquema de ligação é o mesmo para ambas as versões.