Sunteți pe pagina 1din 89

Taller de Proyecto II

2017

Sistema Antichoque

Proyecto N°4

Integrantes

Alvarez Matías 923/3


Cristofano Marco 813/8

Proyecto Disponible en:


https://github.com/alvmatias/SistemaAntichoque
1. Propuesta Original del Proyecto
El objetivo es la construcción de un sistema antichoque para un vehículo que posee
tres velocidades de avance y una velocidad de retroceso. El sistema se encontraría
configurado para moverse en ambos sentidos y para ello se utilizaría, en principio, 2
módulos de ultrasonido, uno detectando los obstáculos en el avance y el otro en el
retroceso.
Desde el punto de vista del usuario, el mismo deberá acceder a una aplicación web
donde encontrará los comandos necesarios para hacer funcionar el vehículo, además de la
información pertinente a la distancia del vehículo con los obstáculos, y otras características
y estados que serán explicados más en detalle. La mencionada aplicación será montada
sobre un servidor HTTP el cual se comunicará con el vehículo mediante el protocolo
TCP/IP. Para llevar a cabo este objetivo se le incorporará al vehículo un módulo wifi
ESP8266.
Cabe aclarar que como medida de seguridad el usuario accederá a la aplicación
haciendo uso de un token o contraseña privada generada por el mismo servidor, de modo
tal que otro usuario no pueda acceder al control del autito. Esto es, que un usuario deberá
primero generar el token o contraseña, accediendo al servidor, luego configurar su autito
para que en la conexión TCP/IP con el servidor, este provea al servidor del token para
poder establecer la conexión. De no existir ese token, la conexión no será posible. Los
tokens serán únicos. Un mismo usuario podría generar más de un token.

El sistema queda graficado de la siguiente manera:

En la imagen anterior se intentan representar los siguientes conceptos:


-El sistema antichoque que posee el vehículo será en ambos sentidos:
-El vehículo contendrá un módulo wifi(ESP8266) con el cual se comunicará con el
servidor.
-La comunicación Vehículo-Servidor será mediante el protocolo TCP/IP.
-El servidor será el encargado de obtener los datos del vehículo y presentarlos al
usuario.
-El servidor será el encargado de enviar al vehículo los comandos del usuario.
-El servidor proveerá un servicio HTTP.

2.Correcciones/Cambios de la Propuesta

2.1 Indicadas por la Cátedra


El módulo WIFI ESP8266 deberá estar configurado como “punto de acceso” (Access
Point), de esta manera es el propio vehículo quien provee la red de interconexión entre el
servidor, el usuario, y el propio vehículo.

2.2 Definidas por el Avance/Disponibilidad


Se realizaron los siguientes cambios producto del avance del proyecto y
disponibilidad de elementos:

● Luego de la modificación del proyecto establecida por la cátedra se pretendía que el


protocolo de seguridad de coneccion sea WPA2, a la hora de llevar a la práctica por
motivos que se desconocen el módulo ESP8266 no permite el establecimiento de
WPA2 como protocolo. En consecuencia se debebeŕa dejar la red sin protección.
Además, al ser el propio vehículo, mediante el ESP8266, quien provee la red sobre
la que se van a encontrar conectados, usuario, servidor y el propio autito, se decidió
eliminar el sistema de token, y agregar un sistema básico de usuarios, donde se
permita registrar una cuenta e ingresar a la misma. El mencionado sistema de
usuario quedará detallado en el transcurso del presente informe.

● El vehículo se diseñó teniendo en cuenta que del banco de baterías que se instalaría
en el mismo, se podría obtener 5V para la alimentación de los sensores de distancia.
A causa de la dificultad para obtener baterías de 5V se decidió utilizar la salida de
5V que posee el doble puente H. Consecuencia de esto se reposicionaron los
componentes en el vehículo siguiendo las siguientes premisas: Primero, mantener
una correcta distribución del peso en el vehículo para que la fuerza entregadas por
los motores sean de magnitudes similares. Segundo, realizar un cableado prolijo y
reducido.

● Al utilizar un vehículo propulsado por dos motores independientes, se esperaba que


los mismos posean un funcionamiento similar. Al hacer pruebas se notó la
imposibilidad de realizar un recorrido en línea recta, pues un motor requiere mayor
potencia que el otro para obtener la misma velocidad. Se intentó corregir esta
variación mediante una asignación independiente de PWM (forma de manejo de
velocidad para cada motor) y se obtuvieron mejoras con respecto a la performance
inicial, pero persiste una considerable curvatura en su desplazamiento. Se procedió
a fijar la rueda móvil de la parte trasera del vehículo, obteniendo significativas
mejoras. Finalmente, se modificaron las librerías previamente implementadas para
que el el vehículo fuera capaz de avanzar con 3 marchas, retroceder y doblar en
ambos sentidos con una marcha y frenar.
● Al buscar información en la web relacionada con los consumos de todos los
componentes se llegó a la siguiente estimación, la cual se encuentra en la bitácora:

A partir de esta informacion se decidió que el vehículo en tu totalidad se alimente


con dos bateria de 9v, una destinada a la alimentación del doble puente H ( y sensores de
distancia), y la restante a la alimentación del arduino ( y ESP8266). Al realizar pruebas se
encontró una autonomía de aproximadamente 7 minutos, la cual no se corresponde con los
valores estimados de consumos. ​El problema más recurrente que se encontró, fue que
si bien las baterías podían seguir alimentando al vehículo, el requerimiento de
corriente por parte de los motores al momento de arrancar era tan alto, que las
baterías no lo podían proveer al descargarse y como consecuencia, los motores no
arrancaban, impidiendo que el autito se moviera. ​Por otro lado, en ocasiones, incluso
con las baterías completamente cargadas, el consumo inicial de los motores, genera
que la tension de las baterías caiga, produciendo valores erróneos en los sensores
y/o impidiendo que los motores arranquen. Sin embargo, este problema se podría
mejorar con la incorporación de baterías de mejor calidad. ​Todos estos inconvenientes no
sucedieron al utilizar una fuente de computadora con un regulador, para proveer al
autito de 9V, es por ello que en todas las pruebas y videos se la utilizó para poder
obtener una mejor presentación.
A pesar del funcionamiento de los motores y el alto consumo, la confección
del informe, fue hecha teniendo en cuenta un caso ideal.
3. Descripción de Hardware y Conexiones
En primera instancia de procede detallar el conexionado individual de cada
componente:
Conexionado HC_SR04 delantero​:

Pin HC_SR04 Pin de Conexion(dispositivo)

GND Neutro (Banco de Baterías)

TRIG Pin 12(Arduino uno)

ECHO Pin 13(Arduino uno)

VCC Positivo 5v( Salida 5v Puente H)

Conexionado HC_SR04 trasero​:

Pin HC_SR04 Pin de Conexion(dispositivo)

GND Neutro (Banco de Baterías)

TRIG Pin 9(Arduino uno)

ECHO Pin 8(Arduino uno)

VCC Positivo 5v( Salida 5v Puente H)


El conexionado de los dos sensores de distancia se refleja en la siguiente imagen:

*El puente H se encuentra en la imagen, pues de él se obtienen los 5V requeridos


para la alimentación los sensores.

Conexionado doble puente H​:

Pin Doble Puente H Pin de Conexion(dispositivo)

INA Pin 3(Arduino uno)

INB Pin 2(Arduino uno)


INC Pin 4(Arduino uno)

IND Pin 7(Arduino uno)

ENA Pin 5(Arduino uno)

ENB Pin 6(Arduino uno)

Bornera Doble Puente H Bornera

1 Cable amarillo motor izquierdo

2 Cable azul motor izquierdo

3 Positivo 9v (Banco de Baterías)

4 Neutro (Banco de Baterías)

5 Alimentación HC_SR04

6 Cable amarillo motor derecho

7 Cable azul motor derecho

*Las referencias a motor derecho e izquierdo tienen validez si se ve el vehículo de la


siguiente manera:
El conexionado antes mencionado se refleja en la siguiente imagen:

Conexionado ESP8266​:

Número Nombre Pin ESP8266 Pin de conexión(Dispositivo)

1 RX Pin 0(Arduino uno)

2 GND GND(Arduino uno)

3 CH 3.3V(Arduino uno)

4 GPIO2 Sin conexión


5 RESET Sin conexión

6 GPIO1 Sin conexión

7 VCC 3.3V(Arduino uno)

8 TX Pin 1(Arduino uno)

El conexionado antes mencionado se refleja en la siguiente imagen:

*Para la alimentación del módulo ESP8266 se utilizó un capacitor de 50V 10uF para otorgar
estabilidad al mismo.

Una vez individualizado cada componente continuamos con el conexionado general


de vehículo. La siguiente imagen incluye a todos los componentes y, medianamente, su
disposición dentro del vehículo. Se recomienda descargar la imagen del repositorio de
github, pues para observar los nombres de los nombres de los pines se requiere realizar un
acercamiento de la imagen.
Aclaraciones generales del conexionado:
-El doble puente H que se observa en la imagen, no es exactamente el modelo con
el cual funciona el vehículo. Sin embargo, la cantidad y nomenclatura de los pines se
asimila con la del utilizado.
-Para la alimentación del módulo ESP8266 se utilizó un capacitor de 50V 10uF para
otorgar estabilidad al mismo.
-En la disposición real de los componentes, las baterías se encuentra debajo del
doble puente H, por una cuestión de legibilidad se colocaron en el gráfico a un lado.

La implementación real es la siguiente:


4. Descripción Funcional
Antes de proceder con la distinción de casos de uso creemos que es necesario
explicar cómo es la estructura y diseño del sistema, para que luego al detallar cada caso de
uso resulte más simple su comprensión. Además, se irá explicitando el nombre del
componente por el cual se puede realizar la acción en cuestión.
Con respecto al vehículo:
● Al encender el vehículo el mismo se encarga en primera instancia de la
configuración de los pines necesarios para la utilización de los dos sensores
de distancia, del módulo wifi(ESP8266-01) y del puente H (L298N).
● Luego crea la red -mediante el módulo wifi- llamada SistemaAntichoque la
cual no posee ningún tipo de seguridad y puede ser accedida por cualquier
dispositivo (máximo de 5). Además se monta servidor TCP por el cual recibirá
“órdenes” por parte de usuario. El mismo se encuentra en el puerto 666 de la
ip 192.168.4.1, pues la dirección IP del vehículo no cambia.
● Para las tareas antes mencionadas se utilizan las siguientes funciones:
○ HC_SR04X2 sensor_distance de la librería HC_SR04X2.
○ ESP8266 wifi() de la librería ESP8266.
○ wifi.Configuration() de la librería ESP8266.
○ sensor_distance.BackSetup de la librería HC_SR04X2.
○ sensor_distance.FrontSetup de la librería HC_SR04X2.
Una vez concluida la etapa de configuración, que aproximadamente tarda 3
segundos, el vehículo se encuentra en condiciones de funcionar.
En cuanto al funcionamiento, se diseñó el software sin la utilización de un sistema
operativo, por ello se aprovechó la estructura LOOP propia de arduino para crear un lazo de
control. El mismo se puede observar en la siguiente imagen.

● Control de Distancia​: Se encarga de la realización de mediciones de distancia


(HC_SR04) en ambas direcciones y su respectivo almacenaje en variables globales
del arduino. A su vez, en el caso de detección de un obstáculo a una distancia
menor que la crítica (40 cm) accionará el freno de emergencia.

Para las tareas del Control de distancia se utilizan las siguientes funciones:
● ”FrontMeasurement” de la librería HC_SR04X2.
● ”BackMeasurement” de la librería HC_SR04X2.
● ”parar” de la librería ControlMotor.

● Control de Desplazamiento​: Se encarga de leer las variables de desplazamiento que


determinan el mismo, ellas son 3:
○direction​: 0 si la dirección no está definida, 1 si la dirección es hacia avanzar,
2 si la dirección es retroceder.
○ speed​: 0 velocidad nula (no se mueve), 1 velocidad menor, 2 velocidad
intermedia, 3 velocidad alta.
○ turn​: 0 no se dobla, 1 se dobla a la izquierda, 2 se dobla a la derecha.
Es importante aclarar lo siguiente:
1. Para avanzar en línea recta se puede utilizar cualquiera de las tres
velocidades.
2. Para retroceder y doblar, la velocidad siempre es la 1.
3. Solo se puede doblar hacia adelante.
Una vez leídas e interpretadas las variables envía al “puente H” (L298N) los valores
de PWM que correspondan para realizar la maniobra.

Para las tareas del Control de Desplazamiento se utilizan las siguientes funciones:
● ”parar” de la librería ControlMotor.
● ”avanzar” de la librería ControlMotor.
● ”girarIzquierda” de la librería ControlMotor.
● ”girarDerecha” de la librería ControlMotor.
● ”retroceder” de la librería ControlMotor.

● Control de Comunicación​: ​En primera instancia verifica si ha recibido algún mensaje


en el servidor TCP (ESP8266), en caso afirmativo procede a su lectura. Si el
mensaje posee largo un byte, se interpreta que el mismo corresponde al pedido de
estadísticas. En este caso se procede a enviar un string al que pidió la mencionada
información con el siguiente formato:
distancia_frontal/distancia_trasera/dirección/velocidad/doblar/
(las distancias son enviadas en centímetros)

Esta informacion corresponde al estado actual del vehiculo, y es necesaria


para que el usuario conozca cómo se encuentra y en particular, si ha frenado para
evitar una colisión.

Si el mensaje posee tres byte de largo, se asume que el mismo corresponde


a una “orden” de movimiento, la cual posee el siguiente formato.
dirección/velocidad/doblar
Los valores se almacenan en la variables de desplazamiento para que
“Control de Desplazamiento” las ejecute. Es importante aclarar que la coherencia o
el correcto significado de esta variables queda en manos del que envía la orden, y el
auto no realiza ninguna validación a las mismas. Es decir, si se envía por ejemplo la
orden “212” que se correspondería con retroceder doblando a la derecha (no se
encuentra permitido) el “control de Desplazamiento” no será capaz de interpretarla y
el vehículo no se moverá

