Sunteți pe pagina 1din 9

Objetivo

Modificar un automóvil a control remoto para que realice tres tareas: conducción autónoma
en la vía, detección señal de stop y del semáforo, y prevención de colisión frontal.

Diseño de sistemas

El sistema consta de tres subsistemas: unidad de entrada (cámara, sensor ultrasónico), unidad
de procesamiento (computadora) y unidad de control de cabina de control Remoto.

Unidad de entrada

Un tablero Raspberry Pi (modelo B ), conectado con un módulo de cámara pi y un sensor


ultrasónico HC-SR04 se utiliza para recopilar datos de entrada. Dos programas para clientes se
ejecutan en Raspberry Pi para transmitir videos en color y datos de sensores ultrasónicos a la
computadora a través de una conexión Wi-Fi local. Para lograr una transmisión de video de
baja latencia, el video se reduce a una resolución QVGA (320 × 240).

Unidad de procesamiento

La unidad de procesamiento (computadora) maneja múltiples tareas: recibir datos de


Raspberry Pi, entrenamiento y predicción de redes neuronales, detección de objetos (señal de
stop y semáforo), medición de distancia (visión monocular) e instrucciones de envío a Arduino
a través de una conexión USB .

Servidor TCP

Se ejecuta un programa de servidor TCP de varios subprocesos en la computadora para recibir


tramas de imágenes transmitidas y datos ultrasónicos del Raspberry Pi. Los marcos de imagen
se convierten a escala de grises y se decodifican en matrices numpy.

Red neuronal

Una de las ventajas del uso de redes neuronales es que una vez que la red está capacitada,
solo necesita cargar parámetros entrenados posteriormente, por lo que la predicción puede
ser muy rápida. Solo la mitad inferior de la imagen de entrada se usa con fines de
entrenamiento y predicción. Hay 38,400 nodos (320 × 120) en la capa de entrada y 32 nodos
en la capa oculta. El número de nodos en la capa oculta se elige bastante arbitrario. Hay cuatro
nodos en la capa de salida donde cada nodo corresponde a las instrucciones de control de
dirección: izquierda, derecha, adelante y atrás respectivamente (aunque el reverso no se usa
en ningún lugar de este proyecto, aún se incluye en la capa de salida).

A continuación se muestra el proceso de recopilación de datos de capacitación. Primero, cada


fotograma se recorta y se convierte en una matriz numpy. Luego, la imagen del tren se
empareja con la etiqueta del tren (entrada humana). Finalmente, todas las etiquetas y los
datos de imagen emparejados se guardan en un archivo npz. La red neuronal está entrenada
en OpenCV usando el método de propagación de retorno. Una vez hecho el entrenamiento, los
pesos se guardan en un archivo xml. Para generar predicciones, se construye la misma red
neuronal y se carga con el archivo xml entrenado.

Detección de objetos

Este proyecto adaptó el enfoque basado en formas y utilizó clasificadores en cascada basados
en características de Haar para la detección de objetos. Dado que cada objeto requiere su
propio clasificador y sigue el mismo proceso en el entrenamiento y la detección, este proyecto
solo se centró en la detección de señales de stop y semáforos.

OpenCV proporciona un entrenador y un detector. Las muestras positivas (que contienen el


objeto de destino) se adquirieron usando un teléfono celular, y se recortaron para que solo el
objeto deseado sea visible. Las muestras negativas (sin objeto objetivo), por otro lado, se
recolectaron aleatoriamente. En particular, las muestras positivas al semáforo contienen la
misma cantidad de semáforos rojos y semáforo verde. El mismo conjunto de datos de muestra
negativo se utilizó para el entrenamiento de señal de stop y semáforo.

Para reconocer diferentes estados del semáforo (rojo, verde), se necesita algo de
procesamiento de imágenes más allá de la detección. El siguiente diagrama de flujo resume el
proceso de reconocimiento del semáforo.

En primer lugar, el clasificador en cascada capacitado se usa para detectar el semáforo. El


cuadro delimitador se considera como una región de interés (ROI). En segundo lugar, el
desenfoque Gaussiano se aplica dentro del ROI para reducir los ruidos. En tercer lugar,
encuentre el punto más brillante en el retorno de la inversión. Finalmente, los estados rojo o
verde se determinan simplemente en función de la posición del punto más brillante en el
retorno de la inversión.

Medición de distancia

Raspberry Pi solo puede admitir un módulo de cámara pi. El uso de dos cámaras web USB
aportará un peso adicional al automóvil RC y también parece poco práctico. Por lo tanto, se
elige el método de visión monocular.

Unidad de control de coche a control remoto

El auto de CR usado en este proyecto tiene un controlador tipo encendido / apagado. Cuando
se presiona un botón, la resistencia entre el pin del chip correspondiente y la tierra es cero.
Por lo tanto, una placa Arduino se usa para simular acciones de presionar un botón. Se eligen
cuatro pines Arduino para conectar cuatro pines de chip en el controlador, que corresponden
respectivamente a las acciones hacia adelante, hacia atrás, hacia la izquierda y hacia la
derecha. Los pines Arduino que envían la señal BAJA indican la conexión a tierra de los pines
del chip del controlador; por otro lado, el envío de la señal HIGH indica que la resistencia entre
los pines del chip y la tierra no cambia. Arduino está conectado a la computadora a través de
USB. La computadora emite comandos a Arduino utilizando la interfaz serie, y luego el Arduino
lee los comandos y escribe señales BAJAS o ALTAS, simulando acciones de presionar un botón
para conducir el auto RC.

Resultados

La predicción en las muestras de prueba arroja una precisión del 85% en comparación con la
precisión del 96% que devuelve la muestra de entrenamiento. En la situación de conducción
real, las predicciones se generan aproximadamente 10 veces por segundo (velocidad de
transmisión de aproximadamente 10 cuadros / s).

Las características de Haar por naturaleza son sensibles a la rotación. En este proyecto, sin
embargo, la rotación no es una preocupación, ya que tanto la señal de pare y el semáforo son
objetos fijos, que también es un caso general en el entorno del mundo real.
Para el aspecto de medición de distancia, el sensor ultrasónico solo se usa para determinar la
distancia a un obstáculo en frente del automóvil RC y proporciona resultados precisos al tomar
en cuenta el ángulo de detección y la condición de la superficie. Por otro lado, la cámara Pi
proporciona resultados de medición "lo suficientemente buenos". De hecho, siempre que
sepamos el número correspondiente a la distancia real, sabemos cuándo detener el automóvil
RC.

En este proyecto, la precisión de la medición de distancia con enfoque de visión monocular


podría verse influenciada por los siguientes factores:

(1) errores en la medición de los valores reales.

(2) variaciones de la caja de delimitación del objeto en el proceso de detección.

(3) errores en el proceso de calibración de la cámara

(4) relación no lineal entre la distancia y la coordenada de la cámara: cuanto mayor es la


distancia, más rápido cambia la coordenada de la cámara, por lo tanto, mayor es el error.

En general, el auto RC podría navegar con éxito en la pista con la capacidad de evitar la colisión
frontal, y responder en consecuencia a la señal de stop y al semáforo.

Recopilación de datos

El algoritmo / modelo de aprendizaje de máquinas TensorFlow necesita datos para


aprender. Los datos constan de dos partes.

