Após ter visto um artigo sobre o Raspberry PI na atmosfera com o projecto Pi in the Sky, decidi, porque não experimentar ? No projeto eles usam uma placa de telemetria para dar informações sobre temperatura, pressão , etc.. Como não tenho acesso a nenhuma placa dessas, porque não fazer o mesmo, mas com componentes disponiveis no mercado? Então, começou a nascer este projeto.
English version
Em primeiro lugar, como localizar o Raspberry PI por GPS.

Material

Raspberry PI B/B+ (usei ambos)

2 GPSs (embora só seja necessário 1, experimentei com os dois)

GPS Receiver – EM-406A SiRF III (20 Channel) – Já não é fabricado

GY-NEO6MV2 Flight Controller GPS Module For Arduino EEPROM MWC APM 2.5

Ligações

Para ligar o(s) GPS(s) ao Raspberry PI precisamos de usar o GPIO. A tabela seguinte mostra os PINs para a versão B onde ligar o GPS.

Raspberry PIN GPS PIN
2 – 5v VIN/VCC
6 – GND GND
8 – TX RX
10 – RX TX

Nota: Reparar que o TX e o RX trocam quando se ligam ao GPS: RX -> TX e TX -> RX

Aqui fica o Pinout do Raspberry PI versão B

GPS GY-NEO6Mv2

GPSv2-3

GPSv2-2

 

Ligação do GPS GY-NEO6Mv2 ao PI

GPS PI

Algumas imagens das ligações do GPS ao Raspberry PI versão B

GPSv2-1 GPIO2 GPIO1

GPS EM-406A

Para ligar o GPS EM-406A precisei de comprar um cabo JST SH Jumper 6 – de 6 pins para encaixar no GPS – embora só sejam necessários 4 pins.

JST-SH6

Esquema das ligações do GPS EM-406A

EM406

GPIOBplus3GPIOBplusEM401

Neste caso, o GPS EM-406A foi ligado a um Raspberry PI B+. Os PINs no GPS são ambos os mesmos e as ligações iguais. A unica coisa que muda é o GPIO do RPI B+.

GPIOBplus2

Ligar o PI e efetuar login

Assim que tiverem uma prompt, é necessário alterar umas configurações para que a UART esteja disponivel para o GPS, uma vez que é usada para permiter ligar-se a um terminal e autenticar-se.

Editar o ficheiro /boot/cmdline.txt e alterar:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

para

dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

 

Depois, editar o ficheiro inittab para comentar uma linha para que não seja lançada uma consola na ligação serie:

Comentar a seguinte linha (deverá ser a ultima):

#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

 

Após estas alterações, efetuar reboot ao PI

sudo reboot

 

Assim que possivel, instalar as aplicações para o GPS

sudo apt-get install gpsd gpsd-clients

 

Executar o gpsd

gsudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock

 

Executar o cliente e esperar que o GPS funcione

cgps -s

 

E ao final de alguns segundos (talvez mais – sair do cgps e voltar a entrar) devem conseguir sinal.

Poupar energia

Podem-se poupar cerca de 20mA (mais ou menos) desligando a saída PAL/HDMI (partindo do principio que não vamos usar) .

Para tal, basta adicionar a linha seguinte ao arranque (Geralmente adicionando a linha ao ficheiro /etc/rc.local)

/opt/vc/bin/tvservice -off

dica via http://www.daveakerman.com/?page_id=1294

Atualizar um mapa com a posição corrente do Raspberry PI

Não serve de nada ter um GPS ligado ao PI se não for para criar uns pontos e uns trilhos com ele.

Criar um mapa com as coordenadas GPS

Agora que já temos os módulos de python para o GPS, vamos usar para reportar as coordenadas.

Como vai o PI fazer isto? Bem, a minha solução foi, com um servidor web, a aplicação em Python coloca as coordenadas num diretório especifico e a aplicação web a correr num outro computador (ou no PI – mais à frente esta solução) vai aceder ao PI e ler esse ficheiro com as coordenadas, que posteriormente vai coloca no mapa.