Para las tareas del Control de Comunicación se utilizan las siguientes funciones:
● ”Receive_data” de la librería ESP8266.
● ”data_send” de la librería ESP8266.
Por otro lado, el sistema web presenta un sistema de usuarios, el cual permite
registro, login, logout y modificación de datos personales. Presenta un apartado de
preguntas frecuentes donde se listan algunos detalles del sistema, su uso, entre otros. En
relación al uso del autito, presenta tres grandes puntos.
● Un enlace en el menú desplegable para conectarse al autito: Permite la
conexión vía TCP al servidor montado en el autito.
● Una vista para el control y visualización del estado actual del autito: Utiliza
querys de ajax para el control del autito y para la consulta y actualización de
los estados. Dentro de los controles tenemos Marcha-, Frenar, Marcha+,
Avanzar, Izquierda, Derecha y Retroceder. Dentro del estado actual, es
posible visualizar la marcha(1, 2 o 3), el estado(Parado, Desconectado,
Avanzando, Retrocediendo, Derecha o Izquierda), la distancia que mide el
sensor frontal y la distancia que mide el sensor trasero.
● Una vista para visualizar las estadísticas/eventos más importantes medidos
por el autito: Es posible visualizar los últimos 10 eventos, con fecha, hora,
distancia y sentido, es decir si es en avance o retroceso. Estos eventos
deben ser menor a 75cm para ser tenidos en cuenta.

Ahora si procedemos dividir los casos de uso según las distintas partes que
componen el sistema antichoque desarrollado. Dentro de ellas se encuentran:

Sistema web:
1. El usuario accede al sitio: Una vez que el usuario accede al sitio a través de la URL
localhost:8000/, el controlador de la vista principal(index), la renderiza. En ella se
visualiza un botón para el registro, un link para iniciar sesión en la barra de
navegación, y ciertos elementos informativos acerca del proyecto, el grupo de
desarrollo, las preguntas frecuentes, entre otros.

2. El usuario presiona el boton “Registrese Ahora!” de la página principal: Una vez que
el usuario ha accedido a la página web y presiona el botón de “Regístrese Ahora!”,
accede a otra vista donde se le presenta un formulario, con cinco campos(Nombre,
Apellido, Email, Nombre de Usuario y Contraseña), el cual debe completar. Una vez
que ha completado todos los campos, presiona el botón “Registrarse”, y allí todos los
datos que el usuario ingresó son tomados por el controlador(signup) que detecta si
el email y nombre de usuario no se encuentran ya utilizados, procediendo a guardar
todos los datos del usuario en la base de datos, si no se encuentran estos campos
utilizados, o a informar al usuario de un error, en caso contrario. Si el usuario pudo
registrarse correctamente, será redirigido a la página donde se le permite el ingreso
a la web. Allí verá un cartel o mensaje indicando el correcto registro.

3. El usuario presiona el link “Iniciar Sesión” en la barra de navegación: Una vez que el
usuario ha accedido a la página web, presiona el link “Iniciar Sesión” en la barra de
navegación, más específicamente en la parte superior derecha. Acto seguido, es
redireccionado a la página que permite el ingreso a la web. Allí verá un formulario
con dos campos, el Nombre de Usuario y la Contraseña. Una vez que completa
dichos campos y presiona el botón “Ingresar”, los datos ingresados son tomados por
el controlador(login), que verifica contra los usuarios almacenados en la base de
datos, si se trata de un usuario registrado, y en tal caso, si la contraseña ingresada
corresponde al usuario. Si el usuario no existe, se informa de un error, al igual que si
la contraseña ingresada no corresponde con el nombre de usuario ingresado. Si, en
cambio, el ingreso fue correcto, el controlador cambiará el estado de la cuenta a
“semi-online”, indicando que se encuentra conectado a la página web, pero no
haciendo uso de la comunicación con el autito. El usuario, ahora ha ingresado a la
web, y es redireccionado a la página principal, donde verá cierta información del
autito y una serie de botones que le permiten controlarlo.

4. El usuario presiona el link “Logout” en la barra de navegación: Una vez que el


usuario ha iniciado sesión, y presiona el link “Logout” en el menú desplegable de la
barra de navegación, en la parte superior derecha, este es redireccionado a la
página de inicio, nuevamente. A su vez, el controlador(logout) toma esta acción, se
desconecta del socket del autito, solo si el usuario lo estaba utilizando, y modifica el
estado de la cuenta a “offline”, indicando que ya no se encuentra conectado.

5. El usuario presiona el link FAQs: Una vez que el usuario ha accedido a la página
web y presiona el link FAQS, tanto en la página de inicio, como en el menú
desplegable de la barra de navegación(si es que el usuario inició sesión), esta
acción es tomada por el controlador(faqs), el cual renderiza la vista de las preguntas
frecuentes, a la cual el usuario es redirigido.

6. El usuario presiona el link/nombre “Sistema Antichoque”: Una vez que el usuario


presiona el link “Sistema Antichoque”, posicionado en cualquier vista dentro de la
página web, es redireccionada a la página principal, la cual varía según si el usuario
está conectado o no. En caso de estar conectado, podrá visualizar la página que
permite el control del autito, caso contrario, visualizará la página de inicio del
sistema.

7. El usuario presiona el link “Mis Datos” en la barra de navegación: Una vez que el
usuario a ha accedido a la página web y ha ingresado a esta, presiona el link “Mis
Datos”, en el menú desplegable de la barra de navegación, y es redirigido a una
vista donde aparecerán cinco campos(los mismos del registro), para poder modificar
sus datos. Salvo la contraseña, los otros cuatros campos, están cargados con los
datos que el usuario posee en dicho momento en el sistema. Para poder visualizar
estos datos, el controlador(account), antes de renderizar dicha vista, realizó una
consulta a la base de datos para obtener todos los datos asociados al usuario, y así
pasarlos a la vista. Una vez en la vista, el usuario puede elegir cuales campos
modificar, ingresa la contraseña, aprieta el botón “Modificar”, y todos los datos son
pasados al controlador, el cual los almacena nuevamente en la base de datos,
previo chequeo que el nuevo nombre de usuario e email no se encuentren utilizados
por otro usuario. En tal caso, informa al usuario de un error, sino informa que los
cambios han sido guardados satisfactoriamente.
8. El usuario presiona el link “Estadísticas” en la barra de navegación: Una vez que el
usuario ha accedido e ingresado al sistema, presiona el link “Estadísticas” en el
menú desplegable de la barra de navegación, y es redirigido a una vista donde son
mostrados los últimos 10 eventos que midió el autito. Si hay menos de 10 eventos,
se muestran los que haya, y si no existen eventos se muestra un mensaje indicando
como hacer para obtener estadísticas. Para mostrar estos eventos, el
controlador(stats), realiza una consulta a la base de datos, obteniendo los últimos 10
eventos asociados al usuario ingresado, y luego los pasa a la vista.

9. El usuario presiona el link “Conectarse” en la barra de navegación: Una vez que el


usuario ha accedido e ingresado al sistema, presiona el link “Conectarse”, allí el
controlador(connect), intenta conectarse al socket('192.168.4.1', 666) del autito.
Tanto si la conexión es exitosa como si ocurre un error al intentar conectase, se le
informa al usuario.

10. El usuario presiona cualquiera de los botones de control del autito(Marcha -, Frenar,
Marcha +, Avanzar, Izquierda, Derecha, Retroceder): Una vez que el usuario ha
accedido a la web, iniciado en el sistema y conectado al autito, presiona los distintos
botones de control del mismo. Allí se realiza una consulta ajax, con un “POST”, al
controlador(control). Dependiendo del botón que fue presionado, es pasado al
controlador un String indicando la acción a realizar. Este envía mediante la
utilización del socket conectado al vehículo la correspondiente dirección, velocidad y
giro al autito. Por su parte, el vehículo recibe la información en su servidor TCP,
interpreta la misma y almacena los valores de desplazamientos en sus propias
variables.

Algunas de las características antes mencionadas se pueden observar en los siguientes


videos:

● Página de inicio(Caso de uso número 1):


https://www.youtube.com/watch?v=_IVAjyVw8xg
● Formulario de registro(Caso de uso número 2):
https://www.youtube.com/watch?v=61Owoo03VwE
● Logueo(Caso de uso numero 3):
https://www.youtube.com/watch?v=f-b5DBM_xwo
● Desplazamiento por la web(Casos de uso número 5, 7, 8 y 9):
https://www.youtube.com/watch?v=VxFJeNa_hK8
https://www.youtube.com/watch?v=BOsTWnTi1b0
https://www.youtube.com/watch?v=gRxe86MR0R0
https://www.youtube.com/watch?v=ZcHfCmAhH70
● Freno de emergencia(Caso de uso número 10):
https://www.youtube.com/watch?v=CePpRy8wxxI
● Desplazamiento(Caso de uso número 10):
https://www.youtube.com/watch?v=Riaf0bewkws
A modo de resumen, dentro del hardware utilizado encontramos:
● El módulo WiFi ESP8266, encargado de levantar la red “SistemaAntichoque” y un
servidor TCP/IP, contra el cual se conecta y comunica el subsistema web.
● El módulo Doble Puente H, encargado del manejo de los motores.
● Dos módulos sensores ultrasónicos HC-SR04, encargados de medir la distancia
entre el vehículo y cualquier objeto al frente o atras.
● Una placa de desarrollo, arduino UNO, encargada de manejar todos los módulos
anteriormente detallados, a través de las librerías ESP8266, ControlMotor y
HC_SR04X2, como fue explicado a lo largo del inciso.
5. Descripción del Software
Dentro del sistema web existen 10 controladores, 2 scripts ajax, y 6 vistas:
● Controlador de la vista principal(index): Es el controlador que renderiza la vista
principal(/). Detecta si hay o no un usuario logueado, y pasa distintos parámetros a la
vista según el caso. A su vez, si el usuario ingreso al sistema, pero no se conectó al
autito, para un parámetro informando de dicha cuestión. También, pasa los
parámetros iniciales del estado del autito. Se encuentra asociado al caso de uso
número 1. Un breve pseudocodigo seria:

@app.route('/')
def index():
Si el usuario no ingreso
renderizar vista de inicio
sí no
Consultar a la base de datos por el estado actual del usuario
Si el usuario no está conectado al autito
Renderizar la vista principal con los parámetros del autito
en cero y un error indicando que no se encuentra conectado
sí no
Renderizar la vista principal con los parámetros del autito
en cero y un mensaje indicando que la conexión fue exitosa

● Controlador del registro al sistema(signup): Este controlador permite el registro del


usuario al sistema. Por un lado renderiza la vista del formulario, y por el otro, si se
accede al mismo con un método “POST”, obtiene todos los valores que el usuario
completo en el formulario de registro, y controlar que no haya un email y nombre de
usuario repetidos en la base de datos. Si existe tal repetición, renderiza la vista del
registro con un error, sino renderiza la vista del login con un mensaje de éxito. Está
asociado al caso de uso número 2. El pseudocódigo del mismo es:

@app.route('/signup', methods=['GET', 'POST'])


def signup():
Si el método de consulta es “POST”
Obtiene todos los valores ingresados por el usuario en el formulario
de registro
Consulta a la base de datos si existe algún nombre de usuario repetido
Si existe nombre de usuario repetido
raise ServerError(“Invalid Username”)
Consulta a la base de datos si existe algún email repetido
Si existe email repetido
raise ServerError(“Invalid Email”)
Si no ocurre lo anterior guarda en la base de datos los valores
ingresados
Si ocurre renderiza la vista con el error correspondiente
Si el método es “GET” y el usuario está logueado
Se lo redirecciona a la página principal
Si el método es “GET” y el usuario NO está logueado
Se renderiza la vista del formulario de ingreso

● Controlador del login al sistema(login): Este controlador permite el ingreso del


usuario al sistema. Por un lado renderiza la vista del formulario de login, y por el otro,
si se trata de un método de consulta “POST”, permite el ingreso al sistema del
usuario, previa consulta a la base de datos, si existe tal nombre de usuario
registrado, y si la contraseña ingresada corresponde al nombre de usuario
ingresado. Está asociado al caso de uso número 3. El pseudocódigo es el siguiente:

@app.route('/login', methods=['GET', 'POST'])


def login():
Si el método de consulta es “POST”
Obtiene el nombre de usuario ingresado en el formulario de ingreso
Consulta a la base de datos si existe tal nombre de usuario
Si no existe ese nombre de usuario
raise ServerError(“Invalid Username”)
Obtiene la contraseña ingresada en el formulario de ingreso
Consulta a la base de datos si la contraseña ingresada es la asociada al
usuario ingresado
Si no es el caso
raise ServerError(“Invalid Password”)
Si no ocurre lo anterior cambia el estado del usuario a “semi-online”,
indicando que ingresó al sistema pero que no se encuentra conectado
al autito y redirecciona a la vista principal
Si ocurre renderiza la vista con el error correspondiente
Si el método es “GET” y el usuario está logueado
Se lo redirecciona a la página principal
Si el método es “GET” y el usuario NO está logueado
Se renderiza la vista del formulario de login

● Controlador del logout del sistema(logout): Este controlador permite que un usuario
ingresado deje el sistema. Simplemente modifica el estado del mismo en la base de
datos a “offline”, cierra el socket, si el usuario se encontraba conectado al autito, y
renderiza a la vista principal. Asociado al caso de uso número 4. El pseudocódigo es
el siguiente:

@app.route('/logout')
def logout()​:
Si el usuario NO esta logueado
Renderiza la vista principal
Si no
Termina la sesión
Si el usuario estaba conectado al autito
Cierra el socket
Modifica el estado del usuario en la base de datos a “offline”
Redirige al usuario a la vista principal

● Controlador de la modificación de los datos personales del usuario(account): Este


