20 mayo 2013

Velocímetro Digital con Raspberry Pi y GPS Venus

En la entrada anterior les mostraba como conectar el útil (y barato) GPS venus a la Raspberry Pi. Sin embargo, quedé pendiente de mostrarles una aplicación práctica que se pudiera armar fácilmente.

Durante esta entrada les mostraré un sencillo proyecto que pueden armar con sus Raspberrys en su tiempo libre y que les servirá mucho si el velocímetro del vehículo ha dejado de funcionar por cualquier motivo.

Antes de continuar, pueden ver un pequeño video donde se demuestra su funcionamiento:

Habiendo dicho esto... ¡Comencemos!

El diseño del sistema


La ventaja de la Raspberry Pi es que al utilizar Linux tenemos a nuestra disposición un sin fin de herramientas de programación disponibles para realizar nuestros proyectos. La idea, como he mencionado en otras entradas, es utilizar la Raspberry para tareas de alto nivel como interactuar con el usuario y desplegar información, dejando a los sensores medir directamente la magnitud en la que estamos interesados.

Este proyecto consta básicamente de tres componentes: El primero, un módulo GPS Venus encargado de obtener la información de posición del GPS y transmitirlo a la Raspberry Pi; el segundo, la Raspberry Pi que se encargará de procesar, desplegar la información y reaccionar a las entradas del usuario; y el tercero, la mini-pantalla LCD que utilizaremos para desplegar la información:


Como pueden observar en el diagrama, el GPS Venus se comunica con la Raspberry Pi a través de comunicación serial (UART). Para este proyecto la única entrada que recibimos del usuario es la señal de "apagado" que le indica a nuestro programa que debe ejecutar el comando que iniciara el proceso de apagado de la Raspberry Pi.

Un pequeño programa en Python se encargará de realizar dos simples tareas: Primero leer los datos del puerto y almacenarlos en variables dentro del programa y segundo dibujar una muy sencilla interfaz en la mini-pantalla LCD. Esta pantalla se conecta por medio de un cable RCA por el que se envía una señal de video compuesto desde la Raspberry Pi.

Materiales


Para realizar este proyecto van a necesitar los siguientes materiales:

Conectando el GPS a la Raspberry Pi


No voy a detenerme mucho en esta parte ya que lo he explicado en la entrada anterior. Únicamente les dejo el diagrama de conexión para que tengan una referencia rápida: 


Procesando los datos del puerto Serial

 

Leyendo el puerto desde un hilo secundario


En entradas anteriores, hemos hecho uso del código que pego a continuación que se encarga de leer línea por linea los datos que se reciben en el puerto serie (/dev/ttyAMA0).

ser = serial.Serial(
  '/dev/ttyAMA0',
  baudrate=9600,
  interCharTimeout=None
)
t = threading.Thread(target=receiving,args=(ser,)).start()

Estas líneas de código se encargaran de iniciar un hilo de secundario que ejecutará las instrucciones contenidas en la función receiving.
def receiving(ser):
  global continue_reading,last_received
  buffer = ''

  while continue_reading:
    buffer += ser.read(ser.inWaiting())
    if '\n' in buffer:
      lines = buffer.split('\n')
      last_received = lines[-2]
      buffer = lines[-1]
      parse_nmea(last_received.strip())

  ser.close()
  print "Port closed."

La función receiving lee caracter por caracter del puerto serial y almacena los datos dentro de un "buffer", al encontrar un fín de línea ( \n ) envía la cadena leída hacia la función parse_nmea que se encargará de procesar los parámetros incluidos en la cadena NMEA.

Debido a que la lectura del puerto serie se ejecuta en un hilo aparte y detener a la fuerza hilos de ejecución es considerado peligroso, se ha incluido la variable "continue_reading" que nos servirá para notificar al hilo secundario que debe detener su ejecución.

Más adelante en esta entrada veremos como capturar las señales de interrupción (Ctrl+C) y las entradas del usuario para detener la lectura. 

Programando el Velocímetro


Por lo general, un receptor GPS reporta su ubicación a un intervalo de tiempo determinado. El GPS Venus está configurado de fábrica para que reporte ubicaciones cada segundo.

En este proyecto nos interesa calcular velocidades, esto puede realizarse fácilmente conociendo el cambio en la ubicación del vehículo respecto a una unidad de tiempo, pero antes de realizar el cálculo es necesario procesar la salida del GPS para obtener la información de ubicación.