Instalar um servidor web para partilhar as coordenadas.

sudo apt-get install nginx

Configurar o nginx

É a primeira vez que trabalho com o nginx. Decidi instala-lo porque consome menos recursos que o apache.

Por questões de segurança, alteramos o porto do nginx. Em vez do 80, vamos usar o 2121 (por exemplo).

sudo vi /etc/nginx/sites-available/default

Alterar a linha de

#listen 80;

para

listen 2121;

Alterar o document_root

Na linha que diz root, alteramos para

root /home/pi/gps/www;

 

Nota: Não esquecer de criar as diretorias gps/www

mkdir -p gps/www

 

Uma vez que o nginx corre com o grupo www-data, vamos adicionar o pi ao grupo para que a diretoria configurada em cima seja acessivel pelo nginx.

sudo gpasswd -a pi www-data

Nota: Para que fique ativo, têm que terminar a sessão e voltar a entrar

Alterar as permissões para que qualquer ficheiro criado seja lido pelo grupo porque qualquer ficheiro criado pertencerá ao grupo www-data – (setgid)

chmod g+s www

Reiniciar o nginx

sudo /etc/init.d/nginx restart

 

Nota: Não esquercer que, se configurado como em cima, têm que aceder usando

http://<rpi_ip>:2121/

 

Código

PI

Instalar o módulo de Python gpxpy

git clone https://github.com/tkrajina/gpxpy.git
cd gpxpy
sudo python setup.py build
sudo python setup.py install

Todo o código para este projeto encontra-se na minha conta do bitbucket.

A diretoria rpi contém um ficheiro chamado gpswww.py .Este ficheiro é colocado no Raspberry PI, onde desejarem – mas têm que posteriormente criar uma diretoria chamada www no mesmo nível – é nesta diretoria que este script vai colocar o ficheiro – chamado coords.txt – que contém as coordenadas naquele momento.

Para o executar, nada mais simples que:

sudo python gpswww.py

Antes de o executar, tenham a certeza que o GPS está bem ligado e a funcionar. Podem usar os examplos em cima, com o comando cgps -s

Para mais informações sobre os módulos de Python do gpsd, basta visitar a página.

# Feiticeir0 - Bruno Santos (feiticeir0@whatgeek.com.pt)
# date: 10.12.2014
# 
# Python script para guardar as coordenadas
# correntes num ficheiro para ser lido via script em PHP
# de um computador remoto

from sys import argv
import gps
import gpxpy
import gpxpy.gpx


#Listen on port 2947 of gpsd
session = gps.gps("localhost", "2947")
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)

while True:
	try:
		report = session.next()
			# wait for a 'TPV' report and display the current time
			# to see all report data, uncomment the line below
			#print report
		if report['class'] == 'TPV':
			# Abrir ficheiro para guardar as coordenadas
			coords = open ("www/coords.txt","w")
			coords.write(str(report.lat))
			coords.write(",");
			coords.write(str(report.lon))
			coords.close()
	except KeyError:
		pass
	except KeyboardInterrupt:
		quit()
	except StopIteration:
		session = None
		print "GPSD has terminated"

 

Computador

No computador que vai mostrar os mapas, é necessário um servidor web (com suporte PHP) e acesso à internet para que possa mostrar os mapas.

No bitbucket encontram-se os ficheiros necessários.

Só é necessário alterar 2 linhas, uma em cada um dos seguintes ficheiros:

– getcoords.php : alterar a linha $rpi_host para o IP do vosso PI

– pingPHP.php :  alterar a linha $host novamente com o IP do vosso PI

Atualização: Com a nova versão, não é preciso alterar ficheiros nenhuns, bastando para isso colocar o IP do RPI na caixa para o efeito e pressionar “Track”

