LED-owy fidget spinner

LED-owy fidget spinner

Fidget, spinner i wiele innych nazw… kilka lat temu tego rodzaju gadżety szturmem zdobyły rynek na całym świecie. Występowały w różnych kształtach i były wykonane z różnych materiałów. To, co je łączyło, to podstawowa zasada działania – ramiona spinnera obracały się wokół centralnie umieszczonego łożyska. Czy da się z tej prostej konstrukcji zrobić zabawkę edukacyjną?

Autor projektu, Kurt Manucredo, postanowił skonstruować prostą elektroniczną zabawkę. Urządzenie bazuje na zasadzie działania fidget spinnera, które posłuży do prezentacji prostego zjawiska fizycznego – wpływu siły ciążenia na sposób obracania się fidget spinnera. Zamiast mechanicznych obrotów autor prezentuje ruch za pomocą diod świecących, które „krążą” po obwodzie urządzenia.

Zasada działania

Do monitorowania fizycznego ruchu urządzenia zastosowano akcelerometr. Solarfidget to zabawka, która prezentuje, jak zmienia się siła ciążenia w naszym Układzie Słonecznym. Można zmieniać jej ustawienie, aby kręciła się tak, jakby znajdowała się na innej planecie. Korzystając z niej, można „podróżować” do następujących planet:

  • Merkury (0,38 g) (biały),
  • Wenus (0,904 g) (jasnoniebieski),
  • Ziemia (1 g) (ciemnoniebieski),
  • Mars (0,3794 g) (bordowy),
  • Jowisz (2,528 g) (szary),
  • Saturn (1,065 g) (żółty),
  • Uran (0,886 g) (fioletowy),
  • Neptun (1,14 g) (zielony),
  • Pluton (0,063 g) (różowy).

Układ został skonstruowany na bazie modułu Arduino (w zasadzie każdy moduł sprawdzi się w tej aplikacji), który steruje pierścieniem złożonym z 36 diod LED RGB. W systemie zastosowano moduł inercyjny MPU6050, integrujący w sobie żyroskop i akcelerometr, które używane są do wykrywania ruchu urządzenia i obliczania, w jakiej pozycji powinno znaleźć się poruszane spinnerem wahadełko w warunkach grawitacji, jaką w danym momencie ustawiono. Aby przemieścić się z planety na planetę, należy umieścić spinner poziomo i dwukrotnie dosyć szybko obrócić o 180 stopni. Jeśli ustawienie nie zmieni się, to znaczy, że ruch wykonaliśmy za wolno.

Potrzebne elementy

Do zbudowania urządzenia potrzebne będą:

  • moduł Arduino – autor zastosował kompaktowe Arduino Nano, ale do obudowy powinno pasować również Arduino Nano 33,
  • moduł z akcelerometrem MPU6050 z wyprowadzeniami na goldpinach lub innych, pozwalających na podłączenie kabli do układu,
  • ładowarka do akumulatora,
  • pasek LED-owy, który ma 36 adresowalnych diod (jest to fragment paska z 144 diodami na metr),
  • ogniwo litowo-polimerowe HS170 o pojemności 380 mAh z wtyczką Molex,
  • wtyczka Molex, pasująca do złącza akumulatora,
  • wydrukowana w 3D obudowa – dostępne są pliki STL przygotowane do druku,
  • kabel z wtyczką miniUSB,
  • cztery sprężynki 0,3×4×5 mm,
  • cztery śruby M3×10 z nakrętkami i zestawem przeciwnakrętek,
  • cztery śruby M3×4,
  • osiem magnesów neodymowych (okrągłych) o średnicy 6 mm i wysokości 2 mm.

Budowa układu

Spinner po zmontowaniu i zainstalowaniu wewnątrz obudowy powinien wyglądać jak na fotografii 1. Przyjrzyjmy się bliżej poszczególnym elementom budowy systemu. W pierwszej kolejności należy przerobić kabel USB. Odcinamy 10 cm od wtyczki miniUSB i delikatnie zdejmujemy izolację z odciętej części przewodu. Powinniśmy w kablu znaleźć przewody w kolorze czarnym, czerwonym, białym i zielonym. Kolory te oznaczają konkretne sygnały w interfejsie i wtyczce USB, dzięki czemu od razu wiadomo, co gdzie możemy znaleźć.

Fotografia 1. Elektronika zamontowana we wnętrzu spinnera

Kluczowe dla nas są linie: czerwona i czarna, czyli, odpowiednio, 5 V oraz masa (GND). Pozostałe dwie linie to linie danych: biały to Data+, a zielony to Data–.

