Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Автомобильный GPS-трекер с интеграцией карты thinger.io

Компоненты и расходные материалы

Ардуино Леонардо
Использование Леонардо для получения выделенного аппаратного последовательного порта.
× 1
Плата для разработки SIM900
× 1
GPS-модуль u-blox NEO-6M
× 1
Антенна, GPS
× 1
Резистор 220 Ом
× 2
LED (общий)
× 2
Плата припоя 7 x 5 см
Я использовал припойную плату, которая подходит к корпусу с 3D-печатью для "схемы" светодиодов состояния. Однако вы можете использовать любую общую макетную плату или вообще пропустить ее, если вам не нужны светодиоды состояния
× 1
Модуль понижающего напряжения с 12 В до 5 В
Для подключения источника питания к автомобильному аккумулятору (или гнезду прикуривателя)
× 1
Устройство чтения SD-карт Adafruit
× 1
Карта флэш-памяти, карта MicroSD
× 1

Необходимые инструменты и машины

Паяльник (общий)

Приложения и онлайн-сервисы

Платформа Thinger.io
Бесплатная служба Интернета вещей с панелями мониторинга!

Об этом проекте

Этот проект начался как простая «идея GPS-трекера», а потом оказался «универсальным GPS-трекером». В моем первом проекте кривая обучения была крутой, и поэтому я всегда открыт для отзывов, отзывов и улучшений в дизайне! :)

Трекер предназначен для установки в моей машине и имеет следующие особенности:

  • Отслеживайте координаты GPS и публикуйте последнее известное местоположение на облачной панели управления Thinger.io IoT каждые 2 минуты (отображается на карте). Публикация на thinger.io с помощью запросов HTTP POST.
  • Отвечает на SMS-команды и возвращает ссылку на карту Google на текущее или последнее известное местоположение (последнее известное местоположение, если текущее местоположение недоступно).
  • Отправлять SMS-уведомление каждые XX километр (идея состоит в том, чтобы трекер напоминал мне опорожнять мой маслосборник каждые 4000 км). Это работает как настраиваемый программный «одометр».

Во время этого проекта я быстро понял, насколько Arduino «ограничен» с точки зрения доступной памяти, и мне пришлось изучить методы сокращения накладных расходов и создания эффективного кода (по крайней мере, я пытался). Я также использовал легкие библиотеки, чтобы уместить все на чипе и доступной оперативной памяти.

Используются следующие компоненты (как в списке компонентов):

  • GPS-навигатор НЕО-6М. Похоже, это очень популярное устройство GPS, которое можно дешево купить на Ebay и т.п. Связь с GPS будет аппаратной последовательной.
  • GPS-антенна. Подойдет любая совместимая, однако я обнаружил, что самые дешевые Ebay работают не так хорошо, то есть плохой прием / низкое количество спутников. Возможно, мне просто не повезло с первой антенной, но для стабильного приема мне пришлось купить другую, более качественную.
  • Плата разработки SIM900 для подключения к GSM и GPRS. Этот проект также должен работать с SIM800- и совместимыми модулями, однако никаких гарантий. Связь с SIM900 будет программной последовательной.
  • Ардуино Леонардо доска. Я использовал плату Леонардо для получения выделенной аппаратной последовательной линии так как нам нужны две последовательные линии. Хотя можно использовать и обычную плату UNO, вам нужно отключить GPS, чтобы загрузить программное обеспечение, а также у вас не будет последовательного монитора для отладки. Нам понадобятся две последовательные линии (одна для GPS и одна для платы SIM900); один серийный номер программного обеспечения и один серийный номер оборудования.
  • Устройство чтения карт SD (я использовал устройство чтения карт Adafruit, совместимое с напряжением 5 В (упрощенное подключение к разъему SPI с напряжением 5 В). Другие более дешевые модули также могут работать. Карта Micro SD будет использоваться для хранения пройденного расстояния. Предупреждение: убедитесь, что ваш кардридер SD поддерживает питание 5 В, если, следуя моей схеме, многие устройства чтения SD-карт используют только 3,3 В. Использование неправильных уровней напряжения, скорее всего, приведет к повреждению электроники. Связь с устройством чтения SD-карт будет осуществляться через интерфейс SPI.
  • Светодиоды и резисторы для создания цепей индикаторов состояния (светодиоды питания и блокировки GPS).
  • SIM-карта с данными.
  • Я также разработал корпус для 3D-печати с прикрепленными файлами STL, которые можно распечатать прямо на 3D-принтере.

Для начала нам нужно установить необходимые библиотеки. В этом проекте я использовал следующие библиотеки:

  • NeoGPS для отслеживания и декодирования GPS. Может быть установлен прямо из диспетчера библиотек в Arduino IDE. Подробнее:https://github.com/SlashDevin/NeoGPS
  • Время библиотека (используется для преобразования часового пояса UTC):https://github.com/PaulStoffregen/Time
  • PetitFS для чтения / записи на SD-карту:https://github.com/greiman/PetitFS Легкая библиотека SD FAT.

Почему бы не использовать доступную библиотеку для Arduino от thinger.io?

Хотя библиотека, предоставляемая thinger.io, очень проста в использовании и значительно упростит работу, не говоря уже о том, что она уже интегрирована в IDE, она занимает почти 80% хранилища на Arduino Leo, не оставляя места для оставшегося кода. Так что это слишком велико для этого проекта, и нам придется делать это нелегко. Для связи с облаком thinger.io мы будем использовать запросы HTTP POST .

SMS команды

Доступные команды в SMS следующие (все заглавные буквы). Это поддерживаемые команды в предоставленном коде; вы можете добавлять / удалять команды для вашего собственного проекта / требований:

  • "POS" возвращает координаты со ссылкой на Google Maps, если координаты доступны. В противном случае возвращается последнее известное местоположение.
  • "GETKM" возвращает текущее расстояние с момента последнего «сброса».
  • "RESETKM" устанавливает счетчик расстояния на 0 (сбросить одометр).

Настройка NeoGPS

Мы используем библиотеку NeoGPS для повышения производительности и использования ресурсов по сравнению с такими альтернативами, как TinyGPS ++. Он потребляет очень мало оперативной памяти, а это необходимо; в противном случае мы получим предупреждения о нехватке памяти и стабильности.

После установки библиотеки измените файл GPSPort.h . в пути установки библиотеки (приведенный пример для OS X - для Windows вы найдете библиотеку в другом месте)

Замените все содержимое в GPSPort.h следующим:

  #ifndef GPSport_h # define GPSport_h # define gpsPort Serial1 # define GPS_PORT_NAME "Serial1" #define DEBUG_PORT Serial # endif  

Этот файл содержит определения, используемые библиотекой NeoGPS. Если вы используете другую плату Arduino, именно здесь вы определяете последовательную линию для GPS-приемника, например «Serial2», «Serial3» для Arduino MEGA.

Примечания относительно точности

Следует отметить, что GPS - не самый точный способ измерения и накопления расстояния, так как положение будет немного смещаться даже в неподвижном состоянии. Вы можете проверить это, стоя на одном и том же месте и заметив, что координаты GPS будут разными для каждого показания. Для этого приложения точность менее важна, и поэтому допустимы меньшие отклонения.

Однако я попытался учесть небольшие отклонения в координатах, и программа добавляет расстояние только для перемещений более 10 м (все перемещения ниже 10 м считаются стационарными) в течение 15 секунд.

Также имейте в виду, что расстояние рассчитывается по прямой линии, тогда как фактическое расстояние, которое проезжает автомобиль, зависит от дороги, поворотов и т. Д. Я установил частоту дискретизации на 15 секунд, однако вы можете уменьшить ее, если хотите больше. точность.

Настройка PetitFS

Эта библиотека представляет собой сверхлегкую библиотеку для чтения / записи на SD-карты с форматом FAT. Мне потребовалось некоторое время, чтобы понять, как это работает, поскольку документации практически не существует, а в некоторых местах даже нет / устарела. Предоставленный пример кода библиотеки даже не компилируется. Поставляется с лотом ограничений (в отличие от «нормальной» библиотеки, такой как SD-библиотека Arduino или SDFat):

  • Невозможно создать файл. Можно записать только существующий файл.
  • Невозможно увеличить размер файла.
  • Невозможно обновить отметку времени файла.
  • Не удается добавить данные в файл (файл перезаписывается каждый раз).
  • Одновременно открывается только один файл.

Зачем использовать небольшую и ограниченную библиотеку с множеством причуд?

Размер, в основном. Я пробовал несколько библиотек, включая Arduino SD Library, SDFat, а также fat16lib. Все они слишком велики, чтобы весь код поместился на чипе, поэтому, чтобы не удалять функциональность, я использовал эту библиотеку (стандартная библиотека Arduino SD занимает примерно на 12% больше места). Даже со всеми причудами и ограничениями он по-прежнему обеспечивает то, что нам нужно для этого приложения:простое чтение и запись одного значения для хранения.

Если вы не используете весь код и есть достаточно места, чтобы втиснуть что-то дополнительное, намного проще работать с библиотеками, такими как стандартная библиотека SD.

Откройте файл pffArduino.h . из папки библиотеки PetitFS. Измените SD_CS_PIN до 10. Это контакт SS, используемый для связи с SD-картой с помощью SPI.

Откройте файл pffconf.h из папки библиотеки. Отключить следующие параметры, переключив заданное значение с 1 на 0:

  • _USE_DIR
  • _USE_LSEEK
  • _FS_FAT12
  • _FS_FAT16

При отключении этих параметров скомпилированная программа занимает меньше места, а это необходимо; Окончательный эскиз занимает ок. 96% памяти.

При первом импорте библиотеки вы получите ошибку компиляции, которую * можно * проигнорировать (при второй компиляции ошибка не отображается - до сих пор не понимаю, почему). Однако, если вы хотите исправить это (оно будет появляться каждый раз при запуске Arduino IDE -> компиляция), добавьте отсутствующий параметр возврата функции «FRESULT», как показано на скриншоте выше. Он находится в файле pff.cpp в папке библиотеки.

Я изо всех сил старался понять, как работает эта библиотека, и хотя у меня есть все для работы, я почти уверен, что ее тоже можно улучшить. Если вы обнаружите ошибки или улучшения в написанных мною процедурах, пожалуйста, поделитесь ими! Я очень хочу учиться и набираться опыта.

Подготовьте SD-карту

Для этого проекта я использовал карту Micro SD. Поскольку библиотека не может создать файл (ы) сама, важно перед использованием создать на карте файлы «dist.txt» и «settings.txt». Я рекомендую скопировать прикрепленные файлы "dist.txt" и "settings.txt" файл со страницы проекта, так как эти файлы уже имеют правильный формат и работают (библиотека очень придирчив к формату текста и содержанию).

Перед тем, как поместить файл на карту Micro SD, обязательно отформатируйте карту должным образом (как FAT32 ). Я рекомендую использовать официальный «SD Card Formatter» от SD Association:https://www.sdcard.org/downloads/formatter/.

Убедитесь, что SD-карта работает (правильно читает / записывает в файл)

Библиотека PetitFS очень придирчив к входным файлам. Если вы загружаете устройство и на последовательном мониторе не отображается никаких выходных данных (просто пусто), оно, скорее всего, застряло в «цикле», где пытается прочитать файл с карты, но не может по какой-то причине (функция initializeSD ()). У меня было бесчисленное количество текстовых файлов, которые по какой-то причине не удалось прочитать, поэтому я включил использованные текстовые файлы, которые работают. Разместите ссылку файлы на SD-карте, и она должна иметь возможность как читать, так и записывать на нее.

Другой вариант - заполнить текстовый файл числом, которое больше чем то, что написано. Я не тестировал это, но поскольку библиотека не может увеличить размер файла, я предполагаю, что это может быть проблемой.

PetitFS запишет в файл всю длину символьного массива, поэтому вы увидите пустые пробелы перед фактическим числом (если число не достаточно велико для заполнения массива - длина «массива» определяется в коде). Эти пробелы необходимо сохранять при внесении изменений в файл - поскольку PetitFS не может изменять размер файла, это может вызвать проблемы при изменении количества символов.

Установите для файла "dist.txt" значение "0", если вы хотите, чтобы одометр начинался с "0", или любое другое число, чтобы упростить проверку его работы, например отправка команды "GETKM" для проверки ответа по SMS.

В "settings.txt" вы устанавливаете расстояние срабатывания уведомления, расстояние, на котором одометр запускает SMS-уведомление (в метрах).

Подготовьте плату SIM900

Прежде чем мы сможем использовать плату SIM900, необходимо настроить несколько параметров. Подробную информацию по настройке этой платы можно найти на https://lastminuteengineers.com/sim900-gsm-shield-arduino-tutorial/.

Источник питания

Плата Arduino не может обеспечить достаточную мощность, поэтому мы должны использовать внешний источник питания. Поскольку пики могут потреблять до 2 А, убедитесь, что вы используете источник питания, который может выдавать не менее 2 А при 5–9 В постоянного тока; в нем используется цилиндрический соединитель 5,5 мм.

Селектор источника питания

Рядом с разъемом постоянного тока находится переключатель источника питания . . Чтобы использовать внешний источник питания, переместите ползунок, как показано на рисунке выше.

Селектор серийного номера

Настройте на плате использование Программного последовательного порта . совместив перемычки, как показано выше.

Программный триггер

Вместо того, чтобы каждый раз вручную нажимать кнопку питания, вы можете включить / выключить SIM900 в программном обеспечении. Для этого необходимо припаять перемычку R13. Затем плата включается путем подключения контакта № 9 SIM900 к контакту № 7 Arduino (как показано на схемах).

Если сохранить функцию «ручного включения», функцию «SIM900power ()» в коде можно удалить.

Снять блокировку PIN-кода SIM-карты

Обязательно снимите блокировку PIN-кода на SIM-карту перед использованием. Это можно сделать, вставив его в любой обычный телефон и сняв блокировку контактов в соответствующем меню настроек.

Также обратите внимание, что модуль SIM900 на схемах может отличаться от реальной платы, однако расположение контактов правильное, что является наиболее важной частью.

Версия прошивки SIM900 (Важно!)

Очень важно, чтобы на микросхеме была загружена правильная версия прошивки. Это связано с тем, что одна из команд для правильной настройки заголовка HTTP POST не поддерживается до версии прошивки B10. Это означает, что для работы HTTP-соединения требуется версия как минимум B10 или выше. В частности, с более ранней версией прошивки нельзя будет установить «Content-type» в заголовке http. Если тип содержимого не установлен в "application / json" в почтовом запросе, он будет отклонен сервером.

Чтобы проверить версию прошивки, используйте следующую AT-команду:

  AT + CGMR  

Затем микросхема SIM900 сообщит вам текущую версию прошивки в выходной консоли. Поместите следующее в конце раздела setup (), чтобы распечатать версию прошивки при запуске:

  SIM900.println (F ("AT + CGMR"));  

В моем случае это было бы (до того, как я обновил):

  Версия:1137B01SIM900M64_ST_AM  

Это была самая старая версия прошивки для этого чипа («B01»), поэтому я обновил ее до версии B10: 1137B10SIM900M64_ST . Более новые прошивки тоже должны работать.

Я не буду рассказывать, как обновить прошивку в этом руководстве, уже есть отличное руководство, как это сделать:Обновление прошивки SIM900 - ACOPTEX (хотя и несколько болезненный процесс).

Я не знаю, будет ли это иметь место для других чипов, таких как SIM800, однако, поскольку это новый чип, я бы сказал, что более вероятно, что он там уже установлен.

Корректировки кода

Чтобы адаптировать код для вашего собственного проекта, необходимо внести несколько изменений:

  • Изменить информацию APN (поставщика сети).
  • Измените URL-адрес thinger.io, чтобы он соответствовал вашему собственному (URL-адрес связывает запрос на обновление с вашей собственной «корзиной» с токеном доступа). Это описано в главе «Интеграция с thinger.io».
  • Установите правильный часовой пояс.
  • Установить расстояние срабатывания для SMS-уведомления.
  • Установить (или отключить) текст SMS-уведомления.
  • Установить номер телефона по умолчанию для уведомлений.

Поставщик APN

  void connectGPRS () {... SIM900.println (F ("AT + SAPBR =3,1, \" APN \ ", \" TeleXXX \ "")); задержка (1000); updateSIM900 (); ...  

Под connectGPRS () вы найдете имя APN, предоставленное вашим сетевым провайдером, показанное выше как "TeleXXX". Замените его своим именем APN.

  ATOKAT + CMGF =1OKAT + CNMI =1,2,0,0,0OKAT + SAPBR =3,1, «CONTYPE», «GPRS» OKAT + SAPBR =3,1, «APN», » TeleXXX "ОКАТ + САПБР =1,1ОКАТ + САПБР =2,1 + САПБР:1,1," 36.57.240.233 "ОК  

Вверху:вывод функции connectGPRS () при рабочем соединении. Все команды должны возвращать статус «ОК».

Часовой пояс

  #define UTC_OFFSET 1 // установить смещение часового пояса, т.е. 1 =UTC + 1  

В разделе «определить» установите часовой пояс в соответствии с вашими требованиями. Код установлен на UTC + 1 . .

SMS-уведомление

Я установил уведомление каждые 4000 км, чтобы опорожнить мой маслосборник. Поскольку я понимаю, что у большинства людей нет маслосборника, это уведомление следует изменить на любое желаемое (или вообще отключить).

  void loop () {... // отправляет уведомление по SMS, если общее расстояние превышает 4000 км if (totalDistance> triggerDistance) {char sms_msg [160]; char distanceTotalMsg [10]; itoa ((totalDistance / 1000), distanceTotalMsg, 10); sprintf (sms_msg, «Пустой резервуар! Текущее расстояние:% skm», distanceTotalMsg); textMessage =""; totalDistance =0; // устанавливает номер телефона по умолчанию для запуска уведомления number =DEFAULT_NUMBER; sendSMS (sms_msg); } ...}  

Вверху:раздел кода, запускающий уведомление (внутри основного цикла ()).

Закомментируйте / удалите этот раздел, если вы не хотите, чтобы срабатывали уведомления. Или измените текст на что-нибудь полезное.

Уведомление запускается, когда «одометр» (накопленное расстояние) достигает сконфигурированного расстояния, установленного в файле «settings.txt».

Номер телефона по умолчанию

Это номер телефона, на который отправляется сработавшее уведомление (поскольку в уведомлении нет номера «отправителя», на который нужно ответить)

  // номер телефона для срабатывающего уведомления # define DEFAULT_NUMBER "+4712345678"  

Дождитесь последовательного подключения

Также неплохо раскомментировать следующую строку кода. Это заставляет плату Arduino ждать, пока не станет активным последовательное соединение, то есть последовательный монитор для отладки. Таким образом, вы не пропустите никаких отладочных сообщений в начале кода до того, как последовательная линия станет активной.

Не забудьте удалить / прокомментировать строку перед включением Arduino от внешних источников питания, иначе она остановится в бесконечном цикле, пока не подключится к ПК.

  // while (! Serial); // ждем подключения последовательного порта - для ATmega32u4 (Leonardo)  

Интеграция с Thinger.io

Я не буду вдаваться в подробности, как настроить thinger.io, так как он довольно прост; вы должны создать учетную запись и «корзину» для получения данных через их веб-сайт, а также «устройство», к которому мы будем подключаться. «Ведро» - это база данных для приема данных. «Устройство» - это точка подключения нашего кода, где мы решаем, что делать с данными (в нашем случае заполняем базу данных «ведра»).

Создайте "ведро", как показано выше, со своим именем и описанием.

Теперь создайте «HTTP-устройство», как описано в официальной документации:https://docs.thinger.io/quick-sart/devices/http-devices.

Используйте короткий устройство имя . Поскольку имя устройства является частью алгоритма, который генерирует ключ авторизации, я обнаружил, что более длинное имя устройства также генерирует более длинный ключ авторизации. Проблема? Ключ авторизации быстро стал длиннее, чем буфер из 256 символов, используемый для отправки строки из Arduino. Вероятно, есть несколько более эффективных способов исправить это, но я нашел самый простой способ сделать имя устройства коротким и избежать проблемы.

В устройстве обратный вызов > настройки Убедитесь, что настройка «запись в корзину» указывает на ранее созданную корзину. Это говорит "устройству" записывать входящие данные в нашу базу данных.

В устройстве обратный вызов > обзор обратите внимание на метод URL и заголовок авторизации (длинная строка без ключевого слова "Bearer").

Для отправки данных на thinger.io мы используем «URL-адрес авторизации» в HTTP-запросе POST. Затем вы должны заменить URL-адрес и ключ авторизации в коде своими собственными.

В postDataThinger () функция вы найдете вызов (фактический ключ авторизации зашифрован):

  SIM900.println (F ("AT + HTTPPARA =\" URL \ ", \" http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization =eyJhbGciOiJIUzI1NiIsInR5cdfkjowiuerdf.sdfsdf.wekrjciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ \ "")); 

Затем вам нужно заменить URL и авторизация ключ в коде с вашим собственным, созданным в соответствии с инструкциями по приведенной выше ссылке.

  http://backend.thinger.io / ...  

По умолчанию создается URL-адрес авторизации https . . SIM900 не поддержка SSL (по крайней мере, у меня он не работает), поэтому обязательно измените "http s :// "на" http:// ". Thinger API также поддерживает соединения без SSL. Это очень важно. Если вы сохраните" https ", он не будет работать. Когда все работает, серийный монитор должен выдать" 200 - ОК "ответ при отправке HTTP-запроса.

После AT-команды "AT + HTTPACTION =1" (отправьте запрос HTTP POST) вы должны получить такой ответ в последовательном мониторе:

  + HTTPACTION:1,200,0  

Если вы получили ответ «400 - неверный запрос» или аналогичный…

  + HTTPACTION:0,400,51  

... скорее всего, что-то не так с URL-адресом, например «https» вместо «http», неверный синтаксис «ключа авторизации» и т. д. Когда вы получаете сообщение «200 - OK», данные должны появиться в сегменте thinger, как показано ниже. Вы также можете получить 400 - "неверный запрос", если у вас нет правильной прошивки, как упоминалось ранее.

Выше показан сегмент после поступления данных (зашифрованный из соображений конфиденциальности). Содержимое (столбцы данных) задается синтаксисом запроса HTTP POST в коде, настройка на thinger.io не требуется.

Ниже приведен последовательный вывод HTTP-запроса POST, как он должен выглядеть, когда все работает. + HTTPACTION:1, 200, 0 указывает, что обновление прошло успешно.

  AT + HTTPINITOKAT + HTTPPARA ="CID", 1OKAT + HTTPPARA ="URL", "OKAT + HTTPPARA =" CONTENT "," application / json "OKAT + HTTPDATA =84,10000DOWNLOADOKAT + HTTPACTION =1OK + HTTPACTION:1,200,0AT + HTTPTERMOK  

Панель управления затем можно легко настроить с помощью виджета карт, используя корзину в качестве источника данных.

Больше данных?

Вы хотите передать больше данных, чем долгота, широта и дата / время? Просто добавьте дополнительные поля данных в HTTP-запрос, как показано ниже.

Формат:{"field1 name":field1, "field2 name":field2, "field3 name":field3}

  sprintf (httpContent, "{\" долгота \ ":% s, \" широта \ ":% s, \" date \ ":\"% s% s \ "}", tempstrLong, tempstrLat , дата1, время1);  

Приведенная выше команда sprintf компилирует строку данных, отправленную в thinger. Синтаксис * очень * строг, и вы должны точно так же добавлять новые поля данных. Пример приведен в коде (раздел комментариев). Хорошая идея - сделать запись на мониторе последовательного порта печати команды, которая будет отображать строку. Затем вы добавляете "field4" и так далее ..

Корпус

Я прикрепил полный корпус для 3D-печати. Он разработан, чтобы соответствовать точным печатным платам, используемым в этом проекте. Для крепления используются винты M3.

Он предназначен для паяльной платы 7x5 см для светодиодной «схемы», а не для макета. Если вы используете макетную плату, просто используйте вместо нее немного клея. Плата GPS и припоя («макет») установлена ​​в верхнем корпусе. Используйте небольшие прокладки для лучшего крепления печатных плат в верхнем корпусе.

Я также сохранил точки крепления в верхнем корпусе сплошными (без отверстий), чтобы упростить печать без опор. Откройте их сверлом на 3 мм.

Хорошо печатает на 0,2 мм без опор.

Connection to car battery / power source

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

Код

  • 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, ВЫХОД); 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); задержка (1000); digitalWrite(PWRPin, HIGH); задержка (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\"") ); задержка (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); задержка (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=1,1") ); задержка (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=2,1") ); задержка (1000); updateSIM900();}void postDataThinger(char *httpDataLen, char* content){ SIM900.println( F("AT+HTTPINIT") ); задержка (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CID\",1") ); задержка (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") ); задержка (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CONTENT\",\"application/json\"") ); задержка (1000); updateSIM900(); SIM900.println(httpDataLen); задержка (1000); updateSIM900(); SIM900.println(content); задержка (1000); updateSIM900(); SIM900.println( F("AT+HTTPACTION=1") ); задержка (10000); updateSIM900(); SIM900.println( F("AT+HTTPTERM") ); задержка (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());}

Изготовленные на заказ детали и корпуса

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.txt

Схема


Производственный процесс

  1. Гладильная доска
  2. Доска для серфинга
  3. Что нового у технологии наружного (GPS) отслеживания активов?
  4. Raspberry Pi разрабатывает собственный MCU вместе с платой за 4 доллара
  5. Интеграция данных датчика с микропроцессором Raspberry Pi
  6. Использование PSoC 6 Pioneer Board с Pioneer IoT Add-on Shield
  7. Измените назначение безопасных лекарств с помощью BIOVIA Living Map
  8. Функция Python map() с ПРИМЕРАМИ
  9. Работа с внутренними системами интеграции
  10. Что произойдет, если я буду ездить на автомобиле с низким уровнем охлаждающей жидкости?