<!DOCTYPE html>
<html>
	<head>
		<title>RPI Tracking</title>
		<meta charset="utf-8">
		<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css"/>
		<style>zoom out
			#map {
				margin-left: auto;
				margin-right: auto;
				width: 1500px;
				height: 900px;
				float: right;
			}
			
			input[type="button"] {
				border: 1px solid #b5c1d5;
				background-color: #94aecf;
				color: white;
				height: 28px;
				border-radius: 3px;
				width: 100px;
			}
		</style>
		<script src="https://code.jquery.com/jquery-2.1.1.js"></script>
	</head>
	<body>
		<div id="map"></div>
		<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
		<script>
			var map = L.map('map').setView([39.823006667, -7.490308333], 14);
			mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>';
			L.tileLayer ('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
				attribution: '&copy; ' + mapLink + ' Contributors',
				maxZoom: 18,
			}).addTo(map);
			var ongoing = 1;
			$(document).ready(function() {
				$('#startTrack').click(function() {
					if (ongoing == 1) {
						startTrackingRPI();
						ongoing = 0;
						/*$(this).css('background-color','#d79d9c');
						$(this).attr('value','Stop');*/
					}
					/*
					else {
						ongoing = 1;
						$(this).css('background-color','#94aecf');
						$(this).attr('value','Track');
					}*/
				});
				
				function startTrackingRPI() {
					var oldlon = 0.00;	//define old coords
					var oldlat = 0.00;	//define old coords
					//get status from robot
					//get IP Address
					var ip = $('#ip').val();
					// red offline - green online
					function getStatus() {
						//new image
						if (!ip.length == 0) {
							//alert (ip);
							var online = 'images/online.png';
							var offline = 'images/offline.png';
							//gerar url
							$.post ('pingPHP.php',{ip:ip},processaDados);
							function processaDados (data) {
								//alert ('data ' + data);
								if (data == 1)
									$('#status').attr('src',online);
								else 
									$('#status').attr('src',offline);
							}
						}
					}
					// 3s em 3s verifica
					setInterval(getStatus,3000);

					//colocar marcador
					function getCoords() {
						$.post('getcoords.php',{ip:ip},processCoords);
						function processCoords(data) {
							$('#coordstoput').val(data);
							//TODO: Verificar se dados devolvidos sao validos
							//TODO: Verificar se nao houver conectividade, nao tentar inserir marcador
							var coords = data.split(",");
							//verificar se sao iguais as que ja temos
							//para nao colocar marcadores no mesmo local
							if ((coords[0] != oldlon) && (coords[1] != oldlat)) {
								//se sao diferentes, inserir marcador
								// insert a new marker
								var marker = L.marker([coords[0],coords[1]]).addTo(map);
								//atribuir estas coordenadas antigas
								oldlon = coords[0];
								oldlat = coords[1];
							}
						}
					}
					// 4s em 4s verifica coordenadas - diminir para aumentar detalhe do mapa
					setInterval(getCoords,4000);
					var newCoord = getCoords();
					//Marker
					//var marker = L.marker([39.823366667, -7.490128333]).addTo(map);
				};
			});
		</script>
		<!-- <textarea id="coordstoput" rows="2" cols="30"></textarea> -->
		<img src="images/offline.png" id="status" style="vertical-align:middle;">&nbsp;<input type="text" size="15" maxlenght="15" placeholder="RPI Endereço IP" name="ip" id="ip">
		<input type="button" value="Track" id="startTrack">
	</body>
</html>

Seguindamente, os ficheiros auxiliares:

<?php
	$host = $_POST['ip'];
	if (!$socket = @fsockopen($host,2121))
		echo 0;
	else
		echo 1;
?>
<?php
	$rpi_host = $_POST['ip'];
	$port = ":2121";
	
	$url = $rpi_host.$port.'/coords.txt';

	$ch = curl_init();
	$timeout = 5;
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
	$data = curl_exec($ch);
	curl_close($ch);
	//return preg_replace("/r|n/", "", $data);
	echo preg_replace("/r|n/", "", $data);
?>

E está tudo configurado.

