Vino la competitia de roboti SciK!DS!

roboti

 

Pe 15-16 octombrie, la etajul 1 din Mall Promenada, are loc SciK!DS Festivalul Stiintei, cea mai cool intalnire cu stiinta!

 

Noi vom premia cei mai buni roboti in cadrul probelor:

LINE FOLLOWER – sambata, 15 octombrie, de la ora 12.00.

MINI SUMO – duminica, 16 octombrie, de la ora 12.00.

 

Detalii despre regulament si inscrieri gasesti AICI.

 

Spor la treaba!

 

Proiect Ceas GPS cu ecran TFT

Sistemul de poziționare GPS este un real ajutor pentru navigație și localizare dar este și un foarte bun furnizor de oră exactă. În cadrul acestui proiect vom construi un ceas care își preia informațiile de oră și dată prin intermediul unui modul GPS. Interfațarea cu utilizatorul va fi asigurată de un ecran TFT de 2.8’’ cu touch capacitiv. Captura de ecran de mai jos ilustrează scopul final al sistemului (afișare oră și dată, bulinele albastre din partea de sus a ecranului indică numărul de sateliți GPS văzuți direct de sistem). Sincronizarea ceasului prin GPS oferă o foarte mare acuratețe și o independență a sincronizării față de un tip de rețea anume (rețea de telefonie mobilă, rețea Internet) putând funcționa oriunde în lume, chiar și în zone extrem de izolate.

1

Ecran principal ceas GPS

Pentru mai multe informații legate de funcționarea sistemului de localizare și sincronizare GPS puteți consulta:

GPS.gov: GPS Overview

http://www.gps.gov/systems/gps/

Global Positioning System

https://en.wikipedia.org/wiki/Global_Positioning_System

Garmin | What is GPS?

http://www8.garmin.com/aboutGPS/

The Global Positioning System

http://www.colorado.edu/geography/gcraft/notes/gps/gps_f.html

Pentru implementarea sistemului vom utiliza:

1. placă de dezvoltare Arduino Uno R3 (sau echivalentă):

2

https://www.robofun.ro/arduino/arduino_uno_v3

2. un Sparkfun GPS Logger Shield (dar programul va funcționa cu orice modul GPS serial); pentru utilizare această componentă necesită și un Kit Conectori Arduino R3 și o baterie 12mm (CR1225):

3

https://www.robofun.ro/gps/gps-logger-shield-sparkfun

Pentru mai multe informații despre funcționarea acestei componente puteți consulta:

GPS Logger Shield Hookup Guide

https://learn.sparkfun.com/tutorials/gps-logger-shield-hookup-guide

3. un ecran Adafruit 2.8″ TFT Touch Shield (240x320pixels, 262K culori)

4

https://www.robofun.ro/lcd/tft-touch-shield-arduino-capacitive

Pentru mai multe informații despre funcționarea acestei componente puteți consulta:

Adafruit 2.8″ TFT Touch Shield v2 – Capacitive or Resistive

https://learn.adafruit.com/adafruit-2-8-tft-touch-shield-v2

Ordinea de instalare a celor două componente de tip shield este: shield-ul GPS se conectează la placa de dezvoltare Arduino Uno iar shield-ul TFT se conectează la shield-ul GPS (ordinea inversă de montare a celor două shield-uri ar face imposibilă utilizarea ecranului…).

Pentru programarea sistemului sunt necesare mai multe biblioteci software externe mediului Arduino IDE:

TinyGPS++ – pentru interpretarea datelor provenite de la modulul GPS

http://arduiniana.org/libraries/tinygpsplus/

Adafruit GFX și Adafruit ILI9341 – pentru partea de afișare pe ecranul TFT

https://github.com/adafruit/Adafruit-GFX-Library

https://github.com/adafruit/Adafruit_ILI9341

Pentru înțelegerea modului de lucru cu ecrane grafice utilizând Adafruit GFX este utilă parcurgerea:

https://learn.adafruit.com/adafruit-gfx-graphics-library

Adafruit FT6206 – necesară pentru lucrul cu partea de touchscreen

https://github.com/adafruit/Adafruit_FT6206_Library

#include <SoftwareSerial.h>

#include <TinyGPS++.h>

TinyGPSPlus tinyGPS;

#define GPS_BAUD 9600

#define ARDUINO_GPS_RX 9

#define ARDUINO_GPS_TX 8

SoftwareSerial gpsPort(ARDUINO_GPS_TX, ARDUINO_GPS_RX);

#include <SPI.h>

#include <Adafruit_GFX.h>

#include <Adafruit_ILI9341.h>

#include <Adafruit_FT6206.h>

#define TFT_DC 9

#define TFT_CS 10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

Adafruit_FT6206 ctp = Adafruit_FT6206();

Din partea de declarații inițiale se poate observa o mică incompatibilitate între cele două componente de tip shield și anume: pinul D9 al plăcii de dezvoltare este utilizat atât pentru semnalul RX al modulului GPS cât și pentru semnalul DC al ecranului TFT. Din fericire această incompatibilitate nu va afecta programul nostru deoarece nu vom trimite comenzi către modulul GPS, doar vom prelua date de la modulul GPS, și nici nu vom trece modulul TFT în modul Command (pinul DC configurează modul de funcționare Data/Command). Cu alte cuvinte pinul este folosit de ambele componente dar nu este utilizat pentru nici una dintre ele în cadrul programului prezentat.

În cadrul secțiunii setup() se vor inițializa componentele declarate anterior (tft – pentru afișaj, ctp – pentru touch și gpsPort – pentru comunicația cu modulul GPS):

void setup() {

  tft.begin();

  ctp.begin(40);

  gpsPort.begin(GPS_BAUD);

  delay(100);

  tft.fillScreen(ILI9341_DARKGREEN);

  yield();

  delay(1000);

}