Los GPS reportan la ubicación calculada por medio de mensajes NMEA, este es un protocolo estándar de comunicación que utiliza cadenas simples de texto que resultan muy fáciles de procesar.

Para este proyecto se debe leer continuamente los datos del GPS recibidos en el puerto serial hasta que se reciba una línea de texto comience con la secuencia "$GPGGA". Esta línea corresponde a los datos que han sido "fijados" del sistema de posicionamiento global (Global Positioning System Fix Data).

La siguiente tabla describe los datos recibidos en la línea:

$GPGGA,170834,4124.8963,N,08151.6838,W,1,5,1.5,280.2,M,-34.0,M,,,*75

NombreDatos de ejemploDescripción
Identificador del comando$GPGGADatos fijados del sistema de posionamiento global
Hora17083417:08:34 Z
Latitud4124.8963, N41d 24.8963' N or 41d 24' 54" N
Longitude08151.6838, W81d 51.6838' W or 81d 51' 41" W
Calidad de los datos:1Los datos provienen del GPS fijado
- 0 = Inválido
- 1 = GPS fijo
- 2 = DGPS
Number of Satellites55 satélites en vista
Dilución vertical de la precisión (HDOP)1.5Precisión relativa de la posición horizontal
Altitud280.2, M280.2 metros sobre el nivel del mar (MSNM)
Altura del geoide arriba del elipsoide WGS84-34.0, M-34.0 metros
Tiempo desde la última actualización DGPS
No se ha actualizado
Identificador de la estación DGPS de referencia
No hay estación de referencia
Suma de verificación*75Puede utilizarlo el programa para verificar la existencia de errores en la transmisión.
Ejemplo traducido de GPS Nmea sentence information $gpgga.

Calculando la velocidad


La velocidad, recordando un poco las clases de física en escuela, se define como la "distancia recorrida por unidad de tiempo". Esta definición es más fácil de representar por medio de la siguiente fórmula:


El GPS lo único que hace es brindarnos la información de ubicación, así que lo único que debemos hacer es calcular la distancia entre los dos puntos obtenidos por el GPS y dividirlo entre el tiempo que ha transcurrido en obtener esas dos posiciones.

Sin embargo habrán notado que las coordenadas que nos brinda el GPS están en grados y fracciones de minuto. Esto no nos sirve para calcular directamente distancias en metros o en Kilómetros.

Calculando distancias a partir de dos coordenadas geográficas


Las coordenadas geográficas nos permiten ubicar un punto sobre un elipsoide que se aproxima a la forma de la tierra. Si estamos trabajando con distancias cortas (P.E. el desplazamiento de un vehículo sobre carretera), podemos "asumir" que la tierra es completamente redonda y esto nos simplificará muchísimo los cálculos.

Para calcular la distancia vamos a utilizar la fórmula de haversine que está definida de la siguiente manera:



Donde φ es la latitud, λ es longitud y R es el rádio de la tierra (radio promedio= 6,371km), solo tengan cuidado que los valores de latitud y longitud se encuentren en radianes, caso contrario la fórmula no les funcionará.

Pero tranquilos, no se asusten con la fórmula, todas las funciones están disponibles en la biblioteca "math" incluída en python.

Pueden visitar  "Calculate distance, bearing and more between Latitude/Longitude points" para mayor información sobre el cálculo y otros ejemplos de implementación en Javascript.

Traduciendo la fórmula a código:
def calc_distance(coord1,coord2):
  R = 6371
  dLat = math.radians(coord2[0]-coord1[0])
  dLon = math.radians(coord2[1]-coord1[1])
  lat1 = math.radians(coord1[0])
  lat2 = math.radians(coord2[0])

  a = math.sin(dLat/2)*math.sin(dLat/2)+math.sin(dLon/2)*math.sin(dLon/2)*math.cos(lat1)*math.cos(lat2)

  c = 2 * math.atan2(math.sqrt(a),math.sqrt(1-a))

  return R*c

La función toma dos coordenadas geográficas, en este caso la posición más reciente y la última posición conocida, aplica la fórmula de haversine y devuelve la distancia calculada  en Km.

Extrayendo los datos de la cadena NMEA