controlador permite al usuario modificar los datos que ingreso al sistema al momento
de su registro. Por un lado, permite la visualización del formulario de modificación de
datos, con los datos almacenados en el sistema, salvo la contraseña, y por el otro si
se accede al mismo con un método de consulta “POST”, permite la modificación de
los datos, previa consulta a la base de datos, para verificar si no existe un nombre de
usuario e email repetidos. Si no es el caso, renderiza de nuevo la vista con los
nuevos datos y un mensaje de éxito, caso contrario renderiza la vista con los datos
ingresados, pero con un mensaje indicando el error ocurrido. Asociado al caso de
uso número 7. Su pseudocódigo es:

@app.route('/account', methods=['GET', 'POST'])


def account():
Si NO hay usuario ingresado al sistema
Renderiza la vista principal
Sí no
Obtiene los datos de la sesión del usuario
Si se trata de un método “POST”
Obtiene los datos ingresados al formulario de modificación de
datos
Consulta a la base de datos para verificar si el nombre de
usuario ingresado no está repetido
Si es el caso
raise ServerError('Invalid username')
Consulta a la base de datos para verificar si el email
ingresado no está repetido
Si es el caso
raise ServerError('Invalid email')
Si ocurrió lo anterior renderiza la vista con el error y los datos
ingresados
Si no, agrega los nuevos datos al sistema, y renderiza la vista
con un mensaje de éxito
Si se trata de un método “GET”
Consulta a la base de datos por los datos del usuario
Renderiza la vista con los datos del usuario

● Controlador de las estadísticas del usuario(/stats): Este controlador permite la


visualización de las estadísticas del uso del autito por parte del usuario.
Simplemente obtiene una lista de los últimos 10 eventos del uso del autito por parte
del usuario. Relacionado al caso de uso número 7. Su pseudocódigo es:

@app.route('/stats')
def stats():
Si NO hay usuario ingresado al sistema
Renderiza la vista principal
Caso contrario
Consulta a la base de datos por los últimos 10 eventos relacionados al
usuario
Renderiza la vista de las estadísticas con la lista de los últimos 10
eventos
● Controlador de las preguntas frecuentes del sistema(faqs): Este controlador permite
la visualización de las preguntas frecuentes del sistema. Simplemente renderiza la
vista donde se visualizan las preguntas frecuentes. Relacionado al caso de uso
número 5. Su pseudocódigo es:

@app.route('/faqs')
def faqs():
Si NO hay usuario ingresado al sistema
Renderiza la vista de las preguntas frecuentes
Caso contrario
Renderiza la vista de las preguntas frecuentes con parámetros de la
sesión del usuario

● Controlador de la conexión del usuario al autito(connect): Este controlador permite la


conexión del usuario al autito para el posterior control del mismo. Intenta conectarse
al socket('192.168.4.1', 666) del autito. Si lo logra renderiza la vista de control con un
mensaje de éxito, caso contrario con un mensaje de error. Previo a la conexión,
consulta a la base de datos para verificar que el usuario no se encuentre ya
conectado al autito. Relacionado al caso de uso número 9. Su pseudocódigo es:

@app.route('/connect')
def connect():
Si NO hay usuario ingresado al sistema
Renderiza la vista principal
Caso contrario
Obtiene los datos de sesión del usuario
Consulta a la base de datos para verificar que el usuario está conectado
al autito
Si está conectado
Redirecciona al usuario a la página de control
Sí no
Intenta conectarse al socket del autito
Si es exitosa la conexión
Modifica el estado del usuario en la base de datos a
“online” para indicar que se encuentra conectado al
autito
Renderiza la vista de control con un mensaje de éxito
Sí no
Cierra el socket
Renderiza la vista de control con un mensaje de error

● Controlador del manejo del autito(control): Este controlador permite el manejo del
autito por parte del usuario. Detecta cuál fue la operación ingresada por el usuario y
envía parámetros de dirección, giro y velocidad al autito de acuerdo al tipo de
acción. Previo al envío de cualquier tipo de acción, consulta a la base de datos para
verificar que el usuario se encuentra conectado al autito. Relacionado al caso de uso
número 10. El pseudocódigo es el siguiente:
@app.route('/control', methods=['GET', 'POST'])
def control():
Si el método es “POST”
Obtiene los datos de sesión del usuario
Consulta a la base de datos para verificar que el usuario se encuentre
conectado al autito
Si se encuentra conectado
Verifica cual es la acción a enviar al autito y acomoda los
parámetros a enviar
Envía los parámetros al autito
Si el método es “GET”
Redirección a la vista principal

● Controlador del pedido y actualizacion de informacion correspondiente al estado


actual del autito(access). Este controlador permite consultar al autito por su estado
actual. Es solo accedido mediante una consulta ajax, la cual será explicada más
adelante. Envía un pedido de información al autito, queda a la espera de una
respuesta y en caso de obtenerla, discrimina la información recibida. Si no recibe
información, cierra el socket, actualiza el estado del usuario para indicar que ya no
se encuentra conectado al autito, y devuelve un json a la query de ajax para que
esta informe una perdida de conexion al usuario. Si al recibir la información, detecta
que es de importancia, almacena los eventos en la base de datos para que estos
puedan ser consultados por el usuario como fue explicado anteriormente. Por ultimo
devuelve un json con la información recibida a la query de ajax, para que esta se
encargue de actualizar los distintos elementos de la vista.

@app.route("/access")
def access():
Si el usuario está ingresado en el sistema
Obtiene los datos de sesión del usuario
Inicializa las variables correspondientes al estado del autito
Consulta a la base de datos para verificar que el usuario está conectado
al autito
Si está conectado
Envía pedido de información al autito
Espera respuesta
Si recibe la respuesta
Discrimina la información recibida para detectar el
estado actual
Si son eventos de importancia
Los almacena en la base de datos
Sí no
Cierra el socket
Actualiza el estado del usuario a “semi-online” para
indicar que ya no se encuentra conectado al autito
Envía un json a la query ajax con un error
Envía un json a la query ajax con la información recibida
Sí no
Envía un json a la query ajax indicando que no hay usuario logueado
● Query de AJAX que permite el control del autito(control): Esta consulta es activada
cada vez que se hace un click en alguno de los botones de la vista de control. Cada
botón, pasa a la query un parámetro distinto, que depende del comando a enviar.
Esta realiza un POST al controlador control, con el parámetro pasado. Su codigo es
el siguiente:

● Query de AJAX que permite la actualización de la información del estado actual del
autito(loadIndex): Se ejecuta cada 2 segundos, y realiza una petición al controlador
access. Recibe un json, y discrimina la información recibida para actualizar los
distintos campos del estado del vehículo(marcha, estado actual, distancia delantera
y distancia trasera). Su pseudocódigo es:

function loadIndex() {
$.get("/access", function(data) {
Si el usuario estaba conectado
Si hubo error de conexión al intentar pedir la información al
autito
Modifica el estilo del mensaje a “alert-danger”
Modifica el texto del mensaje a “Pérdida de conexión”
Sí no
Si el estado recibido es “Avanzando”
Modifica el estilo a “text-success”
Si el estado recibido es “Retrocediendo”
Modifica el estilo a “text-danger”
Sí no
Elimina los estilos
Modifica el texto a Estado Actual
Modifica el texto a Marcha
Si la distancia delantera recibida es mayor a 75cm
Modifica el estilo a “text-success”
Si la distancia delantera recibida es mayor a 50cm
Modifica el estilo a “text-warning”
Sí no
Modifica el estilo a “text-danger”
Si la distancia delantera recibida es mayor a 400cm
Modifica el texto Distancia Adelante: a >400cm
Sí no
Modifica el texto Distancia Adelante: al valor
recibido
Si la distancia trasera recibida es mayor a 75cm
Modifica el estilo a “text-success”
Si la distancia delantera recibida es mayor a 50cm
Modifica el estilo a “text-warning”
Sí no
Modifica el estilo a “text-success”
Si la distancia trasera recibida es mayor a 400cm
Modifica el texto Distancia Atrás: a >400cm
Sí no
Modifica el texto Distancia Atrás: al valor
recibido

Para el caso de las vistas, solo se va a explicar el contenido de las mismas, no se


incluirá codigo ni pseudocodigo, puesto que su lectura resulta engorrosa. Para más detalle
de implementación dirigirse al apéndice B.
Antes de explicar las vistas, vale aclarar que todas poseen una barra de navegación
y un pie de página:
● Barra de navegación​: Si el usuario no está logueado, muestra un link al formulario de
inicio de sesión en la parte superior derecha, y un link a la página principal en la
parte superior izquierda. Si, en cambio, el usuario esta logueado, muestra este
ultimo link, de la misma forma en la parte superior izquierda y un menú desplegable
en la parte superior derecha con las distintas opciones de uso de su cuenta que
tiene un usuario.
● Usuario desconectado​:

● Usuario conectado​:

● Pie de página​: El pie de página muestra el nombre de los integrantes del grupo de
desarrollo en la parte inferior izquierda.

● Vista principal(/)​: Si el usuario no está logueado, muestra la página principal/de


presentación. Es visible un jumbotron en la parte superior, con un botón que permite
el acceso al formulario de registro. Luego, dos filas indicando que el sistema está
basado en arduino y que se controla mediante wifi. Por último, se muestran tres
columnas con información básica del sistema, como quienes somos, que es este
sistema y el acceso a las preguntas frecuentes:

● Parte superior(Jumbotron)​:
● Filas del medio con información:

● Información de la parte inferior:

Si, en cambio el usuario está logueado, muestra la página de control del vehículo,
con una tabla indicando el estado actual del mismo y una serie de botones, posicionados
simulando un “joystick”.
● Vista del formulario de registro(/signup)​: Muestra 5 campos para ingresar nombre,
apellido, nombre de usuario, contraseña y mail, junto con un botón, que permite el
ingreso de dichos campos.

● Vista del formulario de ingreso/login(/login)​: Muestra 2 campos para ingresar nombre


de usuario y contraseña y un botón que permite el ingreso de los mismos.
● Vista de las preguntas frecuentes(/faqs)​: Esta vista presenta 4 componentes
rectangulares(4 filas), con información referida al proyecto.

● Primeras preguntas:

● Últimas preguntas:
● Vista de la modificación de datos personales del usuario(/account)​: Esta vista
muestra un formulario con 5 campos, nombre, apellido, nombre de usuario,
contraseña y email, y un botón que permite el ingreso de dichos campos.

● Vista de las estadísticas(/stats)​: Esta vista muestra una tabla con los últimos 10
eventos/mediciones del usuario logueado. Cabe destacar, que el color en el que es
presentado cada elemento depende de la importancia de cada uno. Si la distancia
medida es mayor a 50cm, el valor es mostrado en verde, si se encuentra entre 25 y
50cm, el valor es mostrado en amarillo y si es menor a 25cm, es mostrado en rojo. Si
no hay eventos aparece un texto indicando como hacer para recibir
eventos/mediciones del autito.

En lo que respecta al vehículo, como ya se ha comentado en el inciso 4 el mismo


utiliza un lazo infinito para su funcionamiento. Como el mismo se repite para cada caso de
uso que involucre al vehículo se detallara el software utilizado en el vehículo
independientemente de un caso de uso específico.
A nivel general se utilizan 3 librerías para el control de todos los periféricos:

HC_SR04X2​: Permite el manejo de los sensores ultrasónicos, calcula la distancia a


la cual se encuentra el autito de los distintos objetos. Una característica fundamental es que
está diseñada para controlar ambos dispositivos a la vez, esto nos brinda practicidad a la
hora de la utilización de los sensores.

ESP8266​: Es una librería de uso libre disponible en la web que permite el manejo
del módulo WiFi. Particularmente, permite la conexión vía TCP/IP con la PC, para la
transmisión de datos referidos a estadísticas y control del autito. Es importante aclarar que
para la adaptarla al sistema se le agregaron funciones, las cuales se explican a
continuación.

ControlMotor​: Permite el control de los motores por PWM. Permite avance en tres
velocidades, el retroceso en una velocidad, frenar y doblar en ambos sentidos.

La descripción detallada de cada librería se observa a continuación. Considerando lo


breve de cada función se decidió explicarlas mediante un comentario de su función y la
inclusión del propio código comentado, pues agregar un pseudocódigo resulta exagerado

Librería HC_SR04X2: ​Librería desarrollada para el manejo del sensor HC_SR04X2,


la cual posee 5 archivos:

-HC_SR04X2.h: Archivo de cabecera de la librería.


-HC_SR04X2.cpp: Archivo con la definición de las declaraciones contenidas en
HC_SR04​X2​.h
-Hoja_de_datosHCSR04.pdf: Contiene la hoja de datos del dispositivo HC_SR04.
-Informacion_de_funcionamiento.pdf: Contiene información gráfica de conexionado
del dispositivo, y breve explicación del funcionamiento del mismo.
-Test.txt: Contiene un pequeño programa Arduino Uno de ejemplo para lograr la
utilización de dispositivo.

Detalle de los documentos más relevantes:

-HC_SR04X2.h​: Posee las siguientes declaraciones de funciones:

void FrontSetup(int FrontPin_start, int FrontPin_data): ​Realiza la configuración


de los pines de Trigger y Echo del sensor colocado en la parte frontal del vehículo.

void BackSetup(int Backpin_start, int BackPin_data): ​Realiza la configuración de


los pines de Trigger y Echo del sensor colocado en la parte trasera del vehículo.

float FrontMeasurement(): ​Realiza una medición y devuelve la distancia obtenida


del sensor colocado en la parte frontal del vehículo.
float FrontMeasurement_for(int cant_measurement): ​Realiza cant_measurement
mediciones con sensor colocado en la parte frontal del vehículo y devuelve el promedio de
ellas. En casos donde se requiera mediciones con mayor precisión, se recomienda el uso
de esta función.

float BackMeasurement(): ​Realiza una medición y devuelve la distancia obtenida


del sensor colocado en la parte trasera del vehículo.

float BackMeasurement_for(int cant_measurement): ​Realiza cant_measurement


mediciones con sensor colocado en la parte trasera del vehículo y devuelve el promedio de
ellas. En casos donde se requiera mediciones con mayor precisión, se recomienda el uso
de esta función.

-HC_SR04X2.cpp​: El código de las funciones previamentes mencionadas es el siguiente:

FrontSetup​:

BackSetup​:

FrontMeasurement​:
El código de la función BackMeasuramente es idéntico, por lo tanto no será copiado.
El mismo se puede obtener del repositorio de Github.

FrontMeasurement_for​:

El código de la función BackMeasuramente_for es idéntico, por lo tanto no será


copiado. El mismo se puede obtener del repositorio de Github.

Libreria ControlMotor​: La librería que se explica a continuación se encuentra


diseñada para 2 motores de funcionamiento similar. Actualmente, el vehículo se encuentra
funcionando con la misma librería pero con la diferencia que la velocidad no es pasada
completamente en forma de parámetro, sino que es colocado de forma estática. Se espera
que con la adquisición de motores similares se utilice la librería con la velocidad pasada
como parámetro, pues la misma es más propensa a recibir mejoras, por ejemplo en
cantidad de marchas (releer inciso 2 para más detalles).

Librería desarrollada para el control PWM de los motores del autito, la cual posee 3
archivos:

-ControlMotor.h: Archivo de cabecera de la librería.


-ControlMotor.cpp: Archivo con la definición de las declaraciones contenidas en
ControlMotor.h
-Test: Contiene un pequeño programa Arduino Uno de ejemplo para lograr la utilización del
autito.
Dentro de ellas podemos mencionar las más importantes:
ControlMotor.h​: Posee las siguientes declaraciones de funciones:

ControlMotor(int md1, int md2, int mi1, int mi2, int pwmD, int pwmI): ​Es el
constructor de la libreria. Permite asignar los pines que van a controlar cada motor.
void girarDerecha(int velocidad): ​Gira a la derecha el vehículo con velocidad
“velocidad”.

void girarIzquierda(int velocidad): ​Gira a la izquierda el vehículo con velocidad


“velocidad”.

void avanzar(int velocidad): ​Permite avanzar el autito con una cierta velocidad.

void retroceder(int velocidad): ​Permite retroceder el autito con una cierta


velocidad.

void parar(int velocidad): ​Permite frenar/detener el autito con una cierta velocidad.

ControlMotor.cpp​: Las funciones anteriormente mencionadas y explicadas fueron


implementadas de la siguiente manera:

Constructor del objeto​:

Para las siguientes funciones es necesario saber que para indicar el sentido de giro
de las ruedas se requieren dos variables por motor, específicamente la variable A y B de
cada motor:
Si queremos que se gire hacia el frente, la variable del motor B se coloca en Alto y
la variable A del motor se coloca en Bajo.
Si queremos que se gire hacia atrás, la variable del motor B se coloca en bajo y la
variable A del motor se coloca en Alto.
La velocidad de giro de cada rueda depende del PWM con el cual se alimente al
motor, para modificar el ciclo de trabajo del PWM utilizamos la variable “velocidad”.
Sabiendo lo antes comentado, la interpretación de las funciones es sencilla
Avanzar​:

Versión con velocidad fijada:

Retroceder​:

Versión con velocidad fijada:


Parar​:

Versión con velocidad fijada:

GirarIzquierda​:

Versión con velocidad fijada:


GirarDerecha​:

Versión con velocidad fijada:

Libreria ESP8266​: Librería de código libre disponible en github


(​https://github.com/itead/ITEADLIB_Arduino_WeeESP8266​) a la cual se le agregaron las
siguientes funciones:

void Configuration(): ​Mediante el llamado de funciones de la propia librería


configura el ESP8266 para brinda una red Wifi denominada SistemaAntichoque sin
contraseña de acceso. Además activa las múltiples conexiones al servidor TCP del puerto
666 que ella misma levanta.
uint32_t Receive_data( uint8_t *buffer): ​Mediante el llamado de funciones de la
propia librería recibe los datos del ESP8266 en la variable buffer y devuelve el tamaño de
los mismos. Si no se recibieron datos, el tamaño es cero. Lo datos recibidos pertenecen a la
conexión 0 del servidor TCP del puerto 666.

voidSend_data( uint8_t *buffer, uint32_t len): ​Mediante el llamado de funciones


de la propia librería envía datos al cliente de la conexión 0 del servidor TCP del puerto 666.

Considerando las funciones originales de la librería y las siguientes definiciones:

Los códigos de las Funciones son los siguientes

Configuration​:

Receive_Data​:

Send_Data​:
6. Guía de Instalación Completa
a) Ambiente de desarrollo:
Instalación del Arduino IDE​:
Se accede a la solapa “software” del sitio oficial de Arduino.
(​https://www.arduino.cc/en/Main/Software​). Luego se selecciona el SO operativo de nuestra
computadora y se procede con la descarga.
Finalizada la descarga se debe instalar de la manera que corresponde con cada SO,
en el caso de linux debemos descomprimir el archivo y mediante el intérprete de comandos
ejecutar “./install.sh”.

Instalación de Base de Datos​:


La instalación será explicada solo para Linux, ya que es el sistema utilizado por los
integrantes del grupo.
Se deberán ingresar los siguientes comandos en la consola:
-sudo apt-get update && sudo apt-get upgrade
-sudo apt-get install mysql-server mysql-common
El segundo comando requerirá el ingreso de una contraseña para el usuario con
todos los privilegios, la misma puede ser vacío.

Instalación del Workbench​:


La instalación será explicada solo para Linux, ya que es el sistema utilizado por los
integrantes del grupo.
Se deberán ingresar los siguientes comandos en la consola:
-sudo apt-get update
-sudo apt-get install mysql-workbench
Si existieron problemas de dependencias:
-sudo apt-get install -f

Instalación de MySQL para python​:


La instalación será explicada solo para Linux, ya que es el sistema utilizado por los
integrantes del grupo.
Se deberán ingresar los siguientes comandos en la consola:
-sudo apt-get install python-mysqldb

Lenguajes utilizados​:
Las librerías en arduino se desarrollan en C++, para lo cual no es necesario la
instalación de ningún paquete.
Para el manejo de la base de datos, es necesario conocimientos en SQL pero no se
requiere la instalación de ningún lenguaje.
Para la programación del servidor HTTP se utiliza flask en Python, para lo cual son
necesarias sus librerías, que se pueden instalar siguiendo los siguientes comandos:
-​sudo apt-get install python
-​sudo apt-get install python-pip
-pip install flask

Instalación de las librerías necesarias​:


Las librerías utilizadas por el vehículo se adjuntan al presente informe en formato
“zip”, para su instalación se debe descomprimir todas ellas, luego copiar cada carpeta
(ControlMotor, ESP8266, HC_SRO4X2) dentro del directorio de instalación e arduino dentro
de la carpeta “libraries”.

Instalación de las sistema en el arduino​:


El programa a cargar en el arduino, se adjunta al presente informe como “autito.ino”.
Para su instalación debemos clickear en él y una vez abierto el IDE de arduino clickear en
subir. Al cabo de unos segundos el programa se encuentra descargado.

Puesta en marcha del sistema por completo:


Si se llevaron a cabo de forma correcta las instalaciones previamente mencionadas
estamos en condiciones de hacer funcionar el sistema, para ello se deben seguir los
siguientes pasos:
1- Abrir una terminal e ingresar ​mysql-workbench, ​al cabo de unos segundos
se abrirá la ventana de trabajo​.
2- Clickear MySQL Connection (tiene forma de llave francesa) y se
desplegará una venta.

3- Clicker “new” e ingresar un nombre de conexión. Si al momento de instalar


la base de datos se le ingresó una contraseña, debemo clickear la solapa “parameters y
dentro de allí “Soter in Keychain” e ingresar la contraseña.
4- Clickear Close.
5- Luego deberemos ver la nueva conexión creada. Doble click en ella e ir a
la solapa Server Status para verificar el estado running.

En caso de no estar en estado runing, abrir una terminal e ingresar ​service mysql
start​ y luego corroborar que se encuentre corriendo con​ ps -e | grep mysqld.

6- Ingresar y ejecutar en la solapa de Query el siguiente comando:


CREATE DATABASE antichoque;
Luego (crea las tablas de la base de datos):
use antichoque;
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
surname VARCHAR(20) NOT NULL,
email VARCHAR(40) NOT NULL,
username VARCHAR(20) NOT NULL,
password VARCHAR(200) NOT NULL,
state VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE eventos (
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
fecha VARCHAR(20) NOT NULL,
hora VARCHAR(10) NOT NULL,
dist INT NOT NULL,
type VARCHAR(10) NOT NULL,
PRIMARY KEY (id)
);
Lo anterior se veŕá de la siguiente manera:

A partir de este momento se debe estar conectado a la red de vehículo, para ello
encender el auto, esperar 5 segundos y conectarse a ella.

7- Acceder a la carpeta antichoque, la cual se adjunta al presente informe


, mediante una terminal e ingresar ​python antichoque.py.
El servidor ya se encuentra funcionando, para acceder al servicio ingresar mediante
un navegador a la url ​localhost:8000.

b) Copia/Instalación de Código:
Las funciones que controlan cada hardware utilizado en el vehículo fueron detalladas con
anterioridad, sin embargo para afianzar la idea de la estructura de archivos se incorpora la
siguiente imagen:
El directorio del sistema web está compuesto de la siguiente manera:
● Directorio global​: Aquí se encuentra almacenado el archivo antichoque.py y se
visualizan las subcarpetas correspondientes a las vistas(templates) y static, que
posee todo lo correspondiente a scripts, fotos(assets), estilos(stylesheets) y
bootstrap.

● Static​: Posee lo mencionado previamente, es decir, scripts, fotos, estilos y bootstrap:

● Vistas​: Aquí se pueden ver las 6 vistas previamente mencionadas a lo largo del
informe

● Estilos​: Se pueden ver dos hojas de estilos, index.css y main.css

● Scripts​: Se visualizan los dos scripts mencionados a lo largo del informe index.js y
control.js
● Assets​: Acá se encuentran todas las fotos y logos utilizados en el armado de las
vistas.

● Bootstrap​: Aca se encuentran los archivos de bootstrap3 y jquery.

c) Guía de Compilación/Instalación/Upload de Ejecutable/s:


El sistema no contiene ninguna configuración extra por realizar para la puesta en marcha.
En el caso del sistema web, solo se debe descomprimir el archivo enviado, y luego
posicionarse en el directorio donde fue descomprimido, para la ejecución del mismo, como
previamente se mencionó.
Apéndice A: Propuesta original del proyecto
Taller de Proyecto II
2017

Sistema Antichoque

Proyecto N°4

Integrantes

Alvarez Matías 923/3


Cristofano Marco 813/8
1.​ ​Introducción
Se dispone de un vehículo o autito de tres ruedas, con chasis de plástico, que en la
actualidad no dispone de un sistema que le permita detectar de forma autónoma obstáculos
en sus trayectoria, esto delega la responsabilidad en el conductor del vehículo el cual debe
estar muy atento para no colisionar. Además de no asistir al conductor en su labor, se pone
en riesgo la vida útil del vehículo ya que sufre de fuertes golpes que con un sistema detector
de obstáculos serían fácilmente evitados.
Si bien la tecnología que se va a utilizar en el proyecto (más adelante será detallada)
no se puede aplicar en un vehículo real, si se puede pensar en aplicarla en algunos de los
siguientes productos:

-”Changuito” de compras: Sí se incorporara el sistema anti-choque se evitarían


colisiones de los changuitos con góndolas y con personas. Así el usuario ahorraría dinero
por romper productos y se evitarían choques con otras personas, detalle que cobra
importancia si hablamos de niños y/o ancianos.

-Autos a baterías para transportar niños: Un regalo común a los niños y niñas es el
auto de juguete en el cual el niño se puede subir y manejar. Si se incorporara este sistema
anti-choque se podría aumentar la vida útil del vehículo gracias a que se le evitarían golpes
innecesarios. Además se protegería de mejor manera tanto al niño que lo conduce como a
cualquier persona cerca.

-Autos/Robots para acceso a lugares inhóspitos o inaccesibles por el humano: Al


igual que en el caso del changuito de compras, podría incorporarse el sistema anti-choque a
un autito o robot de acceso a lugares inhóspitos, como lo son minas, lugares expuestos a
contaminantes, entre otros, para que dicho vehículo pueda evitar obstáculos, y
consecuentemente la pérdida parcial o total del mismo.

2.​ ​ Objetivo
El objetivo es la construcción de un sistema antichoque para un vehículo que posee
tres velocidades de avance y una velocidad de retroceso. El sistema se encontraría
configurado para moverse en ambos sentidos y para ello se utilizaría, en principio, 2
módulos de ultrasonido, uno detectando los obstáculos en el avance y el otro en el
retroceso.
Desde el punto de vista del usuario, el mismo deberá acceder a una aplicación web
donde encontrará los comandos necesarios para hacer funcionar el vehículo, además de la
información pertinente a la distancia del vehículo con los obstáculos, y otras características
y estados que serán explicados más en detalle. La mencionada aplicación será montada
sobre un servidor HTTP el cual se comunicará con el vehículo mediante el protocolo
TCP/IP. Para llevar a cabo este objetivo se le incorporará al vehículo un módulo wifi
ESP8266.
Cabe aclarar que como medida de seguridad el usuario accederá a la aplicación
haciendo uso de un token o contraseña privada generada por el mismo servidor, de modo
tal que otro usuario no pueda acceder al control del autito. Esto es, que un usuario deberá
primero generar el token o contraseña, accediendo al servidor, luego configurar su autito
para que en la conexión TCP/IP con el servidor, este provea al servidor del token para
poder establecer la conexión. De no existir ese token, la conexión no será posible. Los
tokens serán únicos. Un mismo usuario podría generar más de un token.

3.​ ​ Dispositivos a utilizar

Dispositivos/Módulos/Materiales Descripción/Función Precio

Chasis de 3 ruedas(incluye dos Chasis plástico del autito, $585. Disponible en:
motores de cc) con dos ruedas a motor https://articulo.mercadoli
de corriente continua y bre.com.ar/MLA-640018
una libre. 267-kit-chasis-smart-car
-auto-robot-2-ruedas-ard
uino-_JM

Doble Puente H Es el circuito electrónico $140. Disponible en:


que nos permite el control https://articulo.mercadoli
de los motores, de modo bre.com.ar/MLA-610774
tal que puedan avanzar y 289-doble-puente-h-driv
retroceder. er-l298MLA-610774289
MLA-610774289n-motor
-dc-arduino-l298-nubbeo
-_JM

Módulo WiFi ESP8266 Módulo que implementa el $127. Disponible en:


stack TCP/IP, el cual nos va https://articulo.mercadolibre.
a permitir la conexión con el com.ar/MLA-620320780-mo
servidor WEB dulo-wifi-esp8266-serie-stac
k-tcp-ip-antena-lwip-apsta-_
JM
2 sensores de ultrasonido Un sensor de proximidad $39 c/u. Disponible en:
hc-sr04 por ultrasonido para https://articulo.mercadolibre.
detectar objetos en el com.ar/MLA-620084391-sen
avance y el otro para sor-ultrasonico-hc-sr04-para
detectarlos en el retroceso -arduino-pic-robotica-_JM

Arduino UNO Kit de desarrollo con $235. Disponible en:


microcontrolador sobre el https://articulo.mercadolibre.
cual corre el software que com.ar/MLA-619903679-ard
controla al autito, los uino-uno-r3-original-cable-u
sensores y el módulo WiFi sb-chip-desmontable-atmel-
_JM

Batería 9V Batería para la alimentación $50. Disponible en cualquier


del kit Arduino, motores, supermercado o ferretería.
sensores y módulo WiFi.

El presupuesto total es $1215.


4.​ ​ Esquema gráfico del proyecto completo propuesto
En el gráfico anterior se intentan representar los siguientes conceptos:
-El sistema antichoque que posee el vehículo será en ambos sentidos:
-El vehículo contendrá un módulo wifi(ESP8266) con el cual se comunicará con el
servidor.
-La comunicación Vehículo-Servidor será mediante el protocolo TCP/IP.
-El servidor será el encargado de obtener los datos del vehículo y presentarlos al
usuario.
-El servidor será el encargado de enviar al vehículo los comandos del usuario.
-El servidor proveerá un servicio HTTP.

5.​ ​ Identificación de partes


a.​ ​E/S del controlador con el exterior, excepto PC
El microcontrolador adquirirá información del exterior mediante los sensores
ultrasónicos, gracias a ellos se podrá calcular la distancia que posee el auto a cualquier
obstáculo. Más específicamente, cada un cierto tiempo x, a definir, el microcontrolador
obtiene el valor de los sensores de ultrasonido, detectando objetos a su paso. En caso de
detección de un objeto, el microcontrolador comanda los motores para que estos
desaceleren hasta frenar por completo al autito. Por otro lado, el microcontrolador también
comanda el avance/retroceso, en las marchas seleccionadas, mediante el control de los
motores de corriente continua.
El control de aceleración/desaceleración de los motores se realiza mediante el uso
de un puente H, previamente presupuestado.

b.​ ​Comunicaciones con la PC.


Para la comunicación con la PC se montará al arduino un módulo Wifi ESP8266 por
el cual se podrá contactar al servidor, la comunicación se hará mediante el protocolo
TCP/IP. Cabe aclarar que la comunicación en sentido servidor-vehículo consiste en el envío
de los comandos de movimiento, y en el sentido vehículo-servidor consiste en el envío de
estados actuales del vehículo y mediciones de los sensores de distancia. Como fue
explicado previamente, para establecer esta conexión, previamente se debe generar el
token en el servidor, luego el autito o vehículo a usar debe utilizar dicho token para la
comunicación con el servidor.

​c.​ ​Sistema web


El sistema web se basará en un servidor HTTP el cual brindará al usuario del
sistema una interfaz gráfica por la cual podrá hacer que el vehículo se mueva en ambas
direcciones, además presentará datos estadísticos pertinentes al vehículo y la información
obtenida mediante el uso de los sensores.
Además de esto deberá realizar la comunicación con el auto para realizar la propia
transferencia de los comandos y la adquisición de la información de distancia y estado del
vehículo.
Para acceder al control del autito, el usuario deberá ingresar en la página web el
token previamente generado por el servidor, que tiene asociado al autito que desea
controlar.
Para ser más precisos con la aplicación, la misma contendrá las siguientes
funcionalidades:
-Obtención del token
-Ingreso y asociación del token
-Acción de avance.
-Selección de marcha: Se elegirá el sentido de la marcha y la velocidad en caso que
sea hacia delante.
Mostrará los siguientes datos:
-Lectura de datos referidos a la distancia del vehículo con objetos frontales.
-Lectura de datos referidos a la distancia del vehículo con objetos traseros.
-Estado actual del autito(en avance, en retroceso, parado, marcha actual, etc)
-Cantidad de choques evitados del autito del usuario
-Última conexión del usuario
-Frecuencia de uso
Informará sobre las características del autito, para aquellos nuevos usuarios que no
lo sepan utilizar. Esto es:
-Cantidad de marchas posibles en el avance
-La posibilidad de avanzar y retroceder
-Instructivo basico de uso de la plataforma
-Uso del token
-Significado de la información mostrada
Apéndice B
A continuación se adjunta el código correspondiente al sistema web completo
Vistas:
Vista index.html:
<!DOCTYPE html>
<html>
<head>
<title>Sistema Antichoque</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- JQuery -->


<script src="{{url_for('static',
filename='jquery/jquery-3.2.1.min.js')}}"></script>
<script type="text/javascript" src="{{url_for('static',
filename='scripts/index.js')}}"></script>
<script type="text/javascript" src="{{url_for('static',
filename='scripts/control.js')}}"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{url_for('static',
filename='bootstrap3/css/bootstrap.min.css')}}" />
<link rel="stylesheet" href="{{url_for('static',
filename='stylesheets/index.css')}}" />

