Arduino Zombification

În ciuda simplității modului de programare oferit de mediul Arduino IDE și de familia de plăci Arduino există implementată o soluție ce permite utilizarea plăcilor de dezvoltare Arduino ca simple periferice USB fără a fi nevoie a înțelege modul de funcționare și programare a acestora. Prin încărcarea unui program gata scris placa Arduino se transformă într-un echipament „zombie” ce execută instrucțiunile primite prin conexiunea USB conform unui protocol standard.

Protocolul de zombificare a unei plăci Arduino se numește Firmata și este integrat ca suport software (bibliotecă + exemple) în Arduino IDE. Pentru instalare și utilizare puteți consulta materialul „Arduino: Installing Standard Firmata”. După încărcarea exemplului StandardFirmata.ino pe orice placă de dezvoltare Arduino, aceasta se va comporta ca un periferic USB pe care îl putem accesa de pe un sistem de calcul (PC sau chiar Raspberry Pi). Accesul intermediat de protocolul Firmata face disponibile toate perifericele hardware ale plăcii de dezvoltare (pini I/O, convertor analog/numeric, magistrale I2C, SPI, pini de comandă PWM) programelor ce rulează pe sistemul de calcul la care este conectată placa. Biblioteca Firmata oferă exemple pentru majoritatea limbajelor de programare: .NET, Java, Perl, Python, PHP, Processing, Flash etc. Firmata reprezintă o soluție extrem de simplă pentru extinderea funcționalităților unei plăci Raspberry Pi prin conectarea la o placă Arduino (a se vedea și proiectul „Access GPIO of Arduino from Raspberry Pi”).

2

Versiunile recente ale bibliotecii Firmata extind posibilitatea de zombificare și a altor plăci precum ChipKIT (exemplul din bibliotecă: StandardFirmataChipKIT.ino) dar și utilizând alte modalități de interconectare între placa de dezvoltare și sistemul de calcul:

  • Utilizând exemplul ino putem utiliza de la distanță o placă Arduino prin intermediul unei conexiuni bluetooth. Exemplul funcționează pe plăci ce integrează modul de comunicație BLE (de exemplu Arduino 101) sau pe orice placă Arduino cu un modul BLE atașat (de exemplu Adafruit Bluefruit nRF8001).
  • Exemplul ino permite, bineînțeles, controlul de la distanță prin intermediul unei conexiuni WiFi. Este posibilă utilizarea mai multor tipuri de plăci precum Arduino MKR1000 sau plăci de dezvoltare bazate pe circuitul ESP8266 (de exemplu Adafruit Feather HUZZAH). Această variantă de zombificare este utilizată de multe limbaje de control la distanță precum Gobot [13] sau Johny-Five.

3

O altă formă de zombificare prin intermediul unei conexiuni WiFi este oferită de placa de dezvoltare Arduino Yun. Există două variante de control la distanță a perifericelor integrate în microcontrolerul ATmega32U4 aflat pe placa de dezvoltare:

  • Prin intermediul serviciilor web de tip API REST adică prin intermediul unor URL-uri ce pot accesa diverse resurse hardware ale microcontrolerului. Acestea pot fi configurate astfel încât accesul să fie protejat de o parolă. Accesând IP-ul plăcii și calea /arduino putem configura, de exemplu, pinii I/O (pe Arduino Yun vom avea încărcat exemplul ino al bibliotecii Bridge):

4

http://myArduinoYun.local/arduino/digital/13 : calls digitalRead(13);

http://myArduinoYun.local/arduino/digital/13/1 : calls digitalWrite(13,1);

http://myArduinoYun.local/arduino/analog/9/123 : analogWrite(9,123);

http://myArduinoYun.local/arduino/analog/2 : analogRead(2);

http://myArduinoYun.local/arduino/mode/13/input : pinMode(13, INPUT);