Al inicio de nuestro programa, debemos definir una serie de variables que utilizaremos para guardar la información de la última posición que nos servirían para calcular distancias y a su vez tiempos.

# Loop condition
continue_reading = True

# Receive buffer
last_received = ''

# GPS info
last_coord = (0,0)
last_time = 0
spd = 0
altitude = 0
sats = 0

Debido a que las cadenas NMEA son simples cadenas de texto su procesamiento es sumamente sencillo. Si dividimos la cadena cada vez que encontramos una coma (,), podemos fácilmente extraer los datos que necesitamos.

La función parse_nmea es la encargada de extraer todos los datos de la cadena recibida del GPS:
def parse_nmea(line):
  global last_coord,last_time,spd,altitude,sats
  gpsdata = line.split(',')
  if gpsdata[0] == '$GPGGA':

    # Print NMEA GPGGGA
    print line

    # Parse time
    curr_time = parse_time(gpsdata[1])
    print "Time: "+gpsdata[1]

    # Parse latitude
    lat = float(gpsdata[2][:2])+(float(gpsdata[2][2:])/60)
    if gpsdata[3] == 'S':
      lat = lat*-1
    print "Lat: "+str(lat)

    # Parse longitude
    lon = float(gpsdata[4][:3])+(float(gpsdata[4][3:])/60)
    if gpsdata[5] == 'W':
      lon = lon*-1
    print "Lon: "+str(lon)

    # Calculate distance
    curr_coord = (lat,lon)
    dist = calc_distance(curr_coord,last_coord)
    print "Distance to last point: "+str(dist)

    # Print time difference
    print "Time diff: "+str(time_diff(curr_time,last_time))

    # Calculate speed
    spd = (dist/time_diff(curr_time,last_time))*3600
    last_time = curr_time
    print "Speed from last point: "+str(spd)
    last_coord = curr_coord

    # Print satellites
    sats = int(gpsdata[7])
    print "Satellites: "+str(sats)

    # Print altitude
    altitude = float(gpsdata[9])
    print "Altitude (msnm): "+str(altitude)

La función split() permite dividir cadenas de texto devolviendo un arreglo con todas las palabras contenidas, de esta manera lo único que tenemos que hacer para extraer los datos es acceder al arreglo en la posición correspondiente, pueden observar como se han creado varias funciones de ayuda para convertir el "tiempo" y calcular la diferencia de los mismos.

Si son un poco observadores notarán que multiplico la velocidad obtenida por 3600. Esto lo hago porque la división me devolverá Km/s y realmente estamos interesados en calcular Km/h así que se hace necesario aplicar un factor de conversión

Pueden observar en el código como utilizamos la función de distancia que definimos previamente y almacenamos su valor. Al final de cada iteración vamos sobreescribiendo los valores viejos para poder utilizarlos en la siguiente.

Desplegando los datos en pantalla completa


Para desplegar la información vamos a utilizar PyGame. En entradas anteriores hemos utilizado esta biblioteca para realizar visualizaciones sencillas en python.

Siendo la Raspberry Pi un entorno de hardware limitado, cargar el "escritorio" para mostrar un par de gráficos simples cuesta muchos ciclos de procesador que podrían ocuparse para hacer cosas más útiles. Por ello decidí usar el "framebuffer".
Normalmente estamos acostumbrados a utilizar aplicaciones gráficas a través del "escritorio" utilizando ventanas. Sin embargo para esta aplicación estaba interesado en que la única interfaz que se mostrara al usuario fuera el velocímetro digital.

El Framebuffer


El framebuffer es una capa de abstracción del kernel de Linux que permite desplegar gráficos de manera directa sin necesidad de cargar un entorno más complejo como el X o un administrador de ventanas. Esto, en pocas palabras, significa que nos permite desplegar gráficos directamente desde la consola.

Para acceder directamente el Framebuffer hacemos uso de este código de ejemplo que puedes encontrar en los tutoriales de Adafruit:
import os
import pygame
import time
import random