<!-- Bootstrap JS
<script src="{{url_for('static',
filename='bootstrap/js/popper.min.js')}}"></script>-->
<script src="{{url_for('static',
filename='bootstrap3/js/bootstrap.min.js')}}"></script>
</head>

<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Sistema Antichoque</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
{% if session_user_name %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">Mi cuenta <span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="">Control</a></li>
<li><a href="/stats">Estadisticas</a></li>
<li><a href="/account">Mis datos</a></li>
<li><a href="/connect">Conectarse</a></li>
<li><a href="/faqs">FAQs</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout">Logout</a> </li>
</ul>
</li>
{% else %}
<li><a href="/login">Iniciar Sesion</a></li>
{% endif %}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

{% if session_user_name %}

<div class="container">

<div class="row justify-content-md-center">


<div class="col-md-6 col-md-offset-3 col-xs-12">
<div style="background:transparent; margin-top:-25px"
class="jumbotron jumbotron-fluid">
<div class="container">

{% if error %}
<div class="alert alert-danger"
style="text-align: center">{{ error }}</div>
{% elif inform %}
<div class="alert alert-success"
style="text-align: center" id="error">{{ inform }}</div>
{% endif %}

<div class="container text-center"


style="margin-top: -8px">
<h2 class="parTitle"><strong>Estado
Actual</strong></h2>
</div>

<br>

<ul class="list-group">
<li class="list-group-item"><b><span
id="marcha">Marcha: {{marcha}}</span></b></li>
<li class="list-group-item"><b><span
id="state">Estado: {{state}}</span></b></li>
<li class="list-group-item"><b><span
id="front_distance">Distancia Adelante: {{front_distance}}cm</span></b></li>
<li class="list-group-item"><b><span
id="back_distance">Distancia Atras: {{back_distance}}cm</span></b></li>
</ul>
</div>
</div>
</div>
</div>

<div class="row justify-content-md-center">


<div class="col-md-2 col-md-offset-3 col-xs-2" >
<a class="btn btn-primary btn-lg" role="button"
onclick="control('Marcha D')">Marcha -</a>
</div>
<div class="col-md-2 col-md-offset-0 col-xs-2
col-xs-offset-2">
<a class="btn btn-danger btn-lg" role="button"
onclick="control('Frenar')">Frenar</a>
</div>
<div class="col-md-2 col-md-offset-0 col-xs-2
col-xs-offset-1">
<a class="btn btn-primary btn-lg" role="button"
onclick="control('Marcha A')">Marcha +</a>
</div>

</div>

<br>
<br>

<div class="row justify-content-md-center">


<div class="col-md-3 col-md-offset-5 col-xs-2
col-xs-offset-4">
<a class="btn btn-success btn-lg" role="button"
onclick="control('Avanzar')">Avanzar</a>
</div>
</div>

<br>

<div class="row ">


<div class="col-md-3 col-md-offset-3 col-xs-2 ">
<a class="btn btn-primary btn-lg" role="button"
onclick="control('Izquierda')">Izquierda</a>
</div>
<div class="col-md-3 col-md-offset-1 col-xs-2
col-xs-offset-6">
<a class="btn btn-primary btn-lg" role="button"
onclick="control('Derecha')">Derecha</a>
</div>
</div>

<br>

<div class="row justify-content-md-center">


<div class="col-md-3 col-md-offset-5 col-xs-2
col-xs-offset-4">
<a class="btn btn-success btn-lg" role="button"
onclick="control('Retroceder')">Retroceder</a>
</div>
</div>
</div>
{% else %}
<!-- Titulo de arriba con imagen-->
<div class="jumbotron jumbotron-fluid jumbotronHeader">
<div class="container pageTitle">
<h1 class="parTitle"><strong>Sistema Antichoque<strong></h1>
<p class="lead"><i><strong>Poderoso y simple sistema de
evasion de obstaculos</strong></i></p>
<a href="/signup" class="btn btn-dark btn-lg" role="button"
>Registrese Ahora!</a>
</div>
</div>

<div class="container">
<br>
<!-- Primer rectangulo -->
<div class="row">
<div class="col-md-8" style="text-align: center;
margin:auto;">
<h1 class="parTitle"><strong>Basado en
Arduino</strong></h1>
<p class="lead"><i>Se trata de un sistema de control de
un autito de tres ruedas basado en la plataforma Arduino Uno.</i></p>
</div>
<div class="col-md-4" style="text-align: center;
margin:auto;">
<img class="d-block img-fluid"
src="static/assets/arduino-logo.png" alt="First Use" width="220"
height="220">
</div>
</div>

<hr>
<br>
<!-- Segundo rectangulo -->
<div class="row">
<div class="col-md-4" style="text-align: center;
margin:auto;">
<img class="d-block img-fluid"
src="static/assets/wifi.jpeg" alt="Second Use" width="250" height="250">
</div>
<div class="col-md-8" style="text-align: center;
margin:auto;">
<h1 class="parTitle"><strong>Control por
WiFi</strong></h1>
<p class="lead"><i>El autito posee un modulo WiFi ESP8266
que le permite comunicarse con el servidor para ser comandado por el
usuario.</i></p>
</div>
</div>

<hr>
<br>

<!-- Parte de abajo -->


<div class="row row-padded text-center">
<div class="col-sm-4">
<img src="/static/assets/pc.png" heigth="100" width="100"
style="border-radius: 5%">
<h4>¿Quienes somos?</h4>
<p class="text-muted">Somos dos alumnos de la carrera
Ingenieria en Computacion cursando la materia Taller de Proyecto II.</p>
</div>
<div class="col-sm-4">
<img src="/static/assets/micro.png" heigth="81"
width="81" style="border-radius: 5%">
<h4>¿Que es este sistema?</h4>
<p class="text-muted">Es un sistema sencillo de evasion
de obstaculos para autitos basado en la plataforma Arduino Uno.</p>
</div>
<div class="col-sm-4">
<img src="/static/assets/faqs.png" heigth="73" width="73"
style="border-radius: 5%">
<h4>FAQs</h4>
<p class="text-muted">Puede acceder a las preguntas mas
frecuentes en el apartado <a href="/faqs" role="link">FAQs</a>.</p>

</div>
</div>

</div>

{% endif %}

<br>
<br>

<!--Footer-->
<footer class="footer">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<img class="img-fluid footerImg"
src="static/assets/logo1.jpg" alt="Logo" height="90" width="100">
</div>
<div class="col-sm-2 col-sm-offset-8">
<p class="float-right"><strong>Alvarez - Cristofano
2017</strong></p>
</div>
</div>
</div>
</footer>

</body>

</html>

Vista signup.html:
<!DOCTYPE html>
<html>

<head>
<title>Sistema Antichoque</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- JQuery -->
<script src="{{url_for('static',
filename='jquery/jquery-3.2.1.min.js')}}"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{url_for('static',
filename='bootstrap3/css/bootstrap.min.css')}}" />
<link rel="stylesheet" href="{{url_for('static',
filename='stylesheets/main.css')}}"/>
<!-- Bootstrap JS -->
<script src="{{url_for('static',
filename='bootstrap3/js/bootstrap.min.js')}}"></script>
</head>

<body>
<!-- Barra -->
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Sistema Antichoque</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/login">Iniciar Sesion</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

<div class="container">
<!-- Titulo de arriba -->
<div class="container text-center login">
<h1 class="parTitle"><strong>Formulario de Registro</strong></h2>
</div>
<br>

{% if error %}
<div class="row justify-content-md-center">
<div class="col-md-12 col-xs-12">
<div class="alert alert-danger">{{ error }}</div>
</div>
</div>
<br>
{% endif %}

<form action="/signup" method="POST">


<div class="row">
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" class="form-control" id="name"
name="name" aria-describedby="nombreHelp" placeholder="Ingrese su nombre"
required/>
<small id="nombreHelp" class="form-text
text-muted">Aquí debe ingresar su nombre.</small>
</div>
</div>
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Apellido</label>
<input type="text" class="form-control" id="surname"
name="surname" aria-describedby="apellidoHelp" placeholder="Ingrese su
apellido" required/>
<small id="apellidoHelp" class="form-text
text-muted">Aquí debe ingresar su apellido.</small>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Nombre de Usuario</label>
<input type="text" class="form-control" id="username"
name="username" aria-describedby="usernameHelp" placeholder="Ingrese su
nombre de usuario" required/>
<small id="nombreHelp" class="form-text
text-muted">Aquí debe ingresar su nombre de usuario.</small>
</div>
</div>
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Contraseña</label>
<input type="password" class="form-control"
id="password" name="password" aria-describedby="passwordHelp"
placeholder="Ingrese su contraseña" required/>
<small id="apellidoHelp" class="form-text
text-muted">Aquí debe ingresar su contraseña.</small>
</div>
</div>
</div>

<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6">
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" id="email"
name="email" aria-describedby="emailHelp" placeholder="email@example.com"
required>
<small id="emailHelp" class="form-text
text-muted">Aquí debe ingresar su email.</small>
</div>
</div>
</div>
<br>
<div class="row justify-content-md-center">
<div class="col-md-2 col-md-offset-5 col-xs-12">
<div class="text-center">
<button type="submit" class="btn btn-dark
btn-lg"">Registrarse</button>
</div>
</div>
</div>
</form>

</div>

<br>
<br>

<!--Footer-->
<footer class="footer">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<img class="img-fluid footerImg"
src="static/assets/logo1.jpg" alt="Logo" height="90" width="100">
</div>
<div class="col-sm-2 col-sm-offset-8">
<p class="float-right"><strong>Alvarez - Cristofano
2017</strong> </p>
</div>
</div>
</div>
</footer>

</body>

</html>

Vista login.html:
<!DOCTYPE html>
<html>

<head>
<title>Sistema Antichoque</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- JQuery -->
<script src="{{url_for('static',
filename='jquery/jquery-3.2.1.min.js')}}"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{url_for('static',
filename='bootstrap3/css/bootstrap.min.css')}}" />
<link rel="stylesheet" href="{{url_for('static',
filename='stylesheets/main.css')}}" />
<!-- Bootstrap JS -->
<script src="{{url_for('static',
filename='bootstrap3/js/bootstrap.min.js')}}"></script>
</head>

<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<a class="navbar-brand" href="/">Sistema Antichoque</a>
</div>

</div><!-- /.container-fluid -->


</nav>

<br>

<div class="container">
<!-- Titulo de arriba -->
<div class="container text-center login">
<h1 class="parTitle"><strong>Login</strong></h2>
</div>
<br>
{% if error %}
<div class="row justify-content-md-center">
<div class="col-md-4 col-md-offset-4 col-xs-12">
<div class="alert alert-danger">{{ error }}</div>
</div>
</div>
<br>
{% elif inform %}
<div class="row justify-content-md-center">
<div class="col-md-4 col-md-offset-4 col-xs-12">
<div class="alert alert-success">{{ inform }}</div>
</div>
</div>
<br>
{% endif %}
<form action="/login" method="POST">
<div class="row justify-content-md-center">
<div class="col-md-4 col-md-offset-4 col-xs-12">
<div class="form-group">
<label for="nombre">Nombre de Usuario</label>
<input type="text" class="form-control" id="username"
name="username" aria-describedby="usernameHelp" placeholder="Ingrese su
nombre de usuario" required/>
<small id="nombreHelp" class="form-text
text-muted">Aquí debe ingresar su nombre de usuario.</small>
</div>
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-4 col-md-offset-4 col-xs-12">
<div class="form-group">
<label for="nombre">Contraseña</label>
<input type="password" class="form-control"
id="password" name="password" aria-describedby="passwordHelp"
placeholder="Ingrese su contraseña" required/>
<small id="apellidoHelp" class="form-text
text-muted">Aquí debe ingresar su contraseña.</small>
</div>
</div>
</div>
<br>
<div class="row justify-content-md-center">
<div class="col-md-2 col-md-offset-5 col-xs-12">
<div class="text-center">
<button type="submit" class="btn btn-dark
btn-lg"">Ingresar</button>
</div>
</div>
</div>
</form>
</div>

<br>
<br>

<!--Footer-->
<footer class="footer" style="margin-top: 75px">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<img class="img-fluid footerImg"
src="static/assets/logo1.jpg" alt="Logo" height="90" width="100">
</div>
<div class="col-sm-2 col-sm-offset-8">
<p class="float-right"><strong>Alvarez - Cristofano
2017</strong> </p>
</div>
</div>
</div>
</footer>

</body>

</html>

Vista faqs.html:
<!DOCTYPE html>
<html>

<head>
<title>Sistema Antichoque</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- JQuery -->
<script src="{{url_for('static',
filename='jquery/jquery-3.2.1.min.js')}}"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{url_for('static',
filename='bootstrap3/css/bootstrap.min.css')}}" />
<link rel="stylesheet" href="{{url_for('static',
filename='stylesheets/main.css')}}" />

<!-- Bootstrap JS -->


<script src="{{url_for('static',
filename='bootstrap3/js/bootstrap.min.js')}}"></script>

</head>

<body>
<!-- Barra -->
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Sistema Antichoque</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">

{% if session_user_name %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">Mi cuenta <span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/">Control</a></li>
<li><a href="/stats">Estadisticas</a></li>
<li><a href="/account">Mis datos</a></li>
<li><a href="/connect">Conectarse</a></li>
<li><a href="/faqs">FAQs</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout">Logout</a> </li>
</ul>
</li>
{% else %}
<li><a href="/login">Iniciar Sesion</a></li>
{% endif %}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

<div class="container">
<div class="container text-center">
<h1 class="parTitle"><strong>Preguntas frecuentes</strong></h1>
</div>
<br>

<!-- Primer rectangulo -->


<div class="row">
<div class="col-md-8" style="text-align: center; margin:auto;">
<h1 class="parTitle"><strong>¿Como funciona el sistema de
control del autito?</strong></h1>
<p class="lead"><i>El usuario de la plataforma web envia los
comandos al servidor, y este ultimo es el encargado de comunicarse con el
autito para comandarlo. A su vez, recolecta de este los valores mas
importantes, almacenandolos para su posterior presentacion en la
plataforma.</i></p>
</div>
<div class="col-md-4"></div>
</div>

<hr>
<br>
<!-- Segundo rectangulo -->
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-8" style="text-align: center; margin:auto;">
<h1 class="parTitle"><strong>¿Que debo hacer para controlar
un autito con este sistema?</strong></h1>
<p class="lead"><i>Primero usted debe registrarse en la
pagina. Una vez registrado, usted debe acceder a la pestaña de control en su
cuenta, donde dispondra de los botones que le permitiran comandar el
autito.</i></p>
</div>

</div>

<hr>
<br>
<!-- Tercer rectangulo -->
<div class="row">
<div class="col-md-8" style="text-align: center; margin:auto;">
<h1 class="parTitle"><strong>¿Debo conectarme al
autito?</strong></h1>
<p class="lead"><i>Si, usted se debe dirigir a la pestaña de
conectarse. Una vez que la conexion fue exitosa, usted estara en condiciones
de comandar al autito. En caso de perdida de conexion o error en la misma,
usted sera informado, para que pueda conectarse nuevamente.</i></p>
</div>
<div class="col-md-4"></div>
</div>

<hr>
<br>

<!-- Segundo rectangulo -->


<div class="row">
<div class="col-md-4"></div>
<div class="col-md-8" style="text-align: center; margin:auto;">
<h1 class="parTitle"><strong>¿Que estadisticas o informacion
me provee la plataforma?</strong></h1>
<p class="lead"><i>En la pestaña de control del autito es
posible visualizar el estado actual del autito. Por otro lado, en la pestaña
de estadisticas es posible ver los ultimos 10 eventos mas importantes que han
ocurrido con el autito.</i></p>
</div>

</div>
</div>

<br>
<br>

<!--Footer-->
<footer class="footer">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<img class="img-fluid footerImg"
src="static/assets/logo1.jpg" alt="Logo" height="90" width="100">
</div>
<div class="col-sm-2 col-sm-offset-8">
<p class="float-right"><strong>Alvarez - Cristofano
2017</strong> </p>
</div>
</div>
</div>
</footer>
</body>

</html>

Vista account.html:
<!DOCTYPE html>
<html>

<head>
<title>Sistema Antichoque</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- JQuery -->
<script src="{{url_for('static',
filename='jquery/jquery-3.2.1.min.js')}}"></script>

<!-- Bootstrap CSS -->


<link rel="stylesheet" href="{{url_for('static',
filename='bootstrap3/css/bootstrap.min.css')}}" />
<link rel="stylesheet" href="{{url_for('static',
filename='stylesheets/main.css')}}" />

<!-- Bootstrap JS -->


<script src="{{url_for('static',
filename='bootstrap3/js/bootstrap.min.js')}}"></script>

</head>

<body>
<!-- Barra -->
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Sistema Antichoque</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">Mi cuenta <span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/">Control</a></li>
<li><a href="/stats">Estadisticas</a></li>
<li><a href="/account">Mis datos</a></li>
<li><a href="/connect">Conectarse</a></li>
<li><a href="/faqs">FAQs</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout">Logout</a> </li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

<div class="container">
<!-- Titulo de arriba -->
<div class="container text-center login">
<h1 class="parTitle"><strong>Mis Datos</strong></h1>
</div>
<br>

{% if error %}
<div class="row justify-content-md-center">
<div class="col-md-3 col-xs-12">
<div class="alert alert-danger">{{ error }}</div>
</div>
</div>
<br>
{% elif inform %}
<div class="row justify-content-md-center">
<div class="col-md-3 col-xs-12">
<div class="alert alert-success">{{ inform }}</div>
</div>
</div>
<br>
{% endif %}

<form action="/account" method="POST">


<div class="row">
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" class="form-control" id="name"
name="name" aria-describedby="nombreHelp" value= {{name}} required/>
<small id="nombreHelp" class="form-text
text-muted">Aquí debe ingresar su nombre.</small>
</div>
</div>
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Apellido</label>
<input type="text" class="form-control" id="surname"
name="surname" aria-describedby="apellidoHelp" value={{surname}} required/>
<small id="apellidoHelp" class="form-text
text-muted">Aquí debe ingresar su apellido.</small>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Nombre de Usuario</label>
<input type="text" class="form-control" id="username"
name="username" aria-describedby="usernameHelp" value={{username}} required/>
<small id="nombreHelp" class="form-text
text-muted">Aquí debe ingresar su nombre de usuario.</small>
</div>
</div>
<div class="col-md-6 col-xs-12">
<div class="form-group">
<label for="nombre">Contraseña</label>
<input type="password" class="form-control"
id="password" name="password" aria-describedby="passwordHelp"
placeholder="Ingrese su contraseña" required/>
<small id="apellidoHelp" class="form-text
text-muted">Aquí debe ingresar su contraseña.</small>
</div>
</div>
</div>

<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6">
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" id="email"
name="email" aria-describedby="emailHelp" value={{email}} required>
<small id="emailHelp" class="form-text
text-muted">Aquí debe ingresar su email.</small>
</div>
</div>
</div>
<br>
<div class="row justify-content-md-center">
<div class="col-md-2 col-md-offset-5 col-xs-12">
<div class="text-center">
<button type="submit" class="btn btn-dark
btn-lg">Registrarse</button>
</div>
</div>
</div>
</form>

</div>

<br>
<br>

<!--Footer-->
<footer class="footer">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<img class="img-fluid footerImg"
src="static/assets/logo1.jpg" alt="Logo" height="90" width="100">
</div>
<div class="col-sm-2 col-sm-offset-8">
<p class="float-right"><strong>Alvarez - Cristofano
2017</strong> </p>
</div>
</div>
</div>
</footer>

</body>

</html>

Vista stats.html
<!DOCTYPE html>
<html>

<head>
<title>Sistema Antichoque</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- JQuery -->
<script src="{{url_for('static',
filename='jquery/jquery-3.2.1.min.js')}}"></script>
<!-- <script type="text/javascript" src="{{url_for('static',
filename='scripts/stats.js')}}"></script> -->
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{url_for('static',
filename='bootstrap3/css/bootstrap.min.css')}}" />
<link rel="stylesheet" href="{{url_for('static',
filename='stylesheets/main.css')}}" />

<!-- Bootstrap JS -->


<script src="{{url_for('static',
filename='bootstrap3/js/bootstrap.min.js')}}"></script>

</head>

<body>
<!-- Barra -->
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Sistema Antichoque</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">Mi cuenta <span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/">Control</a></li>
<li><a href="/stats">Estadisticas</a></li>
<li><a href="/account">Mis datos</a></li>
<li><a href="/connect">Conectarse</a></li>
<li><a href="/faqs">FAQs</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout">Logout</a> </li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

<br>

<div class="container">

<div class="container text-center">


<h1 class="parTitle"><strong>Estadisticas</strong></h1>
</div>
<br>
<!-- Agregar ifs para que detecte la distancia y los pinte de verde,
amarillo o rojo -->
{% if eventos %}
<div class="table-responsive">
<table class="table">
<thead class="btn-dark">
<tr>
<th>Fecha</th>
<th>Hora</th>
<th>Avance/Retroceso</th>
<th>Distancia</th>
</tr>
</thead>
<tbody>
{% for i in eventos %}
{% if i.4 > 50 %}
<tr class="success">
{% elif i.4 > 25 %}
<tr class="warning">
{% else %}
<tr class="danger">
{% endif %}
<td><b>{{ i.2 }}</b></td>
<td><b>{{ i.3 }}</b></td>
<td><b>{{ i.5 }}</b></td>
<td><b>{{ i.4 }}cm</b></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<br>
<br>
<div class="container text-center">
<h2><strong>No hay eventos disponibles</strong></h2>
<br>
<br>
<h4><strong><i>Conectese y utilice el autito para
obtener estadisticas de uso</i></strong></h4>
</div>
{% endif %}