Dobrze jest też usunąć z wtyczki plastikową obudowę, a przynajmniej znaczną część, aby zmniejszyć jej wymiary, co ułatwi jej zmniejszenie i zmieszczenie płytki z mikrokontrolerem i wtyczką w kompaktowej obudowie spinnera.

W pierwszej kolejności skupimy się na elektronice w samym spinnerze, czyli dolnej części urządzenia – tej, w której znajduj się wpusty na poszczególne moduły. W pierwszej kolejności instalujemy moduł Arduino z podłączonym obciętym kablem USB. Kable podłączamy do wypustów na śruby, widoczne po lewej stronie układu (fotografia 2).

Fotografia 2. Podłączenie modułu z mikrokontrolerem do portu ładowania i rozmieszczenie pozostałych elementów w drukowanej obudowie

W jaki sposób należy je podłączyć? To bardzo proste – stosując śruby M3 o długości 4 mm i pasujące nakrętki. Montaż należy rozpocząć od oczyszczenia wnętrza otworów, jeśli w środku znajduje się luźny materiał z drukarki lub zdeformowane pozostałości po wydruku. Używając dłuższej śruby M3, należy wkręcić nakrętkę na swoje miejsce, na tyle, aby nadal można było wepchnąć przewód do otworu pod nakrętką. Następnie należy dokręcić nakrętki do końca i zabezpieczyć kable. Montując przewody, należy upewnić się, że między nakrętką a obudową znajduje się tylko odizolowany przewód. Przewód ten powinien być krótki – jeśli jest zbyt długi, może zawinąć się wokół śruby, co może utrudnić montaż.

Po przykręceniu przewodów należy podłączyć wtyczkę miniUSB do Arduino i wsunąć je na właściwe miejsce. Następnie należy zainstalować płytkę ładowania akumulatora na właściwym miejscu. Na koniec w obudowie można umieścić moduł z akcelerometrem MPU6050 po prawej stronie, obok baterii. Moduł z MPU6050 powinien być skierowany górną stroną do góry, a oś X powinna znajdować się na osi prawa-lewa strona.

Na kolejnym etapie montażu należy przylutować trzy przewody do paska LED (36 diod). Należy zwrócić uwagę na kierunek propagacji danych w pasku LED i przylutować przewody na jego początku. Jeśli koniec, który mamy przed sobą, jest zaznaczony strzałką, to nie jest to koniec, którego szukamy – przylutujmy przewody na drugim końcu. Trzy przewody przylutowane do paska diodowego to zasilanie, masa i szeregowa linia danych, która służy do programowania kolorów. Masa i zasilanie podłączamy odpowiednio do masy i napięcia z baterii (które dostępne jest na płytce z ładowarką ogniwa). Linia danych dołączana jest do płytki z mikrokontrolerem do cyfrowej linii D6.

Na tym etapie osadzamy w obudowie również moduł do ładowania baterii. Łączymy jego masę z masą modułu Arduino, a linię BAT+ z wejściem zasilania modułu Arduino (VIN). Jeśli używamy Arduino Nano 33, musimy dodatkowo połączyć zworkę VUSB, znajduje się ona pomiędzy wyprowadzeniami RST a A7 modułu.

Jeśli korzystamy z innego modułu Arduino, należy upewnić się, że nasz moduł może pracować poprawnie z zasilaniem na poziomie 3,7 V (tyle daje naładowane ogniwo, użyte w systemie). Arduino Nano zostało zaprojektowane do zasilania z 5 V, ale całkiem nieźle radzi sobie z niższym napięciem.

Następnie należy podłączyć moduł akcelerometru. W pierwszej kolejności należy przylutować VIN modułu MPU6050 do wyjścia 3V3 (napięcie 3,3 V) w module Arduino oraz połączyć masy obu układów. W kolejnym kroku należy podłączyć linie danych (w postaci interfejsu I2C – SCL i SDA) oraz przerwanie (INT). Linie zegarową interfejsu szeregowego I2C (SCL) podłączamy do portu A5, a linię danych (SDA) podłączamy do portu A4. Przerwanie (INT) dołączane jest do portu D2 modułu Arduino. Wskazane porty działają poprawnie w module Arduino Nano i Nano 33, w przypadku innych modułów konieczne może być zastosowanie innych wyprowadzeń.

Finalnie możemy zainstalować w układzie baterię. W tym celu należy przygotować przewód ze złączem Molex, kompatybilnym z wtyczką, jaka zamontowana jest na kablu akumulatora. Drugą stronę przewodu lutujemy do pól BAT+ oraz BAT– w module ładowarki.