class pyscope :
    screen = None;
    
    def __init__(self):
        "Ininitializes a new pygame screen using the framebuffer"
        # Based on "Python GUI in Linux frame buffer"
        # http://www.karoltomala.com/blog/?p=679
        disp_no = os.getenv("DISPLAY")
        if disp_no:
            print "I'm running under X display = {0}".format(disp_no)
        
        # Check which frame buffer drivers are available
        # Start with fbcon since directfb hangs with composite output
        drivers = ['fbcon', 'directfb', 'svgalib']
        found = False
        for driver in drivers:
            # Make sure that SDL_VIDEODRIVER is set
            if not os.getenv('SDL_VIDEODRIVER'):
                os.putenv('SDL_VIDEODRIVER', driver)
            try:
                pygame.display.init()
            except pygame.error:
                print 'Driver: {0} failed.'.format(driver)
                continue
            found = True
            break
    
        if not found:
            raise Exception('No suitable video driver found!')
        
        size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
        print "Framebuffer size: %d x %d" % (size[0], size[1])
        self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN)
        # Clear the screen to start
        self.screen.fill((0, 0, 0))        
        # Initialise font support
        pygame.font.init()
        # Render the screen
        pygame.display.update()

    def __del__(self):
        "Destructor to make sure pygame shuts down, etc."

    def test(self):
        # Fill the screen with red (255, 0, 0)
        red = (255, 0, 0)
        self.screen.fill(red)
        # Update the display
        pygame.display.update()

# Create an instance of the PyScope class
scope = pyscope()
scope.test()
time.sleep(10)

El código anterior se encarga de "configurar" PyGame para que haga uso del framebuffer lo que permite dibujar gráficos directamente desde la consola.

La modificación realizada al código publicado en Adafruit es la eliminación de la funcion  test() que en este proyecto ha sido reemplazada por la función draw():

    def draw(self):
        global last_coord,spd,altitude,sats,continue_reading

        # Draw speed
        self.screen.fill((0,0,0))
        myfont = pygame.font.Font("/home/pi/digital7.ttf",250)
        spdText = myfont.render("{:03d}".format(int(spd)), 1, (0,255,0))
        self.screen.blit(spdText, (120,20))

        # Draw "Km/h"
        labelFont = pygame.font.Font("/home/pi/digital7.ttf",100)
        lblText = labelFont.render("Km/h", 1, (255,255,0))
        self.screen.blit(lblText, (480,130))

        # Draw "altitude"
        subFont = pygame.font.Font("/home/pi/digital7.ttf",130)
        altText = subFont.render("{:04d}".format(int(altitude)), 1, (0,255,0))
        self.screen.blit(altText, (20,240))

        # Draw "msnm"
        labelFont = pygame.font.Font("/home/pi/digital7.ttf",50)
        lblText = labelFont.render("msnm", 1, (255,255,0))
        self.screen.blit(lblText, (260,300))

        # Draw latitude
        subFont = pygame.font.Font("/home/pi/digital7.ttf",75)
        altText = subFont.render("{:07.4f}".format(float(math.fabs(last_coord[0]))), 1, (0,255,0))
        self.screen.blit(altText, (20,370))

        # Draw N or S depending on value
        labelFont = pygame.font.Font("/home/pi/digital7.ttf",50)
        lat_lbl = "N"
        if last_coord[0] < 0:
          lat_lbl = "S"
        lblText = labelFont.render(lat_lbl, 1, (255,255,0))
        self.screen.blit(lblText, (260,390))

        # Draw longitude
        subFont = pygame.font.Font("/home/pi/digital7.ttf",75)
        altText = subFont.render("{:08.4f}".format(float(math.fabs(last_coord[1]))), 1, (0,255,0))
        self.screen.blit(altText, (340,370))

        # Draw E or W depending on value
        labelFont = pygame.font.Font("/home/pi/digital7.ttf",50)
        lat_lbl = "E"
        if last_coord[1] < 0:
          lat_lbl = "W"
        lblText = labelFont.render(lat_lbl, 1, (255,255,0))
        self.screen.blit(lblText, (615,390))

        # Draw number of satellites
        subFont = pygame.font.Font("/home/pi/digital7.ttf",80)
        altText = subFont.render("{:02d}".format(sats), 1, (0,0,255))
        self.screen.blit(altText, (510,240))

        # Draw "SAT FIXED"
        labelFont = pygame.font.Font("/home/pi/digital7.ttf",35)
        lblText = labelFont.render("SAT FIXED", 1, (255,255,0))
        self.screen.blit(lblText, (485,310))

        pygame.display.update()


La idea de la función draw() es mostrar en pantalla los valores leídos y calculados del GPS, esta función es muy sencilla ya que lo único que hace es "renderear" los valores almacenados utilizando la tipografía "digital7.ttf". Esta función se llama constantemente durante la ejecución del programa.