http://myArduinoYun.local/arduino/mode/13/output : pinMode(13, OUTPUT);

  • Ultimele versiuni de plăci Arduino Yun ce rulează LininoOS permit programarea automată a microcontrolerului ATmega32U4 si utilizarea acestuia ca un periferic sub sistemul de operare. Programarea se face cu ajutorul comenzii:

/usr/bin/lininoio start

5

Utilizarea perifericelor se poate face direct din script bash:

echo 1 > /sys/class/gpio/TXLD/value

sau din alte limbaje de programare, de exemplu Node.JS:

var board = new require(‘ideino-linino-lib’).Board();

var led = 1;

board.connect( function(){

    board.pinMode(“D13”, “OUTPUT”);

    setInterval(function(){

        board.digitalWrite(“D13”, led);

        led = 1 – led;

    },500);

});

O soluție de zombificare pentru plăcile de dezvoltare echipate cu circuitul ESP8266 este ESPEasy. Prin încărcare acestui software pe o placă bazată pe ESP8266 vom putea configura foarte simplu atât partea de conectivitate WiFi (credențialele de acces la Internet) cât și perifericele conectate precum și rolul îndeplinit de sistem (configurare conexiune servicii IoT sau Home Automation) – totul prin intermediul unei interfețe web foarte simple.

6

7

Yun Christmas Lights

Luminițele mele de Crăciun rulează Linux! E un lucru cu care putem uimi chiar și cel mai versat invitat. Mai mult decât atât, putem să le comandăm direct de pe telefonul mobil prin WiFi. Acest lucru este posibil și destul de ușor de implementat utilizând o placă de dezvoltare Arduino Yun. Această placă de dezvoltare rulează distribuția Linux OpenWRT și combină conectivitatea de rețea a procesorului Atheros AR9331 cu posibilitatea de comandă în timp real a microcontrolerului ATmega32U4. Pentru lumini vom utiliza 25 de LED-uri RGB WS2801. Aceste LED-uri se comandă simplu prin intermediul a doar două fire (unul de clock și unul de date). Conectarea dintre placa de dezvoltare și LED-uri este următoarea:

2

Pinul D6 al plăcii de dezvoltare se va conecta la firul verde al șirului de LED-uri (firul de clock) iar pinul D5 la firul galben (firul de date). Alimentarea se va face cu ajutorul unei surse de tensiune de 5V minimum 2A, alimentarea va fi comună pentru placa de dezvoltare și pentru LED-uri. Nu alimentați montajul prin portul USB al plăcii de dezvoltare deoarece un port USB nu poate oferi un curent mai mare de 500mA. Pentru mai multe informații legate de utilizarea șirului de LED-uri puteți consulta și materialul „12mm LED Pixels”.

O alternativă mai ieftină pentru sistem este utilizarea plăcii Arduino Industrial 101 – placă mai ieftină și de dimensiuni mai mici. Identică din punct de vedere hardware cu placa Arduino Yun, placa Arduino Industrial 101 expune un număr mai mic de pini ai microcontrolerului ATmega32U4 și nu are interfață ethernet – ambele dezavantaje nu afectează cu nimic montajul propus în proiectul de față. Interfațarea cu șirul de LED-uri în cazul plăcii Arduino Industrial 101 este următoarea:

3

Atât programul cât și configurația conexiunii WiFi sunt identice în cazul ambelor plăci (Arduino Yun și Arduino Industrial 101).

Utilizarea plăcilor de dezvoltare presupune configurarea inițială a conexiunii WiFi (completarea informațiilor de acces WiFi). Utilizarea conexiunii ethernet nu presupune nici o configurație inițială (valabil doar pentru placa Arduino Yun) – interfața ethernet este configurată implicit să obțină o adresă în mod dinamic prin DHCP. Pentru configurarea inițială se recomandă parcurgere materialului „Getting Started with the Arduino Yún LininoOS”.