Se vor utiliza următoarele variabile globale pentru a controla procesul de afișare:

  • timer – numărul de milisecunde de la ultima reîmprospătare a informațiilor de pe ecran; reîmprospătarea se va face o dată la 60.000ms = 60s = 1 minut;
  • show – tipul de informații ce vor fi afișate pe ecran (0 – ceas, 1 – informații GPS, 2 – distanțe față de câteva orașe din România);
  • timezone – ora returnată de sistemul GPS este în fusul orar UTC+0 (ora Londrei); în această variabilă vom calcula decalajul de fus orar bazându-ne pe longitutinea raportată de GPS;
  • Months – vector cu denumirea lunilor anului;
  • ref – variabilă logică care forțează (când este true) reafișare imediată a informațiilor de pe ecran.

uint32_t timer = millis();

byte show = 0;

byte timezone = 0;

const char * Months[12] = { “Ianuarie”, “Februarie”,

 “Martie”, “Aprilie”, “Mai”, “Iunie”, “Iulie”, “August”,

“Septembrie”, “Octombrie”, “Noiembrie”, “Decembrie” };

boolean ref = true;

În cadrul secțiunii loop() se vor citi informațiile venite de la modulul GPS:

void loop(void) {

  while (gpsPort.available())

    tinyGPS.encode(gpsPort.read());

În cazul în care se atinge ecranul se va comuta între cele trei moduri de afișare (ceas, GPS, distanțe – ultimele două sunt exemplificate în următoarele două capturi de ecran):

5

6

if (ctp.touched()) {

    show++;

    show = show % 3;

    ref = true;

  }

La fiecare 60 de secunde afișajul este reîmprospătat cu tipul de informații ales de utilizator (0, 1 sau 2):

 

if ((millis() – timer > 60000) || ref) {

      tft.fillScreen(ILI9341_BLACK);

      yield();

      switch (show) {

În modul 0 (ceas) se afișează ora, data și numărul de sateliți. Tot aici se calculează diferența de fus orar în mod automat plecând de la premiza că la fiecare 15 grade se adaugă o oră, mai multe informații se pot consulta și la adresa:

Latitude, Longitude and Time Zones – the Earth’s Coordinate System

http://www.english-online.at/geography/longitude-latitude/longitude-latitude-time-zones.htm

case 0:

      if (tinyGPS.time.isValid()) {

         tft.setTextSize(8);     

         tft.setTextColor(ILI9341_RED); 

         tft.setRotation(1);

         tft.setCursor(50, 90);

         if (((tinyGPS.time.hour() + timezone) % 24) < 10) tft.print(‘0’);

         if (tinyGPS.location.isValid()) timezone = ((tinyGPS.location.lng()-7.5) / 15)+1;

         tft.print((tinyGPS.time.hour() + timezone) % 24);

        tft.print(‘:’);

         if (tinyGPS.time.minute() < 10) tft.print(‘0’);

                tft.print(tinyGPS.time.minute()); }

      if (tinyGPS.date.isValid()) {

         tft.setTextColor(ILI9341_ORANGE); 

         tft.setTextSize(3);

         tft.setCursor(10, 200);

         tft.print(tinyGPS.date.day()); tft.print(” “);

         tft.print(Months[tinyGPS.date.month()]);

         tft.print(” “);

         tft.print(tinyGPS.date.year()); }

      for (int i=0; i<tinyGPS.satellites.value(); i++)

         tft.fillCircle(300-(25*i),20,10,ILI9341_CYAN);

      break;

În modul 1 – informații GPS – se vor afișa: altitudinea în metri, latitudine, longitudine, acuratețea relativă a poziționării pe orizontală HDOP (horizontal dilution of precision), timpul scurs de la ultima sincronizare AGE, viteza și cursul (ultimii doi parametrii au relevanță doar dacă sistemul este în mișcare).

case 1: 

      if (tinyGPS.location.isValid()) {

        tft.setTextSize(3);

        tft.setRotation(1);

        tft.setCursor(0, 25);

        tft.setTextColor(ILI9341_GREEN);

        tft.print(“ALT: “);

    tft.print(tinyGPS.altitude.meters());

    tft.println(“m”);

        tft.setTextColor(ILI9341_GREEN+5);

        tft.print(“LAT: “);

        tft.println(tinyGPS.location.lat(), 5);

        tft.setTextColor(ILI9341_GREEN+10);

        tft.print(“LON: “);

        tft.println(tinyGPS.location.lng(), 5);

        tft.setTextColor(ILI9341_GREEN+15);

        tft.print(“HDOP: “);

        tft.println(tinyGPS.hdop.value(), 5);

        tft.setTextColor(ILI9341_GREEN+20);

        tft.print(“AGE: “);

        tft.print(tinyGPS.location.age(), 5);

        tft.println(“ms”);

        tft.setTextColor(ILI9341_GREEN+25);

        tft.print(“SPD: “);

tft.print(tinyGPS.speed.kmph(), 5);

tft.println(“kmph”);

        tft.setTextColor(ILI9341_GREEN+30);

        tft.print(“CRS: “);

tft.println(tinyGPS.course.deg(), 5);  }

  break;

În modul 2 – distanțe – se vor afișa distanțele (în kilometri) dintre punctul în care se află sistemul și câteva orașe din România (București, Iași, Constanța, Cluj, Piatra Neamț, Oradea și Satu Mare). Atenție!!! distanța este calculată în linie dreapta pe baza coordonatelor GPS, nu este distanță rutieră sau feroviară.

case 2:

      if (tinyGPS.location.isValid()) {

        tft.setTextSize(3);

        tft.setRotation(1);

        tft.setCursor(0, 25);

        tft.setTextColor(ILI9341_PINK);

        #define BUC_LAT 44.439663

        #define BUC_LON 26.096306

        #define IAS_LAT 47.151726

        #define IAS_LON 27.587914

        #define COS_LAT 44.1833

        #define COS_LON 28.65

        #define CLJ_LAT 46.7772

        #define CLJ_LON 23.5999

        #define PTN_LAT 46.929962

        #define PTN_LON 26.377979

        #define ORD_LAT 47.0666667

        #define ORD_LON 21.9333333

        #define STM_LAT 47.790001

        #define STM_LON 22.889999

        tft.setTextColor(ILI9341_YELLOW);

        unsigned long distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),

BUC_LAT,BUC_LON)/1000;

    tft.print(“Bucuresti: “);

tft.print(distanceKm);

tft.println(“Km”);

    tft.setTextColor(ILI9341_YELLOW+5);

    distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),

IAS_LAT,IAS_LON)/1000;

    tft.print(“Iasi:      “);