Możemy teraz podłączyć baterię do modułu. Jeśli wszystko polutowaliśmy poprawnie, możemy rozłączyć elementy i pozakładać na przewody zasilania i inne koszulki termokurczliwe, które mają zapobiec ewentualnym zwarciom. Po sprawdzeniu poprawności montażu i zabezpieczeniu wszystkich elementów można podłączyć do układu baterię i obsadzić ją w obudowie.

Obudowa

Obudowa została wykonana w technice druku 3D. Do wydrukowania są dwie części – jedna dla samego spinnera Solarfidget (rysunek 1a), a druga dla ładowarki urządzenia (rysunek 1b).

Rysunek 1. Wizualizacja obudowy urządzenia: a) spinnera, b) jego ładowarki

Obie obudowy składają się z dwóch elementów. We wnętrzu obudowy spinnera i jego ładowarki rozmieszczono łącznie osiem magnesów – po cztery w każdym urządzeniu. Ich lokalizacja musi być taka sama w obu urządzeniach, aby orientowały się względem siebie tak, aby złącza ładowania trafiały dokładnie w siebie. Na przykład – dwa można umieścić obok złączy ładowania, a dwa – o odwróconych biegunach, w drugiej części obudowy.

Obudowa przygotowana przez autora projektu ma cztery zagłębienia, które przeznaczone są do umieszczenia opisanych powyżej magnesów. Najwygodniej jest je osadzić, umieszczając w zagłębieniu kroplę kleju i wciskając magnes np. tępą stroną śrubokręta lub innym przedmiotem.

Stacja ładująca

Na fotografii 3 pokazano ułożenie przewodów w obu urządzeniach. Dołącz ładowarkę do urządzenia, umieszczając cztery kable z odciętego końca kabla USB wewnątrz złączy ładujących w stacji ładującej. Nie zapominajmy najpierw poprowadzić kabla przez dolną część stacji ładującej, zanim zostanie on zamontowany w złączu do ładowania spinnera.

Fotografia 3. Ułożenie połączeń do stacji ładowania

Do budowy drugiej części złącza, tej, która znaleźć się ma w ładowarce, zastosowane zostaną śruby M3 o długości 10 mm, sprężyny i przeciwnakrętki, które wymienione są na liście potrzebnych elementów. Montaż przebiega podobnie jak w przypadku złączy w spinnerze, z tym że tutaj dodatkowo zainstalowane są sprężyny, które dociskają odizolowane przewody do śrub. Dokręcając śruby, można regulować ich poziom wysunięcia – należy ustawić je tak, aby minimalnie wystawały powyżej poziomu obudowy. Zapewni to optymalny kontakt pomiędzy elementami w spinnerze i jego ładowarką po dociśnięciu magnesami obu urządzeń do siebie.

Oprogramowanie

Do poprawnego działania szkicu Arduino dla tego urządzenia potrzebuje szeregu bibliotek opracowanych przez autora, które znaleźć można w folderze arduino-solarfidget/libraries/solarfidget w repozytorium z plikami projektowymi na GitHubie, które należy umieścić w folderze Arduino/libraries. Dodatkowo potrzebne są biblioteki:

Wszystkie pobranie biblioteki należy umieścić w podfolderach w folderze Arduino/libraries. Po skompletowaniu wszystkich potrzebnych bibliotek można otworzyć w Arduino IDE szkic z firmware spinnera, który dostępny jest w arduino-solarfidget/arduino-solarfidget.ino.
Ładowarkę należy umieścić na równej, wypoziomowanej powierzchni, a na niej postawić spinner. Poprzez ładowarkę układ można podłączyć do komputera, aby połączyć się z nim za pomocą Arduino IDE.

Listing 1. Szkic Arduino kontrolujący spinner

#include <Adafruit_NeoPixel.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#include <solarfidget.h>

// Pin przerwania MPU6050
#define INTERRUPT_PIN 2
// Pin diody LED
#define LED_PIN 13

bool blinkState = false;

// Pin, do którego podłączone są diody LED RGB
#define PIN_NEOPIXEL        6
// Liczba podłączonych szeregowo diod
#define NUMPIXELS_NEOPIXEL 36

Adafruit_NeoPixel pixels(NUMPIXELS_NEOPIXEL,
 PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

// Include SOLARFIDGET code
#define ACCELX    (float)aaReal.x
#define ACCELY    (float)aaReal.y
#define PITCH   ypr[1]
#define ROLL    ypr[2]
#define MAX_RAD_QUAD  1.57
#define CHARGING_PIN  8

//#define POWERREPORTING
//#define POWERSAVING
#define SERIAL_DEBUG

MPU6050 mpu;      // Domyślny adres 0x68 (AD0 niskie)
//MPU6050 mpu(0x69);  // Adres 0x69 (AD0 wysokie)

// Zmienne kontrolne MPU
bool dmpReady = false;  // Status inicjalizacji
uint8_t mpuIntStatus;   // Status/wartość bajtu przerwania
uint8_t devStatus;      // Status operacji (0 = sukces, !0 = błąd)
uint16_t packetSize;    // Spodziewana wielkość (domyślnie 42 bajty)
uint16_t fifoCount;     // Liczba bajtów w kolejce FIFO
uint8_t fifoBuffer[64]; // Kolejka FIFO

//Obliczenie kwaternionu
Quaternion q;           // [w, x, y, z]
///Pomiar przyspieszenia
VectorInt16 aa;         // [x, y, z]
//Skorygowany o grawitację pomiar przyspieszenia
VectorInt16 aaReal;     // [x, y, z]
///Przyspieszenie przeniesione do ziemskiego układu
VectorInt16 aaWorld;    // [x, y, z]
//Wektor przyciągania ziemskiego
VectorFloat gravity;    // [x, y, z]
//Obliczenia kąta Eulera
float euler[3];         // [psi, theta, phi]
//Kąt odchylenia, nachylenia i przechyłu
float ypr[3];           // [yaw, pitch, roll]
// Struktura pakietu danych dla dema InvenSense teapot
uint8_t teapotPacket[14] = { ‘$’, 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, ‘\r’, ‘\n’ };

// indicates whether MPU interrupt pin has gone high
volatile bool mpuInterrupt = false;
void dmpDataReady() {         // Obsługa przerwania
   mpuInterrupt = true;
}

void setup() {
   pixels.begin();           // Inicjaizacja diod LED
   #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
       Wire.begin();         // Inicjalizacja I2C
       Wire.setClock(400000);      // Zegar I2C = 400kHz I2C clock
   #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
       Fastwire::setup(400, true);
   #endif
   #ifdef SERIAL_DEBUG
   Serial.begin(115200);       // Inicjalizacja portu szeregowego
   Serial.println(F("Initializing I2C devices..."));
   #endif
   mpu.initialize();         // Inicjalizacja MPU
   pinMode(INTERRUPT_PIN, INPUT);    // Konfiguracja pinu przerwania
   #ifdef SERIAL_DEBUG
   Serial.println(F("Testing device connections..."));
   Serial.println(mpu.testConnection() ?
     F("MPU6050 connection successful") :
     F("MPU6050 connection failed"));
   #endif
   #ifdef SERIAL_DEBUG
   Serial.println(F("Initializing DMP..."));
   #endif
   devStatus = mpu.dmpInitialize();
   //mpu.setXAccelOffset(-1754);
   //mpu.setYAccelOffset(-1097);
   //mpu.setZAccelOffset(982);
   //mpu.setXGyroOffset(121);
   //mpu.setYGyroOffset(-12);
   //mpu.setZGyroOffset(4);
   if (devStatus == 0) {
       mpu.CalibrateAccel(6);    // Kalibracja akcelerometru
       mpu.CalibrateGyro(6);     // Kalibracja żyroskopu
       mpu.PrintActiveOffsets();
       #ifdef SERIAL_DEBUG
       Serial.println(F("Enabling DMP..."));
       #endif
       mpu.setDMPEnabled(true);
       #ifdef SERIAL_DEBUG
       Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));

       Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
       Serial.println(F(")..."));
       #endif
   // Przypisanie przerwania
       attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
       mpuIntStatus = mpu.getIntStatus();
       #ifdef SERIAL_DEBUG
       Serial.println(F("DMP ready! Waiting for first interrupt..."));
       #endif
       dmpReady = true;        // Flaga gotowości
       packetSize = mpu.dmpGetFIFOPacketSize();
   } else {
       #ifdef SERIAL_DEBUG
       Serial.print(F("DMP Initialization failed (code "));
       Serial.print(devStatus);
       Serial.println(F(")"));
       #endif
   }
   // Skonfigurowanie pinu sterującego LED-ami jako wyjścia
   pinMode(LED_PIN, OUTPUT);                 
}

void loop() {
   if (!dmpReady) return;
   // Odczytaj najnowszy pakiet z kolejki FIFO
   if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
       mpu.dmpGetQuaternion(&q, fifoBuffer);
       mpu.dmpGetAccel(&aa, fifoBuffer);
       mpu.dmpGetGravity(&gravity, &q);
   mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
       mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
   solarfidget();
       // Mrugnij diodą, by potwierdzić aktywność
       blinkState = !blinkState;         
       digitalWrite(LED_PIN, blinkState);
   }
}

