Grupo 16 Arduino Traffic Clock
Tabla de contenido
Introducción y presentación del proyecto:
Nombre del proyecto: Arduino Traffic Clock
Su nombre lo describe a la perfección ya que se trata de un proyecto que consiste en despertar a una persona a la hora indicada para poder llegar a la hora deseada a algún lugar que haya elegido.
Para ello el usuario debe introducir la hora a la que desea llegar, el tiempo que tarda en prepararse para salir, desde donde sale y a dónde va.
Con estos datos, nuestro proyecto logra calcular la hora a la que debe despertarse actualizando constantemente el tiempo de tráfico. El despertador sólo sonará una vez puesto que si al actualizar de nuevo el tráfico, el tiempo se ha reducido en 2 minutos, sonaría otra vez y así constantemente.
Nuestro proyecto consta de una pantalla principal que mostrará la hora y el tráfico de la ruta indicada en ese momento. Por otro lado tendrá 3 leds: uno rojo, uno amarillo y uno verde. El led verde se encenderá cuando el tiempo de la ruta con el tráfico supere al tiempo de la ruta sin tráfico, en 10 minutos o menos. Si este tiempo supera los 10 minutos pero no los 20, se encenderá el led amarillo. Por último el led rojo se encenderá cuando el tráfico suponga una retención de 10 minutos o superior teniendo en cuenta que calculará estos tiempos sobre la ruta más corta.
También tendremos la pantalla que permite indicar la hora de llegada gracias a una tecla de la aplicación 1sheeld que explicaremos más adelante. Finalmente podemos indicar el tiempo que tarda en arreglarse y finalmente escribir la dirección del origen y el destino.
Materiales utilizados, función y colocación
Arduino UNO:
Esta placa es la base de nuestro proyecto ya que en ella conectamos la placa 1sheeld y donde conectamos la fuente de alimentación.
1Sheeld:
Se usa con la placa anteriormente descrita ya que por sí sola no funcionaría. Esta placa funciona a través de una aplicación con su mismo nombre que nos permite conectarnos con un dispositivo móvil y obtener diferentes datos además de interactuar con ella mediante el bluetooth.
Utilizamos la aplicación para que nuestro proyecto muestre la hora del dispositivo, escribir los tiempos con su teclado, moverse entre pantallas y conectarse a internet para obtener los datos del tráfico de la ruta indicada.
Además los cables irán conectados a sus pines para hacer funcionar todo los que se conecte a las protoboards.
Protoboard:
Utilizamos 2 porque nos es más fácil conectarlo de esa forma. En estas protoboards tenemos conectados los pines de la pantalla LCD, los leds con sus resistencias y el piezoeléctrico.
Cables:
Hemos utilizado cables de un solo hilo ya que es más fácil conectarlos en la protoboard y en la 1sheeld. Al principio hemos utilizado los cables de colores porque era más fácil distinguir los pines conectados pero al final los cambiamos por cables blancos de un rollo que teníamos y podíamos cortar la medida que nos viniese mejor.
Este último paso fue necesario porque los cables de colores que teníamos eran muy cortos para adaptarlo en la caja que lo adorna.
Resistencias:
Nuestro proyecto tiene 4 resistencias iguales de 220 ohms y colores: naranja, naranja, café, dorado. Son necesarias para rebajar la tensión de los leds y el piezoeléctrico. Siempre van conectadas entre estos elementos y los pines analógicos de la pantalla LCD lo cuales están unidos por otro cable con los pines correspondientes de la 1Sheeld.
Leds:
Hemos elegido los leds de 5 mm de diámetro pero también valen de 3 o de 10. Tenemos 3 colores, uno para cada estado del tráfico.
Piezoeléctrico:
Nos permite escuchar la música que introduzcamos en código para que suene el despertador. Como antes hemos comentado se conecta con una resistencia por el cable rojo que a su vez está conectado con el pin analógico elegido, y el cable negro conectado a tierra.
Fuente de alimentación:
Al principio, mientras implementábamos el código y probábamos el proyecto, conectamos la placa de arduino UNO al ordenador pero para transportarlo utilizamos una batería portátil de 5V. Este dato es importante porque debe rondar este valor para que funcione correctamente.
Esbozo del diseño:
Este circuito es el correspondiente a las descripciones de los materiales nombrados anteriormente y su conexión. Desgraciadamente en el programa utilizado para diseñarlo, no había una placa 1Sheeld que iría justo encima de la placa arduino UNO. Los pines de la 1Sheeld son exactos a los de la imagen por lo que no hay ningún tipo de confusión.
Descripción del código:
#define CUSTOM_SETTINGS
#define INCLUDE_CLOCK_SHIELD
#define INCLUDE_INTERNET_SHIELD
#define INCLUDE_KEYPAD_SHIELD
#define INCLUDE_KEYBOARD_SHIELD
#include <TimeLib.h>
/* Include 1Sheeld library. */
#include <OneSheeld.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
Esta primera parte del código importa las librerías necesarias para hacer funcionar todas las funciones. La última línea de este segment de código inicializa los pines de la pantalla LCD respecto a la placa 1Sheeld.
int hora = 0;
int minuto = 0;
int segundo = 0;
String url=»»;
String origen=»»;
String destino=»»;
int InternetError=0;
int ResponseError=0;
String traffic=»Trafico: «;
HttpRequest request(«https://maps.googleapis.com/maps/api/distancematrix/json?origins=Mostoles&destinations=Lisboa&departure_time=now&key=AIzaSyAnvRGrY5ZZIoXuGqsSuReY93ZYHuqkqDA»);
bool actualHora=true;
bool actualURL=true;
bool actualInternet=true;
bool conexion=false;
bool despertad=false;
bool primera1=true;
bool primera2=true;
bool primera3=true;
bool primera4=true;
bool primera5=true;
bool primera6=true;
bool p1=true;
bool p2=true;
bool tt=true;
bool ttttt=true;
int tiemp=0;
unsigned long previousMillis = 0; // Tiempo anterior 0
unsigned long timeToAction = 25000; // Tiempo de espera entre acciones, 1000ms
int cont=0;
int r=0;
//hora que tiene que tiene que estar en el destino
int h1=0;
int h2=0;
int m1=0;
int m2=0;
//tiempo que tarda en arreglarse
int ho1=0;
int ho2=0;
int mo1=0;
int mo2=0;
//Botones de pasar pantalla
int j=0;
int i=0;
int z=0;
int x=0;
int jj=0;
int zz=0;
int xx=0;
int ii=0;
int result=0;
int rlj=0;
int t_llegada=0;
int t_arreglo=0;
/* declaración de variables */
int spk=13; // altavoz a GND y pin 13
int c[5]={131,262,523,1046,2093}; // frecuencias 4 octavas de Do
int cs[5]={139,277,554,1108,2217}; // Do#
int d[5]={147,294,587,1175,2349}; // Re
int ds[5]={156,311,622,1244,2489}; // Re#
int e[5]={165,330,659,1319,2637}; // Mi
int f[5]={175,349,698,1397,2794}; // Fa
int fs[5]={185,370,740,1480,2960}; // Fa#
int g[5]={196,392,784,1568,3136}; // Sol
int gs[5]={208,415,831,1661,3322}; // Sol#
int a[5]={220,440,880,1760,3520}; // La
int as[5]={233,466,932,1866,3729}; // La#
int b[5]={247,494,988,1976,3951}; // Si
void nota(int a, int b);
Como podemos ver, después de importar hay que inicializar las variables necesarias. Entre ellas tenemos la hora, minutos y segundos. Además de todas las variables que hemos necesitado, destacamos http, request con la que conseguimos obtener los datos del tráfico de internet. Las últimas variables son las notas musicales para la melodía elegida y la llamada a la función nota.
void setup() {
/* Start communication. */
OneSheeld.begin();
/* Start the clock shield. */
Clock.queryDateAndTime();
// set up the LCD’s number of columns and rows:
lcd.begin(16, 2);
//inicializar internet
http();
/* LED pin modes OUTPUT.*/
pinMode(A3, OUTPUT);
pinMode(A5, OUTPUT);
pinMode(A4, OUTPUT);
}
Todo código de arduino necesita como mínimo dos métodos principales: el set up() y el loop(). Nos encontramos en el primero que utilizamos para conectar los pines de la placa 1Sheeld con la LCD.
void loop() {
unsigned long currentMilli = millis();
time_t t=now();
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(2)){//Si presionas # pasa a despertador
i=i+1;
i=i%2;
}
switch(i){
case 0: {
principal(currentMilli,t);
break;
}
case 1: {
Despertador();
break;
}
}
}
void onSuccess1(HttpResponse & response){
/* Using the response to query the Json chain till the required value. */
response[«rows»][0][«elements»][0].query();
}
void onJsonReply(JsonKeyChain & hell,char * output) {
char e[250]=»»;
for(int i=0;i<250;i++){
char a=*output;
output++;
e[i]=a;
}
int w=0;
int n=0;
for(int s=0;s<250;s++){
if((e[s]==’n’)&&(e[s+1]==’s’)){
for(int j=s;j<250;j++){
if((e[j]==’}’)&&(e[j+1]==’,’)){
int p=0;
for(int d=j;d>0;d–){
w=p-1;
if(e[d]==’:’){
for(int t=1;t<p;t++){
w=w-1;
int m=(e[d+t]);
m=m-48;
n=n+m*pow(10,w);
}
break;
}
p=p+1;
}
break;
}
}
break;
}
}
int v=0;
int l=0;
for(int s=0;s<250;s++){
if((e[s]==’i’)&&(e[s+1]==’c’)){
for(int j=s;j<250;j++){
if((e[j]==’}’)&&(e[j+1]==’,’)){
int p=0;
for(int d=j;d>0;d–){
v=p-1;
if(e[d]==’:’){
for(int t=1;t<p;t++){
v=v-1;
int m=(e[d+t]);
m=m-48;
l=l+m*pow(10,v);
}
break;
}
p=p+1;
}
break;
}
}
break;
}
}
int minstraf = l/60;
tiemp =minstraf;
int minsdur=n/60;
int rest=minstraf-minsdur;
if(rest>20) {
redLightsOn();
}
else if(rest<=10){
greenLightsOn();
}else if((rest>10)&&(rest<=20)){
yellowLightsOn();
}
}
Empezamos con un switch con 2 casos. Al presionar la tabla # que se sitúa en la posición (3,2), pasamos a la función despertador.
Los dos bucles for que están a continuación sirven para obtener dos datos del output. Uno de ellos es el tiempo de la ruta sin tráfico y el otro es el tiempo de la ruta con tráfico en ese momento.
Finalmente tenemos 3 sentencias con if que definen cuando deben encenderse los leds. En caso de que la diferencia entre los dos tiempos antes mencionados sea superior a 20 minutos se encenderá el led rojo lo que significa que hay una retención bastante lenta. Si esa diferencia es menor que 10 minutos se encenderá un led verde y finalmente si está entre estos dos tiempos se encenderá el led amarillo.
void greenLightsOn(){
digitalWrite(A3,LOW);digitalWrite(A4,LOW);digitalWrite(A5,HIGH);
}
void redLightsOn(){
digitalWrite(A3,HIGH);digitalWrite(A4,LOW);digitalWrite(A5,LOW);
}
void yellowLightsOn(){
digitalWrite(A3,LOW);digitalWrite(A4,HIGH);digitalWrite(A5,LOW);
}
void lightsOff(){
digitalWrite(A3,LOW);digitalWrite(A4,LOW);digitalWrite(A5,LOW);
}
En cada método definido anteriormente se ve que dependiendo del color se activa un pin u otro. El led rojo corresponde al pin A3, el verde al pin A5 y el amarillo al pin A4.
El último método mantiene los 3 leds apagados.
/* Error handling functions. */
void onResponseError(int errorNumber)
{
ResponseError=1;
}
void onInternetError(int requestId, int errorNumber)
{
InternetError=1;
}
void http(){
if(actualURL==true){
url=»https://maps.googleapis.com/maps/api/distancematrix/json?origins=»;
url.concat(origen);
url.concat(«&destinations=»);
url.concat(destino);
url.concat(«&departure_time=now&key=TU CLAVE DE GOOGLE MAPS MATRIX»);
request.setUrl(url.c_str());
actualURL=false;
}
request.setOnSuccess(&onSuccess1);
/* Subscribe to json value replies. */
request.getResponse().setOnJsonResponse(&onJsonReply);
/* Subscribe to response errors. */
request.getResponse().setOnError(&onResponseError);
/* Subscribe to Internet errors. */
Internet.setOnError(&onInternetError);
}
En los primeros métodos nos permiten ver si hay conexión a Internet y si ha podido acceder a la web para obtener los datos.
El método http lo utilizamos para que una vez introducido el origen y destino pueda obtener el fichero json de la web de googlemaps donde se encuentran el tiempo que se tarda, trafico, kilómetros…
void reloj (time_t hor){
/* Always get the date and time. */
lcd.setCursor(6, 0);
if (hour(hor) < 10) {
lcd.print(0);
lcd.print(hour(hor));
}
else {
lcd.print(hour(hor));
}
lcd.print(«:»);
if (minute(hor) < 10) {
lcd.print(0);
lcd.print(minute(hor));
}
else {
lcd.print(minute(hor));
}
}
Este método va imprimir el reloj en la pantalla lcd, el problema que teníamos es que si la hora era solo un número, no lo imprimía en el formato que de dos dígitos, solo de uno, por lo que hicimos fue añadir un 0 delante.
void principal(unsigned long currentMillis,time_t t){
if(OneSheeld.isAppConnected()){
if(tt==true){
hora = Clock.getHours();
minuto = Clock.getMinutes();
segundo= Clock.getSeconds();
tt==false;
setTime(hora,minuto,segundo+4,0,0,0);
}
reloj(t);
if((origen.length()!=0) && (destino.length()!=0)){
if(ttttt==true){
Internet.performGet(request);
request.setOnSuccess(&onSuccess1);
/* Subscribe to json value replies. */
request.getResponse().setOnJsonResponse(&onJsonReply);
/* Subscribe to response errors. */
request.getResponse().setOnError(&onResponseError);
/* Subscribe to Internet errors. */
Internet.setOnError(&onInternetError);
ttttt=false;
}
if(currentMillis – previousMillis >= timeToAction) {//Cuando llegue a 25000 milisegundos entra
if((InternetError==0)&&(ResponseError==0)){
Internet.performGet(request);
request.setOnSuccess(&onSuccess1);
/* Subscribe to json value replies. */
request.getResponse().setOnJsonResponse(&onJsonReply);
/* Subscribe to response errors. */
request.getResponse().setOnError(&onResponseError);
/* Subscribe to Internet errors. */
Internet.setOnError(&onInternetError);
delay(2000);
}
previousMillis = currentMillis;
}
if((InternetError==1)||(ResponseError==1)){
InternetError=0;
ResponseError=0;
Internet.performGet(request);
}
}
lcd.setCursor(0,1);
lcd.print(traffic.c_str());
lcd.print(tiemp);
lcd.print(«min»);
if(despertad==true){
t_arreglo=(((ho1*10)+ho2)*60)+((mo1*10)+mo2); //tmp arreglo minutos
t_llegada=(((h1*10)+h2)*60)+((m1*10)+m2);//tmp llegada minutos
result=t_llegada-t_arreglo-tiemp;
rlj=(hour(t)*60)+minute(t);
if(result==rlj){
Musica();
}
}
}
else{
lightsOff();
reloj(t);
}
}
Este es el método principal de nuestro arduino, aquí va a mostrar la hora sincronizando con el móvil además también calculamos la hora a la que tiene que sonar la alarma y llama al método música donde esta nuestra melodía, además se irá refrescando la web para obtener los datos mas actualizados utilizando el método millis que son los milisegundos del reloj interno de nuestro arduino, posibilitando asi la multitarea sin utilizar los delay que no nos permitiría encender a la vez los leds.
Además sino está conectado al móvil seguirá actualizando la hora como un reloj normal, lo podemos comprobar con un método de la onesheeld para ver si está conectado a la aplicación.
void Despertador(){
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(0)){//Si presionas * pone on/off
z=z+1;
z=z%2;
}
switch(z){
case 0: {
if(primera1==true){
lcd.clear();
primera1=false;
}
lcd.setCursor(0,0);
lcd.print(«Despertador: OFF»);
despertad=false;
borrarLinea();
break;
}
case 1: {
if(primera4==true){
lcd.clear();
primera4=false;
despertad=true;
lcd.print(«Despertador: ON»);
delay(5000);
}
horaLlegada();
break;
}
En el método despertador, si pulsas el botón * en nuestra keypad pondremos el despertador a on y nos llevara al método donde podremos la hora de llegada.
Si damos a la # otra vez iremos al método principal.
void horaLlegada(){
if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(3)){//Si presionas B
ii=ii+1;
ii=ii%2;
}
switch(ii){
case 0: {
if(primera2==true){
lcd.clear();
primera2=false;
lcd.print(«T.Llegar:»);
}
mostrar();
cambiarHora();
break;
}
case 1:{
p1=false;
horaArreglarse();
break;
}
}
}
void mostrar(){
if(p1==true){
lcd.setCursor(6, 1);
lcd.print(h1);
lcd.print(h2);
lcd.print(«:»);
lcd.print(m1);
lcd.print(m2);
}
}
void cambiarHora(){
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(3)){//Si presiona D pasa de numero
j=j+1;
j=j%4;
lcd.print(“ “);
lcd.print(j);
}
switch(j){
case 0:{
if(h2<4){
if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
h1=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
h1=2;
}
else if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
h1=0;
}
}else {
if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
h1=1;
}
else if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
h1=0;
}
}
mostrar();
break;
}
case 1:{
if(h1==2){
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
h2=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
h2=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
h2=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
h2=3;
}
} else {
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
h2=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
h2=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
h2=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
h2=3;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0)){
h2=4;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1)){
h2=5;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(2)){
h2=6;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(0)){
h2=7;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(1)){
h2=8;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(2)){
h2=9;
}
}
mostrar();
break;
}
case 2:{
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
m1=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
m1=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
m1=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
m1=3;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0)){
m1=4;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1)){
m1=5;
}
mostrar();
break;
}
case 3:{
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
m2=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
m2=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
m2=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
m2=3;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0)){
m2=4;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1)){
m2=5;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(2)){
m2=6;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(0)){
m2=7;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(1)){
m2=8;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(2)){
m2=9;
}
mostrar();
break;
}
}
}
Mediante estos métodos podemos introducir el tiempo que se tarda en llegar al destino, si pulsas el botón D del keypad puedes desplazarte por los números y poner la hora que se desee con el formato hh:mm. Se mostraría por pantalla los cambios que se van realizando.
Si pulsas el botón B iras a la pantalla de introducir el tiempo que tardas en arreglarte.
void horaArreglarse(){
if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(3)){//Si presionas A
x=x+1;
x=x%2;
}
switch(x){
case 0: {
if(primera3==true){
lcd.clear();
primera3=false;
lcd.print(«T.Arreglarse:»);
}
mostrar2();
cambiarHoraArreglar();
break;
}
case 1: {
p2=false;
introduceDireccion();
break;
}
}
}
void mostrar2(){
if(p2==true){
lcd.setCursor(6, 1);
lcd.print(ho1);
lcd.print(ho2);
lcd.print(«:»);
lcd.print(mo1);
lcd.print(mo2);
}
// delay(250);
}
void cambiarHoraArreglar(){
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(3)){//Si presiona D pasa de numero
jj=jj+1;
jj=jj%4;
lcd.print(“ “);
lcd.print(jj);
}
switch(jj){
case 0:{
if(ho2<4){
if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
ho1=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
ho1=2;
}
else if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
ho1=0;
}
}else {
if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
ho1=1;
}
else if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
ho1=0;
}
}
mostrar2();
break;
}
case 1:{
if(ho1==2){
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
ho2=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
ho2=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
ho2=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
ho2=3;
}
} else {
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
ho2=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
ho2=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
ho2=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
ho2=3;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0)){
ho2=4;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1)){
ho2=5;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(2)){
ho2=6;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(0)){
ho2=7;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(1)){
ho2=8;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(2)){
ho2=9;
}
}
mostrar2();
break;
}
case 2:{
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
mo1=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
mo1=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
mo1=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
mo1=3;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0)){
mo1=4;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1)){
mo1=5;
}
mostrar2();
break;
}
case 3:{
if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1)){
mo2=0;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0)){
mo2=1;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1)){
mo2=2;
}
else if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2)){
mo2=3;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0)){
mo2=4;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1)){
mo2=5;
}
else if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(2)){
mo2=6;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(0)){
mo2=7;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(1)){
mo2=8;
}
else if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(2)){
mo2=9;
}
mostrar2();
break;
}
}
}
Estos métodos van a hacer algo parecido al de antes pero el usuario va a introducir el tiempo que tarda en arreglarse pasando de valor a valor mediante el botón D del keypad, y se irá mostrando en la pantalla. Una vez que se tenga el tiempo correcto pulsará el botón A para ir al método de introducir dirección.
void introduceDireccion(){
if(primera5==true){
lcd.clear();
primera5=false;
x=x+1;
lcd.print(«Origen:»);
}
AsciiKeyboard.setOnButtonChange(&keyboardFunction1);
origen.replace(» «, «+»);
destino.replace(» «, «+»);
origen.replace(«‘», «,»);
destino.replace(«‘», «,»);
}
void keyboardFunction1(char data)
{
if(int(data)==10){
zz=zz+1;
zz=zz%3;
lcd.setCursor(0,1);
lcd.print(» «);
}
switch(zz){
case 0: {
int tm=origen.length();
if(tm==0){
lcd.clear();
lcd.print(«Origen:»);
}
if(int(data)==8){
origen.remove(tm-1);
tm=origen.length();
lcd.setCursor(tm%16,1);
lcd.print(» «);
if(tm==15){
lcd.clear();
lcd.print(«Origen:»);
lcd.setCursor(0,1);
lcd.print(origen);
}else if(tm==31){
lcd.clear();
lcd.print(«Origen:»);
lcd.setCursor(0,1);
lcd.print(origen.substring(16));
}
}else{
if((tm>=16)&&(tm<32)){
origen=origen+data;
lcd.clear();
lcd.print(«Origen:»);
lcd.setCursor(0,1);
lcd.print(origen.substring(16));
}else if((tm>=32)&&(tm<48)){
origen=origen+data;
lcd.clear();
lcd.print(«Origen:»);
lcd.setCursor(0,1);
lcd.print(origen.substring(32));
}else if(tm<16) {
origen=origen+data;
lcd.clear();
lcd.print(«Origen:»);
lcd.setCursor(0,1);
lcd.print(origen);
}
}
break;
}
case 1: {
if(primera6==true){
lcd.clear();
primera6=false;
lcd.print(«Destino:»);
}
int tm2=destino.length();
if(tm2==0){
lcd.clear();
lcd.print(«Destino:»);
}
if(int(data)==8){
destino.remove(tm2-1);
tm2=destino.length();
lcd.setCursor(tm2%16,1);
lcd.print(» «);
if(tm2==15){
lcd.clear();
lcd.print(«Destino:»);
lcd.setCursor(0,1);
lcd.print(destino);
}else if(tm2==31){
lcd.clear();
lcd.print(«Destino:»);
lcd.setCursor(0,1);
lcd.print(destino.substring(16));
}
}else{
if((tm2>=16)&&(tm2<32)){
destino=destino+data;
lcd.clear();
lcd.print(«Destino:»);
lcd.setCursor(0,1);
lcd.print(destino.substring(16));
}else if((tm2>=32)&&(tm2<48)){
destino=destino+data;
lcd.clear();
lcd.print(«Destino:»);
lcd.setCursor(0,1);
lcd.print(destino.substring(32));
}else if(tm2<16) {
destino=destino+data;
lcd.clear();
lcd.print(«Destino:»);
lcd.setCursor(0,1);
lcd.print(destino);
}
}
break;
}
case 2: {
lcd.clear();
i=0;
break;
}
}
}
Con esta parte del código podremos introducir con el teclado del móvil el origen y destino dando al enter para pasar del uno al otro, cuando se finalice, dando al enter te ira a la panty principal, en este punto lo que hicimos es permitir que el usuario pueda escribir 48 caracteres como dirección, de forma que ponga la dirección separado por <’> ya que en algunos teclados no aparecen las comas, y lo convertimos al formato correcto que nos pide googlemaps que es separado por <+>.
void Musica(){
nota(b[2], 500);
nota(e[3],1000);
nota(g[3], 250);
nota(fs[3],250);
nota(e[3],1000);
nota(b[3],500);
nota(a[3],1250);
nota(fs[3],1000);
nota(b[2], 500);
nota(e[3],1000);
nota(g[3],250);
nota(fs[3],250);
nota(d[3],1000);
nota(e[3],500 );
nota(b[2],1000 );
noTone(spk); delay(1000);
nota(b[2], 500);
nota(e[3],1000);
nota(g[3], 250);
nota(fs[3],250);
nota(e[3],1000);
nota(b[3],500);
nota(d[4],1000);
nota(cs[4],500);
nota(c[4],1000);
nota(a[3],500);
nota(c[4],1000);
nota(b[3],250);
nota(as[3],250);
nota(b[2],1000);
nota(g[3],500);
nota(e[3],1000);
noTone(spk);
delay(2000);
}
}
void nota(int frec, int t)
{
tone(A2,frec); // suena la nota frec recibida
delay(t); // para despues de un tiempo t
}
Por último estos métodos hacen que suene la melodía de Harry potter por piezo eléctrico mediante las frecuencias adecuadas, pudiéndose modificar por otro tipo de música en futuras versiones.
Entradas con las salidas esperadas:
Entrada 1: conexión de bluetooth del dispositivo móvil con el proyecto.
Salida 1: muestra en la pantalla principal, en la primera línea la hora en formato 00:00, y en la segunda línea la frase Tráfico: 00:00.
Entrada 2: en la aplicación de 1Sheeld presionar la tecla #.
Salida 2: En la pantalla LCD aparece lo siguiente:
Línea superior -> Despertador: OFF
Línea inferior -> vacía.
Entrada 3: la aplicación de 1Sheeld presionar la tecla *.
Salida 3: la pantalla LCD muestra Despertador ON. 5 segundos después aparecerá:
Línea superior: Hora llegada
Línea inferior: 00:00 (para cambiar estos valores vamos pulsando la D y el número)
Entrada 4: en la aplicación presionar la tecla A.
Salida 4: la pantalla LCD muestra:
Línea superior: Tiempo Prepararse
Línea inferior: 00:00. (Para cambiar estos valores presionamos la tecla D y el número)
Entrada 5: en la aplicación presionar la tecla A.
Salida 5: en la pantalla LCD muestra:
Línea superior: Origen
Línea inferior: en blanco, aquí se escribe la dirección de origen con el teclado de la app.
Entrada 6: en la aplicación presionar la tecla enter.
Salida 6: en la pantalla LCD muestra:
Línea superior: Destino
Línea inferior: en blanco, se escribe la dirección de destino con el teclado de la app.
Entrada 7: en la aplicación presionar la tecla enter.
Salida 7: muestra la pantalla principal con la hora y el tráfico de esa ruta además de encender el led correspondiente.
Fotos de pasos intermedios:
Demostración en vídeo:
Problemas y soluciones:
Uno de los problemas más importantes que tuvimos fue integrar partes de código y que funcionara al mismo tiempo la actualización de la hora del dispositivo y el tiempo del tráfico.
Otro problema fue al intentar pasar de una pantalla a otra, lograr borrar los valores anteriores o modificar los números.
Posibles mejoras:
Se podría optimizar y organizar muchísimo el código pero no hemos tenido tiempo suficiente para ello.
Otra mejora del proyecto sería que al sonar una vez el despertador, se pudiera elegir que suene más tarde en caso de querer esperar a que el tráfico mejore.
También sería interesante poder elegir entre diferentes melodías o incluso poder importarlas desde el dispositivo.
La idea de mostrar la temperatura de del origen o destino en la pantalla sería una buena idea.
Obviamente, otra de las mejoras sería minimizar la estructura física del proyecto.
Conclusiones y comentarios:
En este proyecto hay que tener claro una serie de cosas:
- El tiempo de tráfico nos lo da google maps con los datos de origen y destino que debemos introducir en la aplicación.
- Para que se encienda el led correspondiente debe existir una función que reste el tiempo que tarda en llegar con tráfico y sin tráfico.
- El tráfico se calculará de una ruta en coche.
- La hora y el despertador se obtendrá de un dispositivo con internet y bluetooth.
- La canción del despertador sonará una sola vez cuando coincidan los tiempos calculados con la hora que se vaya actualizando.
- El led que corresponda en su momento se quedará encendido desde el momento en que se introduzcan todos los datos.
Como conclusión queremos añadir que es un proyecto complicado, que da muchos fallos de código con el que debemos tener muchísimo cuidado, que no tenemos la información suficiente para realizarlo y hay que ir probando continuamente las cosas que vamos modificando para ver si funciona o no. Las dudas que teníamos las hemos ido buscando en internet, sobretodo en el foro de Arduino Forum (muy útil). Como se puede deducir, el código ha sido lo más complicado pero nos ha encantado poder hacer algo útil y visible.
Bibliografía
Apuntes del aula virtual de universidad Rey Juan Carlos referentes a la asignatura Sistemas empotrados en tiempo real.
https://1sheeld.com/