Nota: Deben de copiar la tipografía digital7.ttf en el mismo directorio que el script, en este caso en /home/pi.

Capturando las señales de interrupción


Podemos utilizar señales de "interrupción" para (aunque suene redundante) interrumpir la secuencia que está realizando un programa.

Como el programa lo estoy probando desde la consola decidí capturar la señal "SIGINT", esta señal se envía al programa cuando se presiona Ctrl+C desde la consola. Al capturar la señal el código de manejo de interrupción cambia el valor "continue_reading" a False provocando que termine el hilo de lectura del puerto serie y que se termine el hilo de ejecución principal. En pocas palabras Ctrl-C provocará que se cierre el velocímetro digital.

El código para captura de la señal SIGINT es el siguiente:
def end_read(signal,frame):
  global continue_reading
  print "Ctrl+C captured, ending read."
  continue_reading = False
  sys.exit(0)

signal.signal(signal.SIGINT, end_read)


El hilo de ejecución principal y la función de apagado


Por último, del lado de la programación falta definir un "hilo principal". Este será el encargado de dibujar en pantalla los gráficos y de capturar los eventos que provocarán el apagado de la Raspberry Pi.

El siguiente código contiene las instrucciones inicialización de PyGame, lectura del puerto serie, captura de interrupciónes e hilo de ejecución principal:
# Create an instance of the PyScope class
scope = pyscope()

# Start serial monitor thread
ser = serial.Serial(
  '/dev/ttyAMA0',
  baudrate=9600,
  interCharTimeout=None
)
t = threading.Thread(target=receiving,args=(ser,)).start()

# Capture SIGINT
def end_read(signal,frame):
  global continue_reading
  print "Ctrl+C captured, ending read."
  continue_reading = False
  sys.exit(0)

signal.signal(signal.SIGINT, end_read)

# Setup GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN)

# Main Loop
while True:
  if GPIO.input(18) == 0:
     continue_reading = False
     subprocess.call(["/sbin/init","0"])
     break
  scope.draw()

sys.exit(0)

En el vehículo no pienso tener un teclado para estar presionando Ctrl+C y una vez terminada la ejecución del programa tampoco me interesa tener una consola inútil. Así que decidí utilizar el puerto GPIO 18 para conectar un interruptor que me permita saber que el usuario quiere apagar la raspberry.

Para leer los valores tenemos que inicializar la biblioteca RPi.GPIO y configurar el puerto con el siguiente código:
# Setup GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN)

Pueden observar en el código como se llama a "init 0" con ayuda de subprocess.call para apagar la raspberry cuando se detecta que se ha presionado el botón.

Es necesario que utilicen una resistencia "pull-up" para el interruptor como muestro en el diagrama siguiente:

Para este circuito es necesario agregar una resistencia pull-up ya que de no hacerlo el pin queda "al aire" y el estado no está determinado, al leer su valor el pin mostrará oratoriamente valores de 0 y 1 por lo que nuestra aplicación se interrumpirá inmediatamente luego de iniciar.

A futuro...


La idea a futuro es crear un mini-UPS que provea de energía durante períodos cortos de tiempo lo permitiría, por ejemplo, detectar cuando el usuario quite la llave de encendido y hacer un apagado "limpio" de la raspberry sin intervención del usuario, un simple relé que conecte a tierra podría colocarse en esta línea para indicar a la Raspberry Pi que debe apagarse.

Configurando Linux


Por defecto la Raspberry Pi viene configurada para poner la pantalla en negro luego de pasados 30 minutos sin recibir eventos del usuario (teclado o mouse). Como en el vehículo no pienso llevar siempre un teclado y un mouse se hace necesario des habilitar esta función.

Para ello editamos el archivo /etc/kbd/config y cambiamos la línea BLANK_TIME como se muestra  a continuación:

BLANK_TIME = 0

Lo siguiente es asegurarnos de que nuestro programa inicie automáticamente al arrancar Linux. Para ello editamos el archivo /etc/init.d/rc.local y agregamos las siguientes dos líneas:

echo Starting GPS reader...
/usr/bin/python /home/pi/gpsprocessor.py &

Nota: La "&" al final provoca que el programa se ejecute en segundo plano.

Otra idea...


