Localizador GPS para coche con integración de mapas thinger.io
Componentes y suministros
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 2 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Herramientas y máquinas necesarias
|
Aplicaciones y servicios en línea
|
Acerca de este proyecto
Este proyecto comenzó como una simple "idea de rastreador GPS" y resultó ser un "rastreador GPS multipropósito". Como mi primer proyecto, la curva de aprendizaje ha sido empinada y, por lo tanto, siempre estoy abierto a comentarios, comentarios y mejoras en el diseño. :)
El rastreador está diseñado para colocarse en mi automóvil y tiene las siguientes características:
- Realice un seguimiento de las coordenadas GPS y publique la última ubicación conocida en el panel de control de la nube de IoT de thinger.io cada 2 minutos (que se muestra en un mapa). Publicar en thinger.io con solicitudes HTTP POST.
- Responde a los comandos de SMS y devuelve un enlace de mapa de Google a la ubicación actual o la última ubicación conocida (última ubicación conocida si no hay una ubicación actual disponible).
- Enviar una notificación por SMS cada XX kilómetros (la idea es que el rastreador me recuerde vaciar mi tanque de recolección de aceite cada 4000 km). Esto funciona como un "odómetro" de software personalizable.
Durante este proyecto, rápidamente me di cuenta de lo "limitado" que es Arduino en términos de memoria disponible y tuve que aprender técnicas para reducir la sobrecarga y hacer un código eficiente (al menos lo he intentado). También he utilizado bibliotecas ligeras para que quepan todo en el chip y la RAM disponible.
Los componentes utilizados son los siguientes (como en la lista de componentes):
- Dispositivo GPS NEO-6M. Este parece ser un dispositivo GPS muy popular disponible a bajo precio en Ebay y similares. La comunicación con el GPS será en serie por hardware.
- Antena GPS. Cualquier compatible servirá, sin embargo, encontré que los más baratos de Ebay no funcionaban tan bien, es decir, mala recepción / baja cantidad de satélites. Quizás tuve mala suerte con la primera antena, pero tenía que conseguir otra de mejor calidad para una recepción estable.
- Placa de desarrollo SIM900 para conectividad GSM y GPRS. Este proyecto también debería funcionar con SIM800 y módulos compatibles, sin embargo, no hay garantías. La comunicación con SIM900 será en serie por software.
- Arduino Leonardo Junta. He utilizado la placa Leonardo para tener una línea serie de hardware dedicada ya que necesitamos dos líneas seriales. Si bien también es posible usar una placa UNO normal, debe desconectar el GPS para descargar el software y tampoco tendrá un monitor en serie para la depuración. Necesitamos dos líneas seriales (una para GPS y otra para la placa SIM900); una serie de software y una serie de hardware.
- Lector de tarjetas SD (he usado el lector de tarjetas Adafruit que es compatible con 5V (facilité la conexión al cabezal SPI de 5V). Otros módulos más baratos podrían funcionar igual de bien. La tarjeta micro SD se usará para almacenar la distancia recorrida.
Advertencia: asegúrese de que su lector de tarjetas SD admita un suministro de 5V si sigue mis esquemas, muchos lectores de tarjetas SD solo usan 3.3V. El uso de niveles de voltaje incorrectos probablemente dañará los componentes electrónicos. La comunicación con el lector de tarjetas SD será una interfaz SPI.
- LED y resistencias para hacer circuitos indicadores de estado (LED de encendido y bloqueo de GPS).
- Tarjeta SIM con datos.
- También diseñé un gabinete imprimible en 3D con archivos STL adjuntos que se pueden imprimir directamente en una impresora 3D.
Primero necesitamos instalar las bibliotecas necesarias. He utilizado las siguientes bibliotecas para este proyecto:
- NeoGPS para rastreo y decodificación GPS. Se puede instalar directamente desde el administrador de la biblioteca en Arduino IDE. Más información:https://github.com/SlashDevin/NeoGPS
- Hora biblioteca (utilizada para la conversión de zona horaria UTC):https://github.com/PaulStoffregen/Time
- PetitFS para lectura / escritura en la tarjeta SD:https://github.com/greiman/PetitFS Biblioteca Lightweight SD FAT.
¿Por qué no utilizar la biblioteca disponible para Arduino por thinger.io?
Aunque la biblioteca proporcionada por thinger.io es muy fácil de usar y simplificaría las cosas significativamente, por no decir que ya está integrada en el IDE, consume casi el 80% del almacenamiento en Arduino Leo, dejando poco o ningún espacio para el código restante. Así que es demasiado grande para este proyecto y tendremos que hacerlo por las malas. Para comunicarnos con la nube thinger.io usaremos solicitudes HTTP POST.
SMS comandos
Los comandos disponibles en SMS son los siguientes (todos en mayúsculas). Estos son los comandos admitidos en el código proporcionado; puede agregar / eliminar comandos para su propio proyecto / requisitos:
- "POS" devuelve las coordenadas con el enlace de Google Maps, si las coordenadas están disponibles. De lo contrario, se devuelve la última ubicación conocida.
- "GETKM" devuelve la distancia actual desde el último "reinicio".
- "RESETKM" establece el contador de distancia en 0 (restablecer el odómetro).
Configuración de NeoGPS
Usamos la biblioteca NeoGPS para el rendimiento y el uso de recursos sobre alternativas como TinyGPS ++. Consume muy poca RAM y es necesaria; de lo contrario, recibiremos advertencias de poca memoria y estabilidad.
Una vez instalada la biblioteca, modifique el archivo GPSPort.h en la ruta de instalación de la biblioteca (el ejemplo dado es para OS X; para Windows, encontrará la biblioteca en una ubicación diferente)
Reemplaza todo el contenido de GPSPort.h por lo siguiente:
#ifndef GPSport_h # define GPSport_h # define gpsPort Serial1 # define GPS_PORT_NAME "Serial1" #define DEBUG_PORT Serial # endif
Este archivo contiene definiciones utilizadas por la biblioteca NeoGPS. Si está utilizando una placa Arduino diferente, aquí es donde define la línea serial al receptor GPS, p. Ej. "Serial2", "Serial3" para Arduino MEGA.
Notas sobre la precisión
Cabe señalar que el GPS no es la forma más precisa de medir y acumular distancia, ya que la posición se desviará ligeramente incluso cuando esté parado. Puede probar esto permaneciendo quieto en el mismo lugar y observar que las coordenadas GPS serán diferentes para cada lectura. Para esta aplicación, la precisión es menos importante y, por lo tanto, las desviaciones más pequeñas están bien.
Sin embargo, he intentado tener en cuenta las pequeñas desviaciones en las coordenadas y el software solo agrega distancia para movimientos de más de 10 m (todos los movimientos por debajo de 10 m se asumen estacionarios) durante 15 segundos.
También tenga en cuenta que la distancia se calcula en línea recta, mientras que la distancia real que recorre el automóvil depende de la carretera, las curvas, etc.He establecido la frecuencia de muestreo en 15 segundos, sin embargo, puede reducirla si desea una mayor precisión.
Configuración de PetitFS
Esta biblioteca es una biblioteca superligera para lectura / escritura en tarjetas SD con formato FAT. Me tomó un tiempo descubrir cómo funciona esto, ya que la documentación es prácticamente inexistente y algunos lugares incluso están equivocados / desactualizados. El código de ejemplo de la biblioteca proporcionado ni siquiera se compilará. Viene con un lote de restricciones (a diferencia de una biblioteca "normal" como la biblioteca SD de Arduino o SDFat):
- No se puede crear el archivo. Solo se puede escribir en archivos existentes.
- No se puede expandir el tamaño del archivo.
- No se puede actualizar la marca de tiempo del archivo.
- No se pueden agregar datos al archivo (reescribe el archivo cada vez).
- Solo se abre un archivo a la vez.
¿Por qué utilizar una biblioteca pequeña y limitada con muchas peculiaridades?
Tamaño, básicamente. He probado algunas bibliotecas, incluidas Arduino SD Library, SDFat y también fat16lib. Todos son demasiado grandes para que todo el código quepa en el chip, por lo que para no eliminar la funcionalidad utilicé esta biblioteca (la biblioteca estándar de Arduino SD ocupa aproximadamente un 12% más de espacio). Incluso con todas las peculiaridades y limitaciones, todavía proporciona lo que necesitamos para esta aplicación:lectura y escritura simple de un valor único para el almacenamiento.
Si no usa todo el código y hay suficiente espacio para agregar un poco más, es mucho más fácil trabajar con bibliotecas como la biblioteca SD estándar.
Abra el archivo pffArduino.h de la carpeta de la biblioteca PetitFS. Cambiar el SD_CS_PIN a 10. Este es el pin SS que se usa para comunicarse con la tarjeta SD con SPI.
Abra el archivo pffconf.h de la carpeta de la biblioteca. Desactivar las siguientes opciones cambiando el valor establecido de 1 a 0:
- _USE_DIR
- _USE_LSEEK
- _FS_FAT12
- _FS_FAT16
Al deshabilitar estas opciones, el programa compilado ocupa menos espacio, que es necesario; El boceto final toma aprox. 96% de almacenamiento.
En la primera importación de la biblioteca, obtendrá un error de compilación que * puede * ignorarse (en la segunda compilación no se muestra el error, todavía no entiendo por qué). Sin embargo, si desea arreglar esto (reaparecerá cada vez que inicie Arduino IDE -> compilar) agregue el parámetro de retorno de función faltante "FRESULT" como se muestra en la captura de pantalla anterior. Esto está en el archivo pff.cpp en la carpeta de la biblioteca.
He hecho todo lo posible para averiguar cómo funciona esta biblioteca y, aunque tengo todo en funcionamiento, estoy bastante seguro de que las cosas también se pueden mejorar. Si encuentra errores o mejoras en las rutinas que he escrito, ¡no dude en compartirlo! Me gustaría mucho aprender y desarrollar más experiencia.
Prepare la tarjeta SD
He utilizado una tarjeta Micro SD para este proyecto. Dado que la biblioteca no puede crear los archivos por sí misma, es importante crear el archivo "dist.txt" y "settings.txt" en la tarjeta antes de usarla. Recomiendo copiar los archivos adjuntos "dist.txt" y "settings.txt" archivo de esta página del proyecto, ya que estos archivos ya tienen el formato correcto y funcionan (la biblioteca es muy exigente con el formato y el contenido del texto).
Antes de colocar el archivo en la tarjeta Micro SD, asegúrese de formatear la tarjeta correctamente (como FAT32 ). Recomiendo usar el "Formateador de tarjetas SD" oficial de SD Association:https://www.sdcard.org/downloads/formatter/.
Asegurarse de que la tarjeta SD funcione (leer / escribir en el archivo correctamente)
La biblioteca PetitFS es muy exigente con los archivos de entrada. Si arranca el dispositivo y no se muestra ninguna salida en el monitor serial (solo en blanco), lo más probable es que esté atascado en el "bucle" donde intenta leer el archivo de la tarjeta pero no puede por alguna razón (función initializeSD ()). He tenido innumerables archivos de texto donde, por alguna razón, no ha podido leer, por lo tanto, he incluido los archivos de texto referenciados que he usado que funcionan. Coloque estas referencias archivos en la tarjeta SD y debería poder leer y escribir correctamente.
Otra opción puede ser completar el archivo de texto con un número mayor que el de su escritura. No lo he probado, pero dado que la biblioteca no puede expandir el tamaño del archivo, asumo que esto podría ser un problema.
PetitFS escribirá la longitud completa de la matriz de caracteres en el archivo, por lo que verá espacios vacíos delante del número real (a menos que el número sea lo suficientemente grande para llenar la matriz; la longitud de la "matriz" se define en el código). Estos espacios deben mantenerse al realizar cambios en el archivo; dado que PetitFS no puede realizar cambios en el tamaño del archivo, puede causar problemas si se cambia la cantidad de caracteres.
Configure el archivo "dist.txt" en "0" si desea que el odómetro comience en "0", o cualquier otro número para que sea más fácil verificar que funciona, p. Ej. enviando el comando "GETKM" para verificar la respuesta SMS.
En "settings.txt", estableces la distancia de activación de la notificación, la distancia a la que el odómetro activa el SMS de notificación (en metros).
Prepare la placa SIM900
Se deben configurar algunas cosas en la placa SIM900 antes de que podamos usarla. Para obtener más detalles, hay un gran recurso en https://lastminuteengineers.com/sim900-gsm-shield-arduino-tutorial/ para la configuración de esta placa.
Fuente de energía
La placa Arduino no es capaz de suministrar suficiente energía, por lo que debemos utilizar una fuente de alimentación externa. Como los picos pueden consumir hasta 2 A, asegúrese de utilizar una fuente de alimentación que pueda entregar al menos 2 A a 5 V-9 V CC; utiliza el conector de barril de 5,5 mm.
Selector de fuente de alimentación
Junto a la toma de CC hay un selector de fuente de alimentación . Para utilizar una fuente de alimentación externa, mueva el control deslizante como se muestra en la imagen de arriba.
Selector de serie
Configura la placa para que use Serie de software alineando los puentes como se muestra arriba.
Activador de software
En lugar de presionar manualmente la tecla de encendido cada vez, puede encender / apagar el SIM900 en el software. Para ello, se debe soldar el puente denominado R13. Luego, la placa se enciende conectando el pin # 9 del SIM900 al pin # 7 de Arduino (como se muestra en los esquemas).
Si se mantiene la función "encendido manual", se puede eliminar la función "SIM900power ()" en el código.
Eliminar bloqueo de PIN de la tarjeta SIM
Asegúrate de eliminar el bloqueo de PIN en la tarjeta SIM antes de su uso. Esto se puede hacer insertándolo en cualquier teléfono normal y quitando el pin de bloqueo del menú de configuración correspondiente.
También tenga en cuenta que el módulo SIM900 en los esquemas puede verse diferente a la placa real, sin embargo, la disposición de los pines es correcta, que es la parte más importante.
Versión de firmware SIM900 (¡Importante!)
Es muy importante tener la versión correcta del firmware cargada en el chip. Esto se debe a que uno de los comandos para configurar correctamente el encabezado HTTP POST no es compatible hasta la versión B10 del firmware. Esto significa que debe tener al menos la versión B10 o superior para que funcione la comunicación http. Específicamente, con una versión de firmware más baja, no podrá establecer "Tipo de contenido" en el encabezado http. Si el tipo de contenido no se establece en "application / json" en la solicitud de publicación, el servidor lo rechazará.
Para verificar su versión de firmware, use el siguiente comando AT:
AT + CGMR
El chip SIM900 le dará la versión actual del firmware en la consola de salida. Ponga lo siguiente al final de la sección setup () para imprimir la versión del firmware al inicio:
SIM900.println (F ("AT + CGMR"));
En mi caso, mostraría esto (antes de actualizar):
Revisión:1137B01SIM900M64_ST_AM
Esta era la versión de firmware más antigua posible para este chip ("B01"), por lo que actualicé a la versión B10: 1137B10SIM900M64_ST . Los firmwares más nuevos también deberían funcionar.
No cubriré cómo actualizar el firmware en esta guía, ya hay una excelente guía de cómo hacer esto:Actualización de firmware SIM900 - ACOPTEX (aunque es un proceso algo doloroso).
No sé si este será el caso de otros chips como el SIM800, sin embargo, al ser un chip más nuevo, diría que es más probable que ya esté instalado allí.
Ajustes de código
Para adaptar el código a su propio proyecto, se necesitan algunos ajustes:
- Cambie la información de APN (proveedor de red).
- Modifique la URL thinger.io para que coincida con la suya (la URL vincula la solicitud de actualización a su propio "depósito" con token de acceso). Esto se trata en el capítulo "integración de thinger.io".
- Establezca la zona horaria correcta.
- Establecer la distancia de activación para la notificación por SMS
- Establecer (o deshabilitar) el texto de notificación por SMS.
- Establecer el número de teléfono predeterminado para la notificación.
Proveedor de APN
void connectGPRS () {... SIM900.println (F ("AT + SAPBR =3,1, \" APN \ ", \" TeleXXX \ "")); retraso (1000); updateSIM900 (); ...
Bajo connectGPRS () función encontrará el nombre APN proporcionado por su proveedor de red, que se muestra arriba como "TeleXXX". Reemplace esto con su propio nombre APN.
ATOKAT + CMGF =1OKAT + CNMI =1,2,0,0,0OKAT + SAPBR =3,1, "CONTYPE", "GPRS" OKAT + SAPBR =3,1, "APN", " TeleXXX "OKAT + SAPBR =1,1OKAT + SAPBR =2,1 + SAPBR:1,1," 36.57.240.233 "OK
Arriba:salida de la función connectGPRS () cuando la conexión está funcionando. Todos los comandos deben devolver el estado "OK".
Zona horaria
#define UTC_OFFSET 1 // establece el desplazamiento de la zona horaria, es decir, 1 =UTC + 1
En la sección "definir", establezca la zona horaria de acuerdo con sus requisitos. El código está configurado en UTC + 1 .
Notificación por SMS
He configurado una notificación cada 4000 km para vaciar mi tanque de recogida de aceite. Como me doy cuenta de que la mayoría de las personas no tienen un tanque de recolección de aceite, esta notificación debe cambiarse a lo que desee (o deshabilitarse por completo).
void loop () {... // envía una notificación por SMS si la distancia total supera los 4000 km if (totalDistance> triggerDistance) {char sms_msg [160]; char distanceTotalMsg [10]; itoa ((totalDistance / 1000), distanceTotalMsg, 10); sprintf (sms_msg, "¡Tanque de captura vacío! Distancia actual:% skm", distanceTotalMsg); textMessage =""; totalDistance =0; // establece el número de teléfono predeterminado para activar el número de notificación =DEFAULT_NUMBER; sendSMS (sms_msg); } ...}
Arriba:sección de código que activa la notificación (dentro del bucle principal ()).
Comente / elimine esta sección si no desea que se activen notificaciones. Alternativamente, cambie el texto por algo útil.
La notificación se activa una vez que el "odómetro" (distancia acumulada) alcanza la distancia configurada en el archivo "settings.txt".
Número de teléfono predeterminado
Este es el número de teléfono al que se envía la notificación activada (ya que la notificación no tiene un número de "remitente" al que responder)
// número de teléfono para la notificación activada # define DEFAULT_NUMBER "+4712345678"
Espere la conexión en serie
También es una buena idea descomentar la siguiente línea en el código. Esto hace que la placa Arduino espere a que la conexión en serie se active, es decir, el monitor en serie para la depuración. De esta manera, no se pierde ningún mensaje de depuración al comienzo del código antes de que la línea serial se active.
Recuerde eliminar / comentar la línea antes de encender el Arduino desde fuentes de energía externas, ya que de lo contrario se detendrá en un bucle infinito hasta que se conecte a una PC.
// while (! Serial); // espera a que se conecte el puerto serie, para ATmega32u4 (Leonardo)
Integración de Thinger.io
No entraré en detalles sobre cómo configurar thinger.io ya que es bastante sencillo; debe crear una cuenta y un "depósito" para recibir los datos a través de su sitio web, y un "dispositivo" al que nos conectaremos. Un "depósito" es la base de datos para recibir datos. El "dispositivo" es el punto de conexión de nuestro código donde decidimos qué hacer con los datos (en nuestro caso, rellenar la base de datos del "depósito").
Cree un "depósito" como se muestra arriba con su propio nombre y descripción.
Ahora, siga adelante y cree un "Dispositivo HTTP" como se describe en la documentación oficial:https://docs.thinger.io/quick-sart/devices/http-devices.
Utilice un corto dispositivo nombre . Como el nombre del dispositivo es parte del algoritmo que genera la clave de autorización, descubrí que un nombre de dispositivo más largo también genera una clave de autorización más larga. ¿El problema? La clave de autorización rápidamente se hizo más larga que el búfer de 256 caracteres utilizado para enviar la cadena desde Arduino. Probablemente haya algunas formas mejores de solucionar esto, pero encontré el enfoque más fácil para mantener el nombre del dispositivo corto y evitar el problema.
En la devolución de llamada del dispositivo > configuración sección asegúrese de que la configuración de "escribir depósito" apunte al depósito creado anteriormente. Esto le dice al "dispositivo" que escriba los datos entrantes en nuestra base de datos.
En la devolución de llamada del dispositivo > descripción general sección anote el método URL y encabezado de autorización (cadena larga sin la palabra clave "Portador").
Para enviar datos a un thinger.io usamos una "URL de autorización" en la solicitud HTTP POST. Luego, debe reemplazar la URL y la clave de autorización en el código por las suyas.
En postDataThinger () función encontrará la llamada (clave de autorización real codificada):
SIM900.println (F ("AT + HTTPPARA =\" URL \ ", \" http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization =eyJhbGciOiJIUzI1NiIsInR5cdfkjowiuerdf.sdfsdf.wekrjciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ \ "> "));
Luego tienes que reemplazar la URL y autorización clave en el código con el suyo, generado siguiendo las instrucciones en el enlace proporcionado arriba.
http://backend.thinger.io / ...
De forma predeterminada, la URL de autorización generada será https . El SIM900 no asistencia SSL (al menos no lo he conseguido), así que asegúrese de cambiar "http s :// "a" http:// ". La API más delgada también admite conexiones no SSL. Esto es muy importante. Si mantiene" https ", no funcionará. Cuando todo funcione, el monitor en serie debería dar un" 200 - Aceptar "responder al transmitir la solicitud de publicación http.
Después del comando AT "AT + HTTPACTION =1" (enviar solicitud HTTP POST) debería recibir una respuesta como esta en el monitor serial:
+ HTTPACTION:1,200,0
Si recibe una respuesta "400 - solicitud incorrecta" o similar ...
+ HTTPACTION:0,400,51
... lo más probable es que haya algún problema con la URL, p. ej. "https" en lugar de "http", sintaxis incorrecta de la "clave de autorización", etc. Cuando recibe un mensaje de "200 - OK", los datos deben aparecer en el segmento más delgado, como se muestra a continuación. También puede recibir un 400 - "solicitud incorrecta" si no tiene el firmware correcto como se mencionó anteriormente.
Arriba hay una vista del depósito una vez que llegan los datos (codificados por razones de privacidad). El contenido (columnas de datos) se establece mediante la sintaxis de solicitud HTTP POST en el código, no se necesita configuración en thinger.io.
A continuación se muestra una salida en serie de la solicitud HTTP POST, como debería verse cuando todo funciona. + HTTPACTION:1, 200, 0 indica que la actualización se realizó correctamente.
AT + HTTPINITOKAT + HTTPPARA ="CID", 1OKAT + HTTPPARA ="URL", "OKAT + HTTPPARA =" CONTENT "," application / json "OKAT + HTTPDATA =84,10000DOWNLOADOKAT + HTTPACTION =1OK + HTTPACTION:1,200,0AT + HTTPTERMOK
El panel luego se puede configurar fácilmente en un tamaño más delgado con el widget de mapas utilizando el depósito como fuente de datos.
¿Más datos para diluir?
¿Quiere enviar más datos que longitud, latitud y fecha / hora? Simplemente agregue más campos de datos a la solicitud http como se muestra a continuación.
El formato es {"nombre de campo1":campo1, "nombre de campo2":campo2, "nombre de campo3":campo3}
sprintf (httpContent, "{\" longitude \ ":% s, \" latitude \ ":% s, \" date \ ":\"% s% s \ "}", tempstrLong, tempstrLat , fecha1, hora1);
El comando sprintf anterior compila la cadena de datos enviada a thinger. La sintaxis es * muy * estricta y debe agregar nuevos campos de datos exactamente de la misma manera. Se da un ejemplo en el código (sección de comentarios). Una buena idea es tomar nota de la impresión del monitor en serie del comando que mostrará la cadena. Luego agrega "field4" y así sucesivamente ..
Recinto
He adjuntado un recinto completo imprimible en 3D. Está diseñado para adaptarse a los PCB exactos utilizados para este proyecto. Se utilizan tornillos M3 para el montaje.
Está diseñado para una placa de soldadura de 7x5 cm para el "circuito" de LED y no una placa de pruebas. Si usa una placa de pruebas, solo use un poco de pegamento en su lugar. El GPS y la placa de soldadura ("protoboard") están montados en la carcasa superior. Utilice espaciadores pequeños para un mejor montaje de PCB en la carcasa superior.
También he mantenido sólidos los puntos de montaje en la carcasa superior (sin agujeros) para facilitar la impresión sin soportes. Ábralas con una broca de 3 mm.
Imprime bien en 0,2 mm sin soportes.
Conexión a la batería / fuente de alimentación del automóvil
There are probably hundreds of ways of doing this, so I don't have the only answer, or best answer for that matter; how to wire it up to the car battery. It all depends on your application, but I'll quickly describe my solution.
I wanted the device to start with the car, hence not connected directly to the battery (and drawing power while the car is turned off). So I've connected it to the "cigarette socket" circuit that is already turning on/off with the car. If you want it to be online even when the car is off, you'll have to find a way to wire it to the battery. For most cars the cigarette socket turns off with the car, but you'll have to check this for your own. I will not show the exact wiring for mine as this will also be different for every car. You can also place a battery pack in between to keep the device going for hours after the car has been switched off (or stolen..).
You can of course also just use an adapter, like one of those USB phone chargers, but that defeats my purpose of hiding it (in case the car gets stolen). We also have two power sources, the Arduino board and the SIM900 module. I used a "China cheap-o matic" step-down module, that converts from 12V-5V (the actual input range was said to be 9V-20V). It's probably not good quality, but has been working ok so far :)
The step-down module transforms the 12V input to 5V output to two USB female connectors. I then connected the Arduino- and SIM900 module to each of these USB outputs to power them. There are probably other and more "professional" solutions, but this was cheap and worked well enough.
I have measured the power draw during GSM activity to around 110maH, so very little power consumption. It will probably draw more power in areas with poor GSM coverage.
Known issues
If an SMS command is received at the same time as the thinger.io http request is processed (while data is being pushed to thinger) the command will not be picked up by the software. In this case, you will not receive a SMS reply. Send a new command some seconds later and it will work again. I've not made a workaround for this, as its not a big problem. If someone should make a fix for this, please feel free to share.
Also, if the Arduino is started in an area without network coverage, it won't reconnect when the network is available again, as it only connects during startup. I might modify the code at some point to fix this, but at the moment it
Código
- GPS_tracker_Leonardo_v2.ino
GPS_tracker_Leonardo_v2.inoArduino
#include#include #include #include #include "PF.h"#include "PetitSerial.h"#define UTC_OFFSET 1 // set time zone offset, i.e. 1 =UTC+1#define TXPin 8 // SIM900 Tx pin#define RXPin 9 // SIM900 Rx pin#define PWRPin 7 // SIM900 software power pin// phone number for triggered notification#define DEFAULT_NUMBER "+4712345678"FATFS fs; // file system object - for reading SD card// GSM variablesString textMessage; // holds the last received text messageString number =DEFAULT_NUMBER; // phone number from last text messagechar sms_msg[160]; // holds the SMS reply text// location variablesfloat Lat =0, Long =0;boolean valid_location =false; // initial valid location flaguint8_t num_sat;NeoGPS::Location_t prevFix; // holds previous location for distance calculationNMEAGPS gps; // parses the GPS charactersgps_fix fix; // holds on to the latest valuesconst char *googlePrefix ="http://maps.google.com/maps?q=";const char *filename ="DIST.TXT";const char *settings ="SETTINGS.TXT";// time variablesNeoGPS::time_t timeFix; // time object for current gps fixchar datePrint[13];char timePrint[10];// distance tracking variablesfloat totalDistance =0; // in meters// triggerdistance (odometer notification) is read from SD card on initfloat triggerDistance =4000000;SoftwareSerial SIM900( TXPin, RXPin ); // SIM900 Tx &Rx is connected to Arduino #8 void setup() { pinMode(3, OUTPUT); pinMode(4, OUTPUT); digitalWrite(3, HIGH); // turn on power LED Serial.begin(9600); // serial monitor /* the "while (!serial)" construct below must only be enabled for debugging purposes when connected to a PC. If this is kept in the code the program will stop in a loop when connected to external power sources, as no serial connection will be established */ // while (!Serial); // wait for serial port to connect - for ATmega32u4 (Leonardo) SIM900.begin(9600); // SIM900 module on pins #8 and #9 gpsPort.begin(9600); // GPS receiver on Serial1 pins #0 and #1 - defined in GPSport.h // initialize the SD card and reads standard setting and accumulated distance initializeSD(); // power up SIM900 with software trigger SIM900power(); SIM900.println( F("AT") ); // Handshaking with SIM900 delay(500); SIM900.println( F("AT+CMGF=1") ); // Configuring TEXT mode delay(500); SIM900.println( F("AT+CNMI=1,2,0,0,0") ); // Decides how newly arrived SMS messages should be handled delay(500); connectGPRS();}void loop() { while (gps.available( gpsPort )) { fix =gps.read(); num_sat =fix.satellites; if (fix.valid.location) { digitalWrite(4, HIGH); // sets GPS lock LED Lat =fix.latitude(); Long =fix.longitude(); // saves the first "GPS lock" flag - we now have useful data if (Lat !=0 &&Long !=0 &&!valid_location) { valid_location =true; prevFix =fix.location; } } if (fix.valid.date &&fix.valid.time) { timeFix =fix.dateTime; updateTime(); } // update thinger.io and write values to SD card only for valid gps fix // typically at startup before gps has locked in coordinates first time if (valid_location) { // updates the distance travelled every 15 seconds static const unsigned long REFRESH_INTERVAL_UPD =15000; // 15 seconds static unsigned long lastRefreshTime =millis(); if (millis() - lastRefreshTime>=REFRESH_INTERVAL_UPD) { lastRefreshTime +=REFRESH_INTERVAL_UPD; // calculates distance between current and previous fix in meters float distanceDelta =prevFix.DistanceKm(fix.location) * 1000; // only update if distance is greater than 10 meters and less than 10km // 10km check is implemented to avoid erroneous data reading from GPS if (distanceDelta> 10 &&distanceDelta <10000) { totalDistance +=distanceDelta; } // reset the calculation point for next loop (set "previous" location) prevFix =fix.location; } // writes distance travelled to SD card every 2 minutes // uploads coordinates to thinger.io every 2 minutes static const unsigned long REFRESH_INTERVAL_WRITE_SD =120000UL; // 2 minutes static unsigned long lastRefreshTimeWriteSD =millis(); if (millis() - lastRefreshTimeWriteSD>=REFRESH_INTERVAL_WRITE_SD) { lastRefreshTimeWriteSD +=REFRESH_INTERVAL_WRITE_SD; // file write to SD card begin char buf[9]; dtostrf(totalDistance, 8, 0, buf); if (PF.open(filename)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.writeFile(buf, sizeof(buf), &nr)) Serial.println( F("error write file") ); if (nr ==sizeof(buf)) { PF.writeFile( 0, 0, &nr); // finalize write operation by writing a null pointer break; } } // Petit FS has no "close" operation on file // next section transfers data to thinger.io IoT cloud with HTTP POST request. // only update thinger.io after first successful GPS lock char httpContent[60]; char tempstrLong[10]; char tempstrLat[10]; dtostrf(Lat, 2, 6, tempstrLat); dtostrf(Long, 2, 6, tempstrLong); // data fields to thinger.io bucket. Access to bucket is given through URL authorization in the post function. // format is { "field1 name" :field1 , "field2 name" :field2 , "field3 name" :field3 } with exact byte count. sprintf(httpContent, "{ \"longitude\":%s , \"latitude\":%s , \"date\":\"%s %s\" }", tempstrLong, tempstrLat, datePrint, timePrint); char httpdataLen[20]; // exact byte count for the content must be added to HTTPDATA // otherwise HTTP POST request is invalid, i.e. status 400 is retured. sprintf(httpdataLen, "AT+HTTPDATA=%i,10000", strlen(httpContent)); postDataThinger(httpdataLen, httpContent); } } } // send SMS notification if the total distance exceeds configured limit if (totalDistance> triggerDistance) { char distanceTotalMsg[10]; itoa( (totalDistance / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Empty catchtank! Current distance:%skm", distanceTotalMsg); textMessage =""; number =DEFAULT_NUMBER; totalDistance =0; sendSMS(sms_msg); } updateSerial();}void updateSerial(){ // read incoming buffer. reads content of any text message if (SIM900.available()> 0) { textMessage =SIM900.readString(); } if (textMessage.indexOf("POS")>=0) { extractSenderNumber(); textMessage =""; char latPrint[10]; dtostrf(Lat, 5, 6, latPrint); char LonPrint[10]; dtostrf(Long, 5, 6, LonPrint); if (num_sat>=3 &&valid_location) { sprintf(sms_msg, "Current location:Lat:%s, Long:%s. %s%s,+%s\n", latPrint, LonPrint, googlePrefix, latPrint, LonPrint); } else if (num_sat <3 &&valid_location) { sprintf(sms_msg, "No gps fix. Last seen %s%sat:Lat:%s, Long:%s. %s%s,+%s\n", datePrint, timePrint, latPrint, LonPrint, googlePrefix, latPrint, LonPrint); } else if (!valid_location) { sprintf(sms_msg, "Tom not found. Maybe he is in North-Korea?"); } sendSMS(sms_msg); } // returns the current total accumulated distance if (textMessage.indexOf("GETKM")>=0 ) { char sms_msg[32]; char distanceTotalMsg[10]; itoa( (totalDistance / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Current distance:%skm", distanceTotalMsg); textMessage =""; sendSMS(sms_msg); } // resets the distance counter to 0 if (textMessage.indexOf("RESETKM")>=0) { totalDistance =0; char sms_msg[] ="Acknowledge:distance reset"; textMessage =""; sendSMS(sms_msg); }}void SIM900power(){ // power up SIM900 board from pin #7 (default) -> 2sec. signal pinMode(PWRPin, OUTPUT); digitalWrite(PWRPin, LOW); retraso (1000); digitalWrite(PWRPin, HIGH); retraso (2000); digitalWrite(PWRPin, LOW); delay(15000); // give module time to boot}void updateSIM900(){ // empty incoming buffer from SIM900 with read() delay(500); while (SIM900.available()) { // outputs buffer to serial monitor if connected Serial.write(SIM900.read()); }}void extractSenderNumber(){ uint8_t startPos =textMessage.indexOf("+", 6); uint8_t endPos =textMessage.indexOf(","); number =textMessage.substring(startPos, endPos - 1);}void sendSMS(char *content){ // really crappy string conversion since I was too lazy to do proper // char handling in the first place. // SMS is returned to the sender number. char numberChar[number.length() + 1]; number.toCharArray(numberChar, number.length() + 1); char cmd_sms[50]; sprintf(cmd_sms, "AT+CMGS=%c%s%c", 0x22, numberChar, 0x22); SIM900.println(cmd_sms); updateSIM900(); SIM900.print(content); updateSIM900(); SIM900.write(0x1A);}void connectGPRS(){ SIM900.println( F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"") ); retraso (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); retraso (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=1,1") ); retraso (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=2,1") ); retraso (1000); updateSIM900();}void postDataThinger(char *httpDataLen, char* content){ SIM900.println( F("AT+HTTPINIT") ); retraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CID\",1") ); retraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") ); retraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CONTENT\",\"application/json\"") ); retraso (1000); updateSIM900(); SIM900.println(httpDataLen); retraso (1000); updateSIM900(); SIM900.println(content); retraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPACTION=1") ); retraso (10000); updateSIM900(); SIM900.println( F("AT+HTTPTERM") ); retraso (1000); updateSIM900();}// initialize SD card and retrieves stored distance valuevoid initializeSD(){ // first section read current distance from SD card char buf[10]; // buffer to hold retrieved distance value // Initialize SD card and file system. if (PF.begin(&fs)) Serial.println( F("error begin file") ); // Open file for read - saved accumulated total distance if (PF.open(filename)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.readFile(buf, sizeof(buf), &nr)) Serial.println( F("error read file") ); if (nr ==sizeof(buf)) break; } // no close function for Petit FS. // retrieves stored distance value to program totalDistance =atof(buf); // second section read odometer notification trigger value char bufTrigger[10]; // buffer to hold trigger value if (PF.open(settings)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.readFile(bufTrigger, sizeof(bufTrigger), &nr)) Serial.println( F("error read file") ); if (nr ==sizeof(bufTrigger)) break; } // retrieves odometer notification value triggerDistance =atof(bufTrigger);}// corrects time object with time zone offsetvoid updateTime(){ // set time from GPS data string setTime(timeFix.hours, timeFix.minutes, timeFix.seconds, timeFix.date, timeFix.month, timeFix.year); // calc current time zone time by offset value adjustTime(UTC_OFFSET * SECS_PER_HOUR); sprintf(datePrint, "%02d/%02d/%04d ", day(), month(), year()); sprintf(timePrint, "%02d:%02d:%02d ", hour(), minute(), second());}
Piezas y carcasas personalizadas
Top of casing for more space (taller). The mounting holes are closed and must be drilled after print (to make for easier printing)A compact version of the top casing (less space inside enclosure)Bottom part of casing - for SIM900 and Arduino board with cutouts for connectorsLocks SIM900 board in placeLocks SIM900 board in place (no mounting holes on SIM900 board)rename to "dist.txt" and place on SD card dist_1qOG9VMO2D.txtrename to "settings.txt" and place on SD card settings_iMpR6v81OB.txtEsquemas
Proceso de manufactura
- Tabla de planchar
- Tabla de surf
- ¿Qué pasa con la tecnología de seguimiento de activos para exteriores (GPS)?
- Raspberry Pi diseña su propia MCU junto con la placa de $ 4
- La integración de los datos del sensor con el microprocesador Raspberry Pi
- Uso de la placa Pioneer de PSoC 6 con el escudo complementario de Pioneer IoT
- Reutilice medicamentos seguros con BIOVIA Living Map
- HashMap en Java Learn con ejemplo
- Función Python map() con EJEMPLOS
- Trabajar con sistemas de integración internos
- ¿Qué sucede si conduzco mi automóvil con poco refrigerante?