</div>

<!--Footer-->
{% if eventos %}
<footer class="footer" style="margin-top: 10px">
{% else %}
<footer class="footer" style="margin-top: 230px">
{% endif %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<img class="img-fluid footerImg"
src="static/assets/logo1.jpg" alt="Logo" height="90" width="100">
</div>
<div class="col-sm-2 col-sm-offset-8">
<p class="float-right"><strong>Alvarez - Cristofano
2017</strong> </p>
</div>
</div>
</div>
</footer>

</body>

</html>

Hojas de estilos:
index.css:
.jumbotronHeader {
background-image: url("Fondo.jpg");
background-repeat: no-repeat;
background-size: cover;
height: 600px;
margin-top: -20px;
}

.pageTitle {
color: white;
text-align: center;
margin-top: 140px;
}

.parTitle {
color: #2d7eff !important;
font-size: 35px !important;
}

.footer {
background-color: #101010;
color: white;
margin-bottom: 0px;
}

.footerImg {
padding: 15px;
border-radius: 30%;
}

.float-right {
padding-top: 20%;
}

.btn-dark{
background-color: #333 !important;
color: white;
}

.btn-dark:hover{
color:grey !important;
}

main.css:
.footer {
background-color: #101010;
color: white;
margin-bottom: 0px;
}

.login{
margin-top: 4rem;
}

.footerImg {
padding: 15px;
border-radius: 30%;
}

.float-right {
padding-top: 20%;
}

.parTitle {
color: #2d7eff;
}

.btn-dark{
background-color: #333 !important;
color: white;
}

.btn-dark:hover{
color:grey !important;
}

Scripts:
index.js:
function loadIndex() {
$.get("/access", function(data) {
if(data.error!= "Sin conexion"){
if(data.error == 'Perdida de conexion'){
$('#error').removeClass("alert-success");
$('#error').addClass("alert-danger");
$('#error').text(data.error);
}
else{
if(data.state == "Avanzando")
$('#state').addClass("text-success");
else if(data.state == "Retrocediendo")
$('#state').addClass("text-danger");
else{
$('#state').removeClass("text-danger");
$('#state').removeClass("text-success");
}

$('#state').text("Estado: " + data.state);

$('#marcha').text("Marcha: " + data.marcha);

if(data.front_distance > 75){


$('#front_distance').removeClass("text-danger");
$('#front_distance').removeClass("text-warning");
$('#front_distance').addClass("text-success");
}
else if(data.front_distance > 50){
$('#front_distance').removeClass("text-danger");
$('#front_distance').removeClass("text-success");
$('#front_distance').addClass("text-warning");
}
else{
$('#front_distance').removeClass("text-success");
$('#front_distance').removeClass("text-warning");
$('#front_distance').addClass("text-danger");
}

if(data.front_distance > 400){


$('#front_distance').text("Distancia Adelante: > 400cm");
}
else
$('#front_distance').text("Distancia Adelante: " +
data.front_distance + "cm");

if(data.back_distance > 75){


$('#back_distance').removeClass("text-danger");
$('#back_distance').removeClass("text-warning");
$('#back_distance').addClass("text-success");
}
else if(data.back_distance > 50){
$('#back_distance').removeClass("text-danger");
$('#back_distance').removeClass("text-success");
$('#back_distance').addClass("text-warning");
}
else{
$('#back_distance').removeClass("text-success");
$('#back_distance').removeClass("text-warning");
$('#back_distance').addClass("text-danger");
}
if(data.back_distance > 400){
$('#back_distance').text("Distancia Atras: > 400cm");
}
else
$('#back_distance').text("Distancia Atras: " +
data.back_distance + "cm");
}
}
});
}

$( document ).ready(function () {
setInterval(loadIndex, 2500);
});

control.js:
function control(action) {
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "/control", true);
xhttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xhttp.send("action=" + action);
}

Controladores(antichoque.py):
from flask import Flask, session, redirect, url_for, escape, request,
render_template
from hashlib import md5
from flask import jsonify
import MySQLdb
import socket
import math
import datetime

# Create a TCP/IP socket


sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('192.168.4.1', 666)
#error = ''
#inform = ''
direction = 0
turn = 0
speed = 0

app = Flask(__name__)

if __name__ == '__main__':
db = MySQLdb.connect(host="localhost", user="root", passwd="root",
db="antichoque")
cur = db.cursor()
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

class ServerError(Exception):pass

@app.errorhandler(404)
def page_not_found(e):
return redirect(url_for('index'))

@app.route('/')
def index():
global sock
if not 'username' in session:
return render_template('index.html')
else:
# Definiciones locales
username_session = escape(session['username']).capitalize()
username_session = username_session.lower()
cur.execute("SELECT COUNT(1) FROM users WHERE state = 'online' &&
username = %s;", [username_session])
if not cur.fetchone()[0]:
error = request.args.get("error")
if not error:
error = "Usted no esta conectado"
return render_template('index.html', error=error,
session_user_name=username_session, state='Desconectado', direction=0,
marcha=0 , turn=0, back_distance=0, front_distance=0)
else:
inform = request.args.get("inform")
return render_template('index.html', inform=inform,
session_user_name=username_session, state='Desconectado', direction=0,
marcha=0, turn=0, back_distance=0, front_distance=0)

@app.route("/access")
def access():
global sock
global turn
global direction
global speed
if 'username' in session:
# Definiciones locales
username_session = escape(session['username']).capitalize()
username_session = username_session.lower()
f_distance = ''
b_distance = ''
front_distance = 0
back_distance = 0
state = 'Desconectado'
cur.execute("SELECT COUNT(1) FROM users WHERE state = 'online' &&
username = %s;", [username_session])
#Si estoy conectado al servidor del autito puedo utilizarlo sino no
if cur.fetchone()[0] == 1:
try:
sock.settimeout(3)
sock.sendall('1'); #Envio un pedido de informacion, es decir
un solo byte envio
recibido = sock.recv(15)
j = 0
for i in range(0, 5):
while recibido[j] != '/':
if i == 0:
f_distance = f_distance + recibido[j]
elif i == 1:
b_distance = b_distance + recibido[j]
elif i == 2: # Analisis del avance
direction = int(recibido[j])
if recibido[j] == '0':
state = 'Parado'
elif recibido[j] == '1':
state = 'Avanzando'
elif recibido[j] == '2':
state = 'Retrocediendo'
elif i == 3: # Analisis de la velocidad
speed = int(recibido[j])
else: # Analisis de la direccion(si es cero es
porque va hacia adelante o hacia atras)
turn = int(recibido[j])
if recibido[j] == '1':
state = 'Izquierda'
elif recibido[j] == '2':
state = 'Derecha'
j=j+1
j=j+1
#Verificamos que la marcha sea 0 para indicar que el vehiculo
esta parado
if speed == 0:
state = 'Parado'
front_distance = int(f_distance)
back_distance = int(b_distance)
#Agregamos los eventos, si son de importancia
fecha = datetime.date.today()
hora = str(datetime.datetime.now().time())
hora = hora.split(".")[0]
if front_distance < 100:
cur.execute('INSERT INTO eventos(username, fecha, hora,
dist, type) VALUES (%s,%s,%s,%s,%s)', ([username_session], [fecha], [hora],
[front_distance], 'Avance'))
db.commit()
if back_distance < 100:
cur.execute('INSERT INTO eventos(username, fecha, hora,
dist, type) VALUES (%s,%s,%s,%s,%s)', ([username_session], [fecha], [hora],
[back_distance], 'Retroceso'))
db.commit()
except socket.error as socketerror:
sock.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
error = 'Perdida de conexion'
print(error)
cur.execute("UPDATE users SET state = 'semi-online' WHERE
username = %s;", [username_session])
result = {"error": error}
return jsonify(result)
result = {"error": "Ninguno", "state": state, "direction":
direction, "marcha": speed, "turn": turn, "front_distance": front_distance,
"back_distance": back_distance}
return jsonify(result)
result = {"error": "Sin conexion"}
return jsonify(result)

@app.route('/control', methods=['GET', 'POST'])


def control():
global turn
global direction
global speed
if request.method == 'POST':
username_session = escape(session['username']).capitalize()
username_session = username_session.lower()
cur.execute("SELECT COUNT(1) FROM users WHERE state = 'online' &&
username = %s;", [username_session])
#Si estoy conectado puedo utilizarlo sino no
if cur.fetchone()[0]:
action = request.form['action']
if action == "Frenar":
direction = 0
speed = 0
turn = 0
elif action == "Marcha A":
if turn !=0 or direction !=1:
speed = 1
elif speed < 3:
speed = speed + 1
elif action == "Marcha D":
if turn !=0 or direction !=1:
speed = 1
elif speed>0:
speed = speed - 1
elif action == "Avanzar":
direction = 1
speed = 1
turn = 0
elif action == "Izquierda":
direction = 1
speed = 1
turn = 1
elif action == "Derecha":
direction = 1
speed = 1
turn = 2
elif action == "Retroceder":
direction = 2
speed = 1
turn = 0
sock.sendall(str(direction) + str(speed) + str(turn)); #Envio un
pedido de comando, tres bytes (VER SI FUNCIONA)
return redirect(url_for('index'))

@app.route('/login', methods=['GET', 'POST'])


def login():
if request.method == 'POST':
error = None
try:
username = request.form['username']
cur.execute("SELECT COUNT(1) FROM users WHERE username = %s;",
[username])
# Si no existe ese nombre de usuario, informamos error
if not cur.fetchone()[0]:
raise ServerError('Invalid username')

password = request.form['password']
cur.execute("SELECT password FROM users WHERE username = %s;",
[username])
# Si la contrasena es correcta permitimos el login
for row in cur.fetchall():
if md5(password).hexdigest() == row[0]:
session['username'] = request.form['username']
cur.execute("UPDATE users SET state = 'semi-online' WHERE
username = %s;", [username])
db.commit()
return redirect(url_for('index'))

raise ServerError('Invalid password')


except ServerError as e:
error = str(e)
return render_template('login.html', error=error)
elif 'username' in session:
return redirect(url_for('index'))
else:
return render_template('login.html')

@app.route('/connect')
def connect():
global sock
if not 'username' in session:
return render_template('index.html')
else:
username_session = escape(session['username']).capitalize()
username_session = username_session.lower()
cur.execute("SELECT COUNT(1) FROM users WHERE state= 'online' &&
username = %s;", [username_session])
if cur.fetchone()[0]:
return redirect(url_for('index'))
else:
try:
sock.connect(server_address)
cur.execute("UPDATE users SET state = 'online' WHERE username
= %s;", [username_session])
inform = 'Conexion exitosa'
return redirect(url_for('index', inform=inform))
except socket.error as socketerror:
print(socketerror)
error = 'Error al conectarse'
sock.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return redirect(url_for('index', error=error))

@app.route('/logout')
def logout():
global sock
if not 'username' in session:
return render_template('index.html')
else:
username = escape(session['username']).capitalize()
username = username.lower()
session.pop('username', None)
cur.execute("SELECT COUNT(1) FROM users WHERE state = 'online' &&
username = %s;", [username])
if cur.fetchone()[0]:
sock.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

cur.execute("UPDATE users SET state = 'offline' WHERE username =


%s;", [username])
db.commit()
return redirect(url_for('index'))

@app.route('/signup', methods=['GET', 'POST'])


def signup():
if request.method == 'POST':
error = None
inform = 'Usted se ha registrado correctamente'
try:
name = request.form['name']
surname = request.form['surname']
email = request.form['email']
username = request.form['username']
password = request.form['password']
cur.execute("SELECT COUNT(1) FROM users WHERE name = %s;",
[username])
if cur.fetchone()[0]:
raise ServerError('Invalid username')
cur.execute("SELECT COUNT(1) FROM users WHERE email = %s;",
[email])
if cur.fetchone()[0]:
raise ServerError('Invalid email')
cur.execute('INSERT INTO
users(name,surname,email,username,password,state) VALUES
(%s,%s,%s,%s,%s,%s)', ([name], [surname], [email], [username],
[md5(password).hexdigest()], 'offline'))
db.commit()
except ServerError as e:
error = str(e)
return render_template('signup.html', error=error)
return render_template('login.html', inform=inform)
elif 'username' in session:
return redirect(url_for('index'))
elif request.method == 'GET':
return render_template('signup.html')

@app.route('/stats')
def stats():
if not 'username' in session:
return render_template('index.html')
else:
username = escape(session['username']).capitalize()
username = username.lower()
cur.execute('SELECT * FROM eventos WHERE username = %s ORDER BY id
DESC LIMIT 10;', [username])
lista=[row for row in cur.fetchall()]
return render_template('stats.html', eventos=lista)

@app.route('/faqs')
def faqs():
if not 'username' in session:
return render_template('faqs.html')
else:
username_session = escape(session['username']).capitalize()
return render_template('faqs.html',
session_user_name=username_session)

@app.route('/account', methods=['GET', 'POST'])


def account():
if not 'username' in session:
return render_template('index.html')
else:
username_session = escape(session['username']).capitalize()
username_session = username_session.lower()
if request.method == 'POST':
error = None
inform = 'Usted ha modificado sus datos correctamente'
try:
name = request.form['name']
surname = request.form['surname']
email = request.form['email']
username = request.form['username']
password = request.form['password']
cur.execute("SELECT COUNT(1) FROM users WHERE username =
%s;", [username])
#Si el username fue cambiado y hay otro igual, informamos
error
if username_session != username:
if cur.fetchone()[0]:
raise ServerError('Invalid username')
cur.execute("SELECT email FROM users WHERE username = %s;",
[username_session])
old_email = cur.fetchone()[0]
cur.execute("SELECT COUNT(1) FROM users WHERE email = %s;",
[email])
#Si el email es distinto del actual, y hay otro igual al
nuevo, informamos error
if old_email != email:
if cur.fetchone()[0]:
raise ServerError('Invalid email')
cur.execute('UPDATE users SET name=%s, surname=%s, email=%s,
username=%s, password=%s WHERE username = %s', ([name], [surname], [email],
[username], [md5(password).hexdigest()], [username_session]))
db.commit()
except ServerError as e:
error = str(e)
return render_template('account.html',
username_sesion=username_session, error=error, name=name, surname=surname,
email=email, username=username)
return render_template('account.html',
username_sesion=username_session, inform=inform, name=name, surname=surname,
email=email, username=username)
else:
cur.execute('SELECT * FROM users WHERE username = %s;',
[username_session])
row = cur.fetchone()
name = row[1]
surname = row[2]
email = row[3]
username = row[4]
return render_template('account.html',
username_sesion=username_session, name=name, surname=surname, email=email,
username=username)

if __name__ == '__main__':
app.run(host='localhost', port=8000)
Apéndice C:
A continuación se adjunta el código correspondiente al archivo autito.ino

Sketch actual
/*FUNCIONES ORIGINALES*/
#include <Arduino.h>

/*FUNCIONES EDITADAS O DESARROLLADAS*/

#include <HC_SR04X2.h>
#include <ControlMotor.h>
#include "ESP8266.h"

/*DEFINICIONES DE CONFIGURACION*/
#define BAUDRATE 115200
#define HC_SR04FRONT_OUT 12 // Numero de pin por el cual se envia el pulso
de START
#define HC_SR04FRONT_IN 13 // Numero de pin por el cual se recibe
informacion de la medioción
#define HC_SR04BACK_OUT 9 // Numero de pin por el cual se envia el pulso
de START
#define HC_SR04BACK_IN 8 // Numero de pin por el cual se recibe
informacion de la medioción
#define TAM_BUFFER 128
#define CRITIC_DISTANCE 40

/*DEFINICIONES DE TIEMPO DE EJECUCION*/


#define F_Sensed 27 //revisar valores
#define F_Communication 50
#define F_Movement 97

/*DECLARACION DE VARIABLES GLOBALES*/


ControlMotor control(2,3,7,4,5,6); //
MotorDer1,MotorDer2,MotorIzq1,MotorIzq2,PWM_Derecho,PWM_Izquierdo
HC_SR04X2 sensor_distance;
ESP8266 wifi(Serial);

uint8_t buffer[TAM_BUFFER]={0};//buffer para enviar y recibir informacion


uint32_t len=0;//Tamaño del mensaje recibido o el mensaje a enviar
uint32_t frecuency=1; //variables que nos permite implementar un porgrmacion
de tareas
String data_send;
//variables de almacenamiento de distancias
float distance_front=0;
float distance_back=0;
//variables de desplazamiento -> el vehiculo lee estas variables y decide su
movimiento
uint8_t direction=0; // 0=stop, 1=front, 2=back //si va para adelante o para
atras
uint8_t speed=0; // 0=stop, 1=slow, 2=fast ,3=fasta&furious
uint8_t turn=0; // 0=forward, 1=left, 2=right

void setup(void)
{

Serial.begin(BAUDRATE);
Serial.print("setup begin\r\n");
wifi.Configuration();
sensor_distance.BackSetup(HC_SR04BACK_OUT,HC_SR04BACK_IN);
sensor_distance.FrontSetup(HC_SR04FRONT_OUT,HC_SR04FRONT_IN);
Serial.print("setup end\r\n");
}

void loop(void)
{

// MEDICION DE DISTANCIA Y FRENO DE EMEGENCIA


if (frecuency % F_Sensed == 0){ //SI es momento de sensar la distancia
distance_front=sensor_distance.FrontMeasurement();
Serial.print("front:");
Serial.print(distance_front);
Serial.print("\r\n");
distance_back=sensor_distance.BackMeasurement();
Serial.print("back:");
Serial.print(distance_back);
Serial.print("\r\n");

if (distance_front <= CRITIC_DISTANCE && direction == 1){ //si hay poca


distancia hacia adelante y voy hacia adelante//REVISAR SI NO MOLESTA PARA
DOBLAR
control.parar();
direction=0;
speed=0;
Serial.print("STOP FRONT\r\n");
}else{
if (distance_back <= CRITIC_DISTANCE && direction == 2){ //si hay
poca distancia hacia atras y voy hacia atras
control.parar();// no se que es ese 10
direction=0;
speed=0;
Serial.print("STOP BACKT\r\n");
}

}
}
// FIN MEDICION DE DISTANCIA Y FRENO DE EMEGENCIA

// DEZPLAZAMIENTO
if (frecuency % F_Movement == 0 ){ //Si es momento de realizar un
movimiento
if( direction == 1 && speed != 0 ) { // Si voy hacia adelante
Serial.print("ADELANTE\r\n");
if( turn==0){ // si voy hacia adelante en linea recta
control.avanzar(speed);
}
if( turn==1){ // si voy hacia adelante en hacia la izqueirda
control.girarIzquierda();
}
if( turn==2){ // si voy hacia adelante en hacia la izqueirda
control.girarDerecha();
}
}
if( direction == 2 && speed != 0 ) { // Si voy hacia atrás
Serial.print("ATRAS\r\n");
control.retroceder();
}
if (direction == 0 || speed == 0){
control.parar();
}
Serial.print(direction);
Serial.print(speed);
Serial.print(turn);
Serial.print("\r\n");

}
// FIN DEZPLAZAMIENTO

// COMUNICACION
if (frecuency % F_Communication == 0 ){ //SI es momento de procesar la
comunicacion
len=wifi.Receive_data(buffer);
if (len == 3){ //SI SE RECIBE ORDEN
Serial.print("ORDEN");
Serial.print("\r\n");
//REcibí un mensaje de desplazamiento, almacenamiento de los
movimientos que decidió el usuario
direction=buffer[0]-48; //se resta 48, pues el valro que
se recibe está en ascci
speed=buffer[1]-48;
turn=buffer[2]-48;
Serial.print(direction);
Serial.print(speed);
Serial.print(turn);

}
if (len == 1){ //SI PIDE INFORMACION
Serial.print("Estadisticas");
Serial.print("\r\n");
data_send=(String(distance_front, 0)+'/'+String(distance_back,
0)+'/'+String(direction,DEC)+'/'+String(speed,DEC)+'/'+String(turn,DEC)+'/');
//preparación de la informacio na enviar
for(len=0; len<data_send.length();len++){ // Se coloca el
string en el buffer para su proximo envio
if(data_send[len]!= 32){ //en el caso de que la
conversion a string me de un caracater espacio, lo reemplazo por '0'(En la
práctica sucede)
buffer[len]=data_send[len];
}else{
buffer[len]='0';
}
//Serial.print((char)buffer[len]);
}
//Serial.print("\r\n");
//envio del estado
Serial.print(data_send.length());
Serial.print("\r\n");

wifi.Send_data(buffer,data_send.length());
Serial.print("Envio de datos");
Serial.print("\r\n");
for (len=0;len<data_send.length();len++){
Serial.print((char)buffer[len]);
}
Serial.print("\r\n");

}
// FIN COMUNICACION

// FIN ESCANEO DEL ESTADO DE LA COMUNICACION DEL VEHICULO


frecuency++;//Aumento de la iteracion realizada
if (frecuency == 6300){
frecuency=0;
}
// FIN CONFIGURACION DE TIEMPOS
}

/*FUNCIONES ORIGINALES*/
#include <Arduino.h>
Sketch para vehículo con motores similares.

/*FUNCIONES EDITADAS O DESARROLLADAS*/


#include <HC_SR04X2.h>
#include <ControlMotor.h>
#include "ESP8266.h"

/*DEFINICIONES DE CONFIGURACION*/
#define BAUDRATE 115200
#define HC_SR04FRONT_OUT 12 // Numero de pin por el cual se envia el pulso
de START
#define HC_SR04FRONT_IN 13 // Numero de pin por el cual se recibe
informacion de la medioción
#define HC_SR04BACK_OUT 9 // Numero de pin por el cual se envia el pulso
de START
#define HC_SR04BACK_IN 8 // Numero de pin por el cual se recibe
informacion de la medioción
#define TAM_BUFFER 128
#define CRITIC_DISTANCE 40
#define SPEED_RELATIONSHIP 80 //relacion para auto con 3 marchas

/*DEFINICIONES DE TIEMPO DE EJECUCION*/


#define F_Sensed 27 //revisar valores
#define F_Communication 50
#define F_Movement 97

/*DECLARACION DE VARIABLES GLOBALES*/


ControlMotor control(2,3,7,4,5,6); //
MotorDer1,MotorDer2,MotorIzq1,MotorIzq2,PWM_Derecho,PWM_Izquierdo
HC_SR04X2 sensor_distance;
ESP8266 wifi(Serial);

uint8_t buffer[TAM_BUFFER]={0};//buffer para enviar y recibir informacion


uint32_t len=0;//Tamaño del mensaje recibido o el mensaje a enviar
uint32_t frecuency=1; //variables que nos permite implementar un porgrmacion
de tareas
String data_send;
//variables de almacenamiento de distancias
float distance_front=0;
float distance_back=0;
//variables de desplazamiento -> el vehiculo lee estas variables y decide su
movimiento
uint8_t direction=0; // 0=stop, 1=front, 2=back //si va para adelante o para
atras
uint8_t speed=0; // 0=stop, 1=slow, 2=fast ,3=fasta&furious
uint8_t turn=0; // 0=forward, 1=left, 2=right

void setup(void)
{
Serial.begin(BAUDRATE);
Serial.print("setup begin\r\n");
wifi.Configuration();
sensor_distance.BackSetup(HC_SR04BACK_OUT,HC_SR04BACK_IN);
sensor_distance.FrontSetup(HC_SR04FRONT_OUT,HC_SR04FRONT_IN);
Serial.print("setup end\r\n");
}

void loop(void)
{

// MEDICION DE DISTANCIA Y FRENO DE EMEGENCIA


if (frecuency % F_Sensed == 0){ //SI es momento de sensar la distancia
distance_front=sensor_distance.FrontMeasurement();
Serial.print("front:");
Serial.print(distance_front);
Serial.print("\r\n");
distance_back=sensor_distance.BackMeasurement();
Serial.print("back:");
Serial.print(distance_back);
Serial.print("\r\n");

if (distance_front <= CRITIC_DISTANCE && direction == 1){ //si hay poca


distancia hacia adelante y voy hacia adelante//REVISAR SI NO MOLESTA PARA
DOBLAR
control.parar(3);
direction=0;
speed=0;
Serial.print("STOP FRONT\r\n");
}else{
if (distance_back <= CRITIC_DISTANCE && direction == 2){ //si hay
poca distancia hacia atras y voy hacia atras
control.parar(3);// no se que es ese 10
direction=0;
speed=0;
Serial.print("STOP BACKT\r\n");
}

}
}
// FIN MEDICION DE DISTANCIA Y FRENO DE EMEGENCIA

// DEZPLAZAMIENTO
if (frecuency % F_Movement == 0 ){ //Si es momento de realizar un
movimiento
if( direction == 1 && speed != 0 ) { // Si voy hacia adelante
Serial.print("ADELANTE\r\n");
if( turn==0){ // si voy hacia adelante en linea recta
control.avanzar(SPEED_RELATIONSHIP*speed);
}
if( turn==1){ // si voy hacia adelante en hacia la izqueirda
control.girarIzquierda(SPEED_RELATIONSHIP*speed);
}
if( turn==2){ // si voy hacia adelante en hacia la izqueirda
control.girarDerecha(SPEED_RELATIONSHIP*speed);
}
}
if( direction == 2 && speed != 0 ) { // Si voy hacia atrás
Serial.print("ATRAS\r\n");
control.retroceder(SPEED_RELATIONSHIP);
}
if (direction == 0 || speed == 0){
control.parar(3);
}
Serial.print(direction);
Serial.print(speed);
Serial.print(turn);
Serial.print("\r\n");

}
// FIN DEZPLAZAMIENTO

// COMUNICACION
if (frecuency % F_Communication == 0 ){ //SI es momento de procesar la
comunicacion
len=wifi.Receive_data(buffer);
if (len == 3){ //SI SE RECIBE ORDEN
Serial.print("ORDEN");
Serial.print("\r\n");
//REcibí un mensaje de desplazamiento, almacenamiento de los
movimientos que decidió el usuario
direction=buffer[0]-48; //se resta 48, pues el valro que
se recibe está en ascci
speed=buffer[1]-48;
turn=buffer[2]-48;
Serial.print(direction);
Serial.print(speed);
Serial.print(turn);

}
if (len == 1){ //SI PIDE INFORMACION
Serial.print("Estadisticas");
Serial.print("\r\n");
data_send=(String(distance_front, 0)+'/'+String(distance_back,
0)+'/'+String(direction,DEC)+'/'+String(speed,DEC)+'/'+String(turn,DEC)+'/');
//preparación de la informacio na enviar
for(len=0; len<data_send.length();len++){ // Se coloca el
string en el buffer para su proximo envio
if(data_send[len]!= 32){ //en el caso de que la
conversion a string me de un caracater espacio, lo reemplazo por '0'(En la
práctica sucede)
buffer[len]=data_send[len];
}else{
buffer[len]='0';
}
//Serial.print((char)buffer[len]);
}
//Serial.print("\r\n");
//envio del estado
Serial.print(data_send.length());
Serial.print("\r\n");

wifi.Send_data(buffer,data_send.length());
Serial.print("Envio de datos");
Serial.print("\r\n");
for (len=0;len<data_send.length();len++){
Serial.print((char)buffer[len]);
}
Serial.print("\r\n");

}
// FIN COMUNICACION

// CONFIGURACION DE TIEMPOS
frecuency++;//Aumento de la iteracion realizada
if (frecuency == 6300){
frecuency=0;
}
// FIN CONFIGURACION DE TIEMPOS
}

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