В предыдущих статьях на нашем сайте мы уже рассматривали систему отслеживания местоположения транспортных средств с использованием GSM и GPS, а также систему отображения местоположения автомобиля на гугл картах. В этой же статье мы рассмотрим создание автоматизированной системы предупреждения об авариях транспортных средств (автомобилей) на основе платы Arduino с использованием технологий GPS, GSM и акселерометра. В этой системе акселерометр будет обнаруживать неожиданные изменения осей автомобиля, а GSM модуль передавать сигнал тревоги на ваш мобильный телефон с указанием местоположения аварии.
Местоположение аварии будет передаваться в формате ссылки Google Map, для которой координаты широты и долготы будут извлекаться из GPS модуля. Сообщения также будут содержать сведения о скорости автомобиля в милях. Более подробно все процессы работы системы можно посмотреть в видео в конце статьи. С небольшими изменениями данная система может быть использована для гораздо более широкого спектра применений.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- GSM модуль (SIM900A) (купить на AliExpress).
- GPS модуль (SIM28ML) (купить на AliExpress).
- Акселерометр (ADXL335) (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Потенциометр 10 кОм (купить на AliExpress).
- Источник питания с напряжением 5В.
- Источник питания 12v 1amp.
- Макетная или печатная плата.
- Соединительные провода.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
GPS модуль и его работа
GPS представляет собой глобальную систему навигации и определения положения и используется для определения широты и долготы любой точки на Земле, также с ее помощью можно определить UTC время (всеобщее скоординированное время). В нашем проекте GPS модуль используется для определения местоположения аварии. Он принимает от спутников его текущие координаты каждую секунду, а также время и дату. Более подробно работу с ним мы уже рассматривали в статье про отслеживание местоположения транспортных средств с использованием GSM и GPS.
Примерный вид фиксированных данных глобального позиционирования (Global Positioning System Fix Data) показан на следующем рисунке:
Мы можем извлечь нужные нам данные из строки $GPGGA при помощи подсчета запятых в строке. К примеру, если вы нашли строку $GPGGA и сохранили ее в массиве, то широта может быть найдена в нем после двух запятых, а долгота – после четырех запятых. После извлечения значения широты и долготы можно поместить в другие массивы.
Приведем пример $GPGGA строки с расшифровкой:
$GPGGA,104534.000,7791.0381,N,06727.4434,E,1,08,0.9,510.4,M,43.9,M,,*47
$GPGGA,HHMMSS.SSS,latitude,N,longitude,E,FQ,NOS,HDP,altitude,M,height,M,,checksum data
В следующей таблице представлен перевод (описание) этих данных GPS.
Идентификатор | Описание |
$GPGGA | Фиксированные данные системы глобального позиционирования |
HHMMSS.SSS | Время в формате: час минута секунда и миллисекунда |
Latitude | Широта (координата) |
N | Направление: N=North (север), S=South (юг) |
Longitude | Долгота (координата) |
E | Направление: E= East (восток), W=West (запад) |
FQ | Данные фиксированного качества (Fix Quality Data) |
NOS | Номер использованного спутника |
HPD | Фактор снижения точности при определении положения в горизонтальной плоскости (Horizontal Dilution of Precision) |
Altitude | Высота над уровнем моря |
M | Meter (метр) |
Height | Height (высота) |
Checksum | Данные контрольной суммы |
GSM модуль
SIM900 представляет собой четырех диапазонный GSM/GPRS модуль, который очень удобен для использования в различных DIY (сделай сам) проектах. SIM900 поддерживает технологии GSM/GPRS, может работать в диапазонах частот 850/900/1800/1900 МГц и обеспечивает передачу голоса, SMS и данных с низким энергопотреблением. Его сравнительно легко можно найти в различных магазинах электроники.
Основные особенности данного модуля:
- разработан на основе однокристального процессора, интегрированного в ядро AMR926EJ-S;
- четырех диапазонный GSM/GPRS модуль небольшого размера;
- поддерживает технологию GPRS.
AT команды
AT означает ATTENTION (внимание). Эти команды используются для управления GSM модулем. С примерами использования подобных команд для управления GSM модулем вы можете ознакомиться в проектах по следующей ссылке. Для теста GSM модуля мы отправляем ему AT команду. Если с модулем все нормально, он нам ответит OK. Далее приведены некоторые из наиболее часто используемых AT команд.
ATE0 For echo off – отключение режима «эхо», то есть чтобы модуль не повторял в ответ команды, которые мы ему передаем
AT+CNMI=2,2,0,0,0 <ENTER> включение режима автоматического приема команд
ATD<Mobile Number>; <ENTER> осуществление вызова (ATD+919610126059;\r\n)
AT+CMGF=1 <ENTER> выбор текстового режима
AT+CMGS=”Mobile Number” <ENTER> назначение мобильного номера адресата
>>После этого мы можем писать наше сообщение
>>После написания сообщения
Ctrl+Z передаем команду сообщения (26 в десятичном формате).
ENTER=0x0d in HEX
Акселерометр
Назначение контактов акселерометра:
- Vcc подача постоянного напряжения питания 5 В.
- X-OUT аналоговый выход в направлении x.
- Y-OUT аналоговый выход в направлении y.
- Z-OUT аналоговый выход в направлении z.
- GND земля.
- ST этот контакт используется для установки чувствительности датчика.
Для лучшего понимания материала данной статьи можете посмотреть другие статьи на нашем сайте с использованием акселерометра: игра в Ping Pong с использованием Arduino и робот на Arduino, управляемый с помощью движений рук.
Работа схемы
Схема устройства представлена на следующем рисунке.
Контакт Tx GPS модуля непосредственно подключен к цифровому контакту 10 платы Arduino. С использованием библиотеки последовательной связи (Software Serial Library) мы можем задействовать последовательную связь на любых цифровых контактах платы Arduino, а не только на контактах 0 и 1, которые используются по умолчанию для последовательной связи. В данном случае с помощью этой библиотеки мы задействуем последовательную связь на контактах 10 и 11, при этом контакт Rx GPS модуля оставим незадействованным. Напряжение 12 В используется для питания GPS модуля.
Контакты Tx и Rx GSM модуля непосредственно подключены к контактам D2 и D3 платы Arduino. Для подключения GSM модуля мы также задействовали библиотеку последовательной связи (Software Serial Library). GSM модуль также питается от напряжение 12 В.
Контакты данных ЖК дисплея D4, D5, D6 и D7 подключены к контактам 6, 7, 8 и 9 платы Arduino. Контакты RS и EN ЖК дисплея подключены к контактам 4 и 5 платы Arduino, а контакт RW ЖК дисплея замкнут на землю. Потенциометр используется для установки контарстности или яркости ЖК дисплея.
Акселерометр добавлен в схему для обнаружения аварий автомобиля и его аналоговые выходы x, y и z-оси непосредственно подключены к контактам АЦП (аналогово-цифрового преобразования) A1, A2 и A3 платы Arduino.
Объяснение работы проекта
В этом проекте плата Arduino управляет всеми процессами в схеме. GPS приемник используется для определения координат транспортного средства, GSM – для передачи сигналов тревоги при помощи SMS, которые содержат координаты и ссылку на Google Map. Акселерометр (ADXL335) используется для обнаружения аварии (несчастного случая) вдоль любой оси автомобиля – обнаруживает неожиданные изменения положения транспортного средства вдоль любой из этих осей. ЖК дисплей (опционально) используется для отображения статусных сообщений и координат. Структурная схема проекта приведена на следующем рисунке.
Принцип работы системы заключается в том, что при аварии автомобиль наклоняется в какую-либо сторону и акселерометр вследствие этого изменяет значения на своих выходах (осях). Плата Arduino считывает эти значения и проверяет случились ли какие либо изменения вдоль осей. Если изменения случились, то плата Arduino извлекает координаты из строки $GPGGA, получаемой в составе данных от GPS модуля и передает SMS на заранее предопределенный номер (например, полиции, скорой помощи или члена семьи) с координатами места аварии. SMS также содержит ссылку на координаты автомобиля на Google Map, поэтому место аварии будет легко обнаружить. Для этого надо просто кликнуть по этой ссылке и вас перебросит на сервис Google map, где будет отмечено место аварии. Скорость транспортного средства (в милях в час, knots) также передается в этом SMS и отображается на экране ЖК дисплея. Более подробно все эти процессы можно посмотреть в видео в конце статьи.
В этом проекте мы установили чувствительность акселерометра при помощи указания соответствующих максимального и минимального значений (min и max) в коде программы.
1 2 |
#define minVal -50 #define MaxVal 50 |
Но для более лучших результатов вы можете использовать 200 вместо 50, или установить те значения, которые вам необходимы.
Исходный код программы
Полный текст программы приведен в конце статьи, здесь же кратко обсудим его наиболее значимые части.
Первым делом мы должны подключить все необходимые библиотеки и объявить используемые переменные. После этого мы создадим функцию void initModule(String cmd, char *res, int t) для инициализации GSM модуля и проверки его ответа с помощью AT команд.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void initModule(String cmd, char *res, int t) { while(1) { Serial.println(cmd); Serial1.println(cmd); delay(100); while(Serial1.available()>0) { if(Serial1.find(res)) { Serial.println(res); delay(t); return; } else { Serial.println("Error"); } } delay(t); } } |
После этого в функции void setup() мы инициализируем используемое аппаратное обеспечение (ЖК дисплей, GPS, GSM модули, акселерометр) и последовательную связь с использованием библиотеки software serial.
1 2 3 4 5 6 7 8 9 10 11 12 |
void setup() { Serial1.begin(9600); Serial.begin(9600); lcd.begin(16,2); lcd.print("Accident Alert "); lcd.setCursor(0,1); lcd.print(" System "); delay(2000); lcd.clear(); .... ...... ...... ..... |
Процесс калибровки акселерометра также выполняется в функции setup. Для этого мы берем несколько отсчетов (samples) и находим средние значения для осей x, y и z. И сохраняем их в переменных. Затем мы будем использовать эти значения для определения изменений в состоянии акселерометра, то есть когда транспортное средство наклоняется в каком-либо направлении (происходит авария).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
lcd.print("Callibrating "); lcd.setCursor(0,1); lcd.print("Acceleromiter"); for(int i=0;i<samples;i++) { xsample+=analogRead(x); ysample+=analogRead(y); zsample+=analogRead(z); } xsample/=samples; ysample/=samples; zsample/=samples; Serial.println(xsample); Serial.println(ysample); Serial.println(zsample); |
Затем в функции void loop() мы считываем значения с осей акселерометра и выполняем необходимые вычисления с использованием ранее сохраненных средних значений этих осей чтобы определить произошла авария или нет. И если изменения превосходят некоторый заранее определенный порог (то есть авария случилась), то плата Arduino передает SMS на необходимый номер.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void loop() { int value1=analogRead(x); int value2=analogRead(y); int value3=analogRead(z); int xValue=xsample-value1; int yValue=ysample-value2; int zValue=zsample-value3; Serial.print("x="); Serial.println(xValue); Serial.print("y="); Serial.println(yValue); Serial.print("z="); Serial.println(zValue); ..... ..... ........ ... |
Также в программе будут использоваться еще несколько функций, таких как void gpsEvent() – для получения GPS координат, void coordinate2dec() – для извлечения координат из GPS строки и преобразования их в десятичный формат, void show_coordinate() – для отображения координат в окне последовательного монитора (serial monitor) и ЖК дисплее, void Send() – для передачи SMS на заранее определённый номер.
Далее приведен полный текст программы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
#include<SoftwareSerial.h> SoftwareSerial Serial1(2,3); //make RX arduino line is pin 2, make TX arduino line is pin 3. SoftwareSerial gps(10,11); #include<LiquidCrystal.h> LiquidCrystal lcd(4,5,6,7,8,9); #define x A1 #define y A2 #define z A3 int xsample=0; int ysample=0; int zsample=0; #define samples 10 #define minVal -50 #define MaxVal 50 int i=0,k=0; int gps_status=0; float latitude=0; float logitude=0; String Speed=""; String gpsString=""; char *test="$GPRMC"; void initModule(String cmd, char *res, int t) { while(1) { Serial.println(cmd); Serial1.println(cmd); delay(100); while(Serial1.available()>0) { if(Serial1.find(res)) { Serial.println(res); delay(t); return; } else { Serial.println("Error"); } } delay(t); } } void setup() { Serial1.begin(9600); Serial.begin(9600); lcd.begin(16,2); lcd.print("Accident Alert "); lcd.setCursor(0,1); lcd.print(" System "); delay(2000); lcd.clear(); lcd.print("Initializing"); lcd.setCursor(0,1); lcd.print("Please Wait..."); delay(1000); Serial.println("Initializing...."); initModule("AT","OK",1000); initModule("ATE1","OK",1000); initModule("AT+CPIN?","READY",1000); initModule("AT+CMGF=1","OK",1000); initModule("AT+CNMI=2,2,0,0,0","OK",1000); Serial.println("Initialized Successfully"); lcd.clear(); lcd.print("Initialized"); lcd.setCursor(0,1); lcd.print("Successfully"); delay(2000); lcd.clear(); lcd.print("Callibrating "); lcd.setCursor(0,1); lcd.print("Acceleromiter"); for(int i=0;i<samples;i++) { xsample+=analogRead(x); ysample+=analogRead(y); zsample+=analogRead(z); } xsample/=samples; ysample/=samples; zsample/=samples; Serial.println(xsample); Serial.println(ysample); Serial.println(zsample); delay(1000); lcd.clear(); lcd.print("Waiting For GPS"); lcd.setCursor(0,1); lcd.print(" Signal "); delay(2000); gps.begin(9600); get_gps(); show_coordinate(); delay(2000); lcd.clear(); lcd.print("GPS is Ready"); delay(1000); lcd.clear(); lcd.print("System Ready"); Serial.println("System Ready.."); } void loop() { int value1=analogRead(x); int value2=analogRead(y); int value3=analogRead(z); int xValue=xsample-value1; int yValue=ysample-value2; int zValue=zsample-value3; Serial.print("x="); Serial.println(xValue); Serial.print("y="); Serial.println(yValue); Serial.print("z="); Serial.println(zValue); if(xValue < minVal || xValue > MaxVal || yValue < minVal || yValue > MaxVal || zValue < minVal || zValue > MaxVal) { get_gps(); show_coordinate(); lcd.clear(); lcd.print("Sending SMS "); Serial.println("Sending SMS"); Send(); Serial.println("SMS Sent"); delay(2000); lcd.clear(); lcd.print("System Ready"); } } void gpsEvent() { gpsString=""; while(1) { while (gps.available()>0) //Serial incoming data from GPS { char inChar = (char)gps.read(); gpsString+= inChar; //store incoming data from GPS to temparary string str[] i++; // Serial.print(inChar); if (i < 7) { if(gpsString[i-1] != test[i-1]) //check for right string { i=0; gpsString=""; } } if(inChar=='\r') { if(i>60) { gps_status=1; break; } else { i=0; } } } if(gps_status) break; } } void get_gps() { lcd.clear(); lcd.print("Getting GPS Data"); lcd.setCursor(0,1); lcd.print("Please Wait....."); gps_status=0; int x=0; while(gps_status==0) { gpsEvent(); int str_lenth=i; coordinate2dec(); i=0;x=0; str_lenth=0; } } void show_coordinate() { lcd.clear(); lcd.print("Lat:"); lcd.print(latitude); lcd.setCursor(0,1); lcd.print("Log:"); lcd.print(logitude); Serial.print("Latitude:"); Serial.println(latitude); Serial.print("Longitude:"); Serial.println(logitude); Serial.print("Speed(in knots)="); Serial.println(Speed); delay(2000); lcd.clear(); lcd.print("Speed(Knots):"); lcd.setCursor(0,1); lcd.print(Speed); } void coordinate2dec() { String lat_degree=""; for(i=20;i<=21;i++) lat_degree+=gpsString[i]; String lat_minut=""; for(i=22;i<=28;i++) lat_minut+=gpsString[i]; String log_degree=""; for(i=32;i<=34;i++) log_degree+=gpsString[i]; String log_minut=""; for(i=35;i<=41;i++) log_minut+=gpsString[i]; Speed=""; for(i=45;i<48;i++) //extract longitude from string Speed+=gpsString[i]; float minut= lat_minut.toFloat(); minut=minut/60; float degree=lat_degree.toFloat(); latitude=degree+minut; minut= log_minut.toFloat(); minut=minut/60; degree=log_degree.toFloat(); logitude=degree+minut; } void Send() { Serial1.println("AT"); delay(500); serialPrint(); Serial1.println("AT+CMGF=1"); delay(500); serialPrint(); Serial1.print("AT+CMGS="); Serial1.print('"'); Serial1.print("9821757249"); //mobile no. for SMS alert Serial1.println('"'); delay(500); serialPrint(); Serial1.print("Latitude:"); Serial1.println(latitude); delay(500); serialPrint(); Serial1.print(" longitude:"); Serial1.println(logitude); delay(500); serialPrint(); Serial1.print(" Speed:"); Serial1.print(Speed); Serial1.println("Knots"); delay(500); serialPrint(); Serial1.print("http://maps.google.com/maps?&z=15&mrt=yp&t=k&q="); Serial1.print(latitude,6); Serial1.print("+"); //28.612953, 77.231545 //28.612953,77.2293563 Serial1.print(logitude,6); Serial1.write(26); delay(2000); serialPrint(); } void serialPrint() { while(Serial1.available()>0) { Serial.print(Serial1.read()); } } |