Na listingu 1 pokazano szkic Arduino, który kontroluje system. Należy skompilować go i wgrać do urządzenia, a następnie uruchomić monitor portu szeregowego (np. ten wbudowany w środowisko Arduino IDE), aby połączyć się z urządzeniem.

Kalibracja sensora

Przed pierwszym uruchomieniem systemu należy skalibrować jego sensory. Po ułożeniu spinnera na wypoziomowanej płaszczyźnie wystarczy odczytać dane kalibracyjne, jakie wysyła on poprzez port szeregowy. Po zapisaniu danych kalibracyjnych dla akcelerometrów i dla żyroskopów układu należy wpisać je w szkicu Arduino (plik arduino-solarfidget/arduino-solarfidget.ino). Należy odnaleźć następujące linijki w kodzie:

mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets();

Powyższe linie należy zakomentować, a dane kalibracyjne wstawić w znajdujących się wyżej linijkach (w miejscu XXX):

//mpu.setXAccelOffset(XXX);
//mpu.setYAccelOffset(XXX);
//mpu.setZAccelOffset(XXX);
//mpu.setXGyroOffset(XXX);
//mpu.setYGyroOffset(XXX);
//mpu.setZGyroOffset(XXX);

Oczywiście linie te należy finalnie odkomentować. Po wprowadzeniu współczynników kalibracyjnych szkic można zapisać i ponownie skompilować przed kolejnym wgraniem do urządzenia.

Przygotowanie docelowego szkicu

W docelowym szkicu można wprowadzić jeszcze kilka drobnych zmian, mających za zadanie usprawnić działanie systemu. W pierwszej kolejności należy wyłączyć konsolę szeregową, która przydatna jest tylko na etapie debugowania systemu. Aby to zrobić, wystarczy zakomentować linię kodu z dyrektywą:

#define SERIAL_DEBUG

Dzięki wyłączeniu konsoli szeregowej system szybciej startuje i sprawniej działa, gdyż nie musi czekać na nawiązanie (lub nie i związany z tym timeout) połączenia poprzez USB.

Kolejnym usprawnieniem jest dodanie trybu oszczędzania mocy, który można aktywować, odkomentowując następującą linijkę kodu:

//#define POWERSAVING

W trybie oszczędzania energii, przed próbą włączenia urządzenia, należy przytrzymać je przez kilka sekund w dłoniach. Jeśli w takiej sytuacji występuje problem z włączeniem, wystarczy po prostu obracać spinner o 180°, aż się poprawnie włączy. Tryb oszczędzania energii jest aktywny tylko wtedy, gdy fidget jest wyłączony i jest nieruchomy. Po wprowadzeniu powyższych zmian do programu należy zapisać plik i ponownie wgrać program do pamięci mikrokontrolera.

Na koniec należy tylko upewnić się, że pasek LED jest prawidłowo umieszczony w zabawce, a światło wahadła jest we właściwym miejscu. Aby to sprawdzić, trzymając spinner pod delikatnym kątem należy poczekać, aż wahadło zatrzyma się w stabilnej pozycji. Teraz przesuwając pasek LED w lewo lub w prawo, należy ustawić światło we właściwej, idealnej pozycji. Można już zamknąć pokrywę urządzenia.

Podsumowanie

Solarfidget jest ciekawą zabawką, która sprawdza się i jako zabawka zręcznościowa, i jako gadżet edukacyjny. Z jednej strony urządzenie pozwala na zajęcie dłoni, co może być przydatne w wielu momentach – do odstresowania się czy też zajęcia dłoni w czasie wzmożonego wysiłku. Niektórzy uważają, że tego rodzaju zabawki są przydatne w terapii ADHD, jednakże nie zostało to potwierdzone przez naukowców czy lekarzy. Edukacyjny aspekt tego spinnera jest oczywisty. Pozwala na zaprezentowanie w prosty i zrozumiały sposób elementarnej różnicy występującej na planetach naszego Układu Słonecznego. Taka prezentacja wiedzy jest o wiele czytelniejsza i zrozumiała niż podanie suchych liczb. Sama wiedza na temat siły przyciągania na różnych planetach może być doskonałym wyjściem do szerszego omówienia siły przyciągania planet o różnych rozmiarach.

Nikodem Czechowski, EP

Źródła:

Artykuł ukazał się w
Elektronika Praktyczna
luty 2022

Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik kwiecień 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio marzec - kwiecień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje marzec 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna kwiecień 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich kwiecień 2024

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów