Tecnologia vestible

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

Sensor GPS

El sensor GPS ens permet conèixer la nostra posició geogràfica actual però també ens facilita tota una sèrie de dades addicionals com l'hora actual, l'orientació (angle respecte al nord), l'altitud i la velocitat de desplaçament.

Sensor GPS

El Sensor GPS es comunica amb el microcontrolador amb una connexiò sèrie (la mateixa que fa servir el monitor sèrie). Cal connectar, a més de l'alimentació, la pota TX del sensor amb la RX del microcontrolador i la pota RX del sensor amb la TX del microcontrolador. La figura següent mostra com connectar-lo:

Connexió del sensor GPS

Cal tenir present que el sensor GPS requereix rebre informació des dels satèl·lits del sistema GPS. Per tant cal que estigui a l'exterior o al costat d'una finestra des de la que pugui veure un nombre suficient de satèl·lits.

Els punts de connexió de la placa del sensor GPS són els següents:

Pota Utilització Comentaris
3.3 V Positiu de l'alimentació
GND Negatiu de l'alimentació
TX Transmissió de dades Comunicaciò sèrie
RX Recepció de dades
FIX Connectat als satèl·lits La sortida està desactivada (GND) quan hi ha connexió
i està intermitent si no n'hi ha.
La placa porta un LED connectat a aquesta pota.
BAT Positiu de la bateria Possibilitat de connectar-hi una bateria d'entre 3 i 3,3 V

La funció de la bateria és alimentar el sensor quan no està alimentat el microcontrolador. Amb la bateria el sensor pot mantenir informació de l'hora exacta. Mentre el sensor s'alimenta per la pota BAT només funciona el seu rellotge intern i no es comunica ni amb els satèl·lits ni amb el microcontrolador.

La pota fix la podríem connectar a una entrada del microcontrolador i així ens podríem estalviar de comunicar-nos amb el sensor mentre no està connectat amb els satèl·lits.

En el programa que presentem a continuació podem provar la comunicació del microcontrolador amb el sensor i analitzar les dades que rebem. El probrama obre dos canals sèrie i mira per quin dels dos es reben dades. Quan detecta que un dels canals rep dades les llegeix i les envia cap a l'altre (que suposa que és el monitor sèrie).

void setup() {
	while (!Serial); {
		// Esperem a que hi hagi la connexió sèrie connectada
  }
  		// Obrim dues connexions sèrie, una per al GPS i una amb l'ordinador
		// però no sabem quina és quina
	Serial.begin(9600);	// Primera comunicació sèrie
	Serial1.begin(9600);	// Segona comunicació sèrie
}
void loop() {
	if (Serial.available()) {		// Mira si estan arribant dades per aquesta connexió
		char dades = Serial.read();	// Llegeix les dades i les guarda a una variable
		Serial1.write(dades);		// I les mostra per l'altra connexió,
						// que correspondrà a l'ordinador
	}
	if (Serial1.available()) {		// Mira si estan arribant dades per aquesta connexió
		char dades = Serial1.read();	// Llegeix les dades i les guarda a una variable
		Serial.write(dades);		// I les mostra per l'altra connexió,
						// que correspondrà a l'ordinador
	}
}

Un programa similar en CircuitPython seria el següent

import board
import busio
import digitalio
# LED de la placa
led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT
# Comunicacio serie
serie = busio.UART(board.TX, board.RX, baudrate=9600)
while True:
    # Llegim les dades
    lectura = serie.read(32)  # Llegim fins a 32 bytes
    if lectura is not None:
        led.value = True
        # Convertim a una cadena de caracters
        lectura_text = ''.join([chr(b) for b in lectura])
        print(lectura_text, end="")
        led.value = False

Per exemple, posant el sensor al costat de la finestra del meu despatx vaig rebre, entre altres, les següents dades:

	$GPRMC,141159.000,A,4123.0481,N,00206.9632,E,0.16,295.02,181214,,,D*65
	$GPGGA,141159.000,4123.0481,N,00206.9632,E,2,09,1.14,88.8,M,51.3,M,0000,0000*57

La primera línia ($GPRMC) correspon a les dades mínimes recomanades i la segona ens aporta informació addicional. Anem a analitzar la informació rebuda a la primera línia:

Dades del sensor GPS

Observem com convertir les dades rebudes en informació útil. L'hora actual té les hores, els minuts i els segons abans del punt i les mil·lèsimes de segon després del punt. L'hora indicada és la del meridià de Greenwich o hora GMT que correspon a la nostra hora solar. La nostra hora oficial la podem obtenir sumant 1 a l'hora GMT a l'hivern i sumant-hi 2 a l'estiu.

Hora GPS

Si ens surt una A després de l'hora és que les dades són vàlides. En cas contrari surt una V.

La latitud és l'angle del punt considerat respecte a l'equador. Una latitud zero correspon a l'equador, les latituds positives a punts situats al nord de l'equador i les negatives a punt situats al sud. Els angles de 90 graus (positius o negatius) corresponen als pols. La latitud no pot ser més gran de +90° ni més petita de -90°. A la latitud les dues primeres xifres són els graus i les següents són els minuts. Si la latitud és positiva (nord) surt una N i si és negativa (sud) una S.

Latitud

La longitud correspon a l'angle, dibuixat a l'equador, del punt considerat respecte al meridià de Greenwich. A la longitud les tres primeres xifres són els graus i les següents són els minuts. Si la longitud és positiva (est) surt una E i si és negativa (oest) una W.

Longitud

Les coordenades que rebem directament del sensor no ens serveixen per a la majoria d'aplicacions (per exemple Google Maps) i cal convertir-les. Per exemple, Google Maps no entendrà les coordenades així:

      4123.0481 N, 00206.9632 E

Però sí que les entén d'aquesta altra manera:

      41° 23.0481, 002° 06.9632

Segons el que volguem fer, ens caldrà passar les coordenades a unes unitats diferents. Per fer comparacions ens serà útil tenir-les en una única unitat (graus, minuts o segons). Per fer càlculs, normalment, serà preferible passar-les a radians que és com treballen les funcions trigonomètriques disponibles als microcontroladors.

Si necessitem calcular la distància entre dos punts podem fer servir la fórmula del haversine.

La velocitat de desplaçament es mesura en nusos (knot). Cal multiplicar el valor per 1,852 per obtenir la velocitat en km/h.

Velocitat

L'orientació ens diu l'angle (en graus) respecte al nord.

Orientació

Finalment tenim la data amb l'any indicat amb només dues xifres.

Data

Una part de la informació de la segona línia és redundant.

Dades del sensor GPS

A més hi podem trobar la qualitat del senyal rebut, el nombre de satèl·lits detectats i l'altitud en metres.

Altitud

Per fer servir el sensor en l'entorn Arduino ens convindrà la Adafruit-GPS-Library que ens facilita molt la feina ja que ens dóna les dades per separat. Si és necessari, podeu consultar la instal·lació de biblioteques. Un cop ja tinguem la biblioteca, podem fer els nostres programes. Les diferents dades que podem demanar (suposant que hem definit el sensor amb el nom sensorGPS) són:

Tipus Comanda Utilitat
Configuració sensorGPS.begin(velocitat) Inicialitza el sensor GPS i defineix la velocitat de comunicació
sensorGPS.sendCommand(comanda) Envia una comanda de configuració
sensorGPS.lastNMEA() Dades del sensor en brut
Cobertura sensorGPS.parse(sensorGPS.lastNMEA()) Torna true si les dades són útils
sensorGPS.fix Dóna 0 si no ha trobat prou satèl·lits
sensorGPS.fixquality Qualitat del senyal
sensorGPS.satellites Nombre de satèl·lits
Hora GMT sensorGPS.hour Hora
sensorGPS.minute Minuts
sensorGPS.seconds Segons
sensorGPS.milliseconds Mil·lisegons
Data sensorGPS.day Dia
sensorGPS.month Mes
sensorGPS.year Any (dues xifres)
Coordenades sensorGPS.latitude Latitud en el format del sensor
sensorGPS.lat Sentit de la latitud (N o S)
sensorGPS.longitude Longitud en el format del sensor
sensorGPS.lon Sentit de la longitud (E o W)
Altres dades sensorGPS.speed Velocitat (en nusos)
sensorGPS.angle Orientació (en graus)
sensorGPS.altitude Altitud (en metres)

A continuació tenim un programa bàsic que llegeix les dades del sensor i les envia al monitor sèrie.