Pentru interfața de comandă mobilă vom utiliza serviciul cloud Blynk. Acest serviciu ne va facilita implementarea aplicației de comandă pe dispozitive mobile Android sau iOS. Necesită înregistrarea unui cont gratuit și instalarea aplicației specifice pe dispozitivul mobil. Se poate vedea și materialul „Cum să realizăm un sistem IoT fără să scriem nici o linie de cod?”.

4

Programul pentru placa de dezvoltare a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 având instalate bibliotecile Adafruit WS2801 1.0.0, Blynk 0.4.10 și Time 1.5.0.

#include <Adafruit_WS2801.h>

#include <BlynkSimpleYun.h>

#include <TimeLib.h>

#include <WidgetRTC.h>

WidgetRTC rtc;

int dataPin = 5;

int clockPin = 6;

Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin,clockPin);

În cadrul programului trebuie personalizat codul de autentificare în cadrul serviciului Blynk. Acest cod se obține în momentul în care se creează aplicație mobilă de comandă.

char auth[] = “…”;

Sistemul va avea 4 stări posibile (starea va fi stocată în variabila mode): starea 0 – LED-urile vor fi stinse, starea 1 – toate LED-urile vor fi aprinse și vor avea aceiași culoare dată de aplicația de comandă, starea 2 – stare implicită, toate LED-uri vor fi aprinse dar vor avea culori diferite, starea 3 – un singur LED va fi aprins și se va plimba de la un cap la altul al șirului de LED-uri. În modul automat (variabila automat este implicit true) se va închide automat la ora 23:00 și va reporni la ora 10:00 a doua zi, modul automat va putea fi dezactivat din interfața de comandă mobilă.

byte mode = 2;

byte lastmode = 255;

int lastcolor = -1;

byte r,g,b;

boolean automat = true;

Secțiunea setup va inițializa conexiunea cu serviciul cloud Blynk, comunicația cu LED-urile WS2801 și va configura biblioteca Time să comunice la un interval de o oră (3600 de secunde) cu obiectul RTC (definit în interfața mobilă de comandă) pentru sincronizarea ceasului.

void setup() {

  Blynk.begin(auth);

  setSyncInterval(60*60);

  strip.begin();

  strip.show();

  r = 0; g = 0; b = 0;

}

Procedurile BLYNK_ tratează evenimentele specifice serviciului cloud preluând comenzile din interfața de comandă mobilă.

BLYNK_CONNECTED() {

rtc.begin();

}

BLYNK_WRITE(V7) {

b = param.asInt();

}

BLYNK_WRITE(V6) {

g = param.asInt();

}

BLYNK_WRITE(V5) {

r = param.asInt();

}

BLYNK_WRITE(V2) {

mode = param.asInt();

}

BLYNK_WRITE(V1) {

automat = param.asInt();

}

În cadrul secțiunii loop se implementează comanda efectivă către șirul de LED-uri WS2801 în conformitate cu informațiile primite din interfața mobilă.

void loop() {

Blynk.run();

if (automat) { if ((hour()>22) || (hour()<10)) mode = 0;

else if (mode==0) mode=2; }

if ((lastmode!=mode) || (lastcolor!=Color(r,g,b))) {

switch (mode) {

case 0:

for (int i = 0; i < strip.numPixels(); i++)

strip.setPixelColor(i, 0);

strip.show();

break;

case 1:

for (int i = 0; i < strip.numPixels(); i++)

strip.setPixelColor(i, Color(r,g,b));

strip.show();

break;

case 2:

for (int i = 0; i < strip.numPixels(); i++)

strip.setPixelColor(i, Wheel(((i * 256 /

strip.numPixels()) + Color(r,g,b)) & 255));

strip.show();

break;

case 3:

for (int i = 0; i < strip.numPixels(); i++) {

if(i>0) strip.setPixelColor(i-1, 0);

strip.setPixelColor(i, Color(r,g,b));

strip.show();

Blynk.run();

delay(200);

}

strip.setPixelColor(strip.numPixels()-1, 0);

strip.show();

break;

}

lastmode = mode;

lastcolor = Color(r,g,b);

}

}

Funcțiile Wheel și Color sunt utilizate pentru a calcula comanda de culoare către șirul de LED-uri WS2801.

uint32_t Wheel(byte WheelPos) {

if (WheelPos < 85) {

return Color(WheelPos * 3, 255 – WheelPos * 3, 0);

} else if (WheelPos < 170) {

WheelPos -= 85;

return Color(255 – WheelPos * 3, 0, WheelPos * 3);

} else {

WheelPos -= 170;

return Color(0, WheelPos * 3, 255 – WheelPos * 3);

}

}

uint32_t Color(byte r, byte g, byte b)

{

uint32_t c;

c = r;

c <<= 8;

c |= g;

c <<= 8;

c |= b;

return c;

}

Aplicația mobilă va conține 4 controale (cost total 900 de credite din cele 2000 oferite gratuit):

5

  • Un control Slider pentru stabilirea modului de funcționare (cost 200 de credite);
  • Un control ZeRGBa pentru stabilirea culorii LED-urilor în modurile de funcționare 1 și 3 (cost 400 de credite);
  • Un control Button pentru activarea / dezactivare funcționării automate a sistemului (cost 200 de credite);
  • Un control Real Time Clock (RTC) pentru sincronizarea timpului (cost 100 de credite).

Controlul Slider va fi conectat la pinul virtual V2 și va lua valori între 0 și 3 (cele patru moduri de funcționare ale sistemului).

6

Controlul zeRGBa va fi conectat la pinii virtuali V5, V6 și V7 ce vor trimite către sistem comanda RGB de culoare.

7

Controlul Button se va configura ca fiind de tip Switch și se va conecta la pinul virtual V1.

8

Pentru alte idei și alternative de realizare se pot trece în revistă și următoarele proiecte:

Proiect WiFi Car

Realizarea unei mașini teleghidate este o provocare plăcută pentru orice pasionat de electronică indiferent dacă este începător sau veteran. Dacă soluțiile clasice RC bazate pe frecvențe subgigahertz sau bazate pe protocolul bluetooth sunt exemplificate într-o multitudine de proiecte, varianta de comandă radio prin protocol WiFi este puțin mai problematică din cauza consumului și costurilor mari pentru componenta de comunicație. În cadrul proiectului de față vom prezenta o soluție simplă de realizarea a unei mașini controlate prin WiFi bazându-ne pe următoarele componente:

  1. Un șasiu FlexyBot cu cu două motoare:

2

https://www.robofun.ro/kit-roboti/flexy-bot-2-motoare

  1. O placă de dezvoltare Arduino Yun ce va asigura atât partea de logică de comandă cât și partea de comunicație WiFi:

3https://www.robofun.ro/wireless/wireless-wifi/arduino_yun

  1. Un shield driver de motoare bazat pe circuitul L298:

4

https://www.robofun.ro/shields/shield-motoare-l298-v2

Asamblarea celor trei componente este simplă și este prezentată detaliat în pagina produsului FlexyBot. Nu există deosibiri majore între placa Arduino Uno și placa Arduino Yun în această fază. Nu alimentați ansamblul până nu parcurgeți următorii pași ai lecției (Configurarea inițială a plăcii Arduino Yun și Alimentarea WiFi Car).

Configurarea inițială a plăcii Arduino Yun

Configurarea inițială a plăcii Arduino Yun este prezentată în materialul:

Start with Arduino Yun

http://www.arduino.org/learning/getting-started/getting-started-with-arduino-yun

În funcție de modul în care doriți să interacționați cu WiFi Car există două posibile configurații WiFi:

  1. Să lăsați placa Arduino Yun configurată ca WiFi AP – configurație utilă dacă doriți să accesați WiFi Car și în afara acoperirii unei rețele WiFi cunoscute, vă veți conecta cu un dispozitiv de comandă la AP-ul WiFi Car.
  2. Să configurați placa Arduino Yun să se conecteze la o rețea WiFi – această configurația are avantajul de a oferi posibilă conectivitate Internet plăcii Arduino Yun dar este dependentă de aria de acoperire a rețelei WiFi prin care se va face comanda la distanță.

Indiferent de varianta aleasă, utilizarea plăcii Arduino Yun oferă marele avantaj al posibilității programării la distanță a WiFi Car – nu trebuie să conectați, deconectați, reconectați cablul USB la fiecare nouă testare de program. Totul se poate face la distanță prin selectarea portului OTA (Over-The-Air).

5

 

Alimentarea WiFi Car

Pentru alimentarea WiFi Car se vor folosi două elemente distincte: o cutie de baterii ce va alimenta motoarele prin intermediul shield-ului și o baterie USB pentru a alimenta placa Arduino Yun. În cadrul testelor s-a utilizat o cutie cu 6 baterii AA și un USB Battery Pack de 2000mAh.

6

https://www.robofun.ro/surse_de_alimentare/baterii/cutie-6-baterii-cablu

7

https://www.robofun.ro/surse_de_alimentare/acumulatori/usb-battery-pack-2200-mah-capacity-5v-1a-output

Cele două surse de alimentare distincte oferă o mai mare stabilitate plăcii de comandă Arduino Yun neproducând fluctuații ale tensiunii de alimentare la manevrele de pornire / oprire a motoarelor. În plus de asta, placa Arduino Yun nu are regulator de tensiune integrat (cum are placa Arduino Uno) și din acest motiv trebuie alimentată cu o tensiune de fix 5V.

ATENȚIE!!! Conectarea jumperului de pe shield-ul driver de motoare ce permite alimentarea plăcii de dezvoltare din aceiași sursă ca motoarele va conduce la arderea imediată a plăcii Arduino Yun deoarece aceasta nu acceptă pe pinul Vin altă tensiune decât fix 5V.

8

 

Programarea WiFi Car

Programul ce va rula pe microcontrolerul ATmega32U4 al plăcii Arduino Yun va utiliza biblioteca software Bridge pentru a crea legătura dintre comanda motoarelor și comenzile web pe care le vom trimite prin conexiunea WiFi.

#include <Bridge.h>

#include <BridgeServer.h>

#include <BridgeClient.h>

BridgeServer server;

Configurarea și comanda motoarelor este similară cu utilizarea shield-ului în conjuncție cu o conexiune bluetooth sau un algoritm local de tip evitare de obstacole sau urmărire de linie.

#define MOTOR2_PIN1 3

#define MOTOR2_PIN2 5

#define MOTOR1_PIN1 6

#define MOTOR1_PIN2 9

void setup() {

  Bridge.begin();

  pinMode(MOTOR1_PIN1, OUTPUT);

  pinMode(MOTOR1_PIN2, OUTPUT);

  pinMode(MOTOR2_PIN1, OUTPUT);

  pinMode(MOTOR2_PIN2, OUTPUT);

  server.listenOnLocalhost();

  server.begin();

}

void go(int speedLeft, int speedRight) {

  if (speedLeft > 0) {

    analogWrite(MOTOR1_PIN1, speedLeft);

    analogWrite(MOTOR1_PIN2, 0);

  } else {

    analogWrite(MOTOR1_PIN1, 0);

    analogWrite(MOTOR1_PIN2, -speedLeft);

  }

  if (speedRight > 0) {

    analogWrite(MOTOR2_PIN1, speedRight);

    analogWrite(MOTOR2_PIN2, 0);

  } else {

    analogWrite(MOTOR2_PIN1, 0);

    analogWrite(MOTOR2_PIN2, -speedRight);

  }

}

În cadrul secțiunii loop() se vor prelua, prin intermediul bibliotecii Bridge, conexiunile de comandă și se vor trimite către procedura process() pentru execuție.

void loop() { 

  BridgeClient client = server.accept();

  if (client) {

    process(client);

    client.stop();

  }

  delay(50);

}

void process(BridgeClient client) {

  String command = client.readStringUntil(‘/’);

  command.trim();

  if(command == “forward”) { 

          go(150,150);

          client.println(“Forward”);

          client.println(“Vs: 150 Vd: 150”);

        }

   if(command == “left”) { 

          go(100,150);

          client.println(“Left”);

          client.println(“Vs: 100 Vd: 150”);

        }

  if(command == “stop”) { 

          go(0,0);

          client.println(“Stop”);

        }

  if(command == “right”) { 

          go(150,100);

          client.println(“Right”);

          client.println(“Vs: 150 Vd: 100”);

        }

  if(command == “back”) { 

          go(-150,-150);

          client.println(“Backward”);

          client.println(“Vs: -150 Vd: -150”);

        }

}

După încărcarea programului se vor putea accesa comenzile WiFi Car de pe orice sistem ce deține un client web (browser) și este conectat la aceiași subrețea ca și placa Arduino Yun accesând următoarele URL-uri:

Pentru mers înainte

http://ip_placa_arduino_yun/arduino/forward/

Pentru virare stânga

http://ip_placa_arduino_yun/arduino/left/

Pentru virare dreapta

http://ip_placa_arduino_yun/arduino/right/

Pentru oprire

http://ip_placa_arduino_yun/arduino/stop/

Pentru mers înapoi

http://ip_placa_arduino_yun/arduino/back/

Bineînțeles, partea de comandă poate fi îmbunătățită prin introducerea unor comenzi de accelerare, frânare sau accentuare/încetinire a virării.

 

Realizarea unei interfețe centralizate de comandă

Având în vedere faptul că placa Arduino Yun rulează implicit un server web (uhttp) se poate realiza o pagină html care să centralizeze accesul la URL-urile de comandă. Există două variante de copiere și localizare la nivelul sistemului de fișiere OpenWRT a fișierului html:

 

Utilizarea unui card microSD și includerea fișierului html în proiectul Arduino. Copierea fișierului html se va face automat la încărcarea programului. Această variantă este descrisă în următorul material:

Arduino Yún: Intro to web server

https://create.arduino.cc/projecthub/Arduino_Scuola/arduino-yun-intro-to-web-server-6caf93

 

Crearea manuală a fișierului html în linie de comandă. Aceasta este varianta propusă datorită simplității.

Se va crea un fișier wificar.html în directorul /www cu următorul conținut:

<html>

<head>

<style>

a.button {-webkit-appearance: button;

-moz-appearance: button;

appearance: button;

height:200px;

line-height:200px;

text-align:center;

text-decoration: none;

font-size: 50px;

color: initial;}

</style>

</head>

<body>

<a href=”/arduino/forward/” class=”button”

style=”width:100%;””>FORWARDS</a>

<br />

<a href=”/arduino/left/” class=”button”

style=”width:35%;””>LEFT</a>

<a href=”/arduino/stop/” class=”button”

style=”width:30%;””>STOP</a>

<a href=”/arduino/right/” class=”button”

style=”width:35%;””>RIGHT</a>

<br />

<a href=”/arduino/back/” class=”button”

style=”width:100%;””>BACKWARDS</a>

<br />

</body>

</html>

Se va verifica dacă în fișierul /etc/config/uhttp variabila option home are valoarea /www:

# Server document root

option home             /www

Se va accesa URL-ul:

http://ip_placa_arduino_yun/wificar.html

9

Din păcate latența de comunicație a protocoalelor TCP/IP, mai ales al protocolului HTTP, este destul de mare. Nu vă așteptați să aveți aceiași viteză de răspuns ca în cazul unei mașini teleghidate RC obișnuite.