Mucho del tiempo de carga de Linux se debe al sin fin de servicios que se inician. Es posible deshabilitar todos los servicios no utilizados para acelerar el tiempo de carga. Para aplicaciones como la presente lo ideal sería que el único software que se cargara fuera nuestro velocímetro. A futuro podría escribir una entrada sobre como realizar esto.


Una vez realizado todo lo anterior estamos listos para montar todo en el vehículo.

Montando el hardware


La primera foto es la del "banquillo de pruebas", es decir mi mésa del comedor, para pruebas la Raspberry está conectada vía cable Ethernet a mi laptop y alimento la pantalla LCD con una fuente de computadora.


Como tengo una gran consciencia ecológica (llámese me da pereza armar un case decente) utilizo esta maravillosa caja de cartón a donde por medio del nunca bien ponderado "masking tape" pego la Raspberry Pi. Coloco adentro de tan espaciosa caja el receptor GPS y conecto por medio de un cargador de vehículo la alimentación de la Raspberry.


En esta foto pueden ver la resistencia "Pull-Up" entre los 3.3V y el GPIO 18.


La antena pueden colocarla de preferencia al exterior del vehículo, solo tengan cuidado que el cable de la misma no quede "mordido" por las visagras ya que pueden dañarlo.



Debido a que la salida del puerto USB son solo 5V he sacado un par de líneas del conector de cigarrillos para alimentar la mini pantalla USB.


Aquí se puede ver el interruptor de apagado, esta es mi única forma de hacer un apagado "limpio" de la Raspberry Pi una vez está conectada al vehículo.


La pantalla la he colocado enmedio del tablero justo donde está el velocimetro que no sirve.


La prueba en pista...


El día domingo me llevé el velocímetro digital en mi vehículo para probarlo en carretera (el video que les puse arriba). Ese mismo día se desarrolló la "Copa Sherwin Williams" en el Autódromo El Jabalí, mi amigo Salvador Corado de ACI se Aprende tiene malo su velocímetro.

Como la velocidad que uno lleva en carrera es un parámetro importante para auto-evaluar su desempeño, le ofrecí instalar el velocímetro y así, de paso, me serviría como "beta-tester".

Estas son las fotos del equipo instalado en su carro de competencia:


Aquí pueden ver la pequeña pantalla en el video a bordo, lastimosamente el ángulo y el reflejo no permiten ver el programa funcionando:

Pero la pregunta es ¿Funcionó?... Mejor los dejo con las palabras de mi amigo:

Emigdio Salvador Corado: Doy fe que funcionó muy bien... El único fallo fue el adhesivo (de la pantalla) no soporto la fuerzas g en las curvas y los saltos en la tierra XD jajaja

Así que no habiendo más que decir por ahora, me despido... ¡Hasta la próxima!


Código fuente y referencias

13 comentarios:

Noel Portillo dijo...

Me gustaría retomar tu proyecto pero tomando los datos directamente de la computadora del carro mediante el protocolo ODB-2, para mostrar información ampliada sobre lo que sucede en varios de los sensores del vehículo, ya veré como me va. Felicidades por tu proyecto.

Mario Gómez dijo...

¡Hola Noel!

Si estás interesado en OBD-II y para no re-inventar la Rueda, podrías leer este proyecto de Sparkfun Electronics que utiliza Arduino para leer los parámetros de la ECU del carro.

https://www.sparkfun.com/tutorials/294

Luego puedes utilizar el puerto serial para conectarte a la Raspberry Pi que te funcione de data-logger o como visualizador. Luego puedes agregar info de posición con GPS.

Mi vehículo es viejo ya y no venía con OBD-II así que toca sacar las señales manualmente, pero igual creo que te puede funcionar.

¡Saludos!

Raúl dijo...

