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.
Acestea au fost numeroase și aș vrea să menționez doar trei dintre ele:
Punerea în funcțiune a benzii luminoase NeoPixel Digital RGB LED Strip care a implicat folosirea unei surse de curent de 5V și 10A.
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.
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.
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.
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.
Î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
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.
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.
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.