Con los últimos mini-PCs que están en el mercado (Raspberry Pi, BeagleBoard, BeagleBone...) se hace poco a poco más viable embarcar electrónica en vehículo de cualquier tipo (aéreos, terrestres, acuáticos...) que sean capaces de enviarnos a través del protocolo UDP telemetría en tiempo real, lo que posibilita hacer minería de datos o análisis en tiempo real de la trayectoria del vehículo desde tierra, independientemente del medio físico (WiFi, bluetooth, ZigBee...) que se utilice para ello.

Para ello, lo único que hay que hacer es establecer un socket UDP entre el vehículo (origen de los mensajes UDP) y el PC de tierra (destino de los mensajes UDP). Sigue leyendo si quieres saber cómo.

En primer lugar, definamos unos cuantos conceptos importantes para saber qué estamos haciendo y de qué estamos hablando:

Socket: Un socket literalmente en inglés es un enchufe. En programación, se denomina socket al punto de acceso virtual (abstracción de software) por el que dos computadoras (dos PCs, dos tarjetas de red...) son capaces de hablar la una con la otra. Para establecer un socket normalmente hacen falta dos tuplas: IP origen, puerto origen; IP destino, puerto destino.

Puerto: Se denomina así a una zona, o localización, de la memoria de un ordenador que se asocia con un puerto físico o con un canal de comunicación, y que proporciona un espacio para el almacenamiento temporal de la información que se va a transferir entre la localización de memoria y el canal de comunicación.

UDP: User Datagram Protocol (UDP) es un protocolo del nivel de transporte basado en el intercambio de datagramas (Encapsulado de capa 4 Modelo OSI). Permite el envío de datagramas a través de la red sin que se haya establecido previamente una conexión, ya que el propio datagrama incorpora suficiente información de direccionamiento en su cabecera. Tampoco tiene confirmación ni control de flujo, por lo que los paquetes pueden adelantarse unos a otros; y tampoco se sabe si ha llegado correctamente, ya que no hay confirmación de entrega o recepción. Su uso principal es para protocolos como DHCP, BOOTP, DNS y demás protocolos en los que el intercambio de paquetes de la conexión/desconexión son mayores, o no son rentables con respecto a la información transmitida, así como para la transmisión de audio y vídeo en tiempo real, donde no es posible realizar retransmisiones por los estrictos requisitos de retardo que se tiene en estos casos.

Ahora, con estos conceptos definidos, vamos al grano. En primer lugar, debemos crear una aplicación en el equipo origen (en nuestro caso, una Raspberry Pi) que cree un socket y mande un mensaje de invitación para abrirlo y dejarlo habilitado. Por otro lado, deberemos hacer lo mismo con el PC de tierra (un portátil con Fedora 17 instalado) que abra un socket el cual comparte el puerto con el socket del origen y le mande otro mensaje de invitación para abrirlo y dejarlo habilitado también.

Con esto, tendremos comunicaciónfull-dúplex entre el PC de tierra y el vehículo, aunque nosotros no la necesitamos, ya que nos basta con una comunicación unidireccional (sentido vehículo -> PC de tierra). No obstante, esto es muy útil si queremos mandar comandos de terminación, configuración, etc. al vehículo, aunque en nuestro código hemos deshabilitado el envío de comandos desde el teclado como se puede observar en el programa del PC de tierra.

Y pasemos sin más demora al código, muy sencillo por cierto en Python:

En el PC de tierra:

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import socket
import sys
import select

UDP_IP="0.0.0.0" # Recibir de cualquier cliente
UDP_PORT=10000

UDP_HOST = sys.argv[1]
print "Conectar a %s" % UDP_HOST

sock = socket.socket( socket.AF_INET, # Internet
socket.SOCK_DGRAM ) # UDP

sock.bind( (UDP_IP,UDP_PORT) )

# Pone el socket en modo de no bloqueo,
# evitando poner a recv en bucle infinito si no hay datos en el buffer
sock.setblocking(0)

print "Estableciendo la conexión..."
sock.sendto("Starting socket UDP", (UDP_HOST, UDP_PORT))
print "Conexión establecida."

while True:

# Valida si se recibe captura desde el teclado
HayDatosTeclado = select.select([sys.stdin],[],[],1)
if HayDatosTeclado[0]:
mensaje = sys.stdin.readline()
pass
# Valida si recibe algo por el socket
HayDatosSocket = select.select([sock],[],[],0.5)
if HayDatosSocket[0]:
Socketdata = sock.recv( 1024 ) # Buffer de 1024 bytes de tamaño
print "mensaje Recibido:", Socketdata
HayDatosTeclado = []
HayDatosSocket = []

Para ejecutarlo, tendremos que escribir en un terminal en el PC:

python <nombre_del_programa>.py <IP_del_remoto>

Que en nuestro caso, queda como:

python udp.py 192.168.2.12

En el vehículo:

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import socket
import sys
import re
import select

UDP_IP="0.0.0.0" # Recibir de cualquier cliente
UDP_PORT=10000

UDP_HOST = sys.argv[1]
print "Conectar a %s" % UDP_HOST

sock = socket.socket( socket.AF_INET, # Internet
socket.SOCK_DGRAM ) # UDP

sock.bind( (UDP_IP,UDP_PORT) )

# Pone el socket en modo de no bloqueo,
# evitando poner a recv en bucle infinito si no hay datos en el buffer
sock.setblocking(0)

while True:

# Valida si se recibe captura desde el teclado
HayDatosTeclado = select.select([sys.stdin],[],[],1)
if HayDatosTeclado[0]:
mensaje = sys.stdin.readline()
print "Mensaje para remoto:", mensaje
sock.sendto(mensaje, (UDP_HOST, UDP_PORT))
# Valida si recibe algo por el socket
HayDatosSocket = select.select([sock],[],[],0.5)
if HayDatosSocket[0]:
Socketdata = sock.recv( 1024 ) # buffer size is 1024 bytes
pass
HayDatosTeclado = []
HayDatosSocket = []

Para ejecutarlo, tendremos que escribir en un terminal en la Raspberry Pi (o en un PC conectado a la misma por SSH):

python <nombre_del_programa>.py <IP_del_PC_de_tierra>

Que en nuestro caso, queda como:

python udp.py 192.168.2.11

Y listo. Todo lo que se reciba por el stdin (teclado) de la Raspberry PI, se mandará por el socket al PC de tierra. Y mandar además datos de sensores no es mucho más complicado. Basta con agregar las líneas que necesites en el if del programa del remoto. Sencillo, ¿verdad?


¿Erratas? ¿Errores? No dudes en contactar con nosotros en el foro o por e-mail.