NOTA IMPORTANTE: Pode parecer que o mapa não está a atualizar, mas a verdade é que está. Façam zoom out com o rato e coloquem o mapa no local onde estão. Como é necessário colocar coordenadas iniciais ao criar o mapa, coloquei as de Castelo Branco (a minha cidade). Será uma questão a alterar na próxima versão. (Obrigado Nuno Oliveira)

Num browser, executem o ficheiro RPITracking.html e fiquem à espera que marca a posição do vosso PI.

Nesta versão eu optei por usar marcadores em vez de uma linha. Noto que, ao final de algum tempo, começa a ficar um pouco confuso – mas irei alterar isso numa futura versão para colocar uma linha em vez de marcadores.

Aqui fica o resultado de uma experiencia que fiz hoje de manhã (Imagem da versão anterior)

GPS Track

Usar o PI para mostrar o mapa (em atualização)

Em vez de usar outro computador para ir buscar as coordenadas ao RPI e mostrar no mapa, podemos usar antes o RPI para fazer tudo – acedendo a ele via browser –

Alterar o nginx

Instalar o PHP
sudo apt-get install php5-fpm

A seguir, editar o ficheiro /etc/nginx/sites-available/default

sudo vi /etc/nginx/sites-available/default

e descomentar as seguintes linhas:

location ~ .php$ {
       fastcgi_split_path_info ^(.+.php)(/.+)$;
       # # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
       # fastcgi_pass 127.0.0.1:9000;
       fastcgi_pass unix:/var/run/php5-fpm.sock;
       fastcgi_index index.php;
       include fastcgi_params;
 }

Guardar e recarregar o nginx

sudo /etc/init.d/nginx reload

Para funcionar, os ficheiros que colocaram no PC, coloquem no PI – alterando o IP nos ficheiros indicados para o do PI e devem ter a funcionar o mapa dentro do PI. Conforme configuraram o root no nginx, é nesse local que devem colocar os ficheiros. Uma nota neste caso, e uma vez que está tudo no mesmo local, não havia necessidade de usar o curl – no PHP – para ir buscar as coordenadas, mas mal também não faz e funcionará sem problemas.

Mobilidade do PI

Para que isto tudo funcione, é necessário que o PI funcione com baterias.

No meu caso, estou a usar baterias lipo para alimentar o PI – com duração de cerca de 2h e 30m – não é muito, mas para já é o suficiente.

O material que uso é (Foi nesta loja de comprei) :

Lithium Ion Polymer Battery – 3.7v 1200mAh

– PowerBoost 500 Basic – 5V USB Boost @ 500mA from 1.8V+ (para aumentar os 3.7v da bateria para os 5v do PI)

– USB/DC Lithium Polymer battery charger 5-12V (3.7/4.2v cells) (para carregar as baterias)

Com um cabo mini-usb ligam isto tudo ao PI. Eu acredito que não seja a forma mais eficiente de alimentar o PI, mas após alguns dias de leitura foi o que arranjei. Não sou expert em eletrónica – se houver alguem aí que tenha uma forma mais eficiente de alimentar o PI – faça favor de dizer alguma coisa !

PILipo

Antes de ter resolvido ficar assim – testei com pilhas AA de 1.5v – um adaptador de 6 pilhas AA de 1.5v e um Pololu 5v Step-up/Step-down voltage regulator 5v para controlar a voltagem (6 * 1.5v = 9v). No entanto, não sei o que fiz mal, mas só durava cerca de 40m – além de pesar imenso…

RPI_Pilhas
RPI alimentado com pilhas

 

NOTA: Este projeto (para já) tem a atenuante que, no computador onde estejam a ver a localização do PI tenha que estar ligado à Internet para poder ir buscar os mapas. Tem também outra atenuante que, tanto o PI como o computador têm que estar ligados na mesma rede (ou se preferirem, via internet – com DNS dinamico é possivel conseguir isto) – Essencialmente têm que ter conetividade. Para alterar isto, brevemente (assim que chegarem) quero testar isto com o Xbee ! Os modelos que mandei vir têm alcance de 1,5km – Isto deve ser interessante. Atualizações para essa altura.

Espero que gostem. Algum erro e/ou omissão, avisem.