Práctica 4:

Instalación del ordenador de a bordo en el rover

En esta práctica haremos la Instalación básica de una raspberry pi 4B, así cómo una implementación de códigos que nos permiten interactuar con ella mediante los pines disponibles en la placa.
Para terminar, adaptaremos el código de la práctica anterior para mostrar el estado del vehículo.

Instalación del OS:

El sistema operativo ya se encobraba instalado previamente en la tarjeta SD, solo quedaba configurar algunos parámetros: usuario, contraseña, zona horaria, habilitar el ssh ...

La instalación fué muy simple, se realizó directamente usando la interfaz gráfica. Una vez realizados estos pasos ya podemos trabajar directamente con la ventana de comandos usando ssh.
Para conectarnos por ssh usaremos «ssh nombre-usuario@ip-host» en nuestro caso

ssh el-calmador@192.168.154.179

Una vez hecho esto realizaremos los siguientes comandos:
sudo su
apt update
apt upgrade -y
apt install neofetch
Estos comandos actualizan la raspberry y son importantes, no solo por el tema de eficiencia o seguridad, sino que las librerías que necesitaremos para controlar los pines no funcionarán si no se encuentra nuestro sistema actualizado.

Podemos comprobar que todo funciona correctamente empleando el comando neofetch:

Otro comando que nos puede resultar útil es: pinout que nos da el siguiente resultado:

Cableado de los componentes:

Para realizar el cableado, simplemente se ha seguido el vídeo, cabe destacar que el tutorial está mal explicado, ya que en multiples ocasiones se hace un abuso del lenguaje dando lugar a confusiones, un ejemplo muy claro es cuando se hablan de pins y de GPIOS ya que en el vídeo se usan indiferentemente pero en la realidad, los GPIOs no tienen porqué seguir la misma enumeración que los pines, también la precisión con la que se expresa es un poco inexacta cuando habla de arriba, abajo...
Estos detalles hicieron que una vez terminara de cablear todo y me pusiera a probar el código, este no funcionara.

Configuración del puerto TELEM2

La configura del puerto telem2 se vió en la anterior práctica, solo quedaría configurar el uart para comunicar la raspberry con la pixhawk.
Al intentar realizar este paso y editar el fichero txt, me dí cuenta que no estaba disponible esta opción. La escribí de forma manual pero no he logrado conseguir a fecha de esta entrada. De todos modos, aún queda una alternativa: conectarse al puerto de telemetía mediante un USB tal y cómo se hizo anteriormente. Solo hace falta tener en cuenta que estamos trabajando con una máquina UNIX y que la sintaxis cambia un poco.

Actualización sobre el apartado del puerto TELEM2:

Cómo las indicaciones aportadas por el vídeo de la asignatura no me llevaban a ninguna parte, decidí buscar por mi mismo hasta encontrar los pasos necesarios para habilitar los puertos serie UART:
Para ello lo primero de todo llamaremos al siguiente comando: sudo raspi-config, no s aparecerá un menú como este:
Luego iremos a 3. Interface options, en este menú nuevo seleccionaremos la opción P6 Serial Port. Finalmente nos preguntará si queremos una consola para login, a lo que repondremos no y luego se nos preguntará por si queremos activar el si queremos activar el hardware del serial port a lo que repondremos que sí. Al terminar la Configuración se reiniciará la raspberry.

Para ver que el UART se encuentra activado ejecutaremos el comando tail /boot/config.txt que nos arroja la siguiente información:
Para terminar con la configuración del UART lanzaremos el comando ls -la /dev/ttyAMA* para listar todos los puertos UART activados y asegurarnos que el UART4 se encuentre disponible:

Códigos para controlar la raspberry:

En esta sección se presentarán los distintos códigos e implementaciones para controlar la raspberry y los distintos periféricos:

Botón:

Nuestro montaje dispone de un botón el cual hemos programado para que ser reinicie, el código es el siguiente:

import gpiozero
import signal
import subprocess

def reboot():
    print('Button pressed')
    subprocess.check_call(['sudo','reboot'])


boton = gpiozero.Button(24, hold_time =2)
boton.when_held = reboot

signal.pause()

            
y este es el resultado:

LEDs:

