ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 141
Abonament PDF

Emoții și culoare - un proiect IoT

Ovidiu Mățan
Fondator @ Today Software Magazine



PROGRAMARE


Lumina este unul dintre cele mai spectaculoase elemente pe care le putem controla în proiectele IoT. Proiectul de față vă propune să controlăm o bandă cu leduri de 4 m cu ajutorul unui Arduino conectat serial la un RaspberryPi 5 care procesează datele primite de la o cameră web. Funcționalitatea de bază constă în schimbarea culorilor ledurilor în funcție de starea celui care stă în fața camerei.

Provocări

Acestea au fost numeroase și aș vrea să menționez doar trei dintre ele:

  1. Punerea în funcțiune a benzii luminoase NeoPixel Digital RGB LED Strip care a implicat folosirea unei surse de curent de 5V și 10A.

  2. Procesul de comunicare între Raspberry Pi și Arduino pe portul serial care a necesitat procesarea asincronă a imaginilor și transmiterea datelor mai departe. În caz contrar informațiile ajungeau cu întârziere la Arduino.

  3. Instalarea librăriei NeoPixel pe RaspberryPi nu a fost una încununată de succes și am decis folosirea plăcii Arduino care va primi informații despre emoții de la RaspberryPi și va controla la rândul său ledurile. Această configurație ne dă și mai multe opțiuni pentru produsul final, dar adaugă un pic mai multă complexitate.

Banda de leduri și Arduino

Date fiind cerințele de curent (5V și 10A) a trebuit achiziționată o sursă specială. Am optat pentru Mean Well LRS-50-5, 5V/10A. Aceasta vine fără o conexiune la priză așa că trebuie să luăm un cablu de alimentare de la un calculator și să le conectăm la sursă. Dacă nu am greșit nimic, ar trebui să se aprindă un led verde pe sursă.

Următorul pas este să conectăm la Arduino tensiunea la pinul digital 6 și masa așa cum se poate vedea în figura următoare.

Sistemul tocmai format poate fi și ușor testat. Conectăm placa Arduino la un calculator prin intermediul cablului USB și instalăm în Arduino IDE biblioteca NeoPixel de la Adafruit. Rulăm acum câteva exemple din această librărie din Arduino ID (File -> Examples -> Adafruit NeoPixel) iar banda noastră led ar trebui să prindă viață acum.

RaspberryPi și recunoașterea expresiilor feței

Am folosit un Raspberry Pi 5 căruia i-am adăugat o carcasă cu două ventilatoare pentru o răcire optimă. Camera web folosită este de la Razer și se conectează prin USB.

Vom folosi o implementare în Python bazată pe OpenCV care teoretic detectează șase emoții. În practică, am reușit să descopăr doar primele trei dintre ele.

        0: 'neutral', 
        1: 'happiness', 
        2: 'surprise', 
        3: 'sadness',
        4: 'anger', 
        5: 'disgust', 
        6: 'fear'

Odată pornit Raspberry PI OS vom instala librăria OpenCV

pip install opencv-python

și lansăm codul Python:

.../learnopencv/Facial-Emotion-Recognition $ python expression_ssd_detect.py 

Inițial veți vedea că se rulează recunoașterea feței pe un videoclip. Pentru a trece la cameră schimbăm sursa în cod:

#cap = cv2.VideoCapture('video3.mp4')

cap = cv2.VideoCapture(0)

Acum camera ne recunoaște și de asemenea expresiile noastre.

Conectarea Raspberry Pi și Arduino

Vom folosi un cablu USB pentru conectarea celor două. Practic RaspberryPI 5 va reprezenta PC-ul în această ecuație. De altfel, este suficient de puternic pentru a rula Arduino IDE astfel încât după conectarea celor două, nu am mai apelat la un PC pentru programarea plăcii Arduino.

Prima încercare - sincron

Începem prin a folosi librăria clasică Serial în încercarea de a trimite codul mai departe la Arduino. Modificăm codul existent astfel:

....
import Serial
import time
comm=serial.Serial('/dev/ttyACM0',9600)
time.sleep(1)

.... 
async def FER_live_cam():

....
   for (x1, y1, x2, y2) in boxes:
              .....
                comm.write(b'1')
                time.sleep(1)

Rulăm aplicația și observăm că procesarea se face sacadat din cauza sleepului dar și deoarece este mult întârziată. De asemenea, Arduino primește datele doar după ce oprim aplicația Python. Din ambele probleme rezultă că avem nevoie de o soluție asincronă pentru a trimite datele mai departe pe portul serial.

Am încercat și să setăm o latență scăzută pentru comunicarea serială, din păcate rezultatele au fost aceleași:

sudo apt install setserial
sudo setserial /dev/ttyACM0 low_latency
stty -F /dev/ttyACM0

A doua încercare - asincron

Soluția aleasă este să modificăm codul prin folosirea librăriei asyncio. Practic vom face funcția main și cea în care se procesează imaginea asincrone. Deoarece codul este prea mare pentru a fi listat integral în articol, vă prezint doar modificările aduse sursei inițiale:

....
import asyncio
import serial_asyncio

...
async def send_command(data):
    writer.write(data)
    await writer.drain()
    await asyncio.sleep(0.1)
....
async def FER_live_cam():
       for (x1, y1, x2, y2) in boxes:
                try:

.....
                    print ('idx=',idx)
                    await send_command(bytes(str(idx)
                    ,'utf-8'))
                except:
                    print("invalid frame")

....
if __name__ == "__main__":
    asyncio.run(FER_live_cam())

Câteva observații despre acest cod:

Am folosit asyncio.sleep() în loc de time.sleep() - am avut câteva bătăi de cap până ce am ajuns la această soluție.

Întreg codul de procesare a fost adăugat într-un bloc try - except. Procesarea imaginilor de la cameră implică uneori procesarea unor cadre invalide, inconsistente. Atunci apar erori peste care, însă, se poate trece ușor prin procesarea următoarei imagini.

Pentru o mai simplă procesare pe partea de Arduino, vom transmite date doar atunci când detectăm o față umană. Acestea vor reprezenta valoarea indexului din tabel.

Programarea Arduino

Având instalată deja librăria pentru Arduino de la NeoPixel și având conexiunea Serială cu Raspbery Pi-ul funcțională, tot ce trebuie să facem este să inițializăm banda luminoasă și să îi schimbăm culorile în funcție de datele primite. Codul sursă este următorul:

#include 

#define LED_PIN    6
#define LED_COUNT 240

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN,
  NEO_GRB + NEO_KHZ800);

uint32_t magenta = strip.Color(10, 50, 100);
uint32_t green = strip.Color(0, 150, 0);
uint32_t red = strip.Color(255, 0, 0);
uint32_t other = strip.Color(100, 0, 200);
char in=0;

void setup() {
  Serial.begin(9600);
  strip.begin();
  strip.fill(red, 0, LED_COUNT);
  strip.show();
}
void loop() {
  if (Serial.available()>0){
    in = Serial.read();
    //Serial.flush();
    if (in=='1'){
      strip.fill(magenta, 0, LED_COUNT);
    } else if (in=='2'){
     strip.fill(other, 0, LED_COUNT);        
    } else if (in=='0'){
      strip.fill(green, 0, LED_COUNT);
    } else {
      strip.fill(red, 0, LED_COUNT);
    }
    strip.show();  
  }
}

Așa cum se poate observa, începem prin a inițializa comunicarea serială și vom seta ledurilor culoarea roșie. În momentul în care primim date, culoarea acestuia se va modifica în funcție de caracterul primit.

Concluzie

Proiectul de față poate reprezenta un prim pas spre o soluție complexă prin care cu ajutorul camerei video dar și a unor senzori de temperatură, de lumină, ultrasonici sau de calitate a aerului putem modifica culorile din biroul nostru de exemplu. În cazul de față, banda led urmează să fie încorporată într-o lampă ce își va modifica culoarea în funcție de expresia celor care se uită la ea. Inițiativa este aparține unui proiect cultural și va fi expusă în curând în cadrul proiectului Why the sky is blue.

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects