diseÑo y desarrollo de dipositivo rastreador para ... · escuela de ingenieria diseÑo y...
TRANSCRIPT
PONTIFICIA UNIVERSIDAD CATOLICA DE CHILE
ESCUELA DE INGENIERIA
DISEÑO Y DESARROLLO DE DIPOSITIVO RASTREADOR PARA GENERACIÓN DE DATOS DE MOVILIDAD EN BICICLETA
SEBASTIAN IGNACIO SALINAS PEÑA
Memoria para optar al título de
Ingeniero Civil Industrial, con Diploma en Ingeniería Eléctrica
Profesor Supervisor:
CATALINA CORTAZAR VALDES
FELIPE DELGADO BREINBAUER
Santiago de Chile, 2016
PONTIFICIA UNIVERSIDAD CATOLICA DE CHILE
ESCUELA DE INGENIERIA
Departamento de Ingeniería Eléctrica
DISEÑO Y DESARROLLO DE DIPOSITIVO RASTREADOR PARA GENERACIÓN DE DATOS DE MOVILIDAD EN BICICLETA
SEBASTIAN IGNACIO SALINAS PEÑA
Memoria presentada a la Comisión integrada por los profesores:
CATALINA CORTAZAR V.
KARIM PICHARA B.
MIGUEL TORRES T.
Para completar las exigencias del título de Ingeniero Civil Industrial, con Diploma en Ingeniería Eléctrica
Santiago de Chile, 2016
i
A mi familia, profesores, amigos y
voluntarios que ayudaron e hicieron
realidad esta investigación.
ii
AGRADECIMIENTOS
Agradezco de forma especial a los voluntarios que se ofrecieron para
ocupar el dispositivo. Gracias a su ayuda, se probaron los prototipos de forma exitosa.
Sumo a los agradecimientos a todas las instituciones públicas y privadas ligadas a la
bicicleta, por su aporte invaluable en conocimiento y experiencia.
De forma muy especial, agradezco a profesores, tutores y personas que
trabajan en el DILAB. Su apoyo incondicional, mirada y perspectiva innovadora
lograron contagiarme y embarcarme en esta investigación.
A Catalina Cortázar, profesora guía y tutora, quien durante este tiempo
ha sido una madrina, aportando y apoyando desde todos los ámbitos. Su dedicación,
optimismo y buena voluntad fueron determinantes para el desarrollo de este trabajo.
A mi madre Luisa, por su amor incondicional, paciencia y preocupación,
por escucharme y entenderme. A mi padre Mauricio, por mostrarme que no existe tal
cosa como un problema imposible. A mi hermana Macarena, por su sentido del
humor y darme ánimos cada vez que el trabajo parecía cambiar mi semblante.
Finalmente, agradezco a Emily Mens, quien inspiró a dedicar esta
investigación al uso de la bicicleta y el comportamiento de los ciclistas.
INDICE GENERAL
Pág.
iii
DEDICATORIA........................................................................................................ i
AGRADECIMIENTOS ........................................................................................... ii
INDICE DE TABLAS.............................................................................................. iv
INDICE DE FIGURAS ......................................................................................... v
RESUMEN................................................................................................................ vi
ABSTRACT ............................................................................................................... vii
I. DESARROLLO DE HARDWARE.................................................................. 12
1.1 Prototipo Alfa .......................................................................................... 12
1.1.1 Elección de componentes............................................................... 13
1.1.1.1 Elección de módulo GPS.................................................... 13
1.1.1.2 Elección de memoria ..........................................................15
1.1.1.3 Elección de batería y misceláneos..................................... 16
1.1.1.4 Elección de microcontrolador............................................ 17
1.1.2 Diagrama de bloques de hardware................................................ 19
1.1.3 Diagrama de flujo de software en microcontrolador.................... 20
1.1.4 Comunicación con módulo GPS................................................... 22
1.1.5 Comunicación con memoria SD.................................................. 25
1.1.6 Redacción de código microcontrolador....................................... 26
1.1.7 Construcción de prototipo alfa ..................................................... 32
1.1.8 Testeo con usuarios del prototipo alfa.......................................... 37
1.2 Prototipo Beta ......................................................................................... 38
1.2.1 Elección de componentes ............................................................ 38
1.2.1.1 Elección de acelerómetro........................................................... 39
1.2.1.2 Elección de módulo WiFi........................................................... 39
12
12
13
13
15
16
17
19
20
22
25
26
32
37
38
38
39
39
INDICE GENERAL
Pág.
iii
1.2.1.3 Elección de memoria.......................................................... 40
1.2.1.4 Elección de batería..............................................................40
1.2.1.5 Elección de microcontrolador............................................ 40
1.2.2 Diagrama de bloques de hardware................................................ 41
1.2.3 Diagrama de flujo de microcontrolador maestro.......................... 42
1.2.4 Comunicación con acelerómetro.................................................. 44
1.2.4.1 Detección de movimiento.................................................. 44
1.2.5 Comunicación con módulo WiFi................................................. 48
1.2.6 Comunicación con memoria dataflash......................................... 48
1.2.7 Comunicación entre microcontroladores..................................... 49
1.2.8 Gestión de redes y entrega de datos.............................................. 49
1.2.8.1 Diagrama de flujo de microcontrolador esclavo................ 50
1.2.8.2 Modo AP y configuración de redes................................... 54
1.2.8.3 Modo cliente y detección de redes.................................... 61
1.2.8.4 Envío de información a la aplicación web......................... 64
1.2.8.5 Sleep Mode........................................................................ 66
1.2.9 Redacción de código microcontrolador maestro.......................... 67
1.2.10 Redacción de código microcontrolador esclavo......................... 73
1.2.11 Construcción de prototipo beta.................................................... 83
1.2.12 Testeo con usuarios del prototipo beta......................................... 87
II. DESARROLLO DE SOFTWARE................................................................... 88
2.1 Desarrollo de plataforma ........................................................................ 88
2.1.1 Diseño de base de datos ................................................................ 90
2.1.2 Sistema de autentificación ............................................................ 92
2.1.3 Subir archivos .csv ........................................................................ 95
40
40
40
41
42
44
44
48
48
49
49
50
54
61
64
66
67
73
83
87
88
88
90
92
95
INDICE GENERAL
Pág.
iii
2.2 Desarrollo de aplicación para dispositivo beta........................................ 97
2.2.1 Diagrama de flujo de aplicación para dispositivo beta.................. 97
2.2.2 Redacción de código de la aplicación.......................................... 100
2.3 Visualización de viajes agregados......................................................... 105
2.3.1 Conversión de archivos............................................................... 106
2.3.2 CartoCSS y mapas de calor……………………................…….108
III. RESULTADOS............................................................................................110
3.1 Representatividad de la muestra ............................................................110
3.2 Estadísticas generales de demanda .........................................................112
3.3 Mapas de calor ...................................................................................... 115
3.4 Problemas y mejoras al dispositivo ...................................................... 120
3.5 Problemas y mejoras a la plataforma .................................................... 121
3.6 Recepción del público ........................................................................... 122
BIBLIOGRAFIA .................................................................................................... 123
A N E X O S............................................................................................................. 126
Anexo A : Instrucciones ESP8266 ..................................................................127
Anexo B : Esquemático prototipo alfa.............................................................128
Anexo C : Esquemático prototipo beta.............................................................129
97
97
100
105
106
108
110
110
112
115
120
121
122
123
126
127
128
129
INDICE GENERAL
Pág.
iii
INDICE DE TABLAS
iv
Tabla 1.1: Comparación de módulos GPS ……......................................................... 14
Tabla 1.2: Consumo energético ESP8266 ……......................................................... 39
Tabla 3.1: Voluntarios por sector ............................................................................ 116
iii
INDICE DE FIGURAS
Pág.
v
Figura 1.1: Vista superior de un Arduino Mini..........................................................17
Figura 1.2: Diagrama de bloques de hardware del prototipo alfa ..............................19
Figura 1.3: Diagrama de flujo de software del prototipo alfa ....................................21
Figura 1.4: Caja de mentas Altoids………................................................................32
Figura 1.5: Perforación para interruptor.....................................................................33
Figura 1.6: Montura de abrazadera.............................................................................33
Figura 1.7: Posición de la batería...............................................................................34
Figura 1.8: Posición de Arduino................................................................................34
Figura 1.9: Cableado de componentes.......................................................................35
Figura 1.10: Dispositivo alfa ensamblado...................................................................36
Figura 1.11: Diagrama de bloques de hardware del dispositivo beta……..................41
Figura 1.12: Diagrama de flujo de software del prototipo beta……............................43
Figura 1.13: Filtro detector de movimiento.................................................................45
Figura 1.14: Módulo de la aceleración........................................................................46
Figura 1.15: Histograma módulo aceleración - bicicleta en movimiento....................47
Figura 1.16: Histograma módulo aceleración - bicicleta estática ………....................47
17
19
21
32
33
33
34
34
35
36
41
43
45
46
47
47
iii
INDICE DE FIGURAS
Pág.
v
Figura 1.17: Diagrama de flujo de gestión de redes y entrega de datos……...............53
Figura 1.18: Formulario HTML.................................................................................57
Figura 1.19: Distribución de la EEPROM microcontrolador esclavo……..................60
Figura 1.20: PCB de doble capa …………………....................................................84
Figura 1.21: PCB generado por Oshpark…................................................................84
Figura 1.22: PCB ensamblado....................................................................................85
Figura 1.23: Case modelo 3D……………….............................................................86
Figura 1.24: Prototipo beta ensamblado……...........................................................86
Figura 2.1: Arquitectura base de datos plataforma….................................................90
Figura 2.2: Diagrama de flujo de aplicación web……..............................................99
Figura 2.3: Conversión entre archivos..................................................................... 106
Figura 2.4: Mapa de calor – calles Pocuro y Bilbao…............................................ 108
Figura 3.1: Histograma de kilómetros por viaje….................................................. 112
Figura 3.2: Histograma de minutos por viaje…...................................................... 113
Figura 3.3: Histograma de velocidad promedio por viaje….................................... 114
Figura 3.4: Mapa de calor general………………….............................................. 115
53
57
60
84
84
85
86
86
90
99
106
108
112
113
114
115
iii
INDICE DE FIGURAS
Pág.
v
Figura 3.5: Mapa de calor zonas con mayor flujo…................................................ 117
Figura 3.6: Mapa de calor campus San Joaquín UC…............................................ 118
Figura 3.7: Mapa de calor dividido por días…........................................................ 119
10
vi
INTRODUCCION
El objetivo de esta investigación es desarrollar un dispositivo electrónico
capaz de registrar datos de las rutas generadas por distintos activos y posteriormente
subir la información a una base de datos a través de redes de Internet WiFi privadas.
Como caso de estudio se escogió el “ciclismo urbano” por su creciente
presencia en la región metropolitana (6.8% anual según SECTRA) y la escasez de
datos sobre el comportamiento de los ciclistas en la ciudad de Santiago. La
información obtenida puede ayudar a organismos tomadores de decisión e
investigadores del área de transporte a entender de mejor manera la demanda de
distintas rutas por ciclistas, modelar la locación y el diseño óptimo de
estacionamientos de bicicleta, formular modelos que permitan estimar la demanda
latente por bicicletas en función de las características de la población en un barrio o
por zonas determinadas. Las posibilidades que ofrece el dispositivo desarrollado no
son posibles de explorar actualmente a través del instrumento oficial utilizado por el
ministerio de Transporte, la “Encuesta Origen-Destino” (EOD), ya que esta, como lo
dice su nombre sólo registra el origen y el destino de cada viaje y no entrega
información sobre el contexto y desarrollo del viaje.
La estructura de este documento se desarrolla en tres capítulos. El primer
capítulo trata sobre el desarrollo de hardware del dispositivo. El segundo capítulo
describe el desarrollo del software necesario para interpretar y visualizar los datos
obtenidos con el dispositivo. Finalmente, el tercer capítulo presenta los resultados
obtenidos del testeo con los usuarios, los datos obtenidos y las conclusiones obtenidas
de esta investigación.
11
vii
ABSTRACT
This research persues the design and development of a device capable or
recording variables such as GPS coordinates, speed and acceleration from bikes. The
device has a built in WiFi chip allowing the device to upload content to a server using
pre-configured WiFi networks automatically without the intervention from the user.
The information mined from users who volunteered for using the device is
useful for city and transport planning. Since obtaining infomation from urban bikes is
an expensive process, this kind of devices seem to be an affordable and more efficient
solution compared to old fashioned surveys.
The investigation is composed by 3 chapters. The first chapter describes
the design and building process for the device, software and hardware components are
analized in this chapter. The second chapter explains the web and server architecture
which makes posible the communication between the device and the server. Finally,
the third and last chapter summarizes the results and data obtained from volunteers.
12
I. DESARROLLO DE HARDWARE
Durante la investigación se desarrollan dos tipos de prototipos. El primer
prototipo o prototipo alfa, se diseña con el fin de probar conceptos y definir cuáles
son los problemas a resolver en un prototipo funcional. El segundo dispositivo o
prototipo beta, es una iteración del primer dispositivo y tiene un carácter funcional,
por lo tanto, debe llevar a cabo la tarea de extraer datos y subirlos a la red, de forma
exitosa.
1.1 Prototipo Alfa
El prototipo alfa es un prototipo de prueba de concepto, lo que implica
que servirá para identificar errores, defectos e improvistos a mejorar en la próxima
iteración (beta). Se define como un prototipo alfa exitoso un dispositivo que sea
capaz de:
Extraer ubicación Georreferenciada del dispositivo
Almacenar la información en una memoria extraíble
Almacenar la información en formato georreferenciado (.TXT, .CSV, .GPX, etc)
De esta forma, es posible desde una etapa temprana obtener datos para:
Comenzar a desarrollar el software de visualización de datos
Analizar la calidad de los datos entregados
13
1.1.1 Elección de componentes
Para diseñar el dispositivo se elige una lista de componentes (GPS,
memoria, batería, etc) con tal de satisfacer los requerimientos del dispositivo. A
continuación, se presenta la metodología que fundamenta la elección de cada
componente.
1.1.1.1 Elección de módulo GPS
El dispositivo posee un sensor GPS que permite obtener información
georreferenciada del dispositivo asociado al tiempo de cada medición. Las variables
que se consideran al momento de elegir el módulo GPS son:
Lógica
Consumo Energético
Partida en frio
La lógica representa el nivel de voltaje al que opera el módulo. Existen 2
niveles de lógica dominantes en el campo de los sensores GPS. Por un lado está la
lógica de 5 volts y por el otro la de 3.3 volts. El microcontrolador debe ser
lógicamente compatible (electrónicamente hablando) con el módulo. Por ejemplo, si
se elige un módulo GPS de lógica 3.3V, entonces el microcontrolador debe
comunicarse con señales de lógica 3.3V. De lo contrario, la comunicación no se
efectuará de forma exitosa entre microcontrolador y módulo GPS.
El consumo energético indica cuál es la tasa de consumo de corriente del
módulo. Esta característica es importante si se quiere diseñar un dispositivo con una
larga autonomía energética ya que el módulo GPS es el componente con mayor
14
consumo energético del circuito representando cerca del 90% del consumo total del
dispositivo.
La partida en frio es el tiempo que demora en sincronizar el módulo GPS
con la red de satélites. En otras palabras, indica cuánto tiempo en promedio se debe
esperar desde que se energiza el módulo hasta que este entrega la primera
georreferencia. Es importante notar que la partida en frio considera que el módulo
GPS ha estado apagado por un tiempo mayor a 24 horas.
En la tabla 1.1 se detallan las características (obtenidas de la hoja de
datos del fabricante) de los módulos GPS considerados como candidatos. Los tres
módulos permiten trabajar con una lógica de 3.3V y poseen un tiempo de partida en
frio similar.
Módulo Comunicación Partida en frio Lógica Consumo
(navegando)
Quectel L80 Serial 32 segundos 3.3V – 5V 20 mA
EM406 Serial 38 segundos 3.3V – 5V 30 mA
EM506 Serial 30 segundos 3.3V – 5V 30 mA
Tabla 1.1: Comparación de módulos GPS
El módulo EM506 es una versión posterior al módulo EM406 (serie EM)
mostrando una mejora del tiempo de partida en frio en comparación a su antecesor.
Por otra parte, el módulo Quectel L80 posee un consumo energético 10mA menor que
los módulos serie EM. Este parámetro es crítico, ya que un menor consumo se traduce
en una mayor autonomía energética. Por lo tanto, se decide seleccionar el módulo
Quectel L80 como sensor GPS.
15
1.1.1.2 Elección de memoria
Se decide ocupar una memoria SD porque permite extraer limpiamente
los datos desde el dispositivo sin la necesidad de generar un mecanismo de extracción
adicional. Así, al momento de sacar la tarjeta de memoria desde el dispositivo se
extrae la totalidad de los datos. Por lo tanto, el desafío planteado es lograr comunicar
al microcontrolador con una tarjeta de memoria SD.
El tamaño de la memoria depende de cuantos datos se guardan en esta. A
su vez, la cantidad de datos es proporcional a la tasa de muestreo y el tiempo total que
dura el registro de datos (tiempo de muestreo).
Para estimar una tasa de muestreo aceptable, se averigua el tiempo de
muestreo de la aplicación móvil dominante en el sector del ciclismo urbano Strava. A
través de su sitio web, se indica que la aplicación móvil, realiza mediciones de
posición entre 3 y 4 segundos (“Strava.com”, 2016). Por otro lado, el módulo GPS
posee una tasa de muestreo de 5 segundos, aproximándose a lo realizado por Strava.
Para averiguar cuántos bytes de información genera cada medición, se
propone el siguiente formato:
Longitud(9), latitud(9), tiempo(8), fecha(10)
Por ejemplo
-33.12344,-70.59874,13:25:22,2015-10-11
De esta manera, si se consideran las comas separadoras, cada medición es
representada por una línea compuesta por un máximo de 39 bytes. Finalmente, para
un tiempo de muestreo arbitrario de 100 horas, cada dispositivo genera 2.742.187
16
bytes que es igual a 2.68 Megabytes (considerando una tasa de muestreo de 5
segundos). Este resultado en comparación a la tarjeta SD de menor capacidad
disponible (entre 16 MB y 32 MB) es irrelevante, por lo que la capacidad de la
memoria SD no es una preocupación para el desarrollo del prototipo alfa.
1.1.1.3 Elección de batería y misceláneos
La elección de batería se basa en la tendencia de la industria por ocupar
baterías de Litio-Polímero, la razón es su relación peso-energía (densidad energética)
con respecto a otras baterías, la facilidad con que se pueden recargar y precio. Es
posible encontrar este tipo de baterías con distintas capacidades de carga que van
desde los 10 mAh hasta los 6600 mAh y existen en el mercado chips (MCP73831 y
MAX1555) que se preocupan de cargar la batería externalizando esta función,
reduciendo costos y espacio en el circuito final.
Finalmente se agrega un componente Buzzer (zumbador o bocina) con el
fin de dar alarmas de sonido y dar a conocer el estado de la batería.
17
1.1.1.4 Elección de microcontrolador
Se ocupa una placa de desarrollo llamada Arduino Mini que se caracteriza
por su pequeño tamaño y bajo costo. Se programa mediante protocolo Serial gracias a
un bootloader que viene pre-instalado. Arduino Mini está basado en un
microcontrolador ATMega328, posee una CPU de 8 bits, 32 Kbytes de memoria
Flash, una EEPROM de 1024 bytes, 6 convertidores análogo-digital (ADC), 23
puertos GPIO, comunicación serial, SPI e I2C.
Figura 1.1: Vista superior de un Arduino Mini (Fuente arduino.com, 2015)
La CPU requiere un voltaje de alimentación de 3.3V. La placa de
desarrollo posee un consumo de 20 mA en promedio e incluye otros elementos como
un pulsador que va conectado directamente al pin de reset del microcontrolador,
LED’s y un regulador de voltaje.
18
Otro aspecto que hace al ATMega328 una buena elección como
microcontrolador es la cantidad de periféricos que posee, destacando protocolos de
comunicación SPI, I2C y Serial implementados en hardware. Lo anterior flexibiliza
la elección de distintos componentes y sensores en cuanto a la comunicación. Sin
embargo, el aspecto más importante es su bajo consumo y la habilidad de poder
implementar sleep cycles; periodos en que el microcontrolador se duerme,
consumiendo corrientes del orden de los µA.
19
1.1.2 Diagrama de bloques de hardware
El diagrama de bloques a continuación muestra cómo se coordinan los
componentes y sus relaciones. El diagrama de bloques del prototipo alfa posee un
microcontrolador como componente principal. El microcontrolador juega el papel de
coordinador entre el resto de los componentes. En la Figura 1.2 se observa que el
módulo GPS entrega información de su geo-posición al microcontrolador. Luego, el
microcontrolador envía la información a la tarjeta SD.
El LED y el Buzzer son administrados por el microcontrolador, actuando
como indicadores de estado del dispositivo (para el usuario).
Figura 1.2: Diagrama de bloques de bardware del prototipo alfa
Atmega328 GPS Memoria SD
Buzzer
LED
20
1.1.3 Diagrama de flujo de software en microcontrolador
El software programado en el microcontrolador es el conjunto de
instrucciones que se ejecutarán con el fin de cumplir el propósito del dispositivo.
Para el caso del prototipo alfa, el software debe ser capaz de identificar y coordinar
el accionar de todos los componentes con el fin de guardar la información obtenida
del GPS en la tarjeta de memoria.
La figura 1.3 muestra la arquitectura del software a través del diagrama
de flujo. Al comenzar el programa, el microprocesador recibe información desde el
módulo GPS en forma de Strings. Esta información puede incluir información
relevante sobre la localización como también no hacerlo, al caso positivo lo
llamaremos señal fija (fixed signal en inglés).
Si la señal no es fija, entonces no se hace nada y se espera el siguiente
String. Si el String posee señal fija, se decodifica el contenido y se crea una entrada
en la tarjeta SD. Esta entrada servirá como título de un archivo donde se guardará el
contenido del viaje. Cada archivo representa un viaje distinto.
Finalmente, cada String recibido desde el módulo GPS es decodificado y
almacenado en el archivo ya creado. Es importante aclarar que el módulo GPS
entrega un String cada 5 segundos por defecto.
21
Figura 1.3: Diagrama de flujo de software del prototipo alfa
Recibir señal
GPS
Decodificar
String
Crear un String
personalizado
La señal
es fija
Grabar String en archivo
.csv más reciente
Si
No
o
Inicio
Vuelve al
origen
Generar un nuevo
archivo .csv
Es el primer
String
Si No
22
1.1.4 Comunicación con módulo GPS
El módulo GPS Quectel L80 entrega información de cada medición en
dos frases definidas por la NMEA (National Marine Electronics Association). Las
frases son conocidos por las siglas GGA y RMC y a partir de ambas es posible
obtener longitud, latitud, fecha y hora.
La frase GGA posee la siguiente estructura:
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M
,,*47
123519. Indica la hora a la que se tomó la medición
4807.038, N. Indica la latitud
01131.000,E. Indica la longitud
1. Indica si la señal es fija (fixed signal). En caso contrario posee valor “0”
08. Indica el número de satélites disponibles
0.9. Indica la Dilución de Precisión (DOP)
545.4, M. Indica la altura con respecto al mar
*47. Representa la suma de verificación (checksum)
Por otro lado, La frase RMC posee la siguiente estructura:
$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003
.1,W*6A
123519. Indica la hora de la medición en formato HHMMSS
A. Indica el estado del dispositivo GPS donde A representa un estado activo y V
dormido
23
4807.038,N. Indica la latitud
01131.000,E. Indica la longitud
022.4. Indica la velocidad en nudos
084.4. Representa el ángulo de rastreo o curso de navegación
230394. Representa la fecha en formato DDMMAA
003.1, W. Representa la desviación con respecto al Norte magnético
*6A. Representa la suma de verificación
La interfaz de desarrollo de Arduino posee una librería dedicada a los
módulos GPS que están basados en el chip MT3339 como es el caso del módulo
Quectel L80. La librería desarrollada por la empresa Adafruit permite crear una
comunicación con el módulo GPS a través de cualquier pin digital facilitando una
comunicación serial por Software liberando los puertos seriales por hardware del
microcontrolador.
La librería GPS permite asignar las variables provenientes desde el GPS
a variables definidas por el usuario sin la necesidad de diseccionar la frase GGA ni
RMC. Por ejemplo, para asignar la longitud a una variable sólo basta con definir en
el código la instrucción:
float latitud = GPS.latitude; //Lat posee decimales
24
La librería permite enviar instrucciones al módulo GPS mediante el
comando:
GPS.sendCommand(parámetro);
Donde parámetro es la instrucción que se envía al módulo GPS. La
librería posee instrucciones relacionadas al tiempo de muestreo, sleep mode, reinicio,
y la posibilidad de elegir entre la antena interna o externa.
25
1.1.5 Comunicación con memoria SD
Los datos obtenidos por el modulo GPS serán depositados en la tarjeta
SD. Por lo tanto, el microcontrolador debe establecer una comunicación con la
tarjeta SD cada vez que recibe nueva información desde el módulo GPS.
La tarjeta SD se comunica mediante el protocolo SPI, del inglés Serial
Peripheral Interface, requiriendo la presencia de 4 pines.
Los pines son:
MISO (Master Input Slave Output): Entrada por donde se reciben los datos
provenientes del dispositivo maestro (microcontrolador)
MOSI (Master Output Input Slave): Salida por donde se envían los datos hacia el
dispositivo maestro
CLK: Pulso de reloj que fija la velocidad a la que se realizará la comunicación
CS: Define si la memoria se usará o no. Cuando está en estado alto (uno lógico)
la memoria está lista para recibir instrucciones, en caso contrario (cero lógico) la
memoria no recibirá instrucciones.
Una de las ventajas de la comunicación SPI por sobre otros protocolos
(Serial, I2C) es su velocidad de comunicación que puede llegar hasta 10
Mbits/segundo permitiendo hacer lecturas y escrituras de memoria de forma rápida.
26
1.1.6 Redacción de código del microcontrolador
El código se redacta con el fin de entregar al microcontrolador un listado
de instrucciones a seguir, persiguiendo como fin último, la ejecución de una tarea.
El código está escrito en el lenguaje Arduino y se divide en dos
estructuras. La primera llamada setup, es la estructura del código donde se definen los
periféricos a usar (puertos, comunicación, periféricos, etc). Esta estructura se ejecuta
al arrancar el microcontrolador una sola vez. La segunda estructura, llamada loop, es
una estructura que va después del setup y que define el actuar del microcontrolador. A
diferencia del setup, la estructura loop funciona de forma iterativa mientras el
microcontrolador esté operativo.
Adicionalmente, en caso de definir variables globales o librerías, estas se
definen al comienzo del código y fuera de ambas estructuras. De esta forma, se redacta
el código como:
#include <SdFat.h> // Librería para memoria SD
#include <SPI.h> // Librería comunicación SPI
#include <Adafruit_GPS.h> // Librería para módulo GPS
SoftwareSerial mySerial(8, 9); // Inicia puerto serial en pin 8 y 9
Adafruit_GPS GPS(&mySerial); // Asigna al puerto serial como GPS
uint32_t timer = millis(); // Inicia un timer (tasa de muestreo)
const uint8_t chipSelect = 10; // Pin CS de la tarjeta SD
SdFat sd; // Va riables para la librería mem SD
SdFile file;
boolean inicio = true; // Identifica cuando se recibe el 1° String
char filename[29]; // Arreglo de char donde va el nombre del .CSV
27
Luego, se define el setup, iniciando la comunicación Serial, el módulo
GPS y la tarjeta SD
void setup(void) {
ADCSRA = 0; // Apaga puertos ADC para bajar consumo
Serial.begin(9600); // Inicia la consola (debugging)
GPS.begin(9600); // Inicia la comunicación con el GPS
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // frases del GPS
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // tasa refresco
GPS.sendCommand(PGCMD_ANTENNA); // Ocupa la antena interna
pinMode(5, OUTPUT); // Se inicializa el pin del buzzer
pinMode(10, OUTPUT); // Se inicializa el pin CS de la tarj SD
digitalWrite(10, HIGH); // Se activa la tarjeta SD
digitalWrite(5, LOW); // Se deja en estado bajo el buzzer
if (!sd.begin(chipSelect)) { // Se inicializa la tarjeta SD
sd.initErrorHalt(); // Si hay error se avisa por consola
}
else cancion_on(); // Si todo funciona bien se emite sonido
}
Dentro del loop se recibe el String del módulo GPS y se revisa que
posea señal fija. En caso afirmativo se crea un archivo en la tarjeta SD y se comienza
a llenar con el resto de los Strings entregados por el módulo GPS.
void loop(void) {
// Recibe cada byte del módulo GPS
char c = GPS.read();
// Si hay una nueva frase entonces esta se disecciona
if (GPS.newNMEAreceived()) {
if (!GPS.parse(GPS.lastNMEA()))
return;
}
28
// Se reinicia el timer
if (timer > millis()) timer = millis();
// En caso de que el timer sea mayor a 5 segundos se inicia una
// subrutina
if (millis() - timer > 5000){
timer = millis();
if (GPS.fix) {
// Si la frase posee signal fixed entonces se inicia una segunda
// subsubrutina
if (inicio){
// Como primera instancia se procede a generar un título para el
// archivo
int dia = GPS.day;
int mes = GPS.month;
int year = GPS.year+ 2000;
int hora = GPS.hour;
int minuto = GPS.minute;
int segundo = GPS.seconds;
char dia_c[2];
char mes_c[2];
char year_c[4];
char hou_c[2];
char min_c[2];
char seg_c[2];
String str1 = String(dia, DEC);
String str2 = String(mes, DEC);
String str3 = String(year, DEC);
String str4 = String(hora, DEC);
String str5 = String(minuto, DEC);
String str6 = String(segundo, DEC);
String str7 = str3 + str2 + str1 + "-" + str4 +
str5 + str6 + "-Recorrido.csv";
str7.toCharArray(filename, 29);
29
Serial.println(filename);
// Se genera un archivo con un título que lleva un nombre del tipo
// YYYYMMDD-HHMMSS-Recorrido.csv
file.open(filename, O_CREAT | O_WRITE | O_APPEND);
// Se escribe la primera línea del archivo anteriormente creado que
sirve // como header para los datos que luego se escribirán
file.println("latitud,longitud,tiempo,altitud,fecha
");
file.close();
// Se cambia el estado del boolean inicio para así nunca más entrar
// en esta subsubrutina
inicio = false;
}
file.open(filename, O_CREAT | O_WRITE | O_APPEND);
String dataString = GPS.lastNMEA();
String str8 = String(GPS.latitudeDegrees, 4);
String str9 = String(GPS.longitudeDegrees, 4);
String str10 = String(GPS.hour, DEC);
String str11 = String(GPS.minute, DEC);
String str12 = String(GPS.seconds, DEC);
String str14 = String(GPS.altitude, 2);
String str15 = String(GPS.day, DEC);
String str16 = String(GPS.month, DEC);
String str17 = String(GPS.year, DEC);
String str13 = str8 + "," + str9 + ",\"" + str10 + ":" +
str11 + ":" + str12 + "\"," + str14 + ","
+ str17 + "-" + str16 + "-" + str15;
Serial.println(str13);
// Se escribe en el archivo el valor de la línea que posee un
estructura // de la forma
// latitud,longitud,tiempo,fecha
file.println(str13);
file.close();
30
}
}
}
}
La parte final del código incluye una función función que es invocada
desde el loop con el fin de ahorrar líneas de código. La función se llama
“cancion_on” y permite generar un sonido del tipo beep que se repite 3 veces.
void cancion_on(){
// Se inicializa una variable “a”
int a = 0;
// Se mantiene 200 ciclos el pin 5 prendido y 200 ciclos apagado
while(a < 200){
digitalWrite(5, HIGH);
delayMicroseconds(200);
digitalWrite(5, LOW);
delayMicroseconds(200);
a++;
}
a = 0;
delay(100);
// Se mantiene 200 ciclos el pin 5 prendido y 200 ciclos apagado
while(a < 200){
digitalWrite(5, HIGH);
delayMicroseconds(200);
digitalWrite(5, LOW);
delayMicroseconds(200);
a++;
}
a = 0;
delay(100);
31
// Se mantiene 200 ciclos el pin 5 prendido y 200 ciclos apagado
while(a < 200){
digitalWrite(5, HIGH);
delayMicroseconds(200);
digitalWrite(5, LOW);
delayMicroseconds(200);
a++;
}
}
32
1.1.7 Construcción de prototipo alfa
La placa Arduino mini posee perforaciones en cada pin permitiendo el
cableado directo desde la placa hasta los distintos componentes.
Como case se ocupa una caja de mentas metálica como la que se muestra
en la Figura 1.4, otorgando protección al circuito ante golpes y movimientos bruscos.
Figura 1.4: Caja de mentas Altoids
El primer paso, es realizar una perforación de 5 mm de diámetro en la
cara de la caja que muestra la Figura 1.5. En esta perforación va alojado el interruptor
que da contacto al dispositivo.
33
Figura 1.5: Perforación para interruptor
Se realiza una segunda perforación en la caja (parte trasera) para fijar una
abrazadera plástica de 1.25 cm de radio que sirve como contacto con el fierro del
asiento de la bicicleta. Luego, con un perno de 1/8 de pulgada (cabeza) se cruza la
caja y la abrazadera, fijando por el lado interno una tuerca (Figura 1.6). El excedente
del perno se corta con un alicate.
Figura 1.6: Montura de Abrazadera
34
La batería se coloca en la base para optimizar el espacio y la distribución
del resto de los componentes dentro del case (ver Figura 1.7)
Figura 1.7: Posición de la batería
Luego, se introduce el Arduino Mini en el centro del dispositivo
adhiriéndolo a la batería con cinta doble faz tal como se muestra en la Figura 1.8
Figura 1.8: Posición de Arduino
35
El módulo GPS se coloca por fuera de la caja para asegurar una mejor
recepción evitando pérdidas ante una posible aislación electromagnética por parte de
la caja metálica. Se coloca también el compartimiento de la tarjeta SD por fuera para
facilitar la extracción de la tarjeta. Se recorta un área de 2.1 cm x 1.4 cm de mica de
2mm (espesor). Luego se marcan los pines de los módulos GPS y ranura de memoria
SD sobre la mica con un plumón permanente. Con un taladro de banco o herramienta
similar se perforan las marcas que corresponden a los pins sobre la mica
Se adhiere el módulo GPS y la ranura de tarjeta SD a la mica con un
pegamento de contacto y se realiza el cableado desde los componentes hacia el
microcontrolador a través de las perforaciones (Figura 1.9).
Figura 1.9: Cableado de componentes
36
Se agrega el Buzzer en la parte externa del case y el interruptor se fija en
la perforación hecha en un principio. Finalmente, se presiona la mica para que entre
en la caja (Figura 1.10).
Figura 1.10: Dispositivo Alfa ensamblado
37
1.1.8 Testeo con usuarios del prototipo alfa
El propósito del testeo es encontrar problemas o defectos observados en el
dispositivo alfa para mejorarlos en una versión posterior (dispositivo beta).
Para realizar el testeo se entrega el dispositivo a 64 usuarios durante un
periodo de una semana de uso para cada uno. Cada usuario, al terminar un recorrido,
sube los datos a la plataforma web. Los testeos comienzan el día 30 de Marzo del año
2015 y concluye el día 2 de Junio del mismo año. Para realizar el testeo se construyen
7 unidades del mismo dispositivo.
Un análisis posterior al testeo revela que una fuente de contaminación de
datos se debe a que el usuario olvida apagar el dispositivo al terminar el viaje.
Mientras el dispositivo permanece activo, sigue tomando datos que no pertenecen a
ninguna ruta. Además, se consume energía de igual manera que si se estuviese
registrando una ruta real. Se plantea como mejora, implementar una función que
discrimine de forma automática si el dispositivo se encuentra en viaje o reposo,
eliminando la intervención del usuario.
Desde el punto de vista del usuario, subir los datos desde las de tarjetas de
memoria es un proceso tedioso (en comparación a alternativas en tiempo real) si se
considera que cada tarjeta debe ser retirada manualmente desde el dispositivo para
luego ser vaciada en la base de datos a través de Internet. Se plantea como mejora,
integrar al dispositivo la capacidad de conectarse a redes WiFi automatizando la
subida de datos.
38
1.2 Prototipo Beta
El prototipo beta es una versión funcional (no definitiva) de un posible
producto final. Se define como un prototipo beta exitoso para esta investigación un
dispositivo que sea capaz de:
Extraer ubicación Georreferenciada del dispositivo
Almacenar la información en una memoria interna
Implementar funciones de apagado/prendido automáticamente
Subir información a la base de datos a través de redes WiFi de forma
automatizada
1.2.1 Elección de componentes
Para diseñar el dispositivo beta, además de los componentes ocupados en
el dispositivo alfa, se necesitan componentes adicionales que permiten mejorar y
resolver los defectos encontrados en la versión alfa. Componentes como
acelerómetros y módulos WiFi permiten que el dispositivo registre las rutas sin la
intervención del usuario (ni la presencia de botones) y subir los datos a la red cada
vez una conexión WiFi se encuentra disponible.
39
1.2.1.1 Elección de acelerómetro
Para implementar funciones de apagado/prendido, el dispositivo debe
discriminar cuándo se está de viaje y cuándo se está en reposo. Se intenta resolver el
problema con el uso de un acelerómetro de 3 ejes.
El acelerómetro es un dispositivo que permite la medición de
aceleraciones en el marco de referencia definido por el dispositivo. Existen diversos
tipos diferenciándose en su precisión, cantidad de ejes, comunicación, entre otros.
Se elige el acelerómetro ADXL335, un modelo cuya comunicación con el
microcontrolador es unidireccional, entregando los valores de aceleración de cada eje
de forma análoga. El consumo energético es de 40 uA y su resolución es de 10 bits
considerando aceleraciones máximas de ±3g.
1.2.1.2 Elección de módulo WiFi
Para agregar al dispositivo la capacidad de conectarse a redes WiFi y
comunicarse a través de Internet se escoge el chip ESP8266, principalmente por su
bajo consumo energético cuyo detalle se muestra en la tabla 1.2. Adicionalmente,
este chip cuenta con la capacidad de hibernar, reduciendo su consumo a 530 uA.
Componente Comunicación Consumo
Transmitiendo
Consumo Recibiendo Alcance
ESP8266 Serial 130 mA 60 mA 100 m
Tabla 1.2: Consumo energético ESP8266
40
1.2.1.3 Elección de memoria
Como memoria interna se escoge una memoria dataflash AT45DB161B
de 2 Megabytes que posee un consumo menor a 1mA en modo escritura y 600 uA
en modo Lectura. El cambio de memoria permite reducir el costo energético y el
tamaño del layout final de la Placa de Circuito Impresos o Printed Circuit Board
(PCB) ya que el adaptador de memoria SD posee un área de 300 mm cuadrados
mientras que la memoria AT45DB161DB posee 27 mm cuadrados de área.
1.2.1.4 Elección de batería
El prototipo usa una batería de Iones de Litio con 1200 mAh de
capacidad.
Para cargar la batería se usa el chip MCP73831 que permite cargar la
batería mediante una conexión USB o cualquier fuente de alimentación capaz de
proveer una corriente superior a 500 mA y 3.3 V.
1.2.1.5 Elección de microcontrolador
Se opta por incluir dos microcontroladores (Atmega328) idénticos como
núcleo de procesamiento para el dispositivo beta. La razón se basa en la búsqueda de
paralelismo entre tareas que se ejecutan al mismo tiempo como la lectura del
acelerómetro y la búsqueda de redes WiFi. Con esta configuración se distribuye el
código entre ambos dispositivos, aprovechando la memoria RAM y Flash de ambos
41
microcontroladores. En general, se hablará de un microcontrolador maestro, que
actuará como un coordinador general y un microcontrolador esclavo que ejecutará
tareas en segundo plano informando al maestro.
1.2.2 Diagrama de bloques de hardware
En comparación al prototipo alfa, el nuevo diagrama de bloques se
diferencia en la inclusión de un microcontrolador extra. Se jerarquiza cada
microcontrolador diferenciándose en un microcontrolador maestro y un
microcontrolador esclavo. El microcontrolador maestro, de jerarquía superior,
domina los componentes de memoria, localización, detección de viajes/reposo y
microcontrolador esclavo. Por otro lado, el microcontrolador esclavo está encargado
exclusivamente de las funciones que tienen relación con administración de redes
WiFi y comunicación con el servidor.
Atmega328
Maestro GPS
AT45DB161B
(Memoria)
ESP8266 Atmega328
Esclavo
Acelerómetro
Figura 1.11: Diagrama de bloques de hardware del prototipo beta
42
1.2.3 Diagrama de flujo de microcontrolador maestro
El diagrama de flujo del microcontrolador maestro se preocupa de
capturar información desde el módulo GPS, revisar si el dispositivo se
mueve/descansa y gestionar a través del microcontrolador esclavo las tareas
relacionadas a la subida de datos a través de redes WiFi.
Al iniciar el programa se revisa constantemente la existencia de
movimiento detectable a partir del acelerómetro. En caso afirmativo, se procede a
tomar la posición del GPS para luego almacenarla en la memoria interna.
La comunicación con el módulo WiFi es ejecutada por el
microcontrolador esclavo. Sin embargo, es el microcontrolador maestro el que
ordena al esclavo establecer dicha comunicación. Una vez que ya no existe
movimiento detectable, el microcontrolador maestro ordena al esclavo buscar la
existencia de una red WiFi. Si la red es encontrada, se ordena establecer una
conexión con el servidor. Si la conexión con el servidor es exitosa, se procede a
enviar la información almacenada en la memoria. Una vez que toda la información
ha sido enviada de forma exitosa, se procede a enviar las instrucciones que permiten
dormir tanto al esclavo como al módulo WiFi con el fin de ahorrar energía.
En caso de que la búsqueda de redes WiFi no sea exitosa, se procederá a
dormir inmediatamente al esclavo junto al microcontrolador WiFi.
43
Decodificar
String
Existe
movimiento
Si
Inicio
Existe
Señal GPS fija
Existe
Red WiFi
Conectar a la
red
Conectar al
servidor
Se pudo
Conectar
Enviar
información
No
Si
Si
No
No
El
sistema duerme
Despertar
Si
No
Esperar 5
segundos
No
Guardar String
en la memoria Dormir
Si
Figura 1.12: Diagrama de flujo de software del prototipo beta
44
1.2.4 Comunicación con acelerómetro
El acelerómetro cumple la función de dar aviso cuando el dispositivo se
encuentra en movimiento.
La lectura del acelerómetro se hace a través de tres puertos ADC (un
puerto para cada eje inercial) del microcontrolador maestro. Los valores de las
aceleraciones medidas por el módulo son representados en formas de ondas análogas
con 10 bits de resolución.
1.2.4.1 Detección de movimiento
En reposo, el acelerómetro registra un valor constante llamado offset.
Las perturbaciones mecánicas a las que se ve expuesto se traducen en desviaciones
alrededor del offset proporcionales a la aceleración que experimenta cada eje.
Con el fin de detectar perturbaciones se propone el filtro de la Figura
1.13, entregando como respuesta un pulso cuando existe movimiento.
45
Figura 1.13: Filtro detector de movimiento
El Filtro deriva las entradas provenientes desde el mismo acelerómetro.
Una vez que las entradas son derivadas se obtiene el módulo de la derivada de cada
componente resultando una cifra que varía de forma positiva. Finalmente esta cifra
se expone a un filtro umbral (Threshold) que según sea la referencia, entrega un
pulso cuando la bicicleta se encuentre en movimiento.
Módulo Filtro
Referencia
Respuesta
46
Para obtener el valor del umbral, se genera una prueba donde se obtiene
el módulo de la aceleración a partir del acelerómetro. En la Figura 1.14 se marca con
una línea roja el momento en que la bicicleta comienza a moverse y con una línea
verde cuando la bicicleta se encuentra detenida.
Figura 1.14: Módulo de la aceleración
Luego, se realiza un histograma sobre la curva que representa “la bicicleta
moviéndose” (Figura 1.15) y otro histograma sobre la curva que representa “la
bicicleta estática” (Figura 1.16).
0
20
40
60
80
100
120
140
160
180
200
47
Figura 1.15: Histograma módulo aceleración – bicicleta en movimiento
Figura 1.16: Histograma módulo aceleración – bicicleta estática
0%
2%
4%
6%
8%
10%
12%
0%
10%
20%
30%
40%
50%
60%
48
A partir del análisis de ambos histogramas, se observa que para el caso
de la bicicleta en movimiento, el 74% de las medidas toma un valor entre 21 o
superior. Mientras que para el caso de la bicicleta detenida, el 85% de las medidas
corresponde a un valor ente 0 y 10. A partir del análisis anterior, se elige como
referencia el valor 21.
1.2.5 Comunicación con módulo WiFi
La comunicación con el módulo WiFi se realiza mediante el protocolo
Serial. Este protocolo hace uso de dos pines (receptor y transmisor) cuya velocidad
de transferencia es fijada previamente tanto en el módulo WiFi como en el
microcontrolador. En este caso se fijó 9600 bits/segundo como velocidad de
transferencia.
El módulo WiFi posee un listado de instrucciones disponibles que son
ejecutadas mediante comandos definidos en la hoja de datos del fabricante (ver
anexo A; Instrucciones ESP8266).
1.2.6 Comunicación con memoria dataflash
La comunicación entre el microcontrolador y la memoria se realiza
mediante el protocolo SPI. La memoria posee una capacidad máxima de 16 Mbits (2
Mbytes), conformándose por 4096 páginas de 512 bytes cada una. Cada vez que se
quiere leer/escribir, el microcontrolador debe enviar a la memoria:
49
Instrucción: Leer/Escribir, según sea el caso
Página: La posición donde se comenzará a leer o escribir
Pulso reiterativo: Por cada pulso enviado, la memoria salta al siguiente byte
de forma automática
La memoria no permite leer/escribir sobre un byte en específico. Sólo se
puede dirigir a una de las 4096 páginas disponibles debido a la forma en cómo la
memoria opera (diseño).
1.2.7 Comunicación entre microcontroladores
La comunicación entre el microcontrolador maestro y esclavo se realiza
mediante el protocolo Serial. Previamente, se define en el microcontrolador esclavo
el set de instrucciones necesarias para gestionar redes WiFi y subir datos a la red.
Estas instrucciones son accionadas por el microcontrolador maestro enviando
distintos mensajes al esclavo.
1.2.8 Gestión de redes y entrega de datos
El dispositivo funciona como Punto de Acceso (AP) y/o Cliente.
La función del modo AP es generar una interfaz que le permita al usuario
ingresar los datos de su red WiFi local y entregar al dispositivo una red donde pueda
descargar sus datos. Este paso se realiza sólo una vez.
50
De la misma forma, el dispositivo posee un modo cliente que le permite
conectarse a redes ya configuradas. Así es posible subir los datos a Internet cada vez
que una red conocida esté dentro del alcance del dispositivo.
Al momento de subir los datos al servidor existe una serie de procesos
que se deben comprobar antes de comenzar la entrega:
Verificar la existencia de red
Verificar la existencia de Internet en la red
Verificar el estado del servidor (apagado/activo)
Crear una conexión TCP con el servidor
Una vez creada la conexión TCP con la aplicación, se comienza la entrega
de datos.
1.2.8.1 Diagrama de flujo del microcontrolador esclavo
El microcontrolador esclavo ejecuta las tareas relacionadas a la
configuración de la red, conexión y subida de datos al servidor. Para lo anterior, el
microcontrolador esclavo se comunica serialmente con el chip WiFi.
El módulo WiFi posee la capacidad de funcionar como Access Point y
como cliente. Esta dualidad permite que el módulo en conjunto con el
microcontrolador esclavo actúen como un servidor Web, lo que es aprovechado por
el dispositivo beta como un método de comunicación con el usuario para ingresar las
credenciales de la red WiFi por donde el dispositivo beta se conectará. De esta
manera, el microcontrolador esclavo almacena en su memoria las credenciales de la
red ingresadas por el usuario.
51
Por otro lado, el modo cliente del módulo WiFi permite al
microcontrolador esclavo conectarse a las redes disponibles que coincidan con las
credenciales almacenadas y posteriormente subir la información al servidor. Es
importante notar que tanto conectarse a una red como enviar un mensaje a un
servidor no es una tarea sencilla (en comparación a prender y/o apagar un LED). Al
tratarse de un servicio web, muchas veces el correcto funcionamiento de la
comunicación entre un cliente (como el dispositivo beta) y el servidor depende de
factores externos al dispositivo como lo es la estabilidad de la conexión, la
disponibilidad del servidor, ancho de banda, etc. Por lo tanto, el microcontrolador
esclavo debe garantizar que la información sea entregada de forma satisfactoria y en
caso contrario avisar al microcontrolador maestro con el fin de reintentarlo más tarde
bajo distintas condiciones.
El diagrama de la Figura 1.17 muestra el algoritmo implementado en el
microcontrolador esclavo. En un principio y de forma única se inicializa el modo AP
del módulo WiFi creando una red abierta llamada “Red A”, a partir de este momento
se inicia un primer bucle que dura 60 segundos. Durante este bucle pueden ocurrir
dos casos. El primer caso se asocia a la detección de una solicitud HTML por parte
de un cliente. El cliente es el mismo usuario que se conecta a la red A y hace una
solicitud del tipo GET al dispositivo. Una vez enviada la solicitud, se envía un
formulario HTML que el usuario debe completar con los datos de su red WiFi local.
Después de recibir el formulario se extraen las credenciales y se guardan en la
memoria interna (no volátil) del microcontrolador esclavo (EEPROM). El segundo
caso del bucle ocurre cuando se cumplen los 60 segundos sin recibir una solicitud y
este expira.
Una vez que el bucle expira independiente de cuál sea el caso, se revisa
la existencia de contenido en la memoria dataflash. Si la memoria dataflash se
encuentra vacía, se procede a dormir el módulo WiFi. Por el contrario, si existe
52
contenido entonces se inicia un segundo bucle que de forma iterativa prueba la
existencia de conexiones WiFi probando las credenciales que se encuentran
guardadas en la EEPROM. Si ninguna red es exitosa, se rompe el bucle y se procede
a dormir el módulo WiFi. En cambio, si se logra conectar a una red se rompe el
bucle y se intenta realizar una conexión TCP con el servidor. Si la conexión con el
servidor falla se vuelve al segundo bucle y se siguen probando credenciales desde el
último intento. No obstante, si la conexión TCP es exitosa, se envía al servidor la
dirección MAC correspondiente al módulo WiFi. Después, se procede a extraer la
información de la memoria dataflash para enviarla al servidor. Una vez que se envía
la totalidad de la memoria, se cierra la conexión TCP, durmiendo el módulo WiFi y
microcontrolador esclavo.
Finalmente, en caso de que el microcontrolador maestro lo ordene, se
vuelve a la rutina de revisar la memoria dataflash con el fin de enviar su contenido al
servidor.
53
Inicio
Enviar script
HTML
Existe solicitud
HTML del cliente
Han pasado 60
segundos
Decodificar
variables
Recibió
Formulario
Guarda valores en memoria
Interna
Iniciar Timer, AP y
red “Red A”
La memoria
Dataflash posee
contenido
Si
No
No Si
No
Si
Si
Esperar
solicitud
HTML
Enviar MAC
Address
No
Esperar
formulario
No
Si
Probar
Conexión “C”
Int C = 0
Es Conexión C
Exitosa
Conectar al
Servidor
Conexión TCP
Exitosa
Pull-Push
Dataflash
Vaciar
Dataflash
Eliminar
Conexión
Dormir Módulo
Orden del Microcontrolador
Maestro
Si
Si
C = C +1
Existen
Conexiones
disponibles
No
No
Figura 1.17: Diagrama de flujo de gestión de redes y entrega de datos
54
1.2.8.2 Modo AP y configuración de redes
Con el fin de permitir al usuario enlazar cuantas redes él desee, se hace
uso del modo Punto de Acceso (AP) del módulo WiFi. De esta manera, el módulo
WiFi crea una red local a la que el usuario accede mediante su computador personal
o Smartphone para ingresar las credenciales de su red personal.
En primer lugar, se inicializa la comunicación serial entre el
microcontrolador esclavo y el módulo WiFi
ESP.begin(9600);
Luego, se configura el módulo WiFi en modo Punto de Acceso
ESP.println("AT+CWMODE=2")
Se crea una red abierta (sin autentificación) llamada “Red A”
ESP.println("AT+CWSAP=\"Red A\",\"ABC1234567\",11,0")
El comando anterior muestra cuatro valores. El primero es el nombre de la red (Red
A), el segundo valor es una password (obligatoria), el tercer valor es el canal de
frecuencia en que se transmite y el cuarto valor indica la autentificación de la red.
Después, se configura al módulo WiFi como servidor web
ESP.println("AT+CIPSERVER=1,80")
Por comodidad y orden dentro del código se define un método
setup_ESP que contiene los comandos necesarios para inicializar el módulo en
modo Punto de Acceso y servidor web.
55
void setup_ESP(){
ESP.println("AT+CWMODE=2"); delay(50);
ESP.println("AT+CWSAP=\"Red A\",\"ABC1234567\",11,0"); delay(50);
ESP.println("AT+CIPSERVER=1,80");
// Se hace una espera de 50 milisegundos para darle al módulo WiFi
// tiempo de ejecutar la instrucción requerida.
delay(50);
}
Una vez que el usuario se conecta a “Red A”, haciendo uso de su
explorador de Internet, debe hacer una solicitud (GET) a la dirección
http://192.168.4.1. Por su parte, el módulo WiFi recibirá la solicitud y la entregará al
microcontrolador esclavo
+IPD,0,255:GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0;
rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 192.168.4.88
Connection: Keep-Alive
Para gatillar un evento a partir de la solicitud se implementa el siguiente
trozo de código. Permitiendo detectar la presencia de la solicitud GET y enviar un
mensaje al cliente
56
// Si el char array es de la forma “+XXXXXXXXX:GET”
// entonces envio mensaje HTML al cliente
if (buffer_ESP[0]=='+' & buffer_ESP[10] ==':' & buffer_ESP[11]=='G'
& buffer_ESP[12]=='E' & buffer_ESP[13]=='T'){
int cliente = buffer_ESP[5] - 48;
delay(1000);
envio(cliente, html1);
envio(cliente, html2);
envio(cliente, html3);
envio(cliente, html4);
envio(cliente, html5);
envio(cliente, html6);
envio(cliente, html7);
}
De la misma forma, se define el método envio
void envio(int canal, String frase){
int largo = frase.length();
ESP.println("AT+CIPSEND=" + String(canal) + "," + String(largo));
delay(50);
ESP.println(frase);
delay(300);
}
El método envio define a qué cliente se le envía el mensaje, el largo del mensaje y
el contenido del mismo.
El mensaje se divide en 7 líneas (html1, html2, etc) debido a una
limitación impuesta por el módulo ESP8266 permitiendo enviar 50 bytes por línea
como máximo. Por lo tanto, el mensaje se distribuye de la siguiente forma
57
const String html1 = "<html><body>";
const String html2 = "Rubilink!<br><br>";
const String html3 = "Ingresa el nombre de tu Red y la Password<br><br>";
const String html4 = "<form action=\"demo_form.asp\" method=\"get\">";
const String html5 = "Red :<input type=\"text\" name=\"SSID\"><br><br>";
const String html6 = "Pass:<input type=\"text\" name=\"Pass\"><br><br>";
const String html7 = "<input type=\"submit\" value=\"Conectar\">";
const String htm18 = "</form></body></html>";
El mensaje representa un formulario HTML de 2 campos (SSID y
Password) que el usuario debe completar y enviar haciendo click en “Conectar”. Tal
como se muestra en la Figura 1.18
Figura 1.18: Formulario HTML
58
Al enviar el formulario, el módulo WiFi recibe como respuesta una URL
que contiene las credenciales de la red (azul) ingresadas por el usuario
+IPD,0,255:GET /demo_form.aspx?SSID=nombre_de_red&Pass=clavedelared
Luego, es posible extraer los campos de interés mediante el siguiente
snippet
// Si se encuentra la combinación “SSID=”
// en el char array(buffer_ESP) Entonces extrae todo lo que esté
// entre el carácter “=” y el carácter “&”
// lo estraido se guarda en forma de String en la variable “ssid”
if (buffer_ESP[0]=='S' & buffer_ESP[1] =='S' & buffer_ESP[2]=='I' &
buffer_ESP[3]=='D' & buffer_ESP[4]=='='){
for(int z=4 ; z<29 ; z++){
if(buffer_ESP[z] == '&'){
ssid_end = z;
ssid = String(buffer_ESP).substring(5,ssid_end);
break;
}
}
}
// Si se encuentra la combinación “Pass=” en el char array
// Entonces extrae todo lo que esté entre
// el carácter “=” y el carácter “ ”
// lo estraído se guarda en forma de String en la variable “pass”
if (buffer_ESP[0]=='P' & buffer_ESP[1] =='a' & buffer_ESP[2]=='s' &
buffer_ESP[3]=='s' & buffer_ESP[4]=='='){
for(int z=4 ; z<29 ; z++){
if(buffer_ESP[z] == ' '){
pass_end = z;
pass = String(buffer_ESP).substring(5,pass_end);
59
// Una vez que se obtiene la ssid y la pass se procede a
// crear los arreglos de 32 bytes donde se almacenan las
// credenciales
char pass_array[32];
char ssid_array[32];
ssid.toCharArray(ssid_array, ssid.length() + 1);
pass.toCharArray(pass_array, pass.length() + 1);
int index_0 = EEPROM.read(0) - 48;
// Se guardan los arreglos ssid y pass en la EEPROM del
// microcontrolador
for(int i = 1; i < 1 + ssid.length(); i++){
EEPROM.write(i + index_0*64, ssid_array[i-1]);
delay(50);
}
for(int i = 34; i< 34 + pass.length(); i++){
EEPROM.write(i + index_0*64, pass_array[i-34]);
delay(50);
}
// El primer byte de la EEPROM indica la cantidad de credenciales
// almacenadas. Al guardar las nuevas credenciales, este byte se
// incrementa en un bit
aumentar_index_eeprom();
break;
}}}
60
Adicionalmente, el código utiliza el método llamado
aumentar_index_eeprom que aumenta un contador interno dentro de la
EEPROM del microcontrolador esclavo para llevar la cuenta de cuantas credenciales
de redes han sido ingresadas. El contador posee un byte de información (256
posibilidades) y considera que cada “ssid” y “pass” posee un largo fijo de 32 bytes
cada uno. Esto es suficiente ya que la extensión máxima de una ssid corresponde a
32 caracteres mientras que la password requiere de 8 caracteres si se trata de una red
WEP o 10 caracteres si se trata de una red WPA-PSK (“Telecommunications and
information Exchange between systems – Local and metropolitan área networks”,
IEEE Standard for Information technology, 2007, p. 101).
La EEPROM posee una capacidad de 1024 bytes dando la posibilidad de
almacenar los datos de 16 redes distintas. En la Figura 1.19 se grafica como se
disponen los 1024 bytes de la EEPROM con el fin de guardar las credenciales. Es
importante notar que la última palabra (corresponde a un String pass) posee 31 bytes
de largo ya que se designó el primer byte como contador.
Figura 1.19: Distribución de la EEPROM microcontrolador esclavo
61
1.2.8.3 Modo cliente y detección de redes
El módulo WiFi permite funcionar como cliente, conectándose a redes
WiFi indicando las credenciales y haciendo uso del siguiente comando:
ESP.println("AT+CWJAP= SSID,PASS”);
Con el fin de conectarse al menos a una red, es necesario probar con
todas las redes conocidas hasta que se logre una conexión exitosa. Para lograrlo, se
realiza una lectura iterativa de las redes almacenadas en la EEPROM del
microcontrolador esclavo. Si logra conectarse a una red de forma exitosa se establece
una conexión TCP con el servidor.
Lo expuesto en el párrafo anterior se implementa a través del método
conectar_a_red. Este método cumple la función de probar iterativamente cada
credencial de red almacenada en la EEPROM, dando aviso en caso de que la
búsqueda sea exitosa o fallida
void conectar_a_red(){
// En primera instancia se inicializa el modo AP del módulo WiFi
modo_ap();
// Se obtiene la cantidad de credenciales almacenadas
int get_index = EEPROM.read(0) - 48;
// Se inicia un bucle de extracción de credenciales desde la
// EEPROM. La extracción es una credencial por cada ciclo de bucle
for(int index = 0 ; index < get_index ; index++){
String ssid_con = "";
String pass_con = "";
// Se extrae el valor de la SSID
for(int r=1 + 64*index; r<32 + 64*index ; r++){
62
char value = EEPROM.read(r);
if(int(value)!=-1)ssid_con += String(value);
}
// Se extrae el valor de la Clave (Pass)
for(int r=32 + 64*index; r<64 + 64*index; r++){
char value = EEPROM.read(r);
if(int(value)!=-1)pass_con += String(value);
}
// Se intenta conectar con las credenciales extraidas
ESP.println("AT+CWJAP=” + ssid_con + ”,” + pass_con);
char buffer_ESP_2[4];
// Se inicia un sub-bucle
while(1){
if (ESP.available()){
for(int u=0 ; u<3 ; u++){buffer_ESP_2[u] = buffer_ESP_2[u+1];}
buffer_ESP_2[3] = ESP.read();
}
// Se busca la palabra “FAIL” en el buffer, indicando una conexión
// fallida. Luego, expira el sub-bucle y e itera
if(buffer_ESP_2[0]=='F' && buffer_ESP_2[1]=='A' &&
buffer_ESP_2[2]=='I' && buffer_ESP_2[3]=='L'){
ssid="?";
pass="?";
break;
}
// Se busca la palabra “OK” en el buffer, indicando una conexión
// exitosa. Luego, expira el bucle y el sub-bucle
if(buffer_ESP_2[2]=='O' && buffer_ESP_2[3]=='K'){
index = get_index + 2; // arg del bucle for sobrepasado
get_info = true; // flag, inicia conexión a servidor
break;
}
}
63
}}
En caso de obtener una conexión exitosa se activa un flag llamado
get_info iniciando un nuevo ciclo que intenta conectarse a la app.
if(get_info){
ESP.println("AT+CIPMUX=1");
delay(100);
ESP.println("AT+CIPSTART=4,\"TCP\",\"200.75.125.82\",6000");
get_info = false;
}
La conexión TCP se realiza a través de la dirección IP del servidor donde
se aloja la app (200.75.125.82), indicando además el puerto de comunicación (6000).
Al terminar el ciclo se baja el flag get_info.
En caso de que la conexión con la app sea exitosa, se recibirá la palabra
“hi” (la app está configurada para que todos los nuevos clientes reciban la palabra
“hi” al iniciar una conexión). El código es capaz de identificar este mensaje haciendo
lo siguiente:
// Se busca que los caracteres más recientes en el buffer confirmen
// la palabra :hi
if (buffer_ESP[27]==':' & buffer_ESP[28] =='h' & buffer_ESP[29] =='i'){
delay(1000);
get_id();
}
Una vez recibida la palabra “hi” se inicia el método llamado get_id,
enviando la dirección MAC del módulo WiFi a la app. La dirección MAC, al ser
única, se ocupa como identificación del mismo dispositivo.
64
void get_id(){
ESP.println("AT+CIPSEND=4,25");
delay(50);
ESP.println("get_id," + mac_string + ",");
Serial.println(“1”)
}
Después de enviar la dirección MAC, se envían los datos de las rutas
hacia el servidor a través de la aplicación.
1.2.8.4 Envío de información a la aplicación web
Enviar la información desde la memoria dataflash a la aplicación web es
un trabajo coordinado entre el microcontrolador maestro y esclavo. Si bien el
módulo WiFi pertenece al dominio del microcontrolador esclavo, la memoria
pertenece al dominio del microcontrolador maestro. Por lo tanto, se define un
procedimiento donde ambos se coordinan para enviar la información a la aplicación
web. El procedimiento es
1. La aplicación verifica la id del dispositivo y le manda la palabra ok
2. El microcontrolador esclavo al recibir la palabra ok. Envía el valor 1 (uno) al
microcontrolador maestro
3. El microcontrolador maestro extrae el primer String desde la memoria
dataflash. Cada String posee la siguiente arquitectura
*Latitud, longitud, altura, tiempo, fecha!
65
Adicionalmente se agrega un carácter inicial (*) y un carácter final (!) con el fin
de que el microcontrolador esclavo sepa donde inicia y donde termina el String
enviado por el microcontrolador maestro
4. El microcontrolador esclavo envía el String a la aplicación a través del módulo
WiFi esperando la respuesta del servidor
5. Cuando la aplicación recibe el String, se envía la palabra “ok” al dispositivo
con el fin de darle a conocer que la información fue transmitida de forma
exitosa
6. El microcontrolador esclavo al detectar la palabra ok proveniente desde la
aplicación envía el valor 1 al microcontrolador maestro con el fin de recibir un
nuevo String
7. Se repite desde el paso 2 hasta que la memoria dataflash no tenga contenido
(Esta tarea es administrada por el microcontrolador maestro)
Una vez que la memoria dataflash ha sido vaciada se procede a cerrar la
conexión con la aplicación web, eliminar el contenido de la memoria dataflash y dar
la instrucción para dormir el módulo WiFi y el microcontrolador esclavo.
66
1.2.8.5 Sleep Mode
Para disminuir el consumo energético, una vez terminado el proceso de
transmisión se procede a dormir el módulo WiFi y el microcontrolador esclavo.
Para poner en sleep mode al módulo WiFi, el microcontrolador maestro
envía al esclavo el caracter “D”
if(incomingByte == 'D'){
ESP.println("AT+GSLP=3000");
ESP.end();
enterSleep();
ESP.begin(9600);
delay(100);
reset_ESP();
}
El snippet anterior ocupa el método enterSleep, definido como
void enterSleep(void){
attachInterrupt(0, pin2Interrupt, LOW);
delay(100);
// pone a dormir al microcontrolador
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
}
67
Si el microcontrolador maestro desea despertar al microcontrolador
esclavo, el microcontrolador maestro envía un pulso al pin número 2 del
microcontrolador esclavo despertando a este y al módulo WiFi.
1.2.9 Redacción de código microcontrolador maestro
El microcontrolador maestro es quién orquesta el funcionamiento del
dispositivo beta. Entre sus funciones se encuentran la lectura del módulo GPS,
lectura del acelerómetro, lectura/escritura de datos en memoria y coordinar funciones
de red a alto nivel a través del microcontrolador esclavo.
Como es normal en la IDE de Arduino, en primera instancia se importan
las librerías e inicializan las variables globales que serán usadas durante el
funcionamiento iterativo del código.
#include "LowPower.h" // Invoca sleep modes
#include <SPI.h> // Comunicación SPI
#include <SoftwareSerial.h> // Com. Serial por Software
#include <Adafruit_GPS.h> // Parsing de frases GGA y GRC
#include "at45db161d_commands.h" // Instrucciones memoria Dataflash
#include "at45db161d.h" // Comunicación Dataflash
SoftwareSerial mySerial(9, 8); // Inicializa com. Serial Software
Adafruit_GPS GPS(&mySerial); // Inicializa comunicación con GPS
ATD45DB161D dataflash; // Inicia Dataflash como un objeto
int page=0; // vars para memoria
uint8_t data; // vars para memoria
uint32_t timer = millis(); // Inicia el timer #1
double timer_tilt = millis(); // Inicia el timer #2
char incomingByte; // Byte enviado por mic. esclavo
68
const int xpin = A0; // eje-x de acelerómetro
const int ypin = A1; // eje-y
const int zpin = A2; // eje-z
int aceleracion1 = 0; // var asociada a acelerómetro
int aceleracion2 = 0; // var asociada a acelerómetro
int b = 0; // var de índice tiempo
int ax; // var asociada a acelerómetro
int ay; // var asociada a acelerómetro
int az; // var asociada a acelerómetro
int delta; // var asociada a acelerómetro
int i = 0; // ultima página vista dataflash
unsigned char track = 0; // contador interno de tracks
Luego se procede a indicar las conexiones por donde se comunicará el
microcontrolador maestro con la memoria, microcontrolador esclavo y módulo GPS.
También se declara el formato de Strings NMEA que se obtendrán a partir del
módulo GPS.
void setup(void) {
SPI.begin(); // Se inicia la com. SPI, mem Dataflsh
Serial.begin(9600); // Se inicia la com. Serial uC esclavo
GPS.begin(9600); // Se inicia la com. Con GPS
// Se envían instrucciones a GPS
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
dataflash.begin(10,3,4); // Se inicia la mem. Dataflash
delay(2000);
pinMode(7,OUTPUT); // Se declara el pin 7 como salida
}
69
En el bucle principal se llevan a cabo las tareas principales
void loop(void) {
// Cada “b” equivale a 5 segundos. Por lo tanto, si el tiempo
// esperado es mayor o igual a 15 segundos, se manda a dormir el
// módulo GPS y se declara por concluido el recorrido
if(b >= 5){
track = track + 1;
GPS.sendCommand(PMTK_STANDBY); // Apagar el GPS
mySerial.end(); // Terminar la COM Serial
digitalWrite(10,LOW); // Apagar la Dataflash
// Se comienza bucle que detecta el movimiento
while(1){
// Duerme el microcontrolador maestro por 8 segundos
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
// Lee los los ejes del acelerómetro
ax = analogRead(xpin);
ay = analogRead(ypin);
az = analogRead(zpin);
// Se obtiene el módulo de los tres ejes
aceleracion1 = abs(ax^2 + ay^2 + az^2);
// Se procede a tomar muestras de la aceleración durante 50 ciclos
for(int i=0; i<50 ; i++){
ax = analogRead(xpin);
ay = analogRead(ypin);
az = analogRead(zpin);
aceleracion2 = aceleracion1;
aceleracion1 = abs(ax^2 + ay^2 + az^2);
// Se compara la aceleración actual con la del ciclo anterior
delta = abs(aceleracion1 - aceleracion2);
// Se implementa Threshold. Si se rompe el umbral, el bucle expira.
70
// El bucle continúa hasta indefinidamente hasta que se rompa el
// umbral
if(delta >= 10)break;
delay(100);
}
if(delta >= 10)break;
}
// Se inicia nuevamente la comunicación con el GPS
GPS.begin(9600);
delay(1000);
GPS.sendCommand(PMTK_AWAKE); // Despierto el GPS
digitalWrite(10,HIGH); // Despierto Dataflash
b = 0; // Reinicio la cuenta
}
// Implementación de Filtro de movimiento
// Se obtiene el módulo de la aceleración
ax = analogRead(xpin);
ay = analogRead(ypin);
az = analogRead(zpin);
aceleracion2 = aceleracion1;
aceleracion1 = abs(ax^2 + ay^2 + az^2);
// Se compara la variación de la aceleración entre ciclos
delta = abs(aceleracion2 - aceleracion1);
// si se supera el umbral entonces la cuenta se vuelve a cero
if(delta > 20){
b=0;
}
// En caso de existir una nueva frase GGA o RMC se realiza
// El parsing correspondiente
if (GPS.newNMEAreceived()) {
if (!GPS.parse(GPS.lastNMEA()))
71
return;
}
// Cada vez que pasen 5 segundos aumenta la cuenta de “b”
if (millis() - timer > 5000){
b++;
timer = millis();
// Si la frase de GPS posee signal fixed
if(GPS.fix){
// Se construye el string y posterior arreglo char. En formato
// “t,latitud,longitud,altitud,hora,fecha,f”
String str1 = "t" + String(int(track)) + "," +
String(GPS.latitudeDegrees, 5) + "," +
String(GPS.longitudeDegrees, 5) + "," +
String(GPS.altitude, 2) + "," + String(GPS.hour, DEC) + ":"
+ String(GPS.minute, DEC) + ":" + String(GPS.seconds, DEC)
+ "," + String(GPS.year, DEC) + "-" + String(GPS.month,
DEC) + "-" + String(GPS.day, DEC) + "f\n";
int largo_str1 = str1.length();
char buf[largo_str1+1];
str1.toCharArray(buf, largo_str1 + 1);
// se manda el arreglo char al buffer de la memoria
for(int k=0; k<largo_str1 + 1; k++){
SPI.transfer(buf[k]);
delay(2);
i++;
// si se completan 528 bytes, entonces se escribe el buffer en una
// página. Luego se registra en una variable “page” que para el
// próximo turno se debe escribir en la página que viene después
if(i>527){
dataflash.BufferToPage(1,page,1);
page++;
i=0;
72
dataflash.BufferWrite(1,0);
}
}
}
}
Finalmente, se declaran la función enviar_linea que es usada durante el
envío de información desde la memoria Dataflash hacia el microcontrolador esclavo
// Envia línea por línea al microcontrolador esclavo los strings
// provenientes desde la Dataflash
void enviar_linea(){
char letra;
// Se comienza a leer la Dataflash desde la página cero
for(int k=0; k<4095 ; k++){
dataflash.ReadMainMemoryPage(k,0);
// Se comienza a leer la página desde su primer byte
for(int i=0; i<527 ; i++){
letra = SPI.transfer(0xff);
if(int(letra)==-1){i=1000;k=5000;}
// Si el carácter leído es “t”, significa que este es el comienzo
// de un string. Por lo tanto se reinicia el string
if(letra == 't')linea = "";
linea = linea + letra ; // Se agregan caracteres a String
// Si el carácter leído es “f”, significa que este es el fin
// de un string. Luego, se envía el string al mic. esclavo
if(letra == 'f'){
Serial.println("*" + linea + "!");
while(1){
// Se espera la confirmación del mic. Esclavo
if(Serial.read() == '1')break;
}}}}}
73
1.2.10 Redacción de código microcontrolador esclavo
El microcontrolador esclavo es el encargado de ejecutar las tareas
relacionadas a la conexión misma del dispositivo beta a través de redes WiFi así
como la subida de datos al servidor.
De igual manera que el código del microcontrolador maestro, se
importan las librerías e inicializan las variables globales globales usadas durante el
funcionamiento del código.
#include <SoftwareSerial.h> // Com. Serial por software
#include <EEPROM.h> // EEPROM interna del mic. esclavo
#include <avr/sleep.h> // Sleep Mode mic. esclavo
SoftwareSerial ESP(9,8); // Inicializa com. Serial Software
char incomingByte; // Byte proveniente mic. maestro
char buffer_ESP[30]; // Buffer módulo WiFi
// Arreglos Char’s para credenciales de red
char ssid_eeprom[32];
char pass_eeprom[32];
String stream; // String para guardar Buffer_ESP
// Strings donde se guardan las credenciales de red
String ssid;
String pass;
String mac_string; // String donde se guarda la dir. MAC
// Formulario HTML que se envía al usuario
const String html1 = "<html><body>";
const String html2 = "Rubilink!<br><br>";
const String html3 = "Ingresa el nombre de tu Red y la Password<br><br>";
const String html4 = "<form action=\"demo_form.asp\" method=\"get\">";
const String html5 = "Red :<input type=\"text\" name=\"SSID\"><br><br>";
const String html6 = "Pass:<input type=\"text\" name=\"Pass\"><br><br>";
const String html7 = "<input type=\"submit\" value=\"Conectar\">";
74
const String htm18 = "</form></body></html>";
// Pin por donde se recibe la alarma del mic. maestro para despertar
int pin2 = 2;
// Flags
boolean inicio = true;
boolean flag_track = true;
boolean get_info = false;
boolean flag_line = true;
boolean post_flag = false;
Luego se procede a declarar las conexiones por donde ocurrirá la
comunicación con el módulo WiFi y el microcontrolador maestro
void setup(){
Serial.begin(9600); // Inicia la com. Con el mic. maestro
ESP.begin(9600); // Inicia la com. Con el módulo WiFi
pinMode(7,OUTPUT); // Se declara el pin 7 como salida
digitalWrite(7,HIGH); // Se activa el módulo WiFi
pinMode(pin2, INPUT); // Se declara el pin 2 como entrada
get_mac(); // Se obtiene la dirección MAC
}
En el bucle principal se ejecutan las tareas principales que lleva a cabo el
microcontrolador esclavo
void loop(){
// Si el flag get_info se activa, se intenta crear una conexión TCP
// con la app
if(get_info){
conectar_servidor();
get_info = false;
75
}
// Se recibe cada byte proveniente del módulo WiFi y se empuja
// en el buffer
if (ESP.available()){
for(int z=0 ; z<29 ; z++)buffer_ESP[z] = buffer_ESP[z+1];
buffer_ESP[29] = ESP.read();
}
// Se convierte el arreglo (buffer) en un string (stream)
// Facilita el recortado de palabras y la búsqueda de caracteres
stream = String(buffer_ESP);
// Si se encuentra la palabra “MAC” dentro del stream, se recorta
// la dirección MAC:”xx:xx:xx:xx:xx:xx”
int index1 = stream.indexOf('M');
if (stream.indexOf('A')==index1 + 1 &&
stream.indexOf('C')==index1 + 2 && stream.indexOf(':')==index1 + 3){
mac_string = stream.substring(index1 + 5,index1+22);
}
// Busca la palabra “:ok” dentro de los más recientes bytes del
// buffer. Si es el caso, se baja el flag “post_flag” y
// se envía un “1” al mic. maestro
if (buffer_ESP[18]=='+' & buffer_ESP[26] ==':' &
buffer_ESP[27]=='o' & buffer_ESP[28]=='k' & post_flag){
Serial.println("1");
post_flag = false;
}
76
// Si se recibe la palabra “+:GET” se envía el formulario
// HTML al cliente
if(buffer_ESP[0]=='+' & buffer_ESP[10] ==':' & buffer_ESP[11]=='G'&
buffer_ESP[12]=='E' & buffer_ESP[13]=='T'){
int cliente = buffer_ESP[5] - 48;
delay(1000);
envio(cliente, html1);
envio(cliente, html2);
envio(cliente, html3);
envio(cliente, html4);
envio(cliente, html5);
envio(cliente, html6);
envio(cliente, html7);
}
// Si se recibe el mensaje “hi”, se procede a ocupar el método
// get_id, que envía la dirección MAC a la app
if (buffer_ESP[27]==':' & buffer_ESP[28] =='h' & buffer_ESP[29]
=='i'){
get_id();
}
// Permite encontrar la SSID de la Red, desde el formulario
if (buffer_ESP[0]=='S' & buffer_ESP[1] =='S' & buffer_ESP[2]=='I' &
buffer_ESP[3]=='D' & buffer_ESP[4]=='='){
for(int z=4 ; z<29 ; z++){
if(buffer_ESP[z] == '&'){
ssid_end = z;
ssid = String(buffer_ESP).substring(5,ssid_end);
break;
}
}
77
}
// Permite encontrar la Password de la Red, desde el formulario
if (buffer_ESP[0]=='P' & buffer_ESP[1] =='a' & buffer_ESP[2]=='s' &
buffer_ESP[3]=='s' & buffer_ESP[4]=='='){
for(int z=4 ; z<29 ; z++){
if(buffer_ESP[z] == ' '){
pass_end = z;
pass = String(buffer_ESP).substring(5,pass_end);
char pass_array[32];
char ssid_array[32];
ssid.toCharArray(ssid_array, ssid.length() + 1);
pass.toCharArray(pass_array, pass.length() + 1);
int index_0 = EEPROM.read(0) - 48;
for(int i = 1; i < 1 + ssid.length(); i++){
EEPROM.write(i + index_0*64, ssid_array[i-1]);
delay(50);
}
for(int i = 34; i< 34 + pass.length(); i++){
EEPROM.write(i + index_0*64, pass_array[i-34]);
delay(50);
}
aumentar_index_eeprom();
break;
}
}
}
// Set de instrucciones que el mic. maestro puede ejecutar enviando
serialmente caracteres al mic. esclavo
if (Serial.available()){
incomingByte = Serial.read();
78
if(incomingByte == 'Y')conectar_a_red();
if(incomingByte == 'r')reset_ESP(); // resetea el ESP8266
if(incomingByte == 's')setup_ESP(); // crea red abierta
if(incomingByte == 'h')html(); // envia formulario
if(incomingByte == 'S')sleep(); // duerme ESP8266
if(incomingByte == 'l')conectar_servidor(); // establece TCP
if(incomingByte == 'c')close_TCP(); // cerrar TCP
if(incomingByte == 'm')get_mac(); // obtener dir MAC
if(incomingByte == 'D'){ // duerme todo
ESP.println("AT+GSLP=3000");
ESP.end();
enterSleep(); // duerme mic. esclavo
ESP.begin(9600);
delay(100);
reset_ESP();
}
// Si el carácter que envía es “*” se inicia un sub-bucle
// Esperando que llegue el carácter “!”. Todo lo que este
// entre “*” y “¡” es un String de la Dataflash
if(incomingByte == '*'){
String string_post = "post," + String(track_id) + ",";
while(1){
if (Serial.available()){
char mensaje = Serial.read();
if(mensaje=='!')break;
string_post += mensaje;
}
}
// Se envía el String a la app
int post_largo = string_post.length();
ESP.println("AT+CIPSEND=4," + String(post_largo));
79
delay(50);
post_flag = true;
ESP.println("*" + string_post + "!");
}
}
}
Se declaran las funciones relacionadas a la gestión de datos y conexiones
usadas en el bucle principal
// Se resetea el módulo WiFi
void reset_ESP(){
digitalWrite(7,LOW);
delay(100);
digitalWrite(7,HIGH);
flag_track = true;
flag_line = true;
}
// Se crea una red abierta de nombre Red A y además se configura el
// módulo como servidor HTTP
void setup_ESP(){
ESP.println("AT+CWMODE=2"); delay(50);
ESP.println("AT+CWSAP=\"Red A\",\"ABC1234567\",11,0"); delay(50);
ESP.println("AT+CIPMUX=1"); delay(50);
ESP.println("AT+CIPSERVER=1,80"); delay(50);
}
// Se envía el formulario
void html(){
envio(0, html1);
envio(0, html2);
80
envio(0, html3);
envio(0, html4);
envio(0, html5);
envio(0, html6);
envio(0, html7);
}
// Prepara la frase para enviarla a través del módulo
void envio(int canal, String frase){
int largo = frase.length();
ESP.println("AT+CIPSEND=" + String(canal) + "," + String(largo));
delay(50);
ESP.println(frase);
delay(300);
}
// Obtiene la dirección MAC del módulo
void get_id(){
ESP.println("AT+CIPSEND=4,25");
delay(50);
ESP.println("get_id," + mac_string + ",");
}
// Intenta buscar una red con las credenciales ssid y pass
void conectar(String ssid, String pass){
String conexion = "AT+CWJAP=\"" + ssid + "\",\"" + pass + "\"";
ESP.println(conexion);
}
// Establece una conexión TCP
void conectar_servidor(){
ESP.println("AT+CIPMUX=1");
ESP.println("AT+CIPSTART=4,\"TCP\",\"192.168.1.20\",6000");
81
}
// Pone a dormir el módulo WiFi
void sleep(){
ESP.println("AT+GSLP=3000");
}
// Cierra la conexión TCP
void close_TCP(){
ESP.println("AT+CIPCLOSE=4");
}
// Despierta al mic. esclavo cuando siente la alarma en el pin 2
void pin2Interrupt(void){
detachInterrupt(0);
}
// Rutina que se ejecuta cuando el mic. esclavo entra en
// sleep mode
void enterSleep(void){
attachInterrupt(0, pin2Interrupt, LOW);
delay(100);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
}
// aumenta el índice de credenciales almacenadas
void aumentar_index_eeprom(){
char index_1 = (EEPROM.read(0));
index_1 = index_1 + 1;
EEPROM.write(0, index_1);
}
82
// Rutina que permite iterar las credenciales con el fin de
// encontrar una red disponible
void conectar_a_red(){
int get_index = EEPROM.read(0) - 48; // Se obtiene el índice
for(int index = 0 ; index < get_index ; index++){
String ssid_conexion = "";
String pass_conexion = "";
// Se extraen las credenciales desde la EEPROM
for(int r=1 + 64*index; r<32 + 64*index ; r++){
char value = EEPROM.read(r);
if(int(value)!=-1)ssid_conexion += String(value);
}
for(int r=32 + 64*index; r<64 + 64*index; r++){
char value = EEPROM.read(r);
if(int(value)!=-1)pass_conexion += String(value);
}
ssid = ssid_conexion;
pass = pass_conexion;
// Se busca una red con las credenciales
conectar(ssid_conexion,pass_conexion);
char buffer_ESP_2[4];
while(1){
if (ESP.available()){
for(int u=0 ; u<3 ; u++){
buffer_ESP_2[u] = buffer_ESP_2[u+1];
}
buffer_ESP_2[3] = ESP.read();
}
if(buffer_ESP_2[0]=='F' && buffer_ESP_2[1]=='A' &&
buffer_ESP_2[2]=='I' && buffer_ESP_2[3]=='L'){
ssid="?";
pass="?";
83
break;
}
if(buffer_ESP_2[2]=='O' && buffer_ESP_2[3]=='K'){
index = get_index + 2;
get_info = true;
break; }
}
}
}
1.2.11 Construcción de prototipo beta
Para la construcción del prototipo beta se construye el circuito en una
placa de circuito impreso o en inglés Printed Circuit Board (PCB) con el fin de
obtener un prototipo con un acabado escalable y de menor tamaño que el prototipo
alfa. El PCB se diseña usando el software EagleCAD, generando un PCB de doble
cara de 65mm x 30mm (Figura 1.20). De igual manera, la fabricación del PCB se
encarga a la empresa Oshpark (Figura 1.21).
84
Figura 1.20: PCB de doble capa
Figura 1.21: PCB generado por Oshpark
85
El ensamblaje de los componentes a la placa (PCB) se realiza con la
ayuda de herramientas de montaje superficial como pistolas de calor y microscopios
digitales. El resultado se muestra en la Figura 1.22.
Figura 1.22: PCB ensamblado
Como case se usa un modelo diseñado con el software 3D “Autodesk
Inventor”. El modelo posee dos piezas, permitiendo colocar el circuito entre ambas
partes (Figura 1.23).
86
Figura 1.23: Case modelo 3D
Finalmente, la impresora 3D “Davinci Jr” imprime el case, ajustando el
circuito en el interior de este, obteniendo el prototipo beta que se muestra en la
Figura 1.24.
Figura 1.24: Prototipo beta ensamblado
87
1.2.12 Testeo con usuarios del prototipo beta
El testeo del prototipo beta consistió en entregar el dispositivo a 32
usuarios durante un periodo de una semana de uso para cada uno. La prueba comienza
el día 17 de Agosto del año 2015 y concluye el día 27 de Noviembre del mismo año.
Para esta prueba se construyen 3 unidades del mismo dispositivo.
La autonomía energética bajó 2 horas (32 horas en total) con respecto al
prototipo alfa debido a la incorporación de componentes como el módulo WiFi y el
acelerómetro (no presentes en el prototipo alfa). Por otro lado, la cantidad de viajes
registrados en promedio por el usuario pasó de tres a nueve (en comparación al
prototipo alfa). La implementación del modo detector de movimiento permite al
dispositivo asignar la energía de forma eficiente. Además, se reduce el contenido de
registros falsos (cuando el usuario olvida apagar el dispositivo) ahorrando memoria.
Algunos usuarios revelaron que tuvieron problemas configurando la red y
conectándose a la red abierta “Red A”, posiblemente debido a la interferencia de
distintas redes WiFi. Esto se podría resolver en una versión futura realizando un
escaneo previo de las redes existentes y asignando a la red abierta un canal que no esté
siendo ocupado por otras redes WiFi.
Por otro lado, la subida de datos a la aplicación web funciona de forma
fluida. Sin embargo, vaciar la memoria completa toma entre 5 y 10 minutos. La razón
es que el módulo toma una pausa de 150 milisegundos para enviar una frase y su
capacidad está limitada a 50 bytes por frase, considerando que un recorrido puede
tener más de 1000 frases, cada recorrido toma 150 segundos en subirse. En el futuro se
cambiará el módulo WiFi por un modelo que permita tasas de transferencia mayores
como el chip CC3000 de la Texas Instruments, este chip soporta comunicación SPI
permitiendo tasas de transferencia de hasta a 1 Mbit/segundo.
88
II. DESARROLLO DE SOFTWARE
Para esta investigación en complemento al dispositivo (alfa y beta) se
diseña una plataforma web que permite monitorear y visualizar los datos obtenidos
por los dispositivos. Esta plataforma consiste de dos partes fundamentales, la primera
es una plataforma web basada en Ruby on Rails que permite almacenar los datos
obtenidos por los dispositivos (alfa y beta) como también subir los archivos .csv
generados por el dispositivo alfa. La segunda parte, consiste en una aplicación web
basada en Node.js diseñada específicamente para el dispositivo beta. Esta aplicación
web permite establecer una comunicación con el dispositivo extrayendo el contenido
desde este y almacenándolo en una base de datos. Tanto la plataforma web como la
aplicación web son complementarias.
El desarrollo de este capítulo se divide en tres partes. La primera parte
está enfocada en la creación de la plataforma web y la base de datos. La segunda
parte trata sobre el diseño de la aplicación web para el dispositivo beta. Finalmente, la
tercera parte propone una forma de visualizar los datos del prototipo alfa y beta en un
solo gráfico (mapa de calor).
2.1. Desarrollo de plataforma
Se crea una plataforma web donde se almacenan los datos obtenidos por
cada dispositivo y donde el usuario sube los archivos .csv generados por el dispositivo
alfa. Es importante aclarar que la plataforma está enlazada a una base de datos que es
ocupada por recorridos del dispositivo alfa y beta. Por lo tanto la plataforma es
transversal para ambos dispositivos.
89
La plataforma web cuenta con autentificación que le permite a cada
usuario crear una cuenta y enlazar su dispositivo. La plataforma cuenta con una base
de datos donde se almacena la información de cada usuario, recorrido y estadísticas.
Para implementar la plataforma web se usa como framework de
aplicaciones Ruby on Rails debido a su amplia documentación en línea a partir de
foros y tutoriales creados por distintos desarrolladores. Ruby on Rails o simplemente
Rails goza de gran popularidad en el ambiente del desarrollo web gracias a la facilidad
con que se pueden comenzar proyectos y su filosofía de no repetir o DRY (Don’t
Repeat Yourself) que persigue ocupar la menor cantidad de código y modularizar
partes, evitando errores y reduciendo el tiempo de desarrollo de los proyectos.
90
2.1.1 Diseño de base de datos
Se crea una base de datos donde se guardan las distintas variables que
definen cada viaje realizado por el usuario.
Como se muestra en la Figura 2.1, se crea un modelo User que puede
realizar varios recorridos y cada recorrido está definido por varios puntos. A su vez,
cada usuario puede tener más de un dispositivo a su disposición.
Figura 2.1: Arquitectura de base de datos plataforma
91
El modelo User (usuario), posee atributos que son necesarios para su
login como su correo electrónico y clave. También existen otros atributos que el
usuario debe completar una vez que inicia sesión como su primer nombre, apellido,
fecha de nacimiento y género.
El modelo Dispositivo indica las propiedades del dispositivo y es un
modelo que pertenece a User en una relación muchos a uno, es decir, cada usuario
puede tener muchos Dispositivos pero un Dispositivo no puede pertenecer a muchos
usuarios. A su vez, cada Dispositivo posee un atributo de identificación que
corresponde a la dirección MAC de cada dispositivo y que el usuario debe completar
una vez que inicia sesión por primera vez. El modelo contempla un atributo llamado
nombre que le da la oportunidad al usuario de bautizar al dispositivo con un nombre
en particular. Los atributos latitud y longitud son modificados por la aplicación del
prototipo beta de manera automática (ver capítulo 2.2. Desarrollo de aplicación para
dispositivo beta) e indican cual es la posición más reciente con la que el dispositivo
subió sus datos al servidor. Finalmente, el atributo serie es un campo tentativo que
permite a la aplicación del dispositivo beta registrar cual es la generación de
dispositivo con la que se cuenta, este campo permitiría conocer al usuario qué tipo de
dispositivo posee.
El modelo Track (recorrido o pista en inglés) pertenece al modelo User
en una relación muchos a uno, es decir, un usuario puede poseer muchos Tracks,
pero un Track no puede poseer más de un usuario. El modelo Track posee los
atributos origenlat y origenlon que hacen referencia a las coordenadas del origen del
recorrido. De la misma manera, destinolan y destinolon guardan las coordenadas del
destino del recorrido. name indica el nombre del recorrido. Por otro lado, distancia,
velocidad, tiempo y fecha son atributos que son completados automáticamente por la
aplicación web una vez que los datos del recorrido son subidos completamente al
servidor.
92
El modelo Point pertenece al modelo Track en una relación muchos a
uno. Posee atributos de latitud, longitud y de tiempo que tiene función de timestamp.
2.1.2 Sistema de autentificación
Con el fin de proporcionar acceso a los usuarios para subir los datos a la
plataforma, se crea un sistema de login donde cada usuario crea una cuenta. De esta
manera, se crea una distinción entre los recorridos realizados por los distintos
usuarios.
La gema devise crea un sistema de autentificación sobre la plataforma. De
esta manera, todo usuario accede a la plataforma con credenciales propias (e-mail y
clave). Se compone de 10 módulos
1. Autentificación mediante Base de Datos: La clave creada por el usuario se
encripta y se guarda en la base de datos, bajo el modelo User.
2. Omniautentificable: Capacidad de ingresar a la aplicación con credenciales de
Twitter o Facebook.
3. Confirmación: Envía un e-mail de confirmación al usuario una vez que se crea
una cuenta.
4. Recuperación: En caso de que el usuario olvide su clave, la aplicación envía un
correo electrónico y reinicia su clave.
5. Registro: Permite guiar al usuario en el proceso de registro, editar su cuenta y
también eliminarla.
6. Recordar: Permite recordar las credenciales de usuario en el computador,
usando cookie.
93
7. Rastreo: Guarda información de la dirección IP y estadísticas de ingreso del
modelo User.
8. Expiración: Cuando el usuario no muestra actividad, se cierra sesión
9. Validación: Identifica al usuario al entrar a la aplicación mediante correo y
clave.
10. Bloqueo: Ante reiterativos intentos de login erróneos (ingreso de clave
incorrecta) el módulo bloquea la cuenta.
Por otra parte, la gema cancan define las atribuciones de cada usuario
sobre el contenido. La gema permite que cada usuario agregue, modifique y elimine
contenido de su propia cuenta y no de otros usuarios.
La restricción que cada usuario tiene sobre el contenido se implementa en
el “controlador” del modelo Track. De esta manera, el nuevo modelo Track queda
como:
# Creacion de Contenido, creamos un nuevo track
def create
@track = Track.new(track_params)
@track.user = current_user
# Se autoriza al usuario a crear su propio contenido
authorize! :create, @track
respond_to do |format|
if @track.save
format.html { redirect_to @track, notice: 'Track creado' }
format.json { render :show, status: :created, location:
@track }
else
format.html { render :new }
94
format.json{render json: @track.errors, status:
:unprocessable_entity}
end
end
end
# Eliminar Contenido, Eliminamos un track especifico
def destroy
@track.user = current_user
# Se autoriza al usuario a eliminar su propio contenido
authorize! :destroy, @track
@track.destroy
authorize! :destroy, @track
respond_to do |format|
format.html { redirect_to tracks_url, notice: 'Track eliminado’
}
format.json { head :no_content }
end
end
# Mostrar Contenido, GET request.
def show
@track = Track.find(params[:id])
# Se autoriza al usuario a ver su propio contenido
authorize! :show, @track
gon.track_number = Track.find(params[:id])
respond_to do |format|
format.html
format.json { render :json => @track.to_json(:methods => [:polyline],:only
=> [:name])}
end
end
95
2.1.3 Subir archivos .csv
La transmisión de datos desde el dispositivo alfa a la plataforma web es un
proceso manual. Para esto, el usuario debe extraer la tarjeta SD de cada dispositivo y a
través de la plataforma subir los archivos .csv obtenidos.
Con el fin de incorporar los datos de un archivo .csv en el modelo Points
se agrega un método llamado self.import(file). Este método es capaz de leer el
archivo .csv línea a línea extrayendo los componentes del modelo con que se llena la
base de datos.
Para lograr extraer línea a línea las variables de interés (parsing) se hace
uso del comando provisto por Ruby
CSV.foreach(file.path, headers: true) do |row|
Donde la función foreach de la clase csv permite leer cada línea del
archivo y crear en forma recursiva un vector llamado row en donde se guarda
momentáneamente el contenido de la línea.
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Product.create! row.to_hash
end
end
El método self.import es capaz de leer un archivo línea a línea y al
mismo tiempo asignar las variables obtenidas de la lectura al modelo Point. Sin
embargo, dependiendo de la capacidad del servidor donde corra la aplicación, esto
podría tomar un tiempo considerable. Lo anterior es perjudicial cuando se trata de
96
procesar archivos .csv con un gran número de líneas. Por ejemplo, en una máquina de
1 núcleo corriendo a 3 GHz y de 512 MB de memoria RAM, registrar cada línea toma
un total de 300 milisegundos. Si se considera un viaje de 45 minutos con una tasa de
muestreo de 5 segundos, entonces tendremos 540 líneas lo que significa un tiempo de
162 segundos en procesamiento. Con el objetivo de reducir el tiempo de subida de
información, se decide trabajar directamente sobre la base de datos haciendo uso de
frases SQL. Así, se modifica el método anterior por el siguiente
CSV.foreach(file.path, headers: true) do |row|
sql = "INSERT INTO points (track_id, latitud, longitud, tiempo,
created_at, updated_at) VALUES (" + id + "," + row[0] + "," +
row[1] + ", '" + row[2] + "' , '" + created_at +"', '" +
created_at + "')"
res = ActiveRecord::Base.connection.execute(sql)
end
Este cambio permite reducir a 42 milisegundos cada registro reduciendo el
tiempo de procesamiento en un 86%.
97
2.2 Desarrollo de aplicación para dispositivo beta
Con el fin de establecer un nexo entre el dispositivo beta y la base de datos
se crea una aplicación web que permite comunicarse con el dispositivo, recibiendo su
información y poblando la base de datos.
La aplicación se comunica con el dispositivo a través de comunicación
TCP, recibiendo la información y almacenándola. Por otra parte, verifica la identidad
de cada dispositivo con el fin de asignar los recorridos al usuario correspondiente.
La aplicación alimenta la misma base de datos de la plataforma. Por lo
tanto, es posible visualizar los recorridos subidos en la misma plataforma web.
La aplicación es desarrollada usando Node.js, destacando su
funcionamiento asíncrono que se adapta de mejor manera a una aplicación de
comunicación entre clientes que un lenguaje síncrono.
2.2.1 Diagrama de flujo de aplicación para dispositivo beta
La comunicación entre la aplicación y el dispositivo se compone de dos
pasos, generando un handshake. De este modo, el dispositivo sabe si la información ha
sido recibida de forma correcta o incorrecta
1. Al iniciar la comunicación aplicación-dispositivo, se envía la palabra hi al
dispositivo (cliente)
2. La app al recibir un String, envía la palabra ok
98
Una vez que la comunicación entre la aplicación y el cliente se cierra, se comienza el
procesamiento de la información recibida.
El mensaje completo proveniente desde el cliente tiene la siguiente
arquitectura:
Dirección MAC
Viaje_id, latitud, longitud, altura, hora, fecha
Viaje_id, latitud, longitud, altura, hora, fecha
…
Viaje_id, latitud, longitud, altura, hora, fecha
Lo primero que verifica la aplicación es a quién pertenece el dispositivo
analizando el campo identificación (que corresponda a la dirección MAC) en el
modelo Dispositivo de la base de datos. En caso de encontrar una coincidencia, se
solicita el valor user_id.
Una vez que la aplicación identifica a qué usuario pertenece el dispositivo
se procede a crear una entrada en el modelo Track. Si se reciben múltiples recorridos,
entonces se crean múltiples entradas en el modelo. Cada vez que se crea un nuevo
registro de Track se le agregan los registros correspondientes del modelo Point.
El diagrama de flujo de la app se muestra en la Figura 2.2
99
Existe conexión
con el cliente
Se almacena en
un arreglo A
Enviar “hi”
Obtener
user_id
T = 0
Se cerró la
conexión
Hay un String
nuevo Enviar “ok”
T = número de
Tracks
T = T - 1
Crear Track en la
base de datos
P = número de
puntos de
Track T
P = 0
P = P - 1
Crear Punto en el
Track T en la
base de datos
Inicio Fin
Si
Si
Si
Si
No
No
Si
No
Figura 2.2: Diagrama de Flujo de Aplicación web
Esperar
No
100
2.2.2 Redacción de código de la aplicación
La aplicación se programa en el entorno Node.js basado en el lenguaje
ECMAScript de naturaleza asíncrona. La posibilidad de ejecutar funciones en base a
eventos permite una comunicación en tiempo real entre la aplicación y el dispositivo.
Adicionalmente, se agrega la base de datos como un tercer integrante a la
comunicación. El intermediario entre el dispositivo y la base de datos es la aplicación,
realizando funciones de orden y procesamiento de la información antes de guardarla
en la base de datos. El código de la aplicación web es:
net = require('net'); // Librería TCP
var clients = []; // Arreglo con id de clientes
var mem = []; // Arreglo donde se guarda el string
var pg = require('pg'); // Librería Base de Datos
// Dirección Base de Datos
var url= 'postgres://witnjdnnxafude:cPLXdsq5hQKtG8_syWwW7tsISY@ec2-54-235-
147-211.compute-1.amazonaws.com:5432/d4vrc2c65evcmb?ssl=true'
domain = require('domain'),
d = domain.create();
// función se activa cuando se conecta un nuevo cliente
net.createServer(function (socket) {
socket.name = socket.remoteAddress + ":" + socket.remotePort
clients.push(socket);
mem.push("");
socket.write("hi\n"); // Se envía la palabra “hi”
// Se reciben los Strings del cliente
// Toda la información recibida se guarda en un arreglo “mem”
socket.on('data', function (data) {
101
index = clients.indexOf(socket)
string = data.toString();
mem[index] += string;
});
// Una vez que se termina la comunicación con el cliente
// Se procesa la información
socket.on('end', function () {
var string = (mem[clients.indexOf(socket)]);
var id_socket = clients.indexOf(socket);
var lineas = string.split('\n');
var mac = lineas[0]; // Se obtiene la MAC
clients.splice(clients.indexOf(socket), 1);
var track = [];
var tracks = 0;
track_id = -1;
track_db_id = "0";
var numero_lineas = lineas.length - 1;
i = 1;
// Se calcula cuantos recorridos fueron enviados por el cliente.
// “tracks” indica la cantidad de recorridos
// “track[]” es un arreglo donde cada casillero posee toda la
// información de un recorrido (puntos).
while(i<numero_lineas){
componentes = lineas[i].split(',');
track_id_0 = track_id;
track_id = componentes[0];
if(track_id!=track_id_0){
tracks++;
track[tracks] = ""
}
102
track[tracks] += lineas[i] + '\n';
i++;
}
mem.splice(id_socket, 1);
// Se crea una conexión a la base de datos
pg.connect(url, function(err, client, done) {
if(err) {
return console.error('could not connect to postgres', err);
}
// Se pide toda la tabla que posee la información del modelo Dispositivo
client.query('SELECT * FROM Dispositivos;')
.on('row', function(raw) {
dispositivo_id = raw.identificacion
userid = raw.user_id
// Se busca cuál usuario es el dueño del dispositivo con tal MAC
if(dispositivo_id == mac){
usuario_db = userid.toString();
tracks_cantidad = track.length - 1;
y = 1;
lineas_2 = track[y].split('\n')
componentes_2 = lineas_2[0].split(',')
fecha = componentes_2[5];
tiempo = componentes_2[4];
tiempo_comps = tiempo.split(':');
meridiano = parseInt(tiempo_comps[0]);
titulo = ""
// El nombre del recorrido dependerá de la hora a la que fue
// registrado
if(meridiano >= 0 & meridiano < 12 ) titulo = "'Viaje de Madrugada'";
103
if(meridiano >= 12 & meridiano < 18) titulo = "'Viaje por la Tarde'";
if(meridiano >= 18 & meridiano < 24) titulo = "'Viaje Nocturno'";
// Se crea un nuevo Track en la base de datos
client.query("INSERT INTO tracks (name, fecha, user_id, created_at ,
updated_at) VALUES (" + titulo + ",'" + fecha + "'," +
usuario_db + ",'2015-08-17','2015-08-17')");
done();
// Se obtiene el “id” del Track creado
client.query('SELECT * FROM tracks ORDER BY id DESC LIMIT 1;')
// Se prepara la información del recorrido(Track)
.on('row', function(raw) {
track_db_id = raw.id;
done();
lineas_track = track[y].split('\n');
numero_de_lineas_Arreglo = lineas_track.length;
// Se ingresa toda la información del recorrido en el modelo Point
for(z = 0; z<numero_de_lineas_Arreglo-1; z++){
info = lineas_track[z].split(',')
lon = info[1];
lat = info[2];
alt = info[3];
hora = info[4];
fecha = info[5];
client.query("INSERT INTO points (track_id,
latitud, longitud, tiempo, created_at,
updated_at) VALUES (" + track_db_id + ","+
lon + "," + lat + ", '" + hora + "' , '"+
fecha + "', '"+ fecha +"');");
done();
104
}
});
}
done();
});
});
// Se borra la presencia del cliente
clients.splice(clients.indexOf(socket), 1);
});
}).listen(6000);
105
2.3. Visualización de viajes agregados
Los viajes recopilados durante esta investigación ascienden a un total de
359 recorridos. En promedio cada viaje duró 16 minutos y las mediciones se
realizaron cada 10 segundos. Esto significa que de la muestra total de usuarios tanto
para el dispositivo alfa y beta se almacenaron 34.464 puntos georreferenciados
(además de un timestamp relativo a cada punto). Con el fin de analizar esta
información de forma rápida e intuitiva se usan mapas de calor. Estos mapas, marcan
la frecuencia de las rutas con distintos colores.
Para diseñar los mapas de calor, se ocupa un software llamado Tilemill
proporcionado por la empresa Mapbox. Tilemill es un software abierto que permite
diseñar mapas usando el lenguaje CartoCSS (CSS orientado a mapas).
Tilemill ocupa como input archivos con terminación .shp (shapefiles). El
archivo shapefile es complejo y posee una estructura bien detallada en distintos
papers desde su creación en 1998. Es por lo mismo, que existen distintas
aplicaciones que permiten convertir archivos de distintas terminaciones en archivos
.shp, entre ellos GPSBabel (conversión de CSV a GPX) y Ogr2ogr (conversión de
GPX a .shp) los que se explican a continuación.
106
2.3.1 Conversión de archivos
Ante la necesidad de crear un archivo .shp a partir de distintos archivos
.csv se busca un método que permita la conversión entre archivos y posterior
agrupación. Por un lado, existe la aplicación gpsbabel que permite convertir archivos
.csv a .gpx. Por otro lado, la aplicación ogr2ogr permite agrupar distintos archivos
.gpx en un único archivo .shp.
Figura 2.3: Conversión entre archivos
El software GPSBabel es de código abierto y funciona por comandos en
una terminal de Ubuntu (consola). El comando que permite convertir de formato .csv
a formato .gpx es:
gpsbabel –i csv –f “input.csv” –o gpx –f “output.gpx”
.csv .gpx .shp
107
Donde
–i indica el tipo formato de entrada (csv)
-f indica el archivo de entrada (input.csv)
-o indica el tipo de formato de salida (gpx)
-f indica el archivo de entrada (output.gpx)
Luego, el archivo .gpx es tomado como input por ogr2ogre. Usando el
comando:
ogr2ogr –append destino output.gpx
El comando crea una carpeta que lleva por nombre destino y en su
interior se encuentra un archivo llamado tracks.shp que incluye las formas
geométricas que definen el mapa de calor. Además, el comando permite unir
(append) varios archivos .gpx en el mismo archivo tracks.shp. Por ejemplo, si se
tiene n número de archivos .gpx y se desea crear un único mapa de calor entonces se
crea un script en Python que agregue todos los archivos .gpx que sean necesarios:
import os
from time import sleep
# Todos los archivos deben ir en una única carpeta llamada
# ubicación_archivos
lista = os.listdir("/ubicacion_archivos/")
largo = len(lista)
for i in range(1,largo):
print lista[i]
os.system("ogr2ogr -append destino " + lista[i])
108
2.3.2 CartoCSS y mapas de calor
El software Tilemill permite subir los proyectos al servidor de la empresa
Mapbox. Todos los proyectos subidos a Mapbox cuentan con una dirección web que
permite compartir públicamente el mapa. El servicio que ofrece Mapbox conjunto a
Tilemill los convierte como una alternativa tentadora al momento de iniciarse en el
diseño de mapas.
Tilemill permite importar archivos .shp y manipularlos por capas. Luego,
usando cartoCSS, se define el estilo de cada capa. Para esta investigación se decide
que cada recorrido sea representado por una línea roja, de borde interno amarillo y
borde externo verde, obteniendo un resultado que resalta cuando se agrupan varios
recorridos, tal como se observa en la Figura 2.4. En la figura resaltan 2 flujos de
recorridos paralelos, el flujo de posición superior representa los viajes realizados por
la calle Pocuro. El flujo de posición inferior representa los viajes realizados por la
calle Bilbao.
Figura 2.4: Mapa de calor – Calles Pocuro y Bilbao
109
Finalmente, el código que define el estilo de línea es el siguiente:
/* Borde interno de color amarillo */
#tracks::glow {
line-width:5;
line-color:#ffce09;
line-opacity:0.4;
}
/* Borde externo de color Verde */
#tracks::extraglow {
line-width:13;
line-color:#2ff021;
line-opacity:0.18;
}
/* Linea base de color rojo */
#tracks::base {
line-width:0;
line-color:#fd0505;
line-opacity:0.6;
}
110
III. RESULTADOS
Los resultados de la investigación muestran tanto el desempeño del
dispositivo como también el valor y la autenticidad de los datos generados en el área
del transporte y movilidad después de haber realizado el testeo con los usuarios.
3.1 Representatividad de la muestra
El dispositivo alfa fue testeado con 64 usuarios, mientras que el
dispositivo beta con 32 usuarios, totalizando 96 usuarios entre ambos dispositivos.
Según la encuesta origen-destino, la región Metropolitana registra
diariamente 18 millones de viajes en promedio, de los cuales el 4,2% corresponde a
viajes realizados en bicicleta (747 mil viajes). Adicionalmente, cada usuario realiza
2,78 viajes en promedio al día lo que implica que en Santiago existen al menos 31.374
personas que realizan al menos un viaje en bicicleta diariamente.
El error de una muestra viene dado por la siguiente expresión:
(3.1)
Donde
, nivel de confianza asignado al experimento
, proporción de la población que posee la característica a estudiar
N, tamaño de la población
n, tamaño de la muestra seleccionada
111
Se selecciona un nivel de confianza de un 95% representado por la
constante igual a 1,96. Además se sabe que de la población de 6,47 millones de
usuarios (cada persona realiza 2,78 viajes), el cuatro por ciento corresponde a
bicicletas. Finalmente, la muestra considera a 96 usuarios que aportaron con sus datos.
De esta manera, se sabe que la muestra posee un error muestral de un 11% para una
representatividad del 95%. Este resultado demuestra que el margen de error es alto en
comparación a la Encuesta Origen Destino (2%) debido a que el número de usuarios
considerados es bajo en comparación al universo total de ciclistas. Actualmente se
están produciendo un mayor número de dispositivos para disminuir este margen de
error. Se estima que para obtener una muestra comparativa de igual o mejor calidad
que la EOD se necesita registrar los recorridos de al menos 2400 usuarios distribuidos
por distintos sectores de la ciudad.
112
3.2 Estadísticas generales de demanda
De un total de 96 usuarios, usando el dispositivo durante una semana, se
generaron 359 recorridos. La suma de los recorridos totaliza 166 horas de viajes y
2649 kilómetros recorridos. A continuación se profundiza en las estadísticas y
resultados de los datos obtenidos.
La Figura 3.1 muestra un histograma de la cantidad de kilómetros
recorridos por viaje. La mayor cantidad de viajes (12,7 por ciento) corresponde a
trayectos de entre 8 y 9 kilómetros. Además, el 90.9 por ciento de los viajes
corresponden a recorridos de distancias menores o iguales a 13 kilómetros.
Figura 3.1: Histograma de kilómetros por viaje
113
El resultado anterior revela que la mayoría de los usuarios prefieren los
viajes cortos. Este tipo de viajes generalmente son dentro de la misma comuna, lo que
coincide con la Encuesta Origen Destino donde se detalla que “el 48% de los viajes
son intrasectoriales” (Encuesta Origen Destino STGO, 2012, p. 44).
La Figura 3.2 muestra un histograma del tiempo (en minutos) que toma
cada viaje. La mayor cantidad de viajes (16,6 por ciento) corresponde a trayectos de
entre 15 a 20 minutos. Por otro lado, el 90.1 por ciento de los viajes corresponden a
recorridos que toman menos de 60 minutos.
Figura 3.2: Histograma de minutos por viaje
114
Finalmente, la Figura 3.3 muestra un histograma de la velocidad
promedio de cada viaje. La velocidad predominante (16,9 por ciento) va entre los 18
a 21 kilómetros por hora. Además, el 87 por ciento de los viajes muestra una
velocidad inferior o igual a 24 kilómetros por hora.
Figura 3.3: Histograma de velocidad promedio por viaje
Los tres histogramas presentados contribuyen a la elaboración de un
modelo de usuario (ciclista) más detallado que el que se conoce hoy a través de la
Encuesta Origen Destino. Con estos datos es posible evaluar distintas estrategias en
el área de planificación al momento de incentivar el uso de la bicicleta. Como por
ejemplo, avaluar una combinación Metro–bicicleta o bus-bicicleta que permita atraer
115
a los usuarios que realizan viajes mayores a 10 kilómetros y que actualmente hacen
uso del auto u otro método de transporte motorizado privado.
3.3 Mapas de Calor
Los mapas de calor permiten una visualización general del
comportamiento de los ciclistas así como un entendimiento de la demanda de las
rutas en la ciudad. El mapa de calor de los 359 recorridos se presenta en la Figura
3.4.
Figura 3.4: Mapa de calor general
116
El mapa de calor es representativo de la muestra a pesar de no ser
representativo del universo total de ciclistas de la ciudad (como se discute en la
sección 3.1). Durante la etapa del testeo no todos los sectores de la ciudad se
estudiaron de la misma forma por razones de tiempo y recurso. En etapas futuras de
esta investigación se debe considerar una cantidad de usuarios por sector
proporcional a la cantidad de población ciclista que registra cada sector. La tabla 3.1
muestra la participación de cada sector de la ciudad (según la Encuesta Origen
Destino) y la cantidad de voluntarios que debiese incluir el estudio para poseer un
95% de representatividad junto a un 2% de error.
Sector Ciclistas (%) Voluntarios
Norte 13,3 318
Poniente 20,3 487
Oriente 19,2 461
Centro 5,3 126
Sur 19,4 466
Sur-Oriente 17,6 422
Ext Sur-Poniente 5 120
Total 100 2400
Tabla 3.1: Voluntarios por sector
Sin considerar la representatividad de la muestra es posible estudiar el
comportamiento de los usuarios que si ocuparon el dispositivo. Por ejemplo, según la
Figura 3.5 dentro del universo de ciclistas voluntarios se observa que existe una alta
117
preferencia por las calles Av. Andrés Bello, Pocuro, Bilbao y Vicuña Mackenna por
sobre el resto.
Figura 3.5: Mapa de calor zonas con mayor flujo
En el mapa de la Figura 3.5 es posible distinguir incluso parte de lo que
es el Cerro San Cristóbal siendo frecuentado por ciclistas realizando recorridos de
forma recreativa.
118
De igual forma se muestra la Figura 3.6 el mapa de calor correspondiente
al Campus San Joaquín de la Universidad Católica. Este mapa muestra que la
entrada con mayor flujo es la que enfrenta Vicuña Mackenna.
Un punto interesante de destacar de la Figura 3.6 son las acumulaciones
de puntos representadas como cúmulos rojos. Esta figura evidencia el olvido del
usuario de apagar el dispositivo alfa (registrando información indeseada). Esto fue
mejorado en el dispositivo beta donde el dispositivo se prende y apaga de manera
automática. La locación con mayor presencia de cúmulos rojos es el estacionamiento
de bicicletas del edificio CITEDUC.
Figura 3.6: Mapa de calor campus San Joaquín UC
119
Finalmente, se muestra el mapa de calor de la Figura 3.7. En este mapa
de calor se representan los viajes realizados en días hábiles en color violeta y los
viajes realizados en fines de semana en verde. Es evidente que el ciclista elige
distintas rutas los fines de semana en comparación a los días hábiles. Un estudio de
los viajes en verde revela que la mayoría fueron realizados en día domingo
coincidiendo con la actividad social “Ciclorecreovía”.
Figura 3.7: Mapa de calor dividido por días
120
3.4 Problemas y mejoras al dispositivo
El dispositivo beta logró resolver el problema relacionado al olvido por
parte del usuario de prender-apagar el dispositivo. Por otro lado, dotar al dispositivo
de la capacidad de conectarse a Internet agilizó la recepción de información y desligó
al usuario de la tarea de estar constantemente cargando los datos a la plataforma.
El módulo WiFi posee algunos bugs en su primera versión. Además, el
módulo WiFi limita la comunicación serial a un máximo de 9600 bits/segundo entre
microcontrolador y módulo lo que en versiones recientes se ha incrementado a 115200
bits/segundo. Se propone ocupar chips WiFi que posean comunicación SPI de modo
de acelerar la comunicación entre ambos componentes. Un buen reemplazo sería el
Chip CC3000 producido por la compañía Texas Instruments.
Desde el punto de vista del microcontrolador, ocupar dos
microcontroladores además de ineficiente, es costoso. Una alternativa a lo anterior es
ocupar una CPU de mayor memoria Flash y RAM como lo es la familia de
procesadores ARM Cortex. Además se hace necesario trabajar en un ambiente de
tiempo real como RTOS. Este tipo de ambiente permite hacer multithreads y asignar
el hardware necesario a cada tarea.
Actualmente, con el financiamiento del Centro de Desarrollo Urbano
Sustentable se continuará mejorando el prototipo con el fin de producir una unidad
escalable y de bajo costo. Las unidades producidas irán destinadas a un plan piloto a
mediana escala que pretende medir y modelar a los ciclistas de la comuna de La
Granja.
121
3.5 Problemas y mejoras a la plataforma
La plataforma puede variar con mayor flexibilidad que el hardware.
Algunas veces los voluntarios piden que se les envíe una visualización de sus
recorridos y el método explorado en el capítulo dos puede resultar tedioso en
comparación a un método on-line y automatizado ofrecido por la misma plataforma.
De esta manera e incorporando el feedback de los usuarios se está trabajando en
mejorar la plataforma desde la funcionalidad para así ofrecer a los usuarios la
posibilidad de explorar sus recorridos y crear sus propios mapas de calor.
Actualmente, la plataforma se encuentra alojada en los servidores de la
empresa Heroku. Si en un futuro se desea escalar la plataforma debido a un mayor
número de dispositivos o la inclusión de distintos features como cálculo de variables o
visualizaciones en tiempo real, se hará necesario migrar la plataforma a un distinto
proveedor o pagar a Heroku por recursos adicionales. El departamento de Transporte
de la Universidad Católica cuenta con servidores dedicados destinados a distintas
aplicaciones, es una posibilidad aprovechar las sinergias construidas durante esta
investigación con el departamento de Transporte y el CEDEUS para explorar la
migración de la plataforma a sus instalaciones.
Por otro lado, la aplicación web (comunicación con dispositivo beta)
carece de un método de seguridad. Generalmente en el mundo de las aplicaciones, se
exige la presencia de credenciales conocidas como tokens y cada vez que se realiza
una consulta al servidor, se exige la presencia de un token para confirmar la
autenticidad. Como siguiente iteración a la aplicación será construir un método de
comunicación entre el dipositivo y la plataforma haciendo uso de una API o el
protocolo de comunicación máquina a máquina MQTT.
122
3.6 Recepción del público
Al inicio de esta investigación uno de los puntos más difíciles con respecto
a la implementación fue conseguir voluntarios. Con el fin de revertir esta situación se
habilitó una página web llamada www.stgo2020.cl. En esta página se explica cómo el
aportar con datos de trayectorias generadas al andar en bicicleta puede ayudar a las
autoridades a tomar mejores decisiones con respecto a las condiciones e
infraestructura dedicada a la bicicleta. El sitio web ayudó a capturar más de 600 datos
de voluntarios queriendo participar del proyecto. La promesa del sitio es ayudar a
construir las ciclovías de Santiago que se construyan de acá al año 2020 usando los
datos de voluntarios como fuente de información. En Marzo del año 2016 se presentó
a la Secretaria de Transporte (SECTRA) los datos obtenidos y cómo de forma
conjunta se pueden mejorar las condiciones del ciclista en la ciudad capital.
Durante el desarrollo de esta investigación se expuso en distintas
ponencias y concursos destinados al mundo de la bicicleta, datos abiertos y el
emprendimiento. En el mes de Septiembre del año 2015 se participó en la conferencia
de datos abiertos organizada por el Gobierno de Transparencia obteniendo el premio
de mejor aplicación promoviendo la apertura de datos. Durante el mismo periodo se
participó en el concurso GeekCamp organizado por la Incubadora UC resultando
como ganador bajo el nombre de BikeData junto a otros 18 proyectos. En Octubre del
mismo año se participa en el concurso BRAIN UC organizado por la escuela de
ingeniería de la Pontificia Universidad Católica y el centro de innovación Anacleto
Angelini, llegando a la ronda final junto a otros 9 finalistas. En Abril del año 2016 se
presentó en el Foro Mundial de la Bicicleta, mostrando los avances y resultados
obtenidos en esta investigación. Municipalidades de Colombia, Ecuador, Perú y
Argentina se mostraron interesadas en implementar sistemas rastreadores de bicicletas
con el fin de mejorar su infraestructura destinada al ciclista.
123
BIBLIOGRAFIA
1. Strava (2016). Tasa de Muestreo de Smartphones para app Strava. Obtenido:
Enero del 2016. URL: https://strava.zendesk.com/entries/20950148-Segment
Matching-Issues
2. Marc Barros (2013). Here`s How to make Hardware Startups more than just a
fad. Obtenido: Enero 2015. URL: http://www.wired.com/2013/09/the-hardware-
revolution-will-not-be-hyped-heres-what-itll-take-to-make-this-really-happen/
3. Society of Robots (2014). Mercury Tilt Switch Tutorial. Obtenido: Enero 2015.
URL: http://www.societyofrobots.com/sensors_mercury_switch.shtml
4. Portal Arduino (2008). SD Library for Arduino. Obtenido: Enero 2015.
URL: https://www.arduino.cc/en/Reference/SD
5. Nurdspace (2015). ESP8266 Introduction and guidance. Obtenido: Enero 2015.
URL: https://nurdspace.nl/ESP8266
6. Vincent Cruz (2013). Arduino DataFlash Library. Obtenido: Enero 2015.
URL: https://github.com/BlockoS/arduino-dataflash
7. Adafruit Industries (2015). Li-Ion & LiPoly Batterie. Obtenido: Enero 2015.
URL: https://learn.adafruit.com/li-ion-and-lipoly-batteries
8. Quectel Wireless Module Expert Corporation (2013). L80 Hardware Design
GPS Module Series. Shanghai, China.
9. Atmel Corportation (2004). 16-megabit 2.5-volt Dataflash. California, EEUU.
10. Michochip Technology Inc. (2005). Miniature Single Cell, Fully Integrated Li-
ion, Li-Polymer Charge Management Controller. Arizona, EEUU.
11. Texas Instruments (2012). TI SImpleLink CC3000 Module – Wi-Fi 802.11b/g
Network Processor. Texas, EEUU.
124
12. Universidad Alberto Hurtado, Observatorio Social. (2015). Actualización y
recolección de información del sistema de transporte urbano, IX Etapa:
Encuesta Origen Destino Santiago 2012. Encuesta origen destino de viajes 2012.
Santiago, Chile.
13. Fritz Scheuren (2005). What is a Margin of Error?. Washington D.C, EEUU
14. Michael Volkmer (2014). Radwende, The Bike Lanes a city should have.
Obtenido: Abril, 2015. URL: https://www.radwende.de/en/
15. Tomás Marín (2015). El transporte en bicicleta de las “ciudades inteligentes”.
Obtenido: Julio, 2015. URL: http://thesmartcitizenproject.cl/?p=453
16. Martín Tironi (2013). ¿Smart Cities o Smart Citizens? Obtenido: Julio, 2015.
URL: http://www.plataformaurbana.cl/archive/2013/12/04/%C2%BFsmart-
cities-o-smart-citizens-reflexiones-desde-una-perspectiva-socio-tecnica/
17. Subsecretaría de Transporte (2013). Plan Maestro de transporte de Santiago
2025. Santiago, Chile.
18. Sociedad de Asesorías Profesionales de Urbanismo y Territorio Ltda (2013).
Análisis del comportamiento de la demanda de infraestructura especializada
para bicicletas. Santiago, Chile.
19. Banco Interamericano de Desarrollo (2015). Ciclo-inclusión en América Latina y
el Caribe: Guía para impulsar el uso de la bicicleta. Washington D.C, EEUU.
20. El Definido (2015). ¡Que las bicicletas hablen! El sistema que ayuda a
planificar ciclovías en base a tus recorridos. Obtenido: Marzo 2015.
URL: http://www.eldefinido.cl/actualidad/pais/4897/Que-las-bicicletas-hablen-
El-sistema-que-ayuda-a-planificar-ciclovias-en-base-a-tus-recorridos/
21. Ministerio del Medio Ambiente, Gobierno de Chile (2015). Transporte: El
epicentro de las bicicletas. Obtenido: Agosto 2015. URL:
http://portal.mma.gob.cl/transporte-el-epicentro-de-las-bicicletas/
22. Arriba e la Chancha (2014). Resultados 7ª Medición de Tiempos de Viaje en
Santiago. Obtenido: Enero del 2016. URL: http://www.arribaelachancha.cl/
125
23. Mapbox (2010). CartoCSS & Tilemill Information. Obtenido: Enero 2015.
URL: https://www.mapbox.com/tilemill/docs/manual/carto/
24. Mapbox (2010). API documentation for Mapbox. Obtenido: Enero 2015.
URL: https://www.mapbox.com/mapbox.js/api/v2.4.0/
25. Ryan Bates (2007). RailCasts, Ruby on Rails Screencasts. Obtenido: Enero 2015.
URL: http://railscasts.com/
26. Salesforce Company (2007). Getting Startted with Rails 4.x on Heroku.
Obtenido: Diciembre 2014. URL: http://devcenter.heroku.com/articles/getting-
started-with-rails4
27. Salesforce Company (2007). Heroku Postgres. Obtenido: Diciembre 2014.
URL: http://devcenter.heroku.com/articles/getting-started-with-rails4
126
A N E X O S
ANEXO A: Instrucciones ESP8266
ANEXO B: Esquemático Prototipo Alfa
ANEXO C: Esquemático Prototipo Beta