Saludos a todos, muy buen proyecto! Apenas me ha llegado mi RPi, y me gustaria probar este HMI. Necesito de su ayuda aclarándome (como se lo implementa para que el linux permita que la aplicación de interfaz se ejecute sin necesidad de un login de usuario cada vez que se encienda?. Mil disculpas mi falta de conocimiento.

Mario Gómez dijo...

¡Hola Raúl!

Escencialmente son dos cosas:

1ro: El programa de python que he compartido hace uso del "Framebuffer" es decir no necesita que entres al X para desplegar gráficos.

2do: Como se corre desde la consola, si necesitas que el programa inicie al arrancar la Raspberry, editas el archivo /etc/init.d/rc.local".

Dentro de ese archivo solo colocas la ruta completa al ejecutable y al final agregas una "&" para que se ejecute como tarea en segundo plano.

Tu puedes hacer esto prácticamente con cualquier programa. Si quieres que inicie al inicio sin tener que pasar por el login, solo agrega el comando al archivo /etc/init.d/rc.local.

¡Saludos!
Mario.

Héctor dijo...

Hola!
Excelente tu blog y este tutorial, muchas gracias y felicidades!
Te comento que estoy tratando de hacer una GUI para un proyecto que tengo en mente pero no acabo de entender el código, sobre todo que a mi se me amontonan las letras cada vez que cambia una variable, te importaría explicarlo un poco más a fondo?
Saludos!

Ivan dijo...

Buenas tardes, mi consulta es de indole tecnica, no consigo leer nada en la raspberry aparentemente tengo conectado todo correcto, en el GPS parpadea el led rojo pero a la hora de hacer cat /dev/ttyAMA0 no me muestra nada... Tengo conectadas TX0 y RX0 a TXD y RXD respectivamente.... será problema de la raspberry o problema del chip gps??

Mario Gómez dijo...

¡Hola Ivan!

Si estás usando el GPS Venus, primero has la verificación básica de que tengas las líneas TX y RX cruzadas. Es decir RX(RPi)<->TX(Venus) y RX(Venus)<->TX(RPi)

Si te aparece en linux el puerto /dev/ttyAMA0 significa que esta configurado correctamente, así que el problema puede ser la velocidad. Si has ocupado el Venus con el programador en windows, la velocidad cambia a 115200bps, así que te recomiendo ejecutes el siguiente comando (como root):

stty -F /dev/ttyUSB0 115200

Intenta con distintas velocidades para ver si todo funciona bien.

¡Saludos!

Ivan dijo...

Saludos! muchisimas gracias por la contestación pero sigo con el problema...

Por una parte comprobé las conexiones RX y TX y estan correctas.. el RX(pi) con el RX(gps) y lo mismo con TX.

A que te refieres con.. "Si has ocupado el Venus con el programador en windows" Quiero decir, he hecho el mismo montaje que tu en la entrada... ¿Me habre saltado algo?,

Respecto a lo de aparecer...aparece, cuando hago el $ cat /dev/ttyAMA0 no me da error de ningun tipo (Entiendo que en ese caso si que lo encuentra), simplemente se queda escuchando pero no recibe nada de nada.

La velocidad la tenia a 9600 como lo pusiste tu en el proyecto, pero bueno probaré cuando llegue a casa otra velocidad

Ivan dijo...

Saludos! muchisimas gracias por la contestación pero sigo con el problema...

Por una parte comprobé las conexiones RX y TX y estan correctas.. el RX(pi) con el RX(gps) y lo mismo con TX.

A que te refieres con.. "Si has ocupado el Venus con el programador en windows" Quiero decir, he hecho el mismo montaje que tu en la entrada... ¿Me habre saltado algo?,

Respecto a lo de aparecer...aparece, cuando hago el $ cat /dev/ttyAMA0 no me da error de ningun tipo (Entiendo que en ese caso si que lo encuentra), simplemente se queda escuchando pero no recibe nada de nada.

La velocidad la tenia a 9600 como lo pusiste tu en el proyecto, pero bueno probaré cuando llegue a casa otra velocidad

Ivan dijo...

Vale bien, ya te entendi... muchisimas gracias Mario... va a ser eso de tener cruzadas las RX y TX... que no las tengo... Soy Demasiado novato!!!

Jorge Eliecer Gaviria Garcia dijo...

Hola Mario,

Soy nuevo en el tema, mi proyecto consiste en crear un GPS y que yo pueda visualizar un archivo .SHP (Polígono)sacado de google earth no encuentro la forma configurarlo, atento a tus comentarios

Ruben Alquezar dijo...

Hola estoy intentando realizar el programa. copio todo el codigo fuente tal y como esta en la descarga y no funciona. meto el archivo en python y le doy a run. solo me da errores de sintaxis. Por favor una ayuda.
Soy nuevo en RPI y tendo el velocimetro de mi coche estropeado.
Un saludo

Root dijo...

Que buen proyecto!