1. Datos de video: un video no es más que una serie de fotos. Uso OpenCV para
representar cada cuadro como una matriz de números, donde cada número
representa un píxel. Si desea video en blanco y negro, OpenCV le dará una
matriz bidimensional que consta de la altura y el ancho de un cuadro. Si decides
que quieres un video en color, entonces OpenCV te dará una matriz
tridimensional que consta no solo de alto y ancho sino también de profundidad
de color: rojo, verde y azul. El modelo de aprendizaje automático utilizará los
píxeles de la matriz como predictores.
2. Datos de comando: los comandos le dicen a los motores qué hacer y
representan la variable objetivo. El modelo intentará aprender qué comandos
enviar al motor según el video que ve. Fui por simplicidad, así que solo definí
tres tipos de comandos: izquierda, derecha y adelante. Esto hace que conducir
un problema de clasificación multinomial. La desventaja de tener solo tres
comandos es que las instrucciones pueden ser bastante crudas. No hay
distinción entre un giro amplio y un giro brusco.

Cómo funciona la recopilación de datos


Esta parte del proyecto es muy poco intuitiva y probablemente podría diseñarse
mucho mejor. Hay múltiples componentes.

 Transmisión de video Raspberry Pi usando una complicada utilidad de video


Linux
 Un lío enredado para ver y guardar los datos de video transmitidos
 Un servidor web de API relajante que se ejecuta en el Pi y toma comandos de
un navegador web como Google Chrome ejecutándose en su computadora
portátil.
 Algo para mover los archivos de comando API desde el Pi a su computadora
portátil donde se guardan los datos de video
 Una herramienta de limpieza de datos que coincide con los datos de tu blanco y
del predictor por marca de tiempo y genera un archivo numpy limpio final que
TensorFlow puede ingerir

Instrucciones para recolectar datos


En primer lugar, deberá asegurarse de que la zona horaria de su Raspberry Pi coincida
con la de su computadora portátil. El código no podrá hacer coincidir las marcas de
tiempo en el Pi (los comandos de manejo) con las de los marcos de video en la
computadora portátil si las zonas horarias no coinciden. Ingrese el siguiente comando
en el Pi para actualizar su zona horaria:

sudo dpkg-reconfigure tzdata


Active la transmisión de video desde Pi. Inicie sesión en Raspberry Pi si aún no lo hizo e
ingrese los siguientes comandos:

# Go to wherever you installed ffmpeg


cd /usr/src/ffmpeg

# Run ffmpeg. I have no idea how this command works since I copy-and-pasted it from some website off
of Google
sudo ffserver -f /etc/ff.conf_original & ffmpeg -v quiet -r 5 -s 320x240 -f video4linux2 -i /dev/video0
http://localhost/webcam.ffm
En este punto, el video en tiempo real debe estar disponible en la siguiente URL. Sin
embargo, no podrá ver el video en bruto desde su navegador; su navegador intentará
sin parar descargar el archivo de transmisión. Tenga en cuenta que la IP
probablemente sea diferente para usted.
http://ryanzotti.local/webcam.mjpeg
Inicie el servidor web API. Inicie sesión en Raspberry Pi en otra pestaña. Clona este
repositorio en el Pi y muévete a la carpeta. Luego, inicie el servidor que aceptará
comandos remotos para conducir el automóvil (consulte el drive_api.pysiguiente
comando).
La velocidad de conducción podría ser un parámetro que la IA aprenda, pero por
simplicidad, hice de la velocidad un argumento CLI que es constante para toda la
sesión de manejo. El automóvil usa modulación de ancho de pulso (PWM) para
cambiar la velocidad, y la CLI del servidor acepta un parámetro de velocidad llamado
"speed_percent" que determina la configuración de PWM en el Pi. Un porcentaje de
velocidad de 100 se traduce en velocidad máxima, mientras que 0 significa que el
automóvil nunca se moverá.

Por lo general, usaré una velocidad más alta (90-100) cuando recopile datos de
entrenamiento y una velocidad mucho menor (40-50) cuando dejo que la IA se haga
cargo. A veces también necesitará ajustar la velocidad para que coincida con el
terreno. Por ejemplo, mi coche es lento en la alfombra, así que cuando la IA maneje en
la alfombra, podría establecer una velocidad de 80 o incluso 100. El siguiente comando
iniciará el servidor que acepta comandos de conducción remota.

sudo python3 drive_api.py --speed_percent 50


En mi Pi la secuencia de comandos de la API de unidad falla si la llamo con Python 2 o
si no la llamo con root, pero todo depende de cómo configures todo y puede diferir en
función de cómo hiciste tu instalación.

A continuación, ejecute el script que muestra y guarda los datos de video


entrantes. Ingrese el siguiente comando usando la dirección IP de su Raspberry Pi.

python save_streaming_video_data.py --host ryanzotti.local


Finalmente, abra un navegador web y apúntelo a la URL a continuación (es probable
que la dirección IP sea diferente para usted).

http://ryanzotti.local:81/drive
Haga clic en la página y use las teclas de flecha (izquierda, derecha, arriba, abajo) para
conducir el automóvil. La página en la que acabas de hacer clic tiene algo de jacky
javascript que escribí que dispara una llamada API al servidor web que se ejecuta en el
Pi cada vez que presionas una de las teclas de flecha.

Cuando llegue al final de su sesión de manejo, cambie la URL en el navegador a:

http://ryanzotti.local:81/StoreLogEntries
Luego presiona enter. Esto ejecuta un paso importante de limpieza de datos en todos
los comandos que el servidor web recibió durante la sesión de conducción. Una vez
que la página web diga "Finalizado", vaya a la pestaña Terminal / Masilla que ejecuta el
servidor y presione control + c para finalizar el proceso. Has visto ahora dos archivos.

1. session.txt: contiene comandos accidentales válidos y no válidos


2. clean_session.txt: contiene solo comandos válidos
Ahora mata el save_streaming_video_data.pyscript. Este script debería haber generado dos
archivos.

1. video_timestamps.txt: contiene marcas de tiempo para cada uno de los


cuadros de video guardados
2. output.mov: contiene datos de video

Entonces, en total, hay cuatro archivos para cada sesión de manejo. Normalmente
creo una nueva carpeta para cada sesión. Tenga en cuenta que dos de los archivos
están en el Pi y dos están en su computadora portátil. Sin embargo, los cuatro archivos
deben estar en el mismo lugar para el procesamiento, por lo que normalmente copio
los archivos Pi en mi computadora portátil. Tendrá que generar muchos datos de
manejo, y copiar los archivos del Pi a su computadora portátil puede ser
tedioso. Creé scp_car_data.shpara hacer esto más fácil.
Una vez que todos los archivos estén en el mismo lugar, es hora de limpiar todos sus
datos y crear archivos que TensorFlow pueda digerir para la capacitación del
modelo. Todo esto sucede en el save_all_runs_as_numpy_files.pyguion. Este script asigna
una etiqueta (izquierda, derecha, recta) a cada imagen y realiza una limpieza de datos
básica. Guarda cada sesión de conducción por separado como un archivo .npz.

Inicio rápido de captura de datos


En resumen, para recopilar datos de entrenamiento, debe tener abiertas tres sesiones
de terminal:

# Terminal 1
ssh pi@ryanzotti.local
cd /usr/src/ffmpeg
sudo ffserver -f /etc/ff.conf_original & ffmpeg -v quiet -r 5 -s 320x240 -f video4linux2 -i /dev/video0
http://localhost/webcam.ffm

# Terminal 2
ssh pi@ryanzotti.local
cd /home/pi/Documents/code/Self-Driving-Car
sudo su
python3 drive_api.py --speed_percent 100

# Terminal 3
cd /Users/ryanzotti/Documents/repos/Self-Driving-Car
python save_streaming_video_data.py --host ryanzotti.local

Copias de seguridad
Recomiendo hacer una copia de seguridad de sus datos en algún lugar como el S3 de
AWS. Vea ejemplos de línea de comandos a continuación.
Tenga en cuenta que sin el --deleteindicador, el aws synchcomando no borrará los datos
de S3, sino que lo agregará si no existe. Esto es útil para que no borre accidentalmente
toda su copia de seguridad.
El syncomando es recursivo, por lo que puede copiar archivos dentro de carpetas
anidadas.
# Specify your own locations
LOCAL_FOLDER='/Users/ryanzotti/Documents/repos/Self_Driving_RC_Car/data'
S3_FOLDER='s3://self-driving-car/data'

# To back up to AWS
aws s3 sync ${LOCAL_FOLDER} ${S3_FOLDER}

# To restore backup from AWS


aws s3 sync ${S3_FOLDER} ${LOCAL_FOLDER}

# You can also delete unwanted files from the AWS backup
aws s3 sync ${LOCAL_FOLDER} ${S3_FOLDER} --delete
El comando anterior puede tomar un tiempo extremadamente largo dependiendo de
la velocidad de su conexión a Internet. En un momento tuve un plan básico de Internet
de AT & T básico con solo una velocidad de carga de 250 kbps (anunciado a 5 Mbps), y
tardé entre 5 y 8 horas en cargar aproximadamente una hora de datos de conducción.

EDITAR: Desde entonces, abandoné el paquete de 5 Mbps de $ 40 por mes de AT & T y


lo reemplacé con el paquete Google Fiber de San Francisco (a través de Webpass) a $
42 / mes por 1,000 Mbps (1 Gbps). La velocidad de carga real oscila entre 400-900
Mbps. Ahora cargando de 4 a 5 horas de datos de manejo toma solo 1-2
minutos. Google Fiber es increíble. Lo amo.

Para ejecutar todos estos comandos AWS localmente, debe informar a AWS que tiene
acceso. AWS hace esto con aws_secret_access_keyy aws_access_key_id. Cuando activa una
instancia de AWS (por ejemplo, una GPU), puede asignar un AWS IAM Rolea la instancia
y la instancia heredará estas credenciales. Sin embargo, AWS no puede asignar un rol
de IAM a su computadora portátil, por lo que deberá actualizar ~/.aws/credentialspara
que se parezca a los contenidos a continuación. Obviamente, estos son valores falsos,
pero los valores reales se parecen tanto a las largas cadenas de galimatías. Puede
obtener los valores reales asociados con su cuenta a través de la consola AWS
IAM. Nunca debe exponer sus valores reales al público: los ladrones podrían tomar el
control de toda su cuenta de AWS y, por ejemplo, ejecutar una factura masiva, entre
otras cosas.
[default]
aws_access_key_id = ASDFSDFSDFSDFSDFKKJSDFEUSXN
aws_secret_access_key = SKJE8ss3jsefa3sjKSDWdease3kjsdvna21
region = us-east-1
Los datos de video ocupan mucho espacio en su máquina local. Reviso periódicamente
la cantidad de almacenamiento que he usado ejecutando el siguiente comando.

DATA_DIR='/Users/ryanzotti/Documents/repos/Self_Driving_RC_Car/data'
du -sh ${DATA_DIR}

Procesamiento de datos
Al comienzo de mi proyecto, confié en dataprep.pyagregar todos los datos de imágenes y
etiquetas de mis sesiones en un único archivo para el entrenamiento modelo. A
medida que mi conjunto de datos creció, mi laptop de 16 GB de memoria comenzó a
tener problemas de memoria al procesar todos los archivos simultáneamente. Mi
límite parecía ser 44,000 imágenes de 240x320x3.
Como no quiero gastar dinero en un clúster GPU Apache Spark, decidí probar mis
datos usando el Dataset.pyscript y la Datasetclase. Datasetasume que ya ha ejecutado
el save_all_runs_as_numpy_files.pyscript. La Datasetclase debe crearse una instancia en cada
secuencia de comandos de capacitación del modelo, ya que ahora también se encarga
de crear lotes.

