Felix Maocho

Para quien le interese lo que a nosotros nos interesa

Ejercicio 2 – Simular un semáforo que regula el paso en un túnel

semaforo Félix Maocho
28/2/2017

Enunciado

Para una maqueta deseamos simular un semáforo que regule el paso en un corto túnel que no permite el cruce de dos vehículos, no hay el riesgo que los vehículos choquen, porque desde un extremo se ve la salida, por tanto si hay o no un coche en su interior, pero para regular bien el trafico se desea lo siguiente

1º.- En un extremos se acaba de poner la luz en verde mientras que en el otro extremo está en rojo. Así se mantiene 25 segundos.
2º.- Para estimular el paso de los últimos coches, el verde se pone parpadeante cinco veces con periodos de encendido y apagados de un segundo. o sea esta así 10 segundos más, mientras que el otro extremo esta en rojo<
3º.- El semáforo se pone en rojo en un extremo, pero para dar tiempo a que salgan los coches que estuvieran dentro del túnel el otro extremo también continua en rojo durante otros 10 segundos

Se repite el proceso, pero en este caso el es otro extremo el que se pone en verde y el inicial continúa en rojo. Todos los pines utilizados seran PWM

Material necesario

  • Tarjeta Arduino y cable de conexiones
  • Tarjeta de prototipado o “protoboard”
  • 9 Cables de conexiones macho/macho (preferiblemente 2 rojos, 2 verdes y 5 negros
  • 4 Resistencias de 220 Ω
  • 4 Led (preferible 2 de color rojo y 2 verdes)
  • 1 Cable de conexión macho/macho más, para comprobaciones de los circuitos (naranja o de cualquier otro color)

Hardware

hardware-semaforo

Aunque en la imagen se vean transparentes esos leds son de color verde. Tenemos unidos a los pines 6 y 10 leds verdes y a los pines 9 y 11 afules  los ines 6 y 9 alimentan el semáforo de un lado y el  10 y el 11 el del otro lado , cada circuito está protegido por una resistencia de 220 Ω como es habitual,  Todos los pines utilizados pon PWM como eexigía el enunciado del problema

Software

Simplemente podíamos cambiar en el programa inicial el valor de los pines de salida, que ahora va a ser el 6, 9 10, y 11 puesto que se nos ha pedido que en este caso se utilicen los Pin PWM, eliminar del “setup” la declaraciones de pins como OUPUT, porque los pin PWM no lo necesitan y cambiar el mandato “digitalWrite” por el mandato “analogWriter” al nivel máximo o sea 255. o 0 para apagar

Como ello añadiría muy poco a lo que sabemos prefiero utilizar las “funciones” con el fin de ir viendo no sólo como se usan sino como se platea la resolución de un sketch. Como dijimos las funciones permiten solucionar un sketch que se ve como muy complejo en varias funciones que en principio parecen mas sencillas, probar cada una por separado y montarlas finalmente. Veamos como se establece el proceso.

1º paso Definir el sketch y dividirlo en diferentes funciones

/* Sketch E7.2 Simular de semáforo
* Izquierda (I), Derecha (D), Verde (V), Rojo (R )
* MAYUSCULAS = encendido, minúsculas = apagado
* 1º.- Circulación I >> D (IV) (ir) –- (dv) (DR) tiempo1
* 2º.- Fin I >> D (IV) parpadea 5 veces (tiempo2) resto no cambian
* 3º.- No hay circulación (iv) (IR) –- (dv) (DR) tiempo3
* Se repite el proceso, pero en este caso es el otro extremo el que se pone en verde
* Repetir el ciclo
*/
// Área de definición de variables y parámetros *******************
int pindv = 6;
int pindr = 9;
int piniv = 10;
int pinir = 11;
// Función setup ********************************************
void setup() {
}
// Función loop ********************************************
void loop() {
circulaIzquierdaDerecha();
circulaDerechaIzquierda();
}
// Área de definición de variables y parámetros ********************
void circulaIzquierdaDerecha(){   }
void circulaDerechaIzquierda(){   }

Observen que lo que hemos hecho en este paso es dividir un problema al cual no sabemos como le “hincaremos el diente” en dos problemas mas sencillos, que ademas deben ser muy similares o simétricos.

Observen también que aun no hemos definido nada, salvo declarar los parámetros de los pines que el hardwware nos dice que vamos a utilizar y “bautizado” las dos funciones en que hemos dividido el sketch, que de momento pensamos que no van a tener parámetros de entrada ni de salida, aunque esto no es definitivo.

Si lo compilan y aconsejo que se haga en el simulador UnoArduSim verán que no da error (salvo que hayamos olvidado o algo o cometido una falta de ortografía, aunque naturalmente aun no hace nada,. Como es muy sencillo todos los errores de dactilografía que hayamos cometido los encontraremos muy facilmente y sera muy sencillo subsanarlos. Por otra parte estamos escribiendo un seudocódigo que cualquiera puede entender perfectamente

La ventaja es que si desarrollamos una función pero no tocamos nada más, los errores que detectemos, estarán en este función en concreto no en otro lado.

2º paso Ir introduciendo el contenido de cada función

Desarrollemos pues “circulaIzquierdaDerecha

/* Sketch E7.2 Simular de semáforo
* Izquierda (I), Derecha (D), Verde (V), Rojo (R )
* MAYUSCULAS = encendido, minúsculas = apagado
* 1º.- Circulación I >> D (IV) (ir) –- (dv) (DR) tiempo1
* 2º.- Fin I >> D (IV) parpadea 5 veces (tiempo2) resto no cambian
* 3º.- No hay circulación (iv) (IR) –- (dv) (DR) tiempo3
* Se repite el proceso, pero en este caso es el otro extremo el que se pone en verde
* Repetir el ciclo
*/
// Área de definición de variables y parámetros *******************
int pindv = 6;
int pindr = 9;
int piniv = 10;
int pinir = 11;
int tiempo1 = 4000; // Duración del la circulación en un sentido
int tiempo2 = 200; // Tiempo que dura medio parpadeo de la luz verde
int tiempo3 = 1000; // Tiempo cerrada la circulación en los dos sentidos
// Función setup ********************************************
void setup() {
}
// Función loop ********************************************
void loop() {
circulaIzquierdaDerecha();
circulaDerechaIzquierda();
}
// Área de definición de variables y parámetros ********************
void circulaIzquierdaDerecha(){
encederDosSemaforos(piniv,pindr);
delay(tiempo1);
parpadearSemaforo(piniv,tiempo2,5);
apagarDosSemaforos(piniv,pindr);
sinCirculacion(tiempo3) ;
}
//***
void circulaDerechaIzquierda(){ }
//*****************************
void encederDosSemaforos(int pin1,int pin2) {
analogWrite(pin1, 255);
analogWrite(pin2, 255);
}
//***
void apagarDosSemaforos(int pin1,int pin2) {
analogWrite(pin1, 0);
analogWrite(pin2, 0);
}
//*******************************
void parpadearSemaforo(int pin,int tiempo,int veces) {
for (int i=0; i<veces; i++) {
destelloPWM(pin, tiempo, 0);
destelloPWM(pin, tiempo, 255);
}
}
//***
void sinCirculacion(int tiempo) {
encederDosSemaforos(pinir,pindr);
delay (tiempo);
apagarDosSemaforos(pinir,pindr);
}
//***
void destelloPWM(int pinpwm, int tiempo, int nivel) {
analogWrite(pinpwm, nivel);
delay(tiempo);
analogWrite(pinpwm, 0);
}

Compilen lo que hemos hecho hasta aquí. Por supuesto que la circulación en sentido contrario no está hecha, por lo que de momento aun la función “circulaDerechaIzquierda” aun no hace nada, pero en cambio, la circulación en un sentido está acabada, se enciende en un extremo el semáforo verde y en el otro el rojo y al cabo de un tiempo el verde perpadea 5 veces como estaba previsto y posteriormente los dos extremos se ponen rojos, para dar tiempo a los coches que están dentro del túnel que terminen de salir.

Hemos desarrollado, la función llamada “circulaIzquierdaDerecha”, que se transforma en cuatro funciones y un mandato, “encederDosSemaforos”, “parpadearSemaforo”, “apagarDosSemaforos“, “sinCirculacion” y un “delay”.

Sin embargo, encender dos determinados semáforos o apagarlos es bastante inmediato, aunque no tanto hacer parpadear el semáforo. Podíamos decidir si lo que es sencillo lo hacemos en la misma función o lo sacarlo fuera. Yo me he decidido sacarlo fuera, porque esto de encender y apagar dos semáforos lo vamos a hacer en muchas partes del programa. Por ejemplo la función un poco mas abajo, “sinCirculacion” volverá a utilizar la rutina de encender y apagar dos semáforos.

Quiero que se fijen en la función “parpadearSemaforo”, para ejecutarla hemos hecho uso de una función que ya conocemos, “destelloPWM”, pues la realizamos en ejercicio anterior, Esta es una de las ventajas del uso de funciones, la posibilidad de “reciclar” elementos de código ya finalizados y probados en nuevos sketch. La ventaja es obvia por un lado ya esta perfectamente escrito y por otro está probado que funciona. Tener una amplia librea de rutinas habituales ahora mucho tiempo de programación y da gran fiabilidad a los sketch que escribamos. Observen que la función la estamos utilizando para dos cosas aparentemente contradictorias, encender y apagar una luz para hacer la intermitencia.

Mandato “for”

Estamos usando un nuevo mandato en “parpadearSemaforo”, el el mandato “for”, algo que podemos traducir por “para”. Es un mandato de tipo condicional, como lo es “if”, o sea, que se ejecuta solo si se cumple una condición situada dentro de los paréntesis,(…), se ejecuta lo que haya entre las llaves {…}, y si no se cumple esa condición deja de ejecutarse lo que hay entre llaves.

La condición en nuestro caso es esta (int i=0; i<veces; i++) que quiere decir:

  • “int i = 0; “ – definimos dentro del mandato “for” un contador llamado “i” Que sera un contador con el valor inicial “0”
  • “i <veces; ” – mientras “i” sea inferior a “veces” que tiene el valor “5”, que en este caso hemos pasado por parámetro de entrada, se ejecuta lo que hay entre las llaves { … }.
  • “i++” – es la forma de sumar “1” a “i”al finalizar de hacer lo que haya entre llaves. O sea lo mismo que escribir i=i+1

Lo que “for” hace es crear dentro del bucle cono  “loop”, un pequeño bucle que contiene los mandatos o funciones indicados por las llaves, que se ejecutarán, que se repetirá en tanto se cumpla la condición que gobierna el “for”. En nuestro caso que “i” valga menos de 5. Por tanto si “i” es menor que 5, que va ser lo que valga “veces”, apagara, esperará y encenderá el pin indicado, haciendo la intermitencia tantas veces y en la cadencia que indican los parámetros de entrada. Al final “i” pasará a valer un dígito mas, llega al valor 5 y como ya no se cumple que “(i<5)” y se deja de hacer el bucle.

El mandato “for” es tan importante, que volveremos en ella en múltiples ocasiones. Poco a poco, ira adquiriendo destreza en su uso. Este mandato es fundamental cuando deseamos repetir una misma acción un numero indeterminado a priori de veces. Supongamos que deseamos hacer andar un robot hasta llegar a una pared, el telémetro dirá a que distancia está la pared y en función de eso el mandato “for” dará los pasos que convenga.

3º paso Acabar de definir el resto de las funciones

Nos falta definir la función “circulaDerechaIzquierda” que evidentemente es simétrica a la anterior solo que cambiando los emaforros encendidos denominados “piniv” y “pindr” por los semafors contrarios “pinir” y “pindv”, Veremos una de las mayores ventajas del uso de las funciones, la mitad de sketch que nos falta por definir se completa con cuatro nuevas líneas que en lo único que cambian son los parámetros que pasamos donde ponímamos “piniv” y “pindr” podremos los nuevos paraáetros “pindv” y “pinirr”. Todo lo demás ya lo tenemos definido y probado.

/* Sketch E7.2 Simular de semáforo
* Izquierda (I), Derecha (D), Verde (V), Rojo (R )
* MAYUSCULAS = encendido, minúsculas = apagado
* 1º.- Circulación I >> D (IV) (ir) –- (dv) (DR) tiempo1
* 2º.- Fin I >> D (IV) parpadea 5 veces (tiempo2) resto no cambian
* 3º.- No hay circulación (iv) (IR) –- (dv) (DR) tiempo3
* Se repite el proceso, pero en este caso es el otro extremo el que se pone en verde
* Repetir el ciclo
*/
// Área de definición de variables y parámetros *******************
int pindv = 6;
int pindr = 9;
int piniv = 10;
int pinir = 11;
int tiempo1 = 4000; // Duración del la circulación en un sentido
int tiempo2 = 200; // Tiempo que dura medio parpadeo de la luz verde
int tiempo3 = 1000; // Tiempo cerrada la circulación en los dos sentidos
// Función setup ********************************************
void setup() {
}
// Función loop ********************************************
void loop() {
circulaIzquierdaDerecha();
circulaDerechaIzquierda();
}
// Área de definición de variables y parámetros ********************
void circulaIzquierdaDerecha(){
encederDosSemaforos(piniv,pindr);
delay(tiempo1);
parpadearSemaforo(piniv,tiempo2,5);
apagarDosSemaforos(piniv,pindr);
sinCirculacion(tiempo3) ;
}
//***
void circulaDerechaIzquierda(){
encederDosSemaforos(pinir,pindv);
delay(tiempo1);
parpadearSemaforo(pindv,tiempo2,5);
apagarDosSemaforos(pinir,pindv);
sinCirculacion(tiempo3) ;
}
//*****************************
void encederDosSemaforos(int pin1,int pin2) {
analogWrite(pin1, 255);
analogWrite(pin2, 255);
}
//***
void apagarDosSemaforos(int pin1,int pin2) {
analogWrite(pin1, 0);
analogWrite(pin2, 0);
}
//*******************************
void parpadearSemaforo(int pin,int tiempo,int veces) {
for (int i=0; i<veces; i++) {
destelloPWM(pin, tiempo, 0);
destelloPWM(pin, tiempo, 255);
}
}
//***
void sinCirculacion(int tiempo) {
encederDosSemaforos(pinir,pindr);
delay (tiempo);
apagarDosSemaforos(pinir,pindr);
}
//***
void destelloPWM(int pinpwm, int tiempo, int nivel) {
analogWrite(pinpwm, nivel);
delay(tiempo);
analogWrite(pinpwm, 0);
}

Solo nos basta compilar y la prueba final. La cosa ya funciona como lo previsto, unicvamete yo prolongaría el tiempo en que ambos semáforos están en rojo, que me parece un poco corto. Como el programa estáa suficientemente parametrizado, basta cambiar el valor de “timpo3” a otro valor mayor h y probar hasta que encontremos un valor a nuestro gusto.

Vean el funcionamiento de es sketch en el simulador.

Como puede observe si un extremo del túnel está en verde el opuesto está en rojo, en un momento determinado el semáforo verde parpadea 5 veces y se pone en rojo estando cerrados los dos extremos del túnel . A continuación se abre la circulación en la otra dirección.

Voy a cambiar un poco el sketch para poner un “delay” en el mandato “for”, de modo que haga una pequeña parada que nos permita ver los distintos valores que toma “i” antes de alcanzar el valor 5 y salir del mandato “for” el programa pasa con las opciones “Animate” y “SlowMotion” activadas para que se vea mejor el funcionamiento, Cuando la luz verde comienza a parpadear el sketch ha entrado en el mandato “for”.

El vídeo empieza en el momento que se acaba la circulación en un sentido y el semáforo verde está a punto de empezar a parpadear, o sea un poco antes de que el Sketch entre en el mandato “for”.

Cuando el sketch entra en el mandato “for”, la “i”! adquiere valor, que queda reflejada en el área de las variables, en la parte inferior de la imagen, Fuera de este mandato, la “i” desaparece de la lista de variables, porque “i” es una variable local, o sea definida dentro del mandato “for” que solo tiene valor dentro del mandato, fuera de ese mandato, aunque el programa vaya a una función llamada por un mandato dentro de las llaves del “for” “i” desaparece, porque al ser local, fuera no tiene “existencia” a diferencia de “ por ejemplo “veces” que al estar definida en el área de variables es una variable “global” y tiene existencia en cualquier parte de sketch.

Cuando la “i” adquiere el valor 5 se acaba el mandato “for” porque deja de cumplirse la condición de se produzca el bucle “(i>5)”

 

Félix Maocho

indice

Anuncios

28 febrero 2017 - Posted by | Curso de Arduino | , , ,

Aún no hay comentarios.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: