Wiki do André

Partilha de conhecimento

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

Esquema de ligação para os semáforos

Montagem

  1. 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).
  2. 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.
  3. 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)
  4. 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.

  1. No positivo do LED vermelho do semáforo dos peões, liguem um fio à porta digital 10.
  2. No positivo do LED amarelo, liguem um fio à porta digital 9.
  3. No positivo do LED verde, liguem um fio à porta digital 8.
  4. Se usarem o buzzer, liguem um fio ao positivo do buzzer à porta digital 6.
  5. Liguem um fio do numa das pernas do botão (entre a resistência), e liguem a outra extremidade à porta digital 5
  6. Agora, para o LED vermelho dos peões, no positivo, liguem um fio à porta digital 3
  7. 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
 int ciclo = 10 * 1000; // 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.

Downloads

Código, esquema de ligação e fotos de exemplo