Entrenamiento modelo
El entrenamiento en la GPU es mucho más rápido que el entrenamiento en la CPU que
ahora solo entreno en la GPU, excepto cuando se depura. Tengo una velocidad de
hasta 14x cuando uso una de las GPU Tesla K80 de AWS (p2.xlarge) en comparación
con la CPU de mi Mac. Las Mac no tienen una GPU incorporada soportada por
Tensorflow, así que confío en AWS para hacer mi entrenamiento de GPU.

He escrito guiones para entrenar diferentes tipos de modelos. Para evitar confusiones,
he estandarizado las entradas de la interfaz de línea de comandos en todos los scripts
al aprovechar la misma Trainerclase Trainer.py. Todos los scripts sincronizan / archivan
datos automáticamente con AWS's S3. Esto significa que el modelo siempre entrenará
en el último lote de datos de entrenamiento. También significa que debe estar
preparado para descargar TODOS los datos de capacitación, que a partir de ahora son
aproximadamente 50 GB. Asegúrese de que su computadora portátil o GPU tenga
suficiente espacio antes de intentarlo.
Cada secuencia de comandos se sincroniza con S3 antes del entrenamiento, por lo que
es posible entrenar varios modelos en paralelo sin que las copias de seguridad se
sobrescriban entre sí. La Trainerclase escribe copias de seguridad en S3 después de cada
época.
Entrenar un nuevo modelo es simple. Vea el ejemplo a continuación. El nohupy &decirle
el modelo para entrenar en el fondo para que pueda cerrar el ordenador (suponiendo
que el código se ejecuta en la nube y no en local).
S3_BUCKET=self-driving-car # Specify your own S3 bucket
SCRIPT=train_conv_net.py
# Optionally, in development mode, avoid syncing to save money on S3 data transfers
S3_SYNC=n

# All scripts follow the same command-line interface


nohup python3 ${SCRIPT} --datapath /root/data \
--epochs 100 \
--s3_bucket ${S3_BUCKET} \
--s3_sync ${S3_SYNC} &
La capacitación aún lleva mucho tiempo (por ejemplo, más de 10 horas) incluso
cuando se entrena en una GPU. Para facilitar la recuperación de fallas inesperadas, uso
la función de punto de control de Tensorflow para poder iniciar y detener mis
modelos. Estos se incluyen en las copias de seguridad modelo enviadas a la nube. El
punto de control del modelo Tensorflow también permite confiar en AWS Spot
Instances, que todavía no he probado.

Creé un script llamado resume_training.pyque es agnóstico para el modelo cuyo


entrenamiento se está reiniciando. Lee en un archivo de punto de control Tensorflow
que especifique y reconstruye el modelo en la memoria antes de reanudar el
entrenamiento. Puedes llamarlo así:
# Your paths will differ
DATA_PATH='/Users/ryanzotti/Documents/repos/Self_Driving_RC_Car/data'
EPOCHS=100
MODEL_DIR='/Users/ryanzotti/Documents/repos/Self_Driving_RC_Car/data/tf_visual_data/runs/1'
S3_BUCKET=self-driving-car
# Optionally, in development mode, avoid syncing to save money on S3 data transfers
S3_SYNC=n

# Run the script


python resume_training.py \
--datapath $DATA_PATH \
--epochs $EPOCHS \
--model_dir $MODEL_DIR \
--s3_bucket ${S3_BUCKET} \
--s3_sync ${S3_SYNC}

# Or on a GPU
DATA_PATH='/root/data'
EPOCHS=100
MODEL_DIR='/root/data/tf_visual_data/runs/4'
S3_BUCKET=self-driving-car

# Run the script


nohup python3 resume_training.py \
--datapath $DATA_PATH \
--epochs $EPOCHS \
--model_dir $MODEL_DIR \
--s3_bucket ${S3_BUCKET} \
--show_speed True &

S-ar putea să vă placă și