Выводим скорость на лобовое стекло автомобиля

Очень крутые новинки появляются с определенным постоянством в мире машиностроения. Одна из таких новинок - это проецирование скорости на лобовое стекло, первыми эту фишку использовали в BMW. Идея урока появилась у одного радиолюбителя, когда он оставил листок бумаги с текстом в своей машине, возле лобового окна.

Он был удивлен, когда отражение текста было совершенно читаемым.  В итоге было принято решение попытаться отразить нечто более полезное, чем просто лист бумаги.

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

Шаг 1: Комплектующие для устройства

Нам как обычно понадобятся несколько разных комплектующих. Конечно основа всего - это наша Arduino.

Ниже список комплектующих и примерные цены на эти модули по которым их можно найти:

  • Arduino - Arduino Pro Mini 5V/16Mhz (примерная стоимость - $1,80)
  • Модуль GPS - чип модуля Ublox Neo-M8N UART TTL Smart GPS антенна с двойным приемником ГЛОНАСС ($6,90)
  • Светодиодный матричный дисплей - MAX7219 точечный матричный модуль для микроконтроллера Arduino ($3,75)
  • Фоторезистор - 5549 светочувствительный резистор LDR 5MM ($0.70 за 20 шт)
  • Понижающий преобразователь напряжения - Mini360 DC-DC ($0,33)
  • Резисторы
  • Провода
  • Светодиоды

Arduino. Можно использовать любого типа. Был выбран этот маленький китайский клон. Он работает с логикой 5 В TTL. Если вы используете тот же тип, что и в уроке - вам понадобится USB для TTL-конвертера для загрузки кода в Arduino. Просто для загрузки, для нормальной работы не требуется.

Модуль GPS. На eBay или AliExpress существует множество дешевых модулей GPS. Большинство из них работает на 3,3 В. Но лучше заплатить немного больше и купить логический модуль 5 Вт TTL. Таким образом, не нужны переключатели уровня для связи Rx/Tx, и нужен только один модуль понижающего преобразователя напряжения 12В в 5В. Интегрированная антенна выгодна и может принимать спутники GPS, GLONASS и BAIDOU.

Дисплей. Для целей урока приобретенный модуль слишком большой. Для получения правильной информации о скорости необходимо отобразить три цифры. Есть не так уж много водителей, которые могут разогнаться быстрее чем 999 км/ч. Для отображения половина этого модуля достаточна. К счастью гаджет является модульным и может быть разделен, например, ручной пилой.

Шаг 2: Схема устройства и сборка

Существует опциональное использование двух или одного светодиода для индикации блокировки GPS. В случае двух светодиодов на контактах D8 и D9 подключены зеленый и красный светодиоды. Зеленый означает 2D-исправление, красный означает 3D-исправление. После, примерно,  5 месяцев использования можно сказать, что они не нужны. Но существует также возможность использовать Pps-штырь из модуля GPS - если GPS заблокирован, появляются импульсы 5 В (длительность одной секунды если фиксировано).

Несколько слов о мощности - все компоненты питаются от 5В. Поэтому нужно сделать 5В от 12В (или 24В) от мощности платы. Хороший опыт работы с преобразователем DC-DC, упомянутым выше. Он маленький, дешевый и может обрабатывать ток до 2А. Это намного больше, чем нужно. Устройство имеет расход около 150 мА. Выходное напряжение преобразователя регулируется маленьким винтом - убедитесь, что это 5В перед подключением Arduino и остальной части устройства. Входное напряжение, которое вы можете взять, например, из гнезда прикуривателя в вашем автомобиле или от розетки вашего радио. Но будьте осторожны.

Шаг 3: Программируем Arduino

Код для Arduino ниже:

// Speed HeadUp display with GPS

#include <NeoSWSerial.h> // Is possible to use common SoftwareSerial library
#include <MD_Parola.h>   //Genial library for matrix displays https://github.com/MajicDesigns/MD_Parola
#include <MD_MAX72xx.h>
#include <SPI.h>

//Settings for display
// Define the number of devices we have in the chain and the hardware interface of display
#define MAX_DEVICES 2
#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10
// Hardware SPI connection
MD_Parola P = MD_Parola(CS_PIN, MAX_DEVICES);

//OPTIONAL - Settings for info LED
int GreenLED = 9;
int RedLED = 8;
//end of OPTIONAL

char buffer[99];
String veta;
byte ptr;
char ch;

int pozice;
String fix;
int fix_cislo;
float rychlost;
int rychlost_int;

int intensity = 0;
int svetlo;

NeoSWSerial gps(4, 3); // RX, TX - correct to match

void setup()
{
 Serial.begin(9600);
 gps.begin(9600); // adjust speed to communicate with GPS module
 
Serial.println("Start");

pinMode(GreenLED, OUTPUT); 
pinMode(RedLED, OUTPUT); 
digitalWrite(RedLED, LOW);
digitalWrite(GreenLED, LOW);

  P.begin();//start of display
  P.setZoneEffect(0, true, PA_FLIP_LR);  //PA_FLIP_LR means - mirrored
  P.setIntensity(0);                     //initial intensity of brightness  0-15 steps 
  P.print("---");
  delay(2000);

}

void loop()
{
//measuring of ambient light
 svetlo  = analogRead(0); 
 if (svetlo < 400){svetlo=400;}  //value depends on the lovest value given by voltage divider I´ve used 400
 //Serial.print(svetlo);
 //Serial.print(" - ");
 intensity = map(svetlo, 400, 1024, 0, 15);  //Again 400 is depending on the lovest value of divider
 //Serial.println(intensity);
//end of measuring


 //reading and process GPS NMEA sentences 
 if (gps.available())
 {
   pozice = 0;
   ch=gps.read();
   switch (ch)
   {
      case '$': // this is start of line
      {  
        ptr=0;  break;
      }
      case '*':
      {
        buffer[ptr]= '\0';
       // Serial.println(buffer);
        veta = buffer;   // here is pure NMEA sentence

       pozice = veta.indexOf("GSA"); // in xxGSA is stored information about type of fix and number of used satelites
       
       if (pozice > 0){     //searching for fix
         fix = veta.substring(8,9);
         //Serial.print("fix= ");
         //Serial.print(fix);
         //Serial.println("  ");
         //Serial.println(veta);

         char buf[fix.length()+1];                //conversion String to array of char - we need use atoi()function and it works only with array of char
         fix.toCharArray(buf, fix.length()+1);
         fix_cislo = atoi(buf);                   //final int number
                }     //End of fix search
                
         
        if (fix_cislo > 1){       //searching for speed
                  pozice = veta.indexOf("RMC"); // in xxRMC is stored information about time, pozition, speed etc 
                       if (pozice > 0){
                        
                        pozice = veta.indexOf("E");   //position of speed is in NMEA is fixed to 3th character from E or W in coordinates  
                       // Serial.print("pozice E= ");   //so we look for E - if not present in NMEA sentence, position is set to -1 and we have to look for W
                       // Serial.println(pozice);
                        if (pozice < 0){pozice = veta.indexOf("W");
                       // Serial.print("pozice W= ");
                       // Serial.println(pozice);}
                        
                   fix = veta.substring(pozice+2,pozice+7);
                   rychlost = fix.toFloat();
                   rychlost = rychlost*1.852;         //Original speed from NMEA is in KNOTS... So we have to convert it to km/h 
                                                          // 1 knots =1.85200 kilometers per hour
                   //rychlost = rychlost*1.15077945;      // 1 knots = 1.15077945 miles per hour
                   rychlost_int=(int)rychlost; //conversion from float to int - int is enough to display 🙂
                   if (rychlost_int < 2){rychlost_int=0;} //in small speed GPS give not precise results 
                   P.print(rychlost_int);  //Print speed to display
                   
                   }    //End of speed search
        }
        else{
         P.print("***");  //if GPS is not fixed print *** to display 
          }        
      
        ptr=0;
        break;
      }
      default:
      {
        buffer[ptr++]=ch;
        break;
      }
   }  


     
     //OPTIONAL -- LED indicates of fix mode - If not used, remowe this section
     if (fix_cislo==2){digitalWrite(GreenLED, HIGH);digitalWrite(RedLED, LOW);}     //2D fix  
     else if (fix_cislo==3){digitalWrite(GreenLED, LOW);digitalWrite(RedLED, HIGH);} //3D fix
     else {digitalWrite(GreenLED, LOW);digitalWrite(RedLED, LOW);}
     //OPTIONAL - Led - end of section
     
 }
 P.setIntensity(intensity);  //Setting of display brightness
}

Библиотека для последовательной связи должна быть общей библиотекой SoftwareSerial. В уроке использована библиотека NeoSWSerial, потому что она немного меньше. Вы даже можете использовать Rx / TX контакты Arduino и избегать SoftwareSerial, но в этом случае вы должны соответственно изменить код.

Библиотека для матричного дисплея - PAROLA (https://github.com/MajicDesigns/MD_Parola). Позволяет отображать зеркальный текст только по одной команде.

GPS - модуль дает в текстовом режиме прямую информацию о времени, положении, исправлении, количестве спутников, скорости и т.д. Он определяется протоколом NMEA. Были испробованы некоторые библиотеки парсеров GPS, но принято решение напрямую разобрать сообщения NMEA, чтобы получить необходимую информацию. В основном потому, что все оцененные библиотеки были слишком большими и предоставляли много ненужной информации.

Скорость отображается в км/ч. Если вы хотите использовать мили в час, внесите изменения в код.

rychlost = rychlost*1.852; 
//Скорость от NMEA в узлах. Нужно конвертировать в км/ч 
rychlost = rychlost*1.15077945; 
//Конвертация для миль/ч

Шаг 4: Итоговое видео

В итоге у вас должно получится устройство, принцип действия которого показан на рисунке выше. Небольшое видео, которое демонстрирует итоговый результат - ниже:

Спасибо за интерес. Желаем вам отличных проектов! Подписывайтесь на нашу группу ВКонтакте и оставляйте в ней комментарии к данному уроку.

Ардуино+