| Per començar | Elements d'entrada | Programació CircuitPython | Recursos CITCEA | |
| Elements no electrònics | Elements de sortida | Programació Arduino | ||
| Projectes | Elements de control | Dades pràctiques | Inici |
Es tracta d'una samarreta per a corredors que informa sobre el recorregut que manca per fer i dóna missatges motivadors. Abans de sortir, el corredor indica amb un polsador la distància (en múltiples de 500 m). La distància introduïda es visualitza en un Neo Pixel ring de manera que cada LED encès són 500 m. Per poder fer distàncies superiors a 8 km, el color dels LED canvia a les següents voltes. Si ens trobem entre 0,5 i 8 km el color dels LED serà el vermell, entre 8,5 i 16 km el blau, entre 16,5 i 24 km el verd, entre 24,5 i 32 km el lila, entre 32,5 i 40 km el groc i entre 40,5 i 48 m seran LED de color verd blavós. A mesura que el corredor va fent kilòmetres, els LED es va apagant o canviant de color segons correspongui, de manera que els LED encesos indiquen sempre la distància que manca encara.
La mesura de la distància es fa a partir de la lectura d'un sensor GPS. El sensor fa una lectura cada segon i amb la velocitat mesurada pel sensor se sap el tros recorregut en aquest segon.
Per poder donar missatges motivadors al corredor i posar-li una música que l'acompanyi, s'ha emprat una placa LilyPad MP3 connectada a uns auriculars.
La llista de materials principals és la següent:
1 Neo Pixel ring de 16 LED
1 Polsador
1 Resistència de 10 kΩ
La figura següent mostra l'esquema del circuit:

El Neo Pixel ring va muntat a la màniga de la camiseta, prop del canell i el polsador està en el seu centre. La resta d'elements van situats en les butxaques posteriors de la camiseta.
El prototip va quedar com es mostra a la fotografia següent.

Per calcular les distàncies es fa servir la fórmula del haversine. A continuació tenim el llistat del programa:
#include <SoftwareSerial.h> //GPS #include <Adafruit_GPS.h> #include <Adafruit_NeoPixel.h>
Adafruit_GPS SensorGPS(&Serial1); // Definimos el sensor y le decimos que utilice la conexión Serial1 boolean usingInterrupt = false; // No usaremos interrupciones //La función millis() nos va dando el tiempo transcurrido en milisegundos // Cuando el valor ya no cabe (al cabo de unos 50 días) se reinicia (vuelve a cero) uint32_t timer = millis(); //Variable que guarda información del tiempo char dades = SensorGPS.read(); //Leemos los datos del GPS float lati=SensorGPS.latitude; //Guardamos la latitud inicial float loni=SensorGPS.longitude; //Guardamos la longitud inicial float lata=lati; //Latitud actual es la latitud inicial float lona=loni; //Longitud actual es la longitud inicial float d=0; //Distancia por Haversine float d1=0; //Distancia por velocidad float d2=0; //Distancia temporizada para hacer pruebas //NeoPixel Ring + Pulsador Adafruit_NeoPixel cadena = Adafruit_NeoPixel (16, 10, NEO_GRB + NEO_KHZ800); // NeoPixel Ring de 16 LED en la D10 int pols = 12; //Pulsador en la D12 int lectura; int l=0; //Número de LED encendidos //LilyPad MP3 float d3=0; //Distancia para introducir el mensaje motivador //La función millis() nos va dando el tiempo transcurrido en milisegundos // Cuando el valor ya no cabe (al cabo de unos 50 días) se reinicia (vuelve a cero) uint32_t timer2=millis(); //Variable que guarda información del tiempo uint32_t timer3=millis(); //Variable que guarda información del tiempo
//Función de Haversine
float HaverSine(float lat1, float lon1, float lat2, float lon2){
float ToRad = PI/180.0; //Conversión a radianes
float R = 6371000; //Radio de la Tierra en metros
float dLat = (lat2-lat1) * ToRad;
float dLon = (lon2-lon1) * ToRad;
float a = sin(dLat/2)*sin(dLat/2)+cos(lat1*ToRad)*cos(lat2*ToRad)*sin(dLon/2)*
sin(dLon/2);
float c = 2*atan2(sqrt(a), sqrt(1-a));
float d = R*c;
return d;
}
void setup() {
//GPS
Serial.begin(115200); //Comunicación con el ordenador
SensorGPS.begin(9600); //Comunicación con el sensor GPS
SensorGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); //Configuración del sensor
SensorGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); //El sensor envía datos una vez cada segundo (1 Hz)
delay(1000); //Esperamos un segundo a que el GPS se inicialice con la configuración
//NeoPixel Ring + Pulsador
pinMode(pols, INPUT); //El pulsador es una entrada
cadena.begin(); //Inicializa los NeoPixels
cadena.show();
//LilyPadMP3
pinMode(6,OUTPUT); //D6 es una salida
pinMode(9,OUTPUT); //D9 es una salida
digitalWrite(9,LOW);
delay(700);
digitalWrite(9,HIGH);
//Comienza a sonar la música
}
void loop() {
//GPS
char dades = SensorGPS.read(); //Leemos los datos del sensor GPS
if (SensorGPS.newNMEAreceived()){ //Si han llegado los datos del sensor, envía los datos leídos al ordenador
if (!SensorGPS.parse(SensorGPS.lastNMEA())){ //Mira si los datos tienen información útil
return; // Si no hay datos útiles vuelve a empezar el loop
}
}
//Si timer es más grande que millis quiere decir que millis se ha reiniciado, entonces volvemos a inicializar el timer
if (timer > millis()) {
timer = millis();
}
if (millis() - timer > 1000){
//Si la diferencia es más grande que 1000 quiere decir que ha pasado más de 1 s
d2=d2+501; //Distancia de prueba
//Velocidad
float v = SensorGPS.speed/3.6; //Velocidad en m/s
d1 = d1+(v*1); //Distancia calculada a partir de la velocidad del GPS (velocidad*tiempo(= 1s))
//Haversine
d = d+HaverSine(lati,loni,lata,lona); //Distancia calculada a partir de la fórmula de Haversine
lati = lata; //Latitud inicial pasa a ser latitud actual
loni = lona; //Longitud inicial pasa a ser longitud actual
lata = SensorGPS.latitude; //Latitud actual pasa a ser la leída por el GPS
lona = SensorGPS.longitude; //Longitud actual pasa a ser la leída por el GPS
//Reiniciamos el timer
timer = millis();
}
//}
//NeoPixel Ring + Pulsador
lectura = digitalRead(pols); //Leemos el pulsador
//Para encender los LED
if (lectura == HIGH){ //Si el pulsador está pulsado
if (0 <= l < 16){ //Ronda 1
cadena.setPixelColor(l, 200, 0, 0); //Pixel l al rojo
}
if (15 < l < 32){ //Ronda 2
cadena.setPixelColor(l-16, 0, 0, 200); //Pixel l al azul
}
if (31 < l < 48){ //Ronda 3
cadena.setPixelColor(l-32, 0, 200, 0); //Pixel l al verde
}
if (47 < l < 64){ //Ronda 4
cadena.setPixelColor(l-48, 150, 0 , 150); //Pixel l al lila
}
if (63 < l < 80){ //Ronda 5
cadena.setPixelColor(l-64, 150, 150, 0); //Pixel l al amarillo
}
if (79 < l < 96){ //Ronda 6
cadena.setPixelColor(l-80, 38, 138, 93); //Pixel l al verde azulado
}
l = l + 1; //Sumamos pulsaciones
d3=l; //Variable que se utiliza para el LilyPad MP3
cadena.show();
delay(250); //Esperamos un poco antes de volver a mirar el pulsador
}
//Para apagar
if (d1 > 500) { //Si cambiamos d1 por d2 podemos probar si funcionan los LED sin necesidad de señal GPS
if (79 < l < 96){
cadena.setPixelColor(l-80, 150, 150, 0); //Pixel l vuelve al amarillo
}
if (63 < l < 80){
cadena.setPixelColor(l-64, 150, 0, 150); //Pixel l vuelve al lila
}
if (47 < l < 64){
cadena.setPixelColor(l-48, 0, 200, 0); //Pixel l vuelve al verde
}
if (31 < l < 48){
cadena.setPixelColor(l-32, 0, 0, 200); //Pixel l vuelve al azul
}
if (15 < l < 32){
cadena.setPixelColor(l-16, 200, 0, 0); //Pixel l vuelve al rojo
}
if (0 <= l < 16){
cadena.setPixelColor(l, 0, 0, 0); //Pixel l se apaga
}
d1 = 0; //Si cambiamos d1 por d2 podemos hacer pruebas sin de señal GPS
l = l - 1;
cadena.show();
}
//LilyPad MP3
if (l/d3 < 0.1 and d3 > 5){ //Cuando queda un 10 % de la carreara se activa el mensaje motivador
digitalWrite(6,LOW);
delay(700);
digitalWrite(6,HIGH);
timer3=millis();
}
if (millis()-timer3 > 79000){ //Cuando acaba el mensaje motivador, despuéss de t = ms(mensaje motivador)+ ms(margen), activamos otra vez la música
digitalWrite(9,LOW);
delay(700);
digitalWrite(9,HIGH);
float timer3=9999999999999999;
}
}
En aquest web, les fotografies marcades amb [AF] són del web d'Adafruit, les marcades amb [SF] del web d'Sparkfun i les marcades amb [AU] del web d'Arduino.

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.