Disponemos también de una placa que funciona a modo de tira de LEDs, una cosa que me ha sorprendido, es que no he visto ninguna resistencia en la circuitería y al probar el resultado, los LEDs brillan mucho.
Esto me hace pensar que realmente no tiene ninguna resistencia, pero de ser así seria un fallo muy grande ya que la corriente que pediría el circuito sería muy alta y acabaría por dañar la placa de la raspberry.
El código empleado es el siguiente:

import board
import neopixel
import time

pixels = neopixel.NeoPixel(board.D18,5)

pixels[0] = (62,95,138)

time.sleep(5)
pixels[0]=(0,0,0,0)
time.sleep(2)

pixels.fill((62,95,138))
time.sleep(10)
pixels.fill((0,0,0))
        

integración de los códigos anteriores con la práctica 3:

Ahora se integrarán los códigos anteriores, para ello realizaremos un thread adicional para monitorizar el botón continuamente, también se ha añadido la funcionalidad de los LEDs que cambian de color dependiendo de la fase que se encuentren dentro del ciclo de vida del código. El main contiene un control de excepciones pensado especialmente para cuando no se logre comunicar dronkit con la controlador. A continuación se muestra el main con todas las modificaciones necesarias:

import threading
import dronekit
import time
import datetime
import board
import neopixel
import time
from reboot import * 

from control import controller
from gestor import *
from graficas import *

def mandunga():
    #conexion = '/dev/ttyUSB0 #Linux'
    #conexion = 'tcp:127.0.0.1:5762'
    #conexion =  'com10' #windows
    conexion = '/dev/ttyAMA1' #serial bus 1 'UART'
    baud = 57600 #57600 ==> radio,  baud=115200 net/usb
    try:
        vehicle = dronekit.connect(conexion, wait_ready=True, baud=115200)
        print('vehicle connected')

        pixels[:3]=(225,0,0)
        pixels[3] = (255,215,0)
        pixels[3:] = (225,0,0)

        thread=threading.Thread(target=listener_sql, args=( vehicle,))
        print('SQL thread started')
        thread.start()
        thread=threading.Thread(target=main_reboot)
        print('thread boton started')
        thread.start()
        controller(vehicle=vehicle)
        vehicle.close()
    except dronekit.TimeoutError:
        t=0
        print('Unable to conect to the rover, shutting down ...')
        while t < 10: 
            if t%2 ==0:
                pixels.fill((0,0,0))
            else:
                pixels.fill((0,0,153))
            t+=1
            time.sleep(1)
        pixels.fill((0,0,0))
        quit()

if __name__ == '__main__':
    print('starting')
    global pixels
    pixels = neopixel.NeoPixel(board.D18,5)
    for i in range(5):
        pixels[i] = (225,0,0)
    mandunga()
    for i in range(5):
        pixels[i] = (0,100,0)
    mapa() 

Adaptación del paquete reboot

Para que la función reboot funcione correctamente, es necesario crear otra función desde donde se llamará a reboot. El motivo por el que se tiene que hacer así es porque al hacer el import del paquete se ejecutan todas las líneas.
Haciendo que el hilo principal se quede parado en el signal.pause(), por este motivo, es importante que estas instrucciones se encuentres anidadas dentro de una función desde la cual se creará un hilo secundario donde este sí se congelará.

import gpiozero
import board
import neopixel
import signal
import subprocess


def main_reboot():
    boton = gpiozero.Button(24, hold_time =2)
    boton.when_held = reboot
    signal.pause()


def reboot():
    print('Button pressed')
    pixels = neopixel.NeoPixel(board.D18,5)
    for i in range(5):pixels[i]=(0,0,0,0)
    subprocess.check_call(['sudo','reboot'])


if __name__ =='__main__':
    main_reboot()

Demostración del control de excepciones controladas:

Automatización de los scripts:

Podemos automatizar el proceso para no tener que llamar los códigos y que estos se ejecuten al iniciar la raspberry, para ello lanzaremos el comando:

sudo crontab -e

Podemos lanzar cualquier comando que deseamos, es importante poner la ruta absoluta del archivo y también añadir un & al final de cada comando, para que se realicen en segundo plano.

Comprobación de los resultado:

Una vez llegado a este punto, instalamos la raspberry al rover. Mediante Mission Planner creamos una misión simple, calibramos el compás y nos conectamos por ssh a la raspberry, ejecutando el main del proyecto. Una vez armado el rover, este empezará con su ruta

Telemetía recogida:

A continuación se mostrará algunos datos de telemetía recogidos en la raspberry y con el .tlog de Mission Planner: