¿Quieres construir un coche que conduzca de forma autónoma? Puede hacerse por menos de lo que piensas. En el artículo final de la serie vemos el software y la operativa de manejo.
Introducción
En el artículo del mes pasado hablamos del hardware necesario para construir un coche con capacidad para conducirse de forma autónoma. En este segundo artículo de la serie vamos a instalar el software necesario en la Raspberry Pi y en el PC, y a aprender a configurarlo para lograr al fin que el coche recorra un circuito por sí solo.
Como ya comentamos en el artículo anterior, todo lo que vamos a ver se basa en el proyecto Donkey Car. En general lo que explicaremos es cómo instalar el software que contiene el repositorio del proyecto y el procedimiento de operación con él.
Antes de empezar hay que comentar que el software de DonkeyCar es muy amateur y está en continua evolución, lo que es sinónimo de problemas. Una muestra de ello es que durante las 4 ó 5 veces que en niubit hemos intentado seguir todo el procedimiento (entrenamiento, generación del modelo y conducción autónoma) con uno de los coches, cada intento se ha desarrollado de manera diferente, obligándonos a consultar la documentación, hacer correcciones al software o improvisando soluciones para conseguir resultados.
Instalación de software en Raspberry Pi
El punto de partida será una instalación de Raspbian, el sistema operativo de Raspberry Pi. No utilizaremos la última versión (Bullseye) sino la anterior (Buster), ya que al menos en el momento de escribir este artículo tuvimos problemas de compatibilidad. Como hemos visto en artículos pasados, utilizamos Imager, la utilidad oficial de Raspberry Pi para instalar el sistema en la tarjeta. Elegiremos la opción Raspberry Pi OS Lite (Legacy):

Como estamos utilizando el modelo Zero 2 de Raspberry Pi, que no tiene puerto Ethernet ni facilita la conexión de pantalla y teclado, es importante configurar la conexión Wifi y activar el servicio SSH desde un principio ya que será nuestra única vía de acceso al sistema. Utilizando las opciones avanzadas de Imager (pulsando en el engranaje que hay bajo el botón Write o pulsando la combinación de teclas Ctrl-Mays-X) ajustamos lo siguiente:

Una vez terminada la instalación de Raspbian en la tarjeta microSD, la insertamos en la Raspberry Pi Zero 2 y la alimentamos. A partir de aquí vamos a ver la secuencia de pasos de la instalación.
Como hemos comentado en la introducción, en las fechas en que seguimos todos estos pasos para preparar este artículo, había varias incidencias abiertas en el repositorio que nos afectaron y que hubo que sortear. Por ese motivo se indica el commit concreto que había en ese momento y que habrá que utilizar si se quiere seguir los mismos pasos que nosotros (con las correcciones que hicimos incluidas). Naturalmente si se va a intentar esta instalación, otra opción es utilizar lo que sigue sólo como guía y tratar de utilizar la documentación oficial confiando en que las incidencias habrán sido resueltas, es decir prescindir de los arreglos que hicimos nosotros:
- Conectar por SSH desde el PC:
ssh Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo. - Preparar el sistema activando el interfaz de la cámara e instalando algunas dependencias:
sudo raspi-config # enable Interface Options - Camera
sudo apt update
sudo apt -y upgrade
sudo apt -y install build-essential python3 python3-dev python3-pip python3-virtualenv python3-numpy python3-picamera python3-pandas python3-rpi.gpio i2c-tools avahi-utils joystick libopenjp2-7-dev libtiff5-dev gfortran libatlas-base-dev libopenblas-dev libhdf5-serial-dev git ntp libgeos-dev - Crear entorno virtual para Python:
python3 -m virtualenv -p python3 env --system-site-packages
echo "source /home/pi/env/bin/activate" >> ~/.bashrc
source ~/.bashrc - Clonar el repositorio y apuntar al commit 6c9ecb9188efa3800291ecaf06bed8e78a1d711b:
cd ~
git clone https://github.com/autorope/donkeycar
cd donkeycar
git checkout 6c9ecb9188efa3800291ecaf06bed8e78a1d711b # Wed Apr 6 21:03:26 2022 +0000 - Descargar el Pull Request #1009 en formato patch, copiarlo en el directorio /home/pi y aplicarlo:
cd ~/donkeycar
git am ../1009.patch - Instalar el módulo donkeycar junto a algunas dependencias dentro de nuestro entorno virtual Python:
cd ~/donkeycar
pip install -U setuptools
pip install -e .[pi]
pip install numpy --upgrade - Bajar el instalador de tensorflow 2.2 descargando este fichero whl y dejándolo en /home/pi.
- Instalar tensorflow 2.2:
pip install /home/pi/tensorflow-2.2.0-cp37-cp37m-linux_armv7l.whl - Instalar OpenCV:
sudo apt -y install libilmbase-dev libopenexr-dev libgstreamer1.0-dev libjasper-dev libwebp-dev libatlas-base-dev libavcodec-dev libavformat-dev libswscale-dev libqtgui4 libqt4-test
pip install opencv-python - Crear directorio de trabajo:
donkey createcar --path /home/pi/mycar --template complete
En estos momentos ya tendríamos instalado todo el software en la Raspberry Pi. Toca hacer las configuraciones y corregir los problemas en el código que nos encontramos en el momento de escribir el artículo.
Empezamos personalizando el fichero /home/pi/mycar/myconfig.py con los siguientes parámetros:
DRIVE_TRAIN_TYPE = "DC_TWO_WHEEL"
LEFT_FWD_DUTY_PIN = "RPI_GPIO.BOARD.18"
LEFT_BWD_DUTY_PIN = "RPI_GPIO.BOARD.16"
RIGHT_FWD_DUTY_PIN = "RPI_GPIO.BOARD.13"
RIGHT_BWD_DUTY_PIN = "RPI_GPIO.BOARD.15"
CAMERA_TYPE = "PICAM"
IMAGE_W = 160
IMAGE_H = 128
SHOW_PLOT = True
USE_JOYSTICK_AS_DEFAULT = False
CONTROLLER_TYPE = 'ps3'
JOYSTICK_MAX_THROTTLE = 0.7
Lo que ahí vemos son básicamente los parámetros para la configuración de nuestro coche en los siguientes aspectos:
- Tipo de motor/dirección que lleva el coche que ya mencionamos en el artículo anterior dedicado al hardware.
- Pines de control de motor/dirección de Raspberry Pi. Comentar que en función de cómo se suelden los cables a los motores desde el conector previsto en la placa controladora de motores que diseñamos, puede ser necesario alternar los pines de alguno de los motores si se observa que gira en sentido contrario al que debería (por ejemplo cambiar el 18 por el 16 y viceversa en el motor izquierdo).
- Tipo de cámara y su resolución.
- Joypad que utilizaremos durante el entrenamiento. Nosotros usamos un viejo controlador de PS3 conectado al puerto microUSB de Raspberry Pi Zero 2 con un adaptador. Las opciones previstas en el código son: ps3, ps4, xbox, pigpio_rc, nimbus, wiiu, F710, rc3, MM1, custom
- Limitación de velocidad máxima para facilitar la conducción. Utilizamos un factor 0,7 (70%) que resulta en una velocidad muy manejable cuando accionamos el acelerador a fondo (stick derecho del mando de PS3 hacia delante). De esa forma nos podemos concentrar con más facilidad en manejar la dirección (stick izquierdo).
La corrección que encontramos necesaria en el código (además de aplicar manualmente el parche del Pull Request #1009 durante la instalación del software) es modificar las siguientes líneas del fichero /home/pi/mycar/manage.py:
left_motor = actuator.L298N_HBridge_2pin(
pins.pwm_pin_by_id(dt['LEFT_FWD_DUTY_PIN']),
pins.pwm_pin_by_id(dt['LEFT_BWD_DUTY_PIN']))
right_motor = actuator.L298N_HBridge_2pin(
pins.pwm_pin_by_id(dt['RIGHT_FWD_DUTY_PIN']),
pins.pwm_pin_by_id(dt['RIGHT_BWD_DUTY_PIN']))
por estas otras:
left_motor = actuator.L298N_HBridge_2pin(
pins.pwm_pin_by_id(cfg.LEFT_FWD_DUTY_PIN),
pins.pwm_pin_by_id(cfg.LEFT_BWD_DUTY_PIN))
right_motor = actuator.L298N_HBridge_2pin(
pins.pwm_pin_by_id(cfg.RIGHT_FWD_DUTY_PIN),
pins.pwm_pin_by_id(cfg.RIGHT_BWD_DUTY_PIN))
Entrenamiento
Ya tenemos el coche listo para ser entrenado en un circuito. En teoría el coche no necesita una pista. Puede ser entrenado para desenvolverse por cualquier lugar que presente características diferenciadas en el terreno que puedan utilizarse para identificar su posición. A pesar de ello nosotros dibujamos en el suelo con cinta de carrocero un sencillo circuito oval, más para ayudarnos a nosotros mismos que al coche, para así conducirlo más o menos por el mismo lugar en cada vuelta. Para arrancar el modo conducción/entrenamiento, sólo tenemos que ejecutar el siguiente comando por SSH:
cd ~/mycar
python manage.py drive --js
El último argumento hace que el control prioritario sea el joypad que hemos conectado. En otro caso hay que seleccionar el control deseado desde un interfaz web que genera el propio coche al que se accede con la dirección http://donkeycar.local:8887 y que vemos a continuación:

Como vemos, los controles posibles son:
- Joystick: Se refiere al panel de fondo azul que se ve a la derecha de la imagen anterior. Se puede usar haciendo click con el ratón sobre esa zona cuando la web se usa desde un PC o con el dedo si se visualiza desde un móvil.
- Gamepad: Es la opción que utilizamos nosotros por resultar un control más preciso. Como decimos, utilizamos el controlador de PS3 que aparece en la imagen que muestra la cámara del coche en la foto anterior. Por si alguien usa ese mismo controlador, recordar que hay que pulsar el botón PS para activar el mando (cuando lo hacemos los cuatro LEDs del mando dejan de parpadear y se ilumina uno de ellos).
- Device Tilt: Cuando se abre este interfaz web desde un móvil, el control puede hacerse con los acelerómetros del mismo, inclinando hacia delante el móvil para acelerar y hacia los lados para girar.
Para entrenar el modelo de inteligencia artificial sólo tenemos que conducir el coche por el circuito unas cuantas vueltas. Cuantas más mejor, naturalmente. En nuestras pruebas estuvimos entrenando el coche durante 5 minutos. Durante la conducción, el coche acumula datos en forma de fotos de la cámara asociadas con la posición del acelerador y el volante en cada instante, unas 20 veces por segundo. En el siguiente vídeo podemos ver un fragmento de esos 5 minutos:
El resultado del entrenamiento queda en el directorio /home/pi/mycar/data al que acudiremos más tarde.
Instalación de software en PC
Para generar el modelo de conducción a partir de los datos recopilados durante el entrenamiento, vamos a ejecutar unos algoritmos de inteligencia artificial muy costosos (en cuanto a potencia de proceso y memoria necesarias). Aunque en teoría es posible hacerlo en la propia Raspberry Pi, en la práctica sería muy problemático por sus recursos limitados (procesador y sobre todo memoria). Por este motivo, vamos a instalar el mismo repositorio que hemos instalado antes en la Raspberry Pi, en un PC convencional. Comentar que los pasos indicados corresponden a un PC con sistema Linux. Según la documentación de DonkeyCar, es preferible este sistema sobre Windows, aunque haciendo los ajustes oportunos (sobre todo instalando el WSL) debería ser posible realizar todos los pasos en un equipo con ese sistema.
A continuación indicamos los pasos detallados:
- Creación de entorno virtual para Python:
cd ~
python3 -m virtualenv -p python3 donkeycar_env --system-site-packages
source ~/donkeycar_env/bin/activate - Clonamos el repositorio y nos colocamos en el commit 6c9ecb9188efa3800291ecaf06bed8e78a1d711b:
cd ~
git clone https://github.com/autorope/donkeycar
cd ~/donkeycar
git checkout 6c9ecb9188efa3800291ecaf06bed8e78a1d711b # Wed Apr 6 21:03:26 2022 +0000 - Instalamos el módulo donkeycar junto a algunas dependencias dentro de nuestro entorno virtual Python:
cd ~/donkeycar
pip install --upgrade pip
pip install -e .[pc]
pip install tensorflow==2.2.0 - Creamos directorio de trabajo:
donkey createcar --path ~/mycar --template complete - Copiar el mismo fichero myconfig.py que creamos en la Raspberry Pi en el directorio /home/pi/mycar. Podemos por ejemplo transferirlo por SCP ejecutando lo siguiente en el PC estando la Raspberry Pi encendida y conectada a la misma red:
cd ~/mycar
scp Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.:mycar/myconfig.py .
Generación modelo
Ya tenemos todo lo necesario para generar el modelo, los datos registrados durante el entrenamiento del coche y el entorno en el PC para ejecutar los algoritmos de IA. Empezamos transfiriendo los datos del entrenamiento al PC. Lo podemos hacer por SCP al igual que transferimos el fichero myconfig.py en el apartado anterior:
cd ~/mycar
scp -r Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.:mycar/data .
Ahora, desde el entorno de ejecución Python que creamos durante la instalación del software en el PC (si no se encuentra activado, hacerlo con el comando source ~/donkeycar_env/bin/activate) ejecutar lo siguiente:
donkey ui
Debería aparecer una ventana como la siguiente:

Como vemos la aplicación tiene 4 utilidades. Para el entrenamiento vamos a necesitar la segunda y posiblemente la primera.
Tub Manager sirve para depurar o limpiar el origen de datos. Con la versión del coche que vimos en el artículo anterior, no fue necesario realizar esta operación, pero cuando utilizábamos el Donkey Car "nominal", al ser un coche tan rápido, era habitual que nos saliéramos de pista. La depuración de los datos permite eliminar fragmentos de la serie de datos que consideremos pueden contaminar el modelo, es decir, retirar las "malas lecciones" que le dimos al coche durante su conducción manual. Pulsamos por tanto el botón correspondiente y nos aparece la interfaz de depuración de datos, que nos permite delimitar los fragmentos de los datos que no nos interesen para borrarlos. Puede ser necesario utilizar los botones Load car directory y Load tub para localizar los directorios ~/mycar y ~/mycar/data respectivamente (donde ~ hace referencia al home del usuario).

En el siguiente vídeo vemos una composición de los datos de las fotos con la información de acelerador (longitud de la línea verde) y dirección (ángulo de la línea) que utilizamos nosotros para el entrenamiento del coche en el circuito dibujado en el suelo. Es decir, lo siguiente es lo que "siente" el coche y todo lo que va a utilizar para aprender el circuito, ni más ni menos. Como vemos la imagen no tiene excesiva resolución (corresponde a la resolución que indicamos en el fichero myconfig.py más arriba), pero es mejor así ya que de este mod las fotos son más fáciles de procesar. Paradójicamente para un coche robotizado, interesa que vea menos de lo que a nosotros nos resultaría conveniente:
Una vez que estemos satisfechos con el lote de datos, pasamos a generar el modelo mediante la utilidad Trainer. En la pantalla correspondiente dejamos los ajustes predeterminados y pulsamos el botón Train. Tras unos cuantos minutos durante los cuales el botón Train se coloreará en azul y cambiará su texto a Training running..., veremos cómo aparece una entrada en la lista que hay en la zona central:

Nuestro modelo quedará en el directorio ~/mycar/models. Allí encontraremos el mismo nombre de fichero con dos extensiones distintas:
- h5: Modelo normal
- tflite: Modelo más comprimido
El segundo es de reciente incorporación y es la opción más recomendable, ya que permite que el coche tome decisiones más rápidas cuando utiliza el modelo para conducir autónomamente.
Sólo nos queda copiar el modelo generado al coche, para lo que ejecutamos desde el PC:
cd ~/mycar
scp -r models Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.:mycar
Conducción autónoma
Queda la parte más satisfactoria, obtener el fruto de todo nuestro trabajo, es decir poner al coche a conducir sobre el circuito por sí solo. El procedimiento es muy similar al que vimos en la fase de entrenamiento. Sólo cambiarán algunos argumentos en el comando que ejecutaremos y que ya no necesitaremos conectar el controlador de PS3 para manejar el coche. Para poner en marcha el "motor digital" del coche ejecutamos por SSH en la Raspberry Pi el siguiente comando (sustituyendo el nombre del modelo tflite por el que corresponda):
cd ~/mycar
python manage.py drive --model /home/pi/mycar/models/pilot_22-04-18_0.tflite --type tflite_linear
Por seguridad el coche no arranca en ese momento. Tenemos que acceder al interfaz web que se inicia en la Raspberry Pi y pulsar el botón Start Vehicle (space):

Si todo va bien debería de ocurrir lo siguiente:
Con esto concluimos la serie sobre DonkeyCar. Realmente hay que decir que en este proyecto cuesta obtener resultados. Una de las mayores pegas está en la continua evolución del software, que hace que lo que en un momento funciona, pueda no hacerlo a la semana siguiente si se actualiza el repositorio, o se empiece a hacer de otra manera. Por eso es buena idea anotar los hashes de los commits del repositorio git utilizados para una instalación concreta, por si se quiere reproducir en el futuro o seguir sin problemas la documentación que hayamos hecho en ese caso. A cambio de los problemas, naturalmente el aprendizaje es mayor.
En cualquier caso, dejando a un lado los problemas con el repositorio oficial, nuestro objetivo era construir una versión más sencilla, barata y fácil de conducir/entrenar para poder desarrollar este proyecto con nuestros alumnos. Y en ese aspecto podemos decir que lo hemos conseguido. Si os apetece ver el resultado en persona, estaremos encantados de mostrároslo si os pasáis por nuestro local.