tft.print(distanceKm);

tft.println(“Km”);

    tft.setTextColor(ILI9341_YELLOW+10);

    distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),COS_LAT,COS_LON)/1000;

    tft.print(“Constanta: “);

    tft.print(distanceKm);

    tft.println(“Km”);

    tft.setTextColor(ILI9341_YELLOW+15);

    distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),CLJ_LAT,CLJ_LON)/1000;

tft.print(“Cluj:      “);

tft.print(distanceKm);

tft.println(“Km”);

    tft.setTextColor(ILI9341_YELLOW+20);

    distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),PTN_LAT,PTN_LON)/1000;

tft.print(“Piatra Nt: “);

tft.print(distanceKm);

tft.println(“Km”);

    tft.setTextColor(ILI9341_YELLOW+25);

    distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),

ORD_LAT,ORD_LON)/1000;

    tft.print(“Oradea:    “);

tft.print(distanceKm);

tft.println(“Km”);

    tft.setTextColor(ILI9341_YELLOW+30);

    distanceKm = (unsigned long)

TinyGPSPlus::distanceBetween

(tinyGPS.location.lat(),

tinyGPS.location.lng(),STM_LAT,STM_LON)/1000;

    tft.print(“Satu Mare: “);

tft.print(distanceKm);

tft.println(“Km”); }

  break;    }

timer = millis();

ref = false;

  }

  yield();

}

Programul a fost dezvoltat și testat cu Arduino IDE 1.6.12, Arduino AVR Boards 1.6.14 și bibliotecile TinyGPSPlus 0.94b, Adafruit GFX 1.1.5, Adafruit ILI9341 1.0.2, Adafruit FT6206 1.0.0 .

[Academia inventeaza.ro] Angajăm Profesori de Robotică, Electronică și Programare

Ne mărim echipa și astfel angajăm Profesori de Robotică pentru Academia inventeaza.ro!

Dacă ești o persoană placută, comunicativă și creativă, îți place să lucrezi cu elevi cu vârste între 7 și 17 ani și ești totodată un bun cunoscător al domeniului ‪#‎Robotică, ‪#‎Electronică‬ și ‪#‎IT‬ atunci te așteptăm negreșit să ni te alături!

kids-with-robots

Responsabilități

Întocmește și gestionează curricula cursului și documentele legate de cursul pe care îl livrează;
Realizează materiale de studiu suplimentare (exerciții, studii de caz) și le adaptează nivelului cursanților;
Realizează și comunică în timp util necesarul de materiale;
Ține evidența și prezența participanților la curs;
Oferă feedback cu privire la performanța participanților;
Gestionează relația cu participanții, părinții cursanților și Manager-ul de Proiect;
Pregătește participanții pentru participarea la competiții;
Înainte de fiecare sesiune, pregătește sala și se asigură că are la dispoziție toate materialele necesare pentru buna desfășurare a cursului;
Livrează cursul de Robotică, Electronică și Programare pentru Copii și Adolescenți;
Se asigură de buna desfășurare a cursului de Robotică, Electronică și Programare pentru Copii și Adolescenți;
Participă la evenimentele organizate de Academia inventeaza.ro sau la cele la care organizația este invitată;
Participă la întâlnirile interne de status update.

Cerințe

Studii de specialitate în domeniul electronicii (de bază atât teoretice cât și practice) și mecanicii.
Cunoștințe de robotică și/sau programare, preferabil C++;
Experiență în lucrul cu platforma de dezvoltare Arduino;
Experiență de cel puțin un an în predarea cursurilor într-un centru de pregătire;
Capacitatea de a susține un curs interactiv;
Aptitudini pedagogice;
Răbdare, pasiune pentru activitatea de mentorat;
Persoană motivată, organizată, implicată, punctuală – metode moderne/atractive de predare;
Capacitatea de a preda pe “limba copiilor”;
Abilități foarte bune de comunicare, prezentare și evaluare;
Disponibilitate min. 20 ore săptămânal;
Avantaje: diplomă de formator sau modul psihopedagogic.

Beneficii Oferite:

Program flexibil;
Formare la locul de muncă și mentorat;
Remunerație motivantă (compusă din salariu fix plus bonusuri în funcție de performanțe);
Mediu de lucru plăcut alături de o echipă de profesioniști.

Asteptăm CV-ul tău, împreună cu o scrisoare de intenție pe adresa de e-mail academia@inventeaza.ro!

Doar candidații selectați vor fi contactați. Toate aplicațiile vor fi tratate cu confidențialitate.

Proiect ceas NTP

Protocolul NTP (Network Time Protocol) este folosit de sistemele de calcul de uz general (PC-uri, servere, laptop-uri) pentru a-și sincroniza ceasul intern cu o sursă de încredere. Având în vedere creșterea posibilităților de interconectare a sistemelor embedded acest protocol a devenit accesibil și acestora. În cadrul proiectului de față vom prezenta o soluție de sincronizare a unui ceas cu o sursă NTP Internet. Pentru mai multe detalii legate de protocolul NTP puteți consulta:

What is NTP?

http://www.ntp.org/ntpfaq/NTP-s-def.htm

NTP – How does it work?

http://www.ntp.org/ntpfaq/NTP-s-algo.htm

Network Time Protocol

https://en.wikipedia.org/wiki/Network_Time_Protocol

În cadrul proiectului vom utiliza o placă Arduino Leonardo ETH – o versiune mai nouă a clasicii plăci Arduino Ethernet. Această placă este echipată cu un microcontroler ATmega32U4 (ce permite utilizarea plăcii fără a avea nevoie de programator FTDI) și un controler ethernet W5500 (față de W5100 de pe vechea placă Arduino Ethernet).

1

https://www.robofun.ro/arduino/arduino-leonardo-eth

Pentru afișare vom utiliza un ecran alfanumeric monocrom de dimensiuni generoase (20×4) cu magistrală I2C pentru simplificarea interconectării:

2

https://www.robofun.ro/lcd/lcd_20x4_i2c_negru_verde

 Schema de interconectare între placa de dezvoltare și ecran este următoarea (SDA-D2, SCL-D3, 5V-5V, GND-GND):

3

Conectarea ecranului alfanumeric prin intemediul magistralei I2C necesită utilizarea unei versiuni modificate a bibliotecii LiquidCrystal:

https://github.com/adafruit/Adafruit_LiquidCrystal

#include “Wire.h”

#include “Adafruit_LiquidCrystal.h”

Adafruit_LiquidCrystal lcd(0);

Spre deosebire de alte metode de sincronizare a unui ceas electronic, sincronizarea NTP nu permite o interogare frecventă care să permită afișarea ceasului doar pe baza informațiilor primite de la serverul NTP – este o metodă de sincronizare a ceasului nu o sursă ce oferă ora și data curentă. Din acest motiv este necesar să implementăm un mecanism propriu de contorizare a timpului care să ofere informațiile necesare pentru afișarea orei și datei pe ecran – pentru acest lucru vom utiliza biblioteca Time:

https://github.com/PaulStoffregen/Time

#include <TimeLib.h>

const int timeZone = 3;

Biblioteca Ethernet inclusă în mediul Arduino IDE nu este compatibilă cu controlerul ethernet W5500 din acest motiv este necesară instalarea bibliotecii Ethernet2:

https://github.com/adafruit/Ethernet2

Placa Arduino Leonardo ETH este produsă exclusiv de arduino.org , biblioteca Ethernet2 este parte a versiunii mediului Arduino IDE dezvoltat de arduino.org dar este posibilă programarea acestei plăci și cu versiunea mediului Arduino IDE dezvoltată de arduino.cc: se selectează Arduino Leonardo și se instalează biblioteca Ethernet2.

#include <SPI.h>

#include <Ethernet2.h>

#include <EthernetUdp2.h>

byte mac[] = {  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

unsigned int localPort = 8888;      

// time-a.timefreq.bldrdoc.gov

IPAddress timeServer(132, 163, 4, 101);

// time-b.timefreq.bldrdoc.gov

// IPAddress timeServer(132, 163, 4, 102);

// time-c.timefreq.bldrdoc.gov

// IPAddress timeServer(132, 163, 4, 103);

EthernetUDP Udp;

În cadrul secțiunii setup() se realizează inițializarea ecranului și a conexiunii de rețea. Este necesară conectarea sistemului într-o rețea ce oferă servicii de configurare automată de tip DHCP.

void setup() {

  lcd.begin(20, 4);

  lcd.setBacklight(HIGH);

  lcd.setCursor(0, 1);

  byte n = 1;

  while(!Ethernet.begin(mac)) {

    lcd.print(“DHCP failed…  “);

    lcd.print(n++);

    lcd.setCursor(0, 1);

    delay(10000);

  }

  lcd.print(“MyIP: “);

  for (byte thisByte = 0; thisByte < 4; thisByte++) {

    lcd.print(Ethernet.localIP()[thisByte], DEC);

    if(thisByte<3) lcd.print(“.”);

  }

  Udp.begin(localPort);

  setSyncProvider(getNtpTime);

}

În cadrul secțiunii loop() se realizează partea de afișare propriu-zisă pe ecran a informațiilor de tip oră și dată. Prima linie a afișajului va conține ora și data, a doua linie adresa IP a sistemului, a treia linie ora ultimei sincronizări reușite și a patra linie starea sincronizării NTP.

4

time_t prevDisplay = 0;

time_t lastsyncr;

void loop() {

  lcd.setCursor(0,0);

  if (timeStatus() != timeNotSet) {

    if (now() != prevDisplay) {

      prevDisplay = now();

      digitalClockDisplay(); 

    }

  }

  lcd.setCursor(0,2);

  if(timeStatus()==timeNotSet) lcd.print(“Time Not Set”);

  if(timeStatus()==timeNeedsSync)

lcd.print(“Time Needs Sync”);

  if(timeStatus()==timeSet) {

lcd.print(“Time Set at “);

printDigits(hour(lastsyncr),false);

printDigits(minute(lastsyncr),true); }

  delay(1000);

}

Procedurile digitalClockDisplay() și prinDigits() sunt utilizate în afișarea corectă a orei și datei.

void digitalClockDisplay(){

  printDigits(hour(),false);

  printDigits(minute(),true);

  printDigits(second(),true);

  lcd.print(” “);

  lcd.print(day());

  lcd.print(“/”);

  lcd.print(month());

  lcd.print(“/”);

  lcd.print(year());

}

void printDigits(int digits, boolean dots){

  if (dots) lcd.print(“:”);

  if(digits < 10)

    lcd.print(‘0’);

  lcd.print(digits);

}

Procedurile getNtpTime() și sendNTPpacket() sunt utilizate de biblioteca Time pentru a utiliza protocolul NTP ca sursă de sincronizare. În cazul în care nu se reușește nici o sincronizare (server NTP indisponibil, probleme de conexiune Internet) sistemul nu va fi capabil să afișeze ora și data.

5

Atenție! În cazul în care sistemul nu are probleme de conexiune dar sincronizarea nu se poate realiza, se poate încerca o resetare completă a sistemului (deconectare alimentare, realimentare) deoarece este posibil ca problema să fie cauzată de o blocare a controlerului ethernet.

const int NTP_PACKET_SIZE = 48;

byte packetBuffer[NTP_PACKET_SIZE];

 time_t getNtpTime()

{ while (Udp.parsePacket() > 0) ;

  sendNTPpacket(timeServer);

  uint32_t beginWait = millis();

  while (millis() – beginWait < 1500) {

    int size = Udp.parsePacket();

    if (size >= NTP_PACKET_SIZE) {

      lcd.setCursor(0,3);

      lcd.print(“Receive NTP Response”);

      Udp.read(packetBuffer, NTP_PACKET_SIZE);  

      unsigned long secsSince1900;

      secsSince1900 =  (unsigned long)packetBuffer[40]<< 24;

      secsSince1900 |= (unsigned long)packetBuffer[41]<< 16;

      secsSince1900 |= (unsigned long)packetBuffer[42]<< 8;

      secsSince1900 |= (unsigned long)packetBuffer[43];

      lastsyncr = (time_t) (secsSince1900 – 2208988800UL+ timeZone * SECS_PER_HOUR);

      return lastsyncr;

    }

  }

  lcd.setCursor(0,3);

  lcd.print(“No NTP Response :-(“);

  return 0;

}

void sendNTPpacket(IPAddress &address)

{ memset(packetBuffer, 0, NTP_PACKET_SIZE);

  packetBuffer[0] = 0b11100011;  

  packetBuffer[1] = 0;    

  packetBuffer[2] = 6;    

  packetBuffer[3] = 0xEC; 

  packetBuffer[12]  = 49;

  packetBuffer[13]  = 0x4E;

  packetBuffer[14]  = 49;

  packetBuffer[15]  = 52;

  Udp.beginPacket(address, 123);

  Udp.write(packetBuffer, NTP_PACKET_SIZE);

  Udp.endPacket();

}

Programul a fost realizat și testat cu Arduino IDE 1.6.12, Arduino AVR Boards 1.6.14, Adafruit LiquidCrystal 1.0.0, Time 1.5.0 și Ethernet2 1.0.2.

Exemple de alte proiecte de tip ceas cu sincronizare NTP bazate pe platforma Arduino:

Arduino Internet Time Client

http://www.instructables.com/id/Arduino-Internet-Time-Client/

Network time syncronized clock for Arduino

http://www.instructables.com/id/Internet-time-syncronized-clock-for-Arduino/

Arduino Internet Clock

http://blog.thiseldo.co.uk/?p=336

A simple arduino clock using ethernet shield and ntp for beginners

http://blog.riyas.org/2014/03/a-simple-arduino-led-clock-using-ethernet-ntp-for-beginners.html

Garbage Mate – Version 2

http://www.wabbitwanch.net/blog/?p=744

 

Proiect ceas cu ecran OLED și sincronizare GSM

O problemă des întâlnită la ceasuri este acuratețea cu care indică ora. Câți dintre noi au răbdare să potrivească periodic ceasurile de perete astfel încât să nu arate cu câteva minute / zeci de minute înainte sau mai târziu? Există mai multe soluții de sincronizare automată a ceasurilor electronice dar în cadrul proiectului de față vom utiliza o metodă mai rar întâlnită pentru ceasurile obișnuite: sincronizarea automată dintr-o rețea de telefonie mobilă GSM.

Pentru implementare vom utiliza o placă de dezvoltare Adafruit Feather 32U4 FONA ce include un microcontroler ATmega32U4 (la fel ca și Arduino Leonardo sau alte plăci Feather) și un controler GSM SIM800H (Quad-band 850/900/1800/1900MHz).

1

https://www.robofun.ro/feather-32u4-fona

Pentru utilizarea acestei plăci avem nevoie și de o antenă GSM uFL, un acumulator LiPo 3.7V de minim 500mAh și de un SIM GSM 2G.

2

https://www.robofun.ro/accesorii/accesorii-antene/slim-sticker-type-gsm-cellular-quad-band-antenna-3dbi-ufl

3

https://www.robofun.ro/surse_de_alimentare/acumulatori/Acumulator-LiPo-3.7v-800mAh

Pentru mai multe informații despre funcționarea plăcii Adafruit Feather 32U4 FONA puteți consulta și materialul:

Adafruit Feather 32u4 FONA – Take your Feather anywhere in the world

https://learn.adafruit.com/adafruit-feather-32u4-fona/

Pentru partea de afișare vom utiliza un afișaj OLED monocrom 1.3’’ 128×64 pixeli și conexiune I2C:

4

https://www.robofun.ro/lcd/monochrome-1-3-128×64-oled-graphic-display

Schema de interconectare între placa de dezvoltare și ecranul OLED este tipică unei conexiuni I2C (pin Data – pin 2 SDA, pin Clk – pin 3 SCL, pin Rst – pin 5, pin 3v3 – pin 3V, pin GND – pin GND):

5

Programul necesită instalarea mai multor biblioteci externe mediului de dezvoltare Arduino IDE:

Adafruit FONA – pentru lucrul cu modulul GSM

https://github.com/adafruit/Adafruit_FONA

Adafruit GFX și Adafruit SSD1306 – pentru lucrul cu ecranul OLED

https://github.com/adafruit/Adafruit-GFX-Library

https://github.com/adafruit/Adafruit_SSD1306

Scopul sistemului este de a prelua data și ora din rețeaua GSM și de o afișa pe ecranul OLED. Se poate utiliza o cartelă PrePay și nu este nevoie să aibă credit activ – se poate utiliza o cartelă aflată în perioada de grație. Pe lângă oră și dată pe ecranul sistemului se va afișa și procentul de încărcare a acumulatorului (stânga sus) și Network Status / puterea semnalului GSM (dreapta sus):

6

În cadrul programului se vor inițializa într-o primă fază obiectele de lucru cu modulul GSM și cu ecranul OLED:

#include “Adafruit_FONA.h”

#define FONA_RX  9

#define FONA_TX  8

#define FONA_RST 4

#define FONA_RI  7

char replybuffer[255];

#include <SoftwareSerial.h>

SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);

SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

uint8_t type;

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#define OLED_RESET 5

Adafruit_SSD1306 display(OLED_RESET);

Secțiunea setup() cuprinde partea de inițializare a ecranului OLED și a modulului GSM (inclusiv deblocare cartelă SIM, activare sincronizare ceas din rețea).

void setup() {

  display.begin(SSD1306_SWITCHCAPVCC, 0x3D);

  display.display();

  delay(2000);

  display.clearDisplay();

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0,0);

  display.println(“Initializing…”);

  display.display();

  delay(1);

  fonaSerial->begin(4800);

  if (! fona.begin(*fonaSerial)) {

    display.println(F(“Couldn’t find FONA”));

    display.display();

    delay(1);

    while (1);

  }

  type = fona.type();

  display.println(F(“FONA is OK”));

  display.print(F(“Found “));

  switch (type) {

      case FONA800L:

        display.println(F(“FONA 800L”)); break;

      case FONA800H:

        display.println(F(“FONA 800H”)); break;

      case FONA808_V1:

        display.println(F(“FONA 808 (v1)”)); break;

      case FONA808_V2:

        display.println(F(“FONA 808 (v2)”)); break;

      case FONA3G_A:

        display.println(F(“FONA 3G (American)”)); break;

      case FONA3G_E:

        display.println(F(“FONA 3G (European)”)); break;

      default:

        display.println(F(“???”)); break;

  }

  display.display();

  delay(1);

  char imei[15] = {0};

  uint8_t imeiLen = fona.getIMEI(imei);

  if (imeiLen > 0) {

    display.print(“Module IMEI: “); display.println(imei);

    display.display();

    delay(1);

  }

Atenție!!! Codul de deblocare a cartelei SIM GSM trebuie modificat în program în concordanță cu pinul cartelei utilizate.

 if (! fona.unlockSIM(“0000“)) {

    display.println(F(“Failed”));

  } else {

    display.println(F(“PIN OK!”));

  }

  display.display();

  delay(1);

  fona.getSIMCCID(replybuffer); 

  display.print(F(“SIM CCID = “));

  display.println(replybuffer);

  display.display();

  delay(1);

  if (!fona.enableNetworkTimeSync(true)) {

     display.println(F(“Failed to enable”));

     display.display();

     delay(1);

  }

  delay(5000);

}

Secțiunea loop() se ocupă cu citirea din modulul GSM și afișare informațiilor enumerate anterior: procent încărcare acumulator, stare rețea, putere semnal rețea, oră și dată calendaristică.

void loop() {

  display.clearDisplay();

  display.setTextSize(1);

  display.setTextColor(WHITE);

  display.setCursor(0,0);

  uint16_t vbat;

  if (fona.getBattPercent(&vbat)) {

    display.print(vbat);

    display.print(F(“%         “));

  }

  uint8_t n = fona.getNetworkStatus();

  if (n == 0) display.print(F(“N “)); //Not register

  if (n == 1) display.print(F(“H “)); //Register (home)

  if (n == 2) display.print(F(“S “)); //Searching

  if (n == 3) display.print(F(“D “)); //Denied

  if (n == 4) display.print(F(“U “)); //Unknown

  if (n == 5) display.print(F(“R “)); //Register (roamning)

  n = fona.getRSSI();

  int8_t r;

  if (n == 0) r = -115;

  if (n == 1) r = -111;

  if (n == 31) r = -52;

  if ((n >= 2) && (n <= 30))

{ r = map(n, 2, 30, -110, -54); }

  display.print(r); display.println(F(“dBm”));

  display.setTextSize(3);

  display.setCursor(20,20);

  char buffer[23];

  char temp[10];

  fona.getTime(buffer, 23);

  memcpy(temp,&buffer[10],5); 

  temp[5]=’\0′;

  display.println(temp);

  display.setTextSize(2);

  display.setCursor(17,50);

  memcpy(temp,&buffer[1],8); 

    temp[8]=’\0′;

  display.println(temp);

  display.display();

  delay(1);

  while (fona.available()) {

    fona.read();

  }

  delay(10000);

}

Programul a fost dezvoltat și testat cu Arduino IDE 1.6.9, Adafruit AVR Boards 1.4.9, Adafruit FONA Library 1.3.2, Adafruit GFX Library 1.1.5 și Adafruit SSD1306 1.1.0.

Proiectul prezentat poate să reprezinte punctul de plecare în realizarea unui sistem mai complicat de tip telefon mobil. Câteva exemple de astfel de proiecte:

ArduinoPhone

http://www.instructables.com/id/ArduinoPhone/

Arduin-o-Phone

https://learn.adafruit.com/arduin-o-phone-arduino-powered-diy-cellphone/

My open-source, do-it-yourself cellphone (built with Arduino)

https://blog.arduino.cc/2013/08/12/diy-cellphone/

Cell phone text using an Arduino

http://duino4projects.com/cell-phone-text-using-an-arduino/

Proiect ceas/calendar cu termometru și configurare prin bluetooth

Chiar dacă la prima vedere realizarea unui ceas electronic pare o sarcină simplă există anumite aspecte practice reale ce îngreunează implementarea unui astfel de sistem.

1

 

Prima problemă pe care o ridică implementarea unui ceas este contorizarea timpului: la nivel de secundă (dependentă de acuratețea ceasului intern al microcontrolerului) și la nivel de minut, oră, zi, săptămână, lună, an (număr diferit de zile ale lunii, calculul zilei săptămânii, an bisect etc.). Pentru a simplifica acest aspect vom utiliza în cele ce urmează un circuit specializat RTC (Real Time Clock) DS1307 ce se va ocupa în mod precis de ambele aspecte de contorizare.

2

https://www.robofun.ro/module/module-rtc/real_time_clock

 

Un al doilea aspect delicat este interfața utilizator de comandă prin care se ”potrivește ceasul” – în mod tradițional implementată de un set de butoane pentru setarea orei, datei, alarmei etc. În cadrul unui proiect DIY butoanele sunt simplu de conectat la o placă de dezvoltare dar ridică dificultăți de ordin mecanic și estetic când vine vorba de montat într-o carcasă. Din acest motiv proiectul de față nu va utiliza butoane pentru interacțiunea cu sistemul ci un modul bluetooth prin care se vor recepționa comenzi echivalente. Modulul utilizat este Bluetooth Mate Silver dar se poate utiliza orice modul bluetooth serial:

3

https://www.robofun.ro/wireless/wireless-bluetooth/bluetooth_arduino

 

Ca și placă de dezvoltare vom utiliza o placă Arduino Uno (sau echivalentă) și pentru afișare un clasic afișaj LCD alfanumeric monocrom 16×2:

4

https://www.robofun.ro/arduino/arduino_uno_v3

 5

https://www.robofun.ro/lcd/lcd_16x2_negru_verde

 

Pentru a diversifica funcționalitatea sistemului, pe lână afișarea orei, a zilei săptămânii și a datei calendaristice, vom implementa și afișarea temperaturii și umidității mediului ambiental utilizând un senzor digital SNS-DH11 (sau DHT11):

6

https://www.robofun.ro/senzori/vreme/senzor-temperatura-umiditate-sns-dh11

 

Schema de interconectare a componentelor este următoarea:

 

7

 

LCD-ul se interconectează cu placa de dezvoltare utilizând patru linii de date și două linii de comandă (pinii D3, D4, D5, D5, D11, D12) și are lumina de fundal aprinsă permanent și contrastul la maxim:

#include <LiquidCrystal.h>

LiquidCrystal lcd(12,11,6,5,4,3);

Dacă se dorește simplificarea conectării afișajului la placa de dezvoltare se poate opta pentru un modul I2C:

https://www.robofun.ro/lcd/lcd-16×2-i2c-negru-verde

Modulul RTC se conectează pe magistrala I2C a plăcii de dezvoltare, pinii A4 și A5, și are adresa fixă 0x68.

#include <Wire.h>

#define DS1307_I2C_ADDRESS 0x68

Modulul bluetooth se conectează la pinii A1 și A0 deoarece se utilizează biblioteca SoftwareSerial ce permite utilizarea a oricăror doi pini ca port de comunicație serială.

#include “SoftwareSerial.h”;

int bluetoothTx = A1;

int bluetoothRx = A0;

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

Senzorul de temperatură și umiditate se conectează la pinul D2 al plăcii de dezvoltare și necesită utilizarea bibliotecii SimpleDHT:

https://github.com/winlinvip/SimpleDHT

#include <SimpleDHT.h>

int pinDHT11 = 2;

SimpleDHT11 dht11;

Programul folosește două variabile globale pentru controlul afișării: sec_afis – număr de secunde ce permite alternarea afișării temperaturii / umidității – datorită numărului limitat de caractere acestea sunt afișate alternativ la 10 secunde; afis – permite reîmprospătarea ecranului nu mai des de o secundă.

volatile int sec_afis=1;

volatile boolean afis=true;

În cadrul secțiunii setup() se inițializează componentele din sistem și timerul 1 intern ce va fi utilizat în incrementarea variabilei sec_afis.

void setup() { 

  bluetooth.begin(9600);

  digitalWrite(9,LOW);

  Wire.begin();

  lcd.begin(16, 2);

  lcd.noCursor();

  lcd.clear();

  TIMSK1 = 0x01;

  TCCR1A = 0x00;

  TCNT1 = 0x0BDC;

  TCCR1B = 0x04;

}

În cadrul secțiunii loop() se preiau de la modulul RTC valorile de oră și dată (getDateDs1307)

void loop(){

  byte temp, hum;

  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek,&dayOfMonth, &month, &year);

și apoi se verifică dacă se primește comandă pe conexiunea bluetooth – comenzile se pot trimite cu orice program de tip terminal bluetooth, se trimite mai întâi un caracter care să indice ce valoare dorim să modificăm (y – an, m – lună, d – zi, w – zi a săptămânii, h – oră, t – minut) și după aceia + sau – pentru incrementare sau decrementare.

   if(bluetooth.available()) {

    char comanda = (char)bluetooth.read();

    switch (comanda) {

    case ‘y’:

      while (bluetooth.available()==0) { delay(10); }

      comanda = (char)bluetooth.read();

      if (comanda==’+’) year++;

      else if (comanda==’-‘) year–;

      setDateDs1307(second, minute, hour, dayOfWeek,dayOfMonth, month, year);

      break;

    case ‘m’:

      while (bluetooth.available()==0) { delay(10); }

      comanda = (char)bluetooth.read();

      if (comanda==’+’) month++;

      else if (comanda==’-‘) month–;

      setDateDs1307(second, minute, hour, dayOfWeek,dayOfMonth, month, year);

      break;

    case ‘d’:

      while (bluetooth.available()==0) { delay(10); }

      comanda = (char)bluetooth.read();

      if (comanda==’+’) dayOfMonth++;

      else if (comanda==’-‘) dayOfMonth–;

      setDateDs1307(second, minute, hour, dayOfWeek,dayOfMonth, month, year);

      break;

   case ‘w’:

      while (bluetooth.available()==0) { delay(10); }

      comanda = (char)bluetooth.read();

      if (comanda==’+’) dayOfWeek++;

      else if (comanda==’-‘) dayOfWeek–;

      setDateDs1307(second, minute, hour, dayOfWeek,dayOfMonth, month, year);

      break;

    case ‘h’:

      while (bluetooth.available()==0) { delay(10); }

      comanda = (char)bluetooth.read();

      if (comanda==’+’) hour++;

      else if (comanda==’-‘) hour–;

      setDateDs1307(second, minute, hour, dayOfWeek,dayOfMonth, month, year);

      break;

    case ‘t’:

      while (bluetooth.available()==0) { delay(10); }

      comanda = (char)bluetooth.read();

      if (comanda==’+’) minute++;

      else if (comanda==’-‘) minute–;

      setDateDs1307(second, minute, hour, dayOfWeek,dayOfMonth, month, year);

      break;

  }}

Următoarea parte din secțiunea loop() se ocupă cu partea de afișare efectivă a informațiilor pe LCD – rezultatul fiind ca cel din captura de mai jos.

8

lcd.setCursor(0,0);

  switch (dayOfWeek) {

   case 1:

     lcd.print(“LUN”);

     break;

   case 2:

     lcd.print(“MAR”);

     break;

   case 3:

     lcd.print(“MIE”);

     break;

   case 4:

     lcd.print(“JOI”);

     break;

   case 5:

     lcd.print(“VIN”);

     break;

   case 6:

     lcd.print(“SAM”);

     break;

   case 7:

     lcd.print(“DUM”);

     break;

  }

  lcd.print(” “);

  lcd.print(dayOfMonth, DEC);

  lcd.print(” “);

  switch (month) {

   case 1:

     lcd.print(“ian”);

     break;

   case 2:

     lcd.print(“feb”);

     break;

   case 3:

     lcd.print(“mar”);

     break;

   case 4:

     lcd.print(“apr”);

     break;

   case 5:

     lcd.print(“mai”);

     break;

   case 6:

     lcd.print(“iun”);

     break;

   case 7:

     lcd.print(“iul”);

     break;

   case 8:

     lcd.print(“aug”);

     break;

   case 9:

     lcd.print(“sep”);

     break;

   case 10:

     lcd.print(“oct”);

     break;

   case 11:

     lcd.print(“noi”);

     break;

   case 12:

     lcd.print(“dec”);

     break;

  }

  lcd.print(” 20″);

  lcd.print(year, DEC);

  lcd.setCursor(0,1);

  if (hour<10) lcd.print(” “);

  lcd.print(hour, DEC);

  lcd.print(“:”);

  if (minute<10) lcd.print(“0”);

  lcd.print(minute, DEC);

  lcd.print(“:”);

  if (second<10) lcd.print(“0”);

  lcd.print(second, DEC);

  lcd.print(”   “);

     }

  if (((sec_afis%10)==0) && afis)

  {

    byte chk = dht11.read(pinDHT11, &temp, &hum, NULL);

    lcd.setCursor(12,1);

    switch(chk)

    {

        case 0:

        if (sec_afis==10) {

        lcd.print(temp);

        lcd.print(char(223));

        lcd.print(“C”);

        }

        else

        {

         lcd.print(” “);

         lcd.print(hum);

         lcd.print(“%”);

        }

        break;

      default:

        lcd.print(“Error”);

        break;

  }

   afis=false;

  }

}

Subrutina de ceas se ocupă cu incrementarea variabilei sec_afis și cu alternarea (true/false) conținutului variabilei afis, valoarea maximă a variabilei sec_afis este 21 deoarece se doreste afișarea combinată (10 secunde + 10 secunde) a celor două valori: temperatură și umiditate.

ISR(TIMER1_OVF_vect) {

  TCNT1=0x0BDC;

  sec_afis++;

  afis=true;

  if (sec_afis==21) sec_afis=1;

}

Ultimele proceduri din program sunt necesare pentru comunicația cu modulul RTC – proceduri de preluare și modificare a valorilor interne ale modulului RTC.

byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); }

byte decToBcd(byte val) { return ((val/10*16) + (val%10)); }

void getDateDs1307(byte *second,

          byte *minute,

          byte *hour,

          byte *dayOfWeek,

          byte *dayOfMonth,

          byte *month,

          byte *year)

{

  Wire.beginTransmission(DS1307_I2C_ADDRESS);

  Wire.write(0);

  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  *second     = bcdToDec(Wire.read() & 0x7f);

  *minute     = bcdToDec(Wire.read());

  *hour       = bcdToDec(Wire.read() & 0x3f); 

  *dayOfWeek  = bcdToDec(Wire.read());

  *dayOfMonth = bcdToDec(Wire.read());

  *month      = bcdToDec(Wire.read());

  *year       = bcdToDec(Wire.read());

}

void setDateDs1307(byte second,

          byte minute,

          byte hour,

          byte dayOfWeek,

          byte dayOfMonth,

          byte month,

          byte year)

 {

      Wire.beginTransmission(DS1307_I2C_ADDRESS);

      Wire.write(byte(0));

      Wire.write(decToBcd(second));

      Wire.write(decToBcd(minute));

      Wire.write(decToBcd(hour));

      Wire.write(decToBcd(dayOfWeek));

      Wire.write(decToBcd(dayOfMonth));

      Wire.write(decToBcd(month));

      Wire.write(decToBcd(year));

      Wire.write(byte(0));

      Wire.endTransmission();

     }

Programul a fost dezvoltat și testat cu Arduino IDE 1.6.9, Arduino AVR Boards 1.6.14 și SimpleDHT 1.0.2.