Inicialment inclou les biblioteques del sensor GPS i de la comunicació sèrie. Després defineix un objecte corresponent al sensor (en el que hem d'indicar la comunicació sèrie que farà servir), una variable per controlar el temps i una per indicar si farem servir interrupcions que definirem com a false perquè no les farem servir.

En el setup obrim una comunicació sèrie amb l'ordinador, inicialitzem i configurem el sensor GPS i esperem un segon a que el sensor es reconfiguri.

En el bucle loop llegim el sensor i mirem si han arribat dades correctes. Si no han arribat dades tornem a començar el loop fins que arribin. Per no saturar la comunicació, només tractem les dades cada dos segons. Això ho fem guardant el valor inicial de la funció millis en una variable i comparant-los. Quan la diferència sigui més gran que 2000 vol dir que ja han passat dos segons. També vigilem que millis no s'hagi reinicialitzat i si és el cas actualitzem la variable.

Cada dos segons mostrem les dades llegides. Primer mostrem les dades tal com han arribat i seguidament hi ha aquelles que es poden obtenir amb pocs satèl·lits detectats i després aquelles que requereixen més satèl·lits i que només mostrarem si SensorGPS.fix està a 1 que vol dir que hem pogut connectar amb el mínim nombre de satèl·lits necessàris.

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
Adafruit_GPS SensorGPS(&Serial1);	// Definim el sensor i li diem que faci servir la connexió Serial1
boolean usingInterrupt = false;		// No farem servir interrupcions
		// La funció millis() ens va donant el temps transcorregut en mil·lisegons
		// Quan el valor ja no hi cap (al cap d'uns 50 dies) es reinicialitza (torna a zero)
uint32_t timer = millis();		// Variable que guarda informació del temps
void setup() {
	Serial.begin(115200);		// Comunicació amb l'ordinador
	SensorGPS.begin(9600);		// Comunicació amb el sensor GPS
	SensorGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);	// Configuració del sensor
	SensorGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // El sensor envia dades un cop cada segon (1 Hz)
	delay(1000);		// Espera un segon a que el GPS s'inicialitzi amb la configuració
}
void loop() {
	char dades = SensorGPS.read();	// Llegim dades del Sensor GPS
	if (SensorGPS.newNMEAreceived()) {		// Si han arribat dades del sensor
		Serial.println(SensorGPS.lastNMEA());   // Envia a l'ordinador les dades llegides
		if (!SensorGPS.parse(SensorGPS.lastNMEA())) {   // Mira si les dades tenen informació útil
			return;  // Si no, torna a començar el loop per llegir dades noves
		}
	}
		// Si timer és més gran que millis vol dir que millis s'ha reiniciat
		// Llavors tornem a inicialitzar timer
	if (timer > millis()) {
		timer = millis();
	}
 	if (millis() - timer > 2000) {  // Si la diferència és més gran que 2000 vol dir
					// que han passat més de 2 s
		timer = millis();	// Reiniciem timer
		Serial.println();		// Una línia en blanc
			// Enviem dades de la connexió
		Serial.print("Connectat: ");
		Serial.println((int)SensorGPS.fix);	// Serà 0 si no ha trobat prou satèl·lits
		Serial.print("Qualitat del senyal: ");
		Serial.println((int)SensorGPS.fixquality); 
			// Enviem l'hora
		Serial.print("Hora actual: ");
		Serial.print(SensorGPS.hour, DEC);
		Serial.print(".");
		Serial.print(SensorGPS.minute, DEC);
		Serial.print(".");
		Serial.print(SensorGPS.seconds, DEC);
		Serial.print(",");
		Serial.print(SensorGPS.milliseconds);	// Acabada l'hora, fem un salt de línia
		Serial.println(" GMT");
			// Enviem la data
		Serial.print("Data actual: ");
		Serial.print(SensorGPS.day, DEC);
		Serial.print("-");
		Serial.print(SensorGPS.month, DEC);
		Serial.print("-20");		// Envia l'any amb dues xifres
		Serial.println(SensorGPS.year, DEC);		// Acabada la data, fem un salt de línia
		if (SensorGPS.fix) {	// El que segueix no té sentit si no ha trobat prou satèl·lits
			Serial.print("Sats: ");		// Nombre de satèl·lits
			Serial.println((int)SensorGPS.satellites);
			// Dades de posició
			Serial.print("Coordenades: ");
			Serial.print(SensorGPS.latitude, 4);	// Angle latitud amb quatre decimals
			Serial.print(SensorGPS.lat);		// Lletra latitud
			Serial.print(", "); 
			Serial.print(SensorGPS.longitude, 4);	// Angle longitud amb quatre decimals
			Serial.println(SensorGPS.lon);		// Lletra longitud
			// Altres dades
			Serial.print("Velocitat: ");
			Serial.print(SensorGPS.speed);
			Serial.println(" nusos");
			Serial.print("Velocitat: ");
			Serial.print(1.852*SensorGPS.speed);
			Serial.println(" km/h");
			Serial.print("Angle respecte al nord: ");
			Serial.print(SensorGPS.angle);
			Serial.println(" graus");
			Serial.print("Altitud: ");
			Serial.print(SensorGPS.altitude);
			Serial.println(" m");
    }
  }
}

A continuació hi ha un exemple del que s'ha mostrat pel monitor sèrie a l'executar aquest programa:

	Connectat: 1
	Qualitat del senyal: 2
	Hora actual: 14.11.59,0 GMT
	Data actual: 18-12-2014
	Sats: 9
	Coordenades: 4123.0483N, 206.9632E
	Velocitat: 0.16 nusos
	Velocitat: 0.30 km/h
	Angle respecte al nord: 295.02 graus
	Altitud: 88.80 m

Per fer servir el sensor en CircuitPython ens convindrà la biblioteca adafruit_gps.mpy que ens facilita molt la feina ja que ens dóna les dades per separat. Si és necessari, podeu consultar la instal·lació de biblioteques. Un cop ja tinguem la biblioteca, podem fer els nostres programes. Les diferents dades que podem demanar (suposant que hem definit el sensor amb el nom gps) són:

Tipus Comanda Utilitat
Configuració gps.send_command(comanda) Envia una comanda de configuració
gps.update() Llegeix les dades del sensor
Cobertura gps.has_fix Dóna 0 si no ha trobat prou satèl·lits
gps.fix_quality Qualitat del senyal
gps.satellites Nombre de satèl·lits
Hora GMT gps.timestamp_utc.tm_hour Hora
gps.timestamp_utc.tm_min Minuts
gps.timestamp_utc.tm_sec Segons
Data gps.timestamp_utc.tm_mday Dia
gps.timestamp_utc.tm_mon Mes
gps.timestamp_utc.tm_year Any (dues xifres)
Coordenades gps.latitude Latitud en el format del sensor
gps.longitude Longitud en el format del sensor
Altres dades gps.speed_knots Velocitat (en nusos)
gps.altitude_m Altitud (en metres)

import time
import board
import busio
import adafruit_gps
# Crea un canal serie per comunicar amb el sensor
# Posem un timeout raonable per llegir cada segon
uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=3000)
# Crea un objecte GPS
gps = adafruit_gps.GPS(uart)
# Configura la comunicacio amb el sensor en el format mes habitual
gps.send_command(b'PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
# I llegint valors cada segon (1000 ms)
gps.send_command(b'PMTK220,1000')
darrer_valor = time.monotonic()
while True:
    # Llegim el sensor
    # La lectura nomes sera diferent si ha passat mes d'un segon
    # ja que hem dit que llegeixi cada segon
    gps.update()
    # Mirem la marca de temps de la darrera lectura
    actual = time.monotonic()
    if actual - darrer_valor >= 1.0:    # Ha passat 1 s?
        darrer_valor = actual
        if not gps.has_fix:
            # Encara no tenim un senyal estable
            print('Esperant un valor estable...')
        else:
            # Tenim un senyal estable
            print('')    # Linia de separacio
            print('Qualitat del senyal: ', gps.fix_quality)
            print('Hora actual: {:02}.{:02}.{:02} GMT'.format(
                gps.timestamp_utc.tm_hour,
                gps.timestamp_utc.tm_min,
                gps.timestamp_utc.tm_sec))
            print('Data actual: {}-{}-{}'.format(
                gps.timestamp_utc.tm_mday,
                gps.timestamp_utc.tm_mon,
                gps.timestamp_utc.tm_year))
            if gps.satellites is not None:
                print('Sats: ', gps.satellites)
            print('Latitud: ', gps.latitude, ' graus')
            print('Longitud: ', gps.longitude, ' graus')
            if gps.speed_knots is not None:
                print('Velocitat: ', gps.speed_knots, ' nusos')
            if gps.speed_knots is not None:
                print('Velocitat: ', 1.852*gps.speed_knots, ' km/h')
            if gps.altitude_m is not None:
                print('Altitud: ', gps.altitude_m, ' m')

A continuació hi ha un exemple del que s'ha mostrat pel monitor sèrie a l'executar aquest programa:

Qualitat del senyal:  1
Hora actual: 14.11.59 GMT
Data actual: 12-07-2018
Sats:  6
Latitud:  41.2305  graus
Longitud:  2.06963  graus
Velocitat:  0.0  nusos
Velocitat:  0.0  km/h
Altitud:  88.8  m

 

 

 

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.

 

 

 

 

 

 

 

 

 

 

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