Choinka Follow Me podąża za przechodzącym człowiekiem (w promieniu do około 4 metrów od niej). Do wykrywania osób zastosowano kamerę termowizyjną zainstalowaną w module Adafruit oraz moduł Arduino Uno, natomiast poruszanie choinką zrealizowano za pomocą serwomechanizmu. Potrzebnych jest jeszcze kilka komponentów mechanicznych, większość z nich można wyprodukować na drukarce 3D.
Ta ciekawa konstrukcja pozwala nie tylko na wykonanie nietypowej ozdoby bożonarodzeniowej (z pewnością ciekawszej niż kolejna mrugająca diodami bombka), ale także na zapoznanie się z ciekawym komponentem – matrycowym sensorem temperatury, który pozwala na proste obrazowanie termiczne.
Potrzebne elementy
Do budowy tego urządzenia będą potrzebne:
- moduł Arduino Uno.
- moduł kamery termowizyjnej AMG 8833 8×8,
- serwomechanizm FT5335M (można użyć również innego mechanizmu i np. obracającej się na łożysku platformy),
- metalowy mimośród do serwa,
- zasilacz 6 V DC/3 A (do serwomotoru),
- zasilacz 9 V DC/200 mA (dla modułu Arduino),
- 3×dioda LED,
- 3×rezystor 220 Ω,
- arkusz sklejki o grubości 8 mm, o wymiarach około 60×120 cm,
- śruby M3,
- dwie sprężyny 8,7×46 mm,
- niewielka choinka (maksymalnie do 120 cm wysokości),
- elementy do ozdobienia choinki – istotne będą plastikowe poruszające się oczka i materiał, np. filc, do wycięcia elementów twarzy. Oprócz tego oczywiście choinkę ubieramy wedle własnych preferencji – w bombki, łańcuchy itd.
- taśma klejąca, przewody, cyna do lutowania itp.
Układ mechaniczny
Części drukowane w 3D obejmują mocowanie serwomechanizmu i mocowanie czujnika termowizyjnego (aby nie drukować tych części można zastąpić je odpowiednio długimi śrubami oraz małymi klockami drewna, do których zamontowane będą, odpowiednio, serwomechanizm oraz sensor termowizyjny. Jednak najwygodniej będzie skorzystać z drukarki 3D, jeśli mamy do niej dostęp).
Montaż zaczynamy od wycięcia dwóch kwadratów 40×40 cm ze sklejki. Zaznaczamy następnie ich środki i wiercimy w sklejce otwory do zamontowania mimośrodu serwomechanizmu. Do drugiej płyty ze sklejki montujemy serwo za pomocą wydrukowanego w 3D uchwytu lub po prostu kawałka drewna. Zamontowane serwo pokazano na fotografii 1.
Następnie mocujemy serwomechanizm (z wałem pośrodku drugiego arkusza sklejki). Musimy też zamocować sprężyny (dwie szeregowo) do sklejki, jak pokazano na fotografii 2.
Sprężyny są potrzebne do utrzymania napięcia obracającego się kawałka sklejki. Bez przyłożonej siły serwosilnik ma tendencję do przesterowania zadanej lokalizacji, którą następnie koryguje, wpadając w ten sposób w oscylacje.
Finalnie, na górnym fragmencie sklejki instalujemy płytkę z sensorem, korzystając z uchwytu z druku 3D. Układ instalowany jest na skraju jednej ze ścianek, jak pokazano na fotografii 3.
Układ elektroniczny
Na rysunku 1 pokazany jest schemat układu. System jest bardzo prosty. Arduino Uno i serwomechanizm mają swoje osobne zasilacze. Do Arduino podłączony jest sensor termiczny przez odpowiednie wyprowadzenia interfejsu I²C oraz zasilanie. Dodatkowo dołączone są trzy diody LED. Nie są wymagane, ale będą przydatne do sprawdzenia, czy czujnik dokładnie wykrywa człowieka.
Sensor
Dzięki układowi AMG8833 można łatwo dodać prostą termowizję do swojego projektu. Ten sensor firmy Panasonic to matryca 8×8 czujników termicznych pracujących w podczerwieni. Po podłączeniu do mikrokontrolera układ zwraca macierz 64 indywidualnych odczytów temperatury. Układ ten nie różni się zasadą działania od typowych kamer termowizyjnych, ale jest wystarczająco kompaktowy i prosty, aby można go było łatwo i niedrogo zastosować w hobbystycznych projektach. Element ten mierzy temperatury w zakresie od 0°C do 80°C z dokładnością ±2,5°C. Może wykryć człowieka z odległości do 7 metrów. Dzięki maksymalnej częstotliwości odświeżania 10 Hz idealnie nadaje się do stworzenia własnego detektora ludzi czy minikamery termowizyjnej. W Internecie dostępnych jest również szereg projektów, zawierających ten sensor do mniej lub bardziej poważnych zastosowań.
Do obsługi tego układu stosuje się typowo Arduino – jak w tym projekcie – lub Raspberry Pi z Pythonem. To drugie środowisko, przy użyciu bardziej zaawansowanych narzędzi numerycznych, takich jak biblioteki SciPy czy OpenCV, może osiągać naprawdę dobre rezultaty, takie jak wygładzone obrazy termograficzne, jakie pokazano na fotografii 4. W zaprezentowanym systemie w zupełności wystarczyło Arduino.
AMG8833 to nowa generacja czujników termicznych IR 8×8 firmy Panasonic, która oferuje wyższą wydajność niż poprzednik – AMG8831. Czujnik obsługuje tylko I²C, ale ma konfigurowalny pin przerwania, który może zadziałać, np. gdy dowolny piksel przekroczy lub spadnie poniżej ustawionego progu temperatury. Aby ułatwić korzystanie z tego sensora, dostępny jest u wielu dostawców w postaci gotowych do podłączenia modułów dla ekosystemu Arduino. Moduły te integrują w sobie stabilizatory napięcia 3,3 V, przesuwniki poziomu do 5 V itp. potrzebne elementy. Dodatkowo, jeśli chcemy uniknąć lutowania, moduły te często wyposażone są w złącza, goldpiny itd. Wybrany w tym projekcie moduł wyposażony jest w złącza Stemma QT (kompatybilne ze SparkFun Qwiic). Za pomocą tych poręcznych złączy można po prostu podłączyć czujnik bez konieczności lutowania.
Firmware
W Internecie jest wiele przykładowych implementacji oprogramowania obsługującego ten moduł. Dostępna jest także biblioteka, która pozwala na prostą obsługę tego sensora termowizyjnego w zaledwie kilku wierszach kodu. Pierwszym krokiem jest zainstalowanie biblioteki Adafruit_AMG88xx, aby Arduino rozpoznało czujnik termiczny. Czujnik termiczny używa biblioteki I²C (Wire.h) do komunikacji z Arduino. Na listingu 1 zaprezentowano kod aplikacji, jaką zastosowano w choince.
#include <Servo.h>
#include <Wire.h>
#include <Adafruit_AMG88xx.h>
Adafruit_AMG88xx amg; // Obiekt obsługujący sensor
float pixels[64];
float a=0;
float b=0;
float c=0;
float d=0;
float e=.2; // Im wyższe, tym układ czulszy,
float aa=0; // Maksimum
float bb=0;
float cc=0;
int aaa=0; // Licznik do odczytu
int bbb=0;
int cccc=0;
int eee=0;
int z=90; // Startowa pozycja serwomechanizmu
int y=0; // Zmiana pozycji serwomechanizmu
Servo motor; // Obiekt obsługujący serwomechanizm
void setup() {
motor.attach(7); // Serwo dołączone do pinu 7
Serial.begin(9600);
Serial.println(F("AMG88xx pixels"));
bool status;
status = amg.begin();
Serial.println("-- Pixels Test --");
Serial.println();
delay(100); // Oczekiwanie na uruchomienie sensora
pinMode (7,OUTPUT); // Wyjście serwomechanizmu
pinMode (2,OUTPUT); // LED obrotu w lewo
pinMode (4,OUTPUT); // LED pozycji środkowej
pinMode (6,OUTPUT); // LED obrotu w prawo
digitalWrite(2,HIGH); // Zapalenie LED-ów
digitalWrite(4,HIGH);
digitalWrite(6,HIGH);
delay(3000);
digitalWrite(2,LOW);
digitalWrite(4,LOW);
digitalWrite(6,LOW);
}
void loop() {
// Odczyt całej macierzy z sensoru
amg.readPixels(pixels);
// Wyłączenie diod LED
digitalWrite (2,LOW);
digitalWrite (4,LOW);
digitalWrite (6,LOW);
delay(10);
for (int i=0; i<=63; i=i+8) {
d = (pixels[i]);
a = (a + d);
if (d > aa) {
aa = d;
}
d = (pixels[(i+1)]);
a = (a + d);
if (d > aa) {
aa = d;
}
d = (pixels[(i+2)]);
a = (a + d);
if (d > aa) {
aa = d;
}
}
for (int i=3; i<=63; i=i+8) {
d = (pixels[i]);
b = (b + d);
if (d > bb) {
bb = d;
}
d = (pixels[(i+1)]);
b = (b + d);
if (d > bb) {
bb = d;
}
}
for (int i=5; i<=63; i=i+8) {
d = (pixels[i]);
c = (c + d);
if (d > cc) {
cc = d;
}
d = (pixels[(i+1)]);
c = (c + d);
if (d > cc) {
cc = d;
}
d = (pixels[(i+2)]);
c = (c + d);
if (d > cc) {
cc = d;
}
}
// Średnie wartości w grupach
a=(a/24);
b=(b/16);
c=(c/24);
if (aa > bb && aa > cc) {
if (aa - a > .9) {
aaa = aaa + 1;
bbb = 0;
cccc = 0;
if (aaa == 2) {
aaa = 0;
// Zapalenie diody LED obrotu w lewo
digitalWrite (2,HIGH);
delay(100);
// Rozpoczynamy obrót w lewo
y = -4;
z = (z + y);
if (z < 20) {
z = 20;
}
if (z > 160) {
z = 160;
}
motor.write(z);
}
}
}
if (bb > aa && bb > cc) {
if (bb - b>.4) {
bbb = bbb + 1;
aaa = 0;
cccc = 0;
if (bbb == 2) {
bbb = 0;
// Zapalenie diody pozycji środkowej
digitalWrite (4,HIGH);
delay(100);
// Brak ruchu serwomechanizmu
y = 0;
z = (z + y);
if (z < 20) {
z = 20;
}
if (z > 160) {
z = 160;
}
motor.write(z);
}
}
}
if ((cc > aa) && (cc > bb)) {
if (cc - c > 1.2) {
cccc = cccc + 1;
aaa = 0;
bbb = 0;
if (cccc == 2) {
cccc = 0;
// Zapalenie diody LED obrotu w prawo
digitalWrite (6,HIGH);
delay(100);
// Rozpoczynamy obrót w prawo
y = 4;
z = (z + y);
if (z < 20) {
z = 20;
}
if (z > 160) {
z = 160;
}
motor.write(z);
}
}
}
// Konieczne są dwa odczyty pod rząd
// aby ruszyć choinką
eee = eee + 1;
if (eee == 2) {
eee = 0;
aaa = 0;
bbb = 0;
cccc = 0;
}
a = 0;
b = 0;
c = 0;
aa = 0;
bb = 0;
cc = 0;
}
Algorytm zaszyty w firmware jest bardzo prosty. W pierwszej sekcji programu – setup() – konfigurowane są wszystkie podzespoły układu. Druga sekcja – loop(), jak sama nazwa wskazuje, działa w nieskończonej pętli. Algorytm detekcji obiektów zaszyty jest w tej drugiej sekcji. Oblicza on średnią wartość temperatury w trzech różnych strefach sensora. To, w którą stronę przemieści się choinka (o ile w ogóle), zależne jest od wartości temperatury w tych strefach. Aby detektor choinki był bardziej odporny na zakłócenia itp., konieczne są dwa odczyty z rzędu.
Podsumowanie
Choinkę ubieramy wedle własnego uznania i preferencji. Montujemy ją do sklejkowej podstawy, autor zastosował w tym celu taśmę klejącą (którą możemy ukryć pod np. sztucznym śniegiem z waty), ale każda metoda trwałego montażu będzie dobra. Na koniec do już ubranej i umocowanej choinki montujemy elementy twarzy i oczy. Elementy te powinniśmy zamontować w takim samym kierunku, w jakim patrzy sensor termiczny, aby układ najmocniej sprawiał wrażenie, że oczka naklejone na choince patrzą tam, gdzie znajduje się źródło ciepła.
Nikodem Czechowski, EP
Źródła:
https://www.instructables.com/Follow-Me-Christmas-Tree/
https://bit.ly/3VDkOOF
https://bit.ly/3H269b9