Spisu treści:
- Krok 1: W górę iw dół
- Krok 2: A co z lewą i prawą stroną?
- Krok 3: Podnoszenie ciała… JAK?
- Krok 4: Ale te pudełka nie są takie ładne…
- Krok 5: Slinky Zabawki? O mój
- Krok 6: Wydrukuj swojego smoka
- Krok 7: Czas wzmocnić smoka za pomocą NeoPixels
- Krok 8: Czas programowania
- Krok 9: Kontynuacja programowania
- Krok 10: Ciesz się swoim smokiem
2025 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2025-01-13 06:58
Sine-ese Dragon to nastrojowy element wystroju domu, który wykorzystuje mechaniczne ruchy i światła, aby przekazać prognozę pogody na następne trzy godziny. Z definicji otoczenie opisuje bezpośrednie otoczenie czegoś; dlatego zdecydowano, że właściwe będzie włączenie danych pogodowych do wyświetlacza otoczenia. Pogoda to aspekt, który nieumyślnie zmienia ludzkie dni i jest informacją, która zmienia się co minutę, a nawet co sekundę.
Chiński Smok jest „symbolem władzy, siły i szczęścia” i często ma wysoką kulturową i tradycyjną wartość na subkontynencie azjatyckim. Oprócz przynoszenia szczęścia, chiński smok ma również potężne moce, które kontrolują „wodę, opady deszczu, tajfuny i powodzie”. Ostatecznie chiński smok został uznany za odpowiedni do reprezentowania danych pogodowych.
Wyobrażanie sobie
Sine-ese Dragon jest manipulowany w sześciu głównych punktach w trzech oddzielnych sekcjach reprezentujących prognozę pogody w trzech 3-godzinnych odstępach. Dla każdego 3-godzinnego interwału zostaną uwzględnione następujące informacje:
- Opis pogody - określa kolor aktualnych informacji o pogodzie.
- Temperatura - określa wysokość ciała
- Wilgotność - miganie segmentów LED
- Prędkość wiatru - kontroluje prędkość poruszającego się ciała w lewo iw prawo.
Wymagane materiały
- 3 mm sklejka/karton
- Drewniane kołki lub pałeczki 5 mm
- 2 fotony cząstek
- 3 zabawki Slinky
- 6 serwosilników
- Lampy NeoPixel (zszyte ze sobą pasmo lub pojedyncze światła)
- Dużo super kleju
- Gwint przewodzący
- Farba akrylowa
- Tkanina dekoracyjna
- Wycinarka laserowa
- drukarka 3d
Krok 1: W górę iw dół
Twoim pierwszym krokiem do zbudowania Sine-ese Dragona jest skonstruowanie elementu, który kontroluje ruch ciała w górę iw dół. Jak ekscytujące!
-
Pobierz pliki Adobe Illustrator (.ai) i wydrukuj je za pomocą wycinarki laserowej.
upDownBoxWithPlatform.ai należy wydrukować na kartonie
-
Pobierz pliki do drukowania 3D (.stl) i użyj swojej ulubionej drukarki 3D, aby je wydrukować.
Kolor nie ma znaczenia dla dysku ani tokarki. Na drugim zdjęciu obracacz tarczy został włożony w otwór tarczy
-
Złóż pierwsze dwa elementy i sklej je razem, jak pokazano na rysunkach 3 do 5.
- Platforma
- Rowki na dysk
-
Teraz ułóż pudełko zgodnie z poniższymi wskazówkami.
- Przewody serwomechanizmu powinny przejść przez prostokątny otwór z boku puszki.
- Najkrótszy koniec tokarki zostaje przymocowany do głowicy serwomechanizmu, a dłuższy przechodzi przez otwór po drugiej stronie pudełka z okrągłym otworem. Pokazuje to rysunek 6.
- Teraz potrzebujemy czegoś, co zapewni, że platforma pozostanie wypoziomowana, gdy dysk zostanie obrócony. Pokrój pałeczki na patyczki o długości 75 mm (rysunek 7) i przyklej je przez górną część pudełka do górnej części platformy za pomocą gorącego kleju. Upewnij się, że patyki są wypoziomowane pod kątem 90 stopni do platformy.
- Włóż patyczek o długości 212 mm do środkowego otworu na górze pudełka na platformie.
Słodki! Teraz masz kompletne pudełko (rysunek 8) do poruszania się smoka w górę iw dół. Teraz powtórz powyższe kroki jeszcze dwa razy!
Krok 2: A co z lewą i prawą stroną?
Teraz nie możemy zapominać o ruchu lewego i prawego smoka Sine-ese, prawda? Przejdźmy do drugiego kroku!
-
Pobierz pliki Adobe Illustrator (.ai) i wydrukuj je za pomocą wycinarki laserowej.
- leftRightBoxWithPlatforms.ai należy wydrukować na kartonie.
- Plik armTurner.ai należy wydrukować na materiale o grubości 3 mm.
-
Pobierz pliki do drukowania 3D (.stl) i użyj swojej ulubionej drukarki 3D, aby je wydrukować.
Upewnij się, że wydrukujesz dwa ramiona! Kolor nie ma tu znaczenia
- Połącz ze sobą dwie platformy, jak pokazano na rysunku 3, używając gorącego kleju.
-
Złóż pudełko. Chociaż może to być trudne, łatwiej jest to osiągnąć poprzez:
- Włożenie dwóch platform między dwie duże szczeliny po obu stronach pudełka.
- Umieszczenie pierwszego ramienia na górze górnej platformy.
- Przewlekanie ramienia obracającego przez ramię, a następnie przez górną platformę.
- Umieszczenie drugiego ramienia na górze dolnej platformy.
- Przewlekanie ramienia obracającego przez drugie ramię, a następnie dolną platformę.
- Wkładanie ramienia obracającego przez prostokątny otwór drukowanego w 3D ramienia obracającego.
- Drugi koniec tokarki idzie na górę serwomotoru.
- Dodaj górną, dolną i tylną część do pudełka.
Twoje ostateczne zmontowane pudełko powinno wyglądać jak szóste zdjęcie. Teraz możesz powtórzyć to jeszcze dwa razy!
Pod koniec tego kroku powinieneś mieć sześć pudełek z trzema systemami ruchu w górę/dół i lewo/prawo.
Krok 3: Podnoszenie ciała… JAK?
Dobre pytanie! Wtedy pojawiają się te wydrukowane w 3D, cienkie uchwyty. Pobierz dołączony plik.stl i wydrukuj go za pomocą drukarki 3D. Pamiętaj, aby wydrukować łącznie 6 uchwytów na 6 różnych pudełek.
Jeśli widzieliście powyżej zdjęcie slinky posiadacza, niespodzianka została zrujnowana - taki jest kolor naszego Sine-ese Dragona!
Krok 4: Ale te pudełka nie są takie ładne…
I zgadzam się! Dlatego użyjemy wycinarki laserowej, aby wyciąć o wiele bardziej atrakcyjne pudełko, aby pomieścić wszystkie te pudełka i je ukryć.
Pobierz te pliki Adobe Illustrator i wytnij je za pomocą wycinarki laserowej. Projekt chmur został narysowany ręcznie przez jednego z kontrybutorów. Możesz je modyfikować, usuwając je w pliku programu Illustrator i dodając własny projekt według własnego uznania! Poniżej znajdują się sugerowane kroki, aby wszystko połączyć.
- Złóż i sklej wszystkie trzy elementy z pierwszego pliku (outerBoxFinal_1) razem.
- Nie dodawaj jeszcze kawałka z drugiego pliku (outerBoxFinal_2).
- Umieść kawałek z trzeciego pliku (outerBoxFinal_3) na dole pudełka i powinien zamknąć się u góry. Klej TYLKO na spodzie pudełka.
- Dwukrotnie wydrukuj innerBoxesPlatform. Sklej ze sobą dwa kawałki, które mają duże prostokątne otwory. Następnie sklej ze sobą trzy pozostałe kawałki. Na koniec przyklej go do drugiego klejonego zestawu z otworami.
- Umieść platformę na dole dużego pudełka.
- Włóż wszystkie 6 mniejszych pudełek w odpowiednie miejsca na platformie.
- Teraz umieść kawałek z drugiego pliku (outerBoxFinal_2) na górze pudełka i przyklej wokół krawędzi. Otwory w górnej części powinny być wyrównane z otworami w mniejszych pudełkach. Jeśli nie, przestaw swoje mniejsze pudełka. W ogóle nie dodawaj kleju do mniejszych pudełek.
- Jeśli używasz płytki stykowej, która ma lepki kawałek na dole, umieść go w pobliżu środka dolnego kawałka w miejscu, w którym po zamknięciu pudełka płytka prototypowa wraz z fotonami powinna zniknąć. W dolnej części znajdują się małe szczeliny ułatwiające podłączenie do Photonów z zewnątrz.
Krok 5: Slinky Zabawki? O mój
Ciało smoka:
1. Połącz ze sobą trzy slinky za pomocą gorącego kleju lub taśmy.
2. Zmierz długość i średnicę slinków i wytnij kawałek tkaniny dekoracyjnej.
3. Przynieś dwa końce materiału i zszyj je razem.
4. Po zakończeniu szycia wsuń slinki jak skarpetę.
5. Przyszyj końce slinky do szytej tkaniny.
Krok 6: Wydrukuj swojego smoka
Wydrukowane w 3D części smoka:
1. Części zostały zaczerpnięte z
2. Wykorzystaliśmy tylko głowę, nogi i oczy.
3. Po wydrukowaniu części wygładź ją papierem ściernym i acetonem.
4. Pomaluj części tak, jak chcesz je ozdobić.
Krok 7: Czas wzmocnić smoka za pomocą NeoPixels
Segment lekki:
1. Możesz po prostu użyć nici neopixel do stworzenia świateł, jeśli chcesz. (Skończyły się nici).
2. Użyliśmy 20 lamp neopikselowych i połączyliśmy je przewodami. Przewody te zostały do nich przylutowane i połączone z fotonem za pomocą czerwonych przewodów, aby pasowały do motywu smoka.
3. Możesz również przyszyć swoje neopikselowe światła na długim kawałku materiału, ale nie użyliśmy ich, ponieważ mieliśmy slinky wykonane z metalu.
Montaż części: Zabezpiecz segment świetlny wewnątrz korpusu smoka za pomocą nici lub drutów. Upewnij się, że jesteś w stanie podłączyć światła do fotonu wewnątrz skrzynki bazowej. Przymocuj głowę, nogi i ogon do ciała za pomocą kleju. Gdy są na miejscu, przymocuj ciało do slinky uchwytów, które wydrukowaliśmy wcześniej. Teraz ciało jest gotowe do zaprogramowania.
Krok 8: Czas programowania
Ponieważ będziemy używać dwóch fotonów cząstek do pracy z sześcioma oddzielnymi serwomotorami (jeden foton może działać tylko z czterema), napiszemy dwa oddzielne, ale podobne kody, które będą migać na mikrokontrolerach.
Teraz dla pierwszego mikrokontrolera…
W pliku Arduino (.ino) dołącz następujące biblioteki i definiuje:
#include "neopixel.h"
#include "ArduinoJson.h"
#define PIXEL_PIN D4
#define PIXEL_COUNT 18
Następnie zadeklaruj następujące zmienne:
Pasek Adafruit_NeoPixel = Adafruit_NeoPixel(LICZBA_PIKSELÓW,PIN_PIKSELÓW);
Serwo serwoLeftRight_1; Serwo serwoUpDown_1; Serwo serwoLeftRight_2; Serwo serwoUpDown_2; int pozycjaLeftPrawy_1 = 0; int pozycjaGóraDół_1 = 0; int lewyPrawy_1 = 1; int góraDół_1 = 1; int pozycjaLeftPrawy_2 = 100; // musi mieścić się w zakresie od 0 do 180 (w stopniach) int positionUpDown_2 = 180; // musi mieścić się w zakresie od 0 do 180 (w stopniach) int leftRight_2 = 1; //0=w lewo, 1=w prawo int upDown_2 = 1; //0=w górę, 1=w dół const size_t bufferSizeCurrent = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) 390; const size_t bufferSizeForecast = 38*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(38) + 2*JSON_OBJECT_SIZE(0) + 112*JSON_OBJECT_SIZE(1) + 39*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 38*JSON_OBJECT_SIZE(4) + 38*JSON_OBJECT_SIZE(4) (5) + 76*JSON_OBJECT_SIZE(8) + 12490; String weatherArray[3]; float temperatureArray[3]; pływak wilgotnościArray[3]; pływająca tablica prędkości wiatru[3]; String timestampArray[3]; int upDownMaxDegree[3]; int leftRightSpeed[3]; Ciąg allData5DaysPrognoza;
Kliknij tutaj, aby dowiedzieć się, jak skonfigurować webhooki. Kiedy skończysz, dodaj następujące deklaracje i funkcje i wprowadź odpowiednie zmiany, jeśli to konieczne:
void getWeather5DayForecast() { Particle.publish("get_weather5DayForecast"); allData5DaysForecast = ""; } Timer timerWeatherForecast(60000, getWeather5DayForecast); void pobierzCurrentWeather() { Particle.publish("get_currentWeather"); } Timer timerWeatherCurrent(60000, getCurrentWeather);
Następujące funkcje sterują ruchami smoka w górę/dół i lewo/prawo:
void zmieńLeftRight1() { if (leftRight_1) { positionLeftRight_1 = positionLeftRight_1 + leftRightSpeed[0]; if (pozycjaLeftRight_1 > 100) { leftRight_1 = 0; } } else { pozycjaLeftPrawo_1 = pozycjaLeftPrawo_1 - leftRightSpeed[0]; if (pozycjaLeftRight_1 < 0) { leftRight_1 = 1; } } servoLeftRight_1.write(positionLeftRight_1); }
nieważna zmiana w lewo w prawo2 () {
if (leftRight_2) { pozycjaLeftRight_2 = pozycjaLeftRight_2 + LeftRightSpeed[1]; if (pozycjaLeftRight_2 > 100) { leftRight_2 = 0; } } else { pozycjaLeftPrawo_2 = pozycjaLeftPrawo_2 - leftRightSpeed[1]; if (pozycjaLeftRight_2 < 0) { leftRight_2 = 1; } } servoLeftRight_2.write(positionLeftRight_2); }
nieważna zmianaW górę1() {
if (upDown_1) { positionUpDown_1++; if (positionUpDown_1 > upDownMaxDegree[0]) { upDown_1 = 0; } } else { positionUpDown_1--; if (pozycjaUpDown_1 < 1) { upDown_1 = 1; } } servoUpDown_1.write(positionUpDown_1); }
nieważna zmianaW górę2() {
if (upDown_2) { positionUpDown_2++; if (positionUpDown_2 > upDownMaxDegree[1]) { upDown_2 = 0; } } else { positionUpDown_2--; if (pozycjaUpDown_2 < 1) { upDown_2 = 1; } } servoUpDown_2.write(positionUpDown_2); }
Aby móc zmieniać ruchy w interwale, tworzone są timery.
Licznik czasowyLeftRight1(100, zmieńLeftRight1);
Licznik czasowyLeftRight2(100, zmieńLeftRight2); Timer timerUpDown1(10, zmianaUpDown1); Timer timerUpDown2(10, zmianaUpDown2);
Na koniec dodawana jest funkcja konfiguracji. Pamiętaj, aby wprowadzić odpowiednie zmiany w wierszach kodu, które dotyczą webhooków.
void setup() { // uruchomienie liczników pogody timerWeatherForecast.start(); timerWeatherCurrent.start(); //Neopiksele strip.begin(); // Umieść inicjalizację jak pinMode i rozpocznij funkcje tutaj. // Ustaw serwo Micro ServoLeftRight_1.attach(D1); servoUpDown_1.attach(D0); serwoLeftPrawo_2.attach(D3); servoUpDown_2.attach(D2); servoLeftRight_1.write(positionLeftRight_1); //zainicjuj pozycję serwa servoUpDown_1.write(positionUpDown_1); //zainicjuj pozycję serwa servoLeftRight_2.write(positionLeftRight_2); //zainicjuj pozycję serwa servoUpDown_2.write(positionUpDown_2); //zainicjuj timer pozycji serwaLeftRight1.start(); timerLewoPrawo2.start(); timerUpDown1.start(); timerUpDown2.start(); // Otwórz konsolę Serial.begin(9600); opóźnienie (2000); Serial.println("Cześć!"); // Zapisz się do get_weather5DayForecast i get_currentWeather webhooków Particle.subscribe("hook-response/get_weather5DayForecast", gotWeather5DayForecast, MY_DEVICES); Particle.subscribe("hook-response/get_currentWeather/0", gotCurrentWeatherData, MOJE_URZĄDZENIA); pobierzAktualnąPogodę(); getWeather5DayForecast(); }
W tym projekcie nie jest używana funkcja pętli. Nie możemy zapomnieć o funkcjach do obsługi danych otrzymanych z webhooków!
void gotWeather5DayForecast(const char *event, const char *data){ allData5DaysForecast += dane; // zapisuje wszystkie dane w jednym ciągu. int allData5DaysForecastLen = allData5DaysForecast.length(); bufor znaków[allData5DaysForecastLen + 1]; allData5DaysForecast.toCharArray(bufor, allData5DaysForecastLen + 1); // utwórz bufor dla łańcucha int bufferLength = sizeof(buffer); DynamicJsonBuffer jsonBufferWeather(bufferLength); JsonObject& root = jsonBufferWeather.parseObject(bufor); // Sprawdź, czy parsowanie się powiodło. if (!root.success()) { //Serial.println("Parsowanie prognozy pogody na 5 dni…BŁĄD!"); powrót; } int i = 1; JsonArray& lista = root["lista"]; for (JsonObject& currentObject: lista){ if (i < 3){ JsonObject& main = currentObject["main"]; temperatura pływaka = main["temp"]; int wilgotność = main["wilgotność"]; JsonObject& pogoda = obecnyObiekt["pogoda"][0]; const char* weatherInfo = pogoda["główna"]; pływająca prędkość wiatru = bieżącyObiekt["wiatr"]["prędkość"]; const char* znacznik czasu = bieżącyObiekt["dt_txt"]; int tempFah = przelicz naFahrenheita(temperatura); int servoMaxDegree = updateUpDown(tempFah); upDownMaxDegree = servoMaxDegree; int servoIncrement = updateleftRight(windSpeed); leftRightSpeed = servoIncrement; setColor(informacje o pogodzie, ja); temperatureArray = tempFah; wilgotnośćArray = wilgotność; weatherArray = weatherInfo; windSpeedArray = windSpeed; tablica znaczników czasu = znacznik czasu; i++; } jeszcze{ przerwa; } } }
void gotCurrentWeatherData(const char *event, const char *data){ DynamicJsonBuffer jsonBufferWeather(bufferSizeCurrent); JsonObject& root = jsonBufferWeather.parseObject(dane); // Sprawdź, czy parsowanie się powiodło. if (!root.success()) { //Serial.println("Parsing dla aktualnej pogody…BŁĄD!"); powrót; } JsonObject& pogoda = root["pogoda"][0]; const char* weather_main = pogoda["główna"]; JsonObject& main = root["główny"]; float main_temp = main["temp"]; int główna_wilgotność = główna["wilgotność"]; float prędkość_wietrza = root["wiatr"]["prędkość"]; const char* znacznik czasu = root["dt_txt"]; int tempFah = konwertuj naFahrenheita(main_temp); int servoMaxDegree = updateUpDown(tempFah); upDownMaxDegree[0] = servoMaxDegree; int servoIncrement = updateleftRight(wind_speed); leftRightSpeed[0] = servoIncrement; setColor(weather_main, 0); weatherArray[0] = pogoda_główna; temperatureArray[0] = tempFah; wilgotnośćArray[0]= główna_wilgotność; windSpeedArray[0] = wind_speed; timestampArray[0] = znacznik czasu; }
Poniżej znajdują się dodatkowe funkcje sterujące aktualizacją pozycji serwonapędów, konwersją temperatury z Kelvina na Fahrenheita oraz ustawianiem kolorów diod LED.
int updateUpDown(float temp){ //Odwzoruj stopień na zakres [0, 180] float servoMaxDegree = temp * 45 / 31 + (990 / 31); Serial.print("nowy stopień serwo: "); Serial.println(servoMaxDegree); powrót servoMaxDegree; }
int updateleftRight(pływająca prędkość wiatru){
//Przypisz prędkość wiatru do zakresu [1, 100] float servoIncrement = windSpeed * 99 / 26 + 1; Serial.print("nowa wartość przyrostu serwa: "); Serial.println(servoPrzyrost); zwróć servoInkrement; }
int konwertuj na stopnie Fahrenheita(zmienna tempKel){
int tempFah = tempKel * 9,0 / 5,0 - 459,67; powrót tempFah; }
void setColor(String weatherDesc, int index){
int ledIndex = 0; if (indeks == 0){ ledIndex = 0; } else if (indeks == 1){ ledIndex = 6; } else if (indeks == 2){ ledIndex = 12; } else{ powrót; } if(weatherDesc == "Clear") { //żółty for (int j = ledIndex; j < ledIndex+6; j++){ strip.setPixelColor(j, strip. Color(253, 219, 62));// żółty pasek.pokaż(); opóźnienie(20); } } else if(weatherDesc == "Chmury"){ //grey for (int j = ledIndex; j < ledIndex+6; j++){ strip.setPixelColor(j, strip. Color(223, 229, 237)); //szary pasek.show(); opóźnienie(20); } } else if (weatherDesc == "Snow"){ //biały for (int j = ledIndex; j < ledIndex+6; j++){ strip.setPixelColor(j, strip. Color(255, 225, 225)); //biały pasek.show(); opóźnienie(20); } } else if (weatherDesc == "Deszcz"){//blue for (int j = ledIndex; j < ledIndex+6; j++){ strip.setPixelColor(j, strip. Color(119, 191, 246)); //niebieski pasek.show(); opóźnienie(20); } } else{ //red for (int j = ledIndex; j < ledIndex+6; j++){ strip.setPixelColor(j, strip. Color(254, 11, 5));//red strip.show(); opóźnienie(20); } } }
Po dodaniu wszystkiego do pliku Arduino skompiluj go. Jeśli nie ma błędów, śmiało prześlij kod do pierwszego Photona. W następnym kroku otrzymasz podobny kod do flashowania na drugim Photonie.
Krok 9: Kontynuacja programowania
Ponieważ kod drugiego Photona jest prawie identyczny z kodem pierwszego, cały kod jest kopiowany i wklejany poniżej:
#include "ArduinoJson.h"
Serwo serwoLeftRight_3;
Serwo serwoUpDown_3;
int pozycjaLewaPrawa_3 = 45;
int pozycjaGóraDół_3 = 0; int lewyPrawy_3 = 1; int w górę w dół_3 = 1;
const size_t bufferSizeCurrent = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 390;
const size_t bufferSizeForecast = 38*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(38) + 2*JSON_OBJECT_SIZE(0) + 112*JSON_OBJECT_SIZE(1) + 39*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 38*JSON_OBJECT_SIZE(4) + 38*JSON_OBJECT_SIZE(4) (5) + 76*JSON_OBJECT_SIZE(8) + 12490;
String weatherArray[3];
float temperatureArray[3]; pływak wilgotnościArray[3]; pływająca tablica prędkości wiatru[3]; String timestampArray[3]; int upDownMaxDegree[3]; int leftRightSpeed[3];
Ciąg allData5DaysPrognoza;
void pobierzWeather5DayForecast()
{ Cząstka.publish("get_weather5DayForecast2"); allData5DaysForecast = ""; }
Licznik czasuWeatherForecast(60000, getWeather5DayForecast); //10, 800 000 ms = 3 dni
void pobierzAktualnąPogodę()
{ Cząstka.publish("get_currentWeather2"); }
Timer timerWeatherCurrent(60000, getCurrentWeather);
nieważna zmiana w lewo w prawo3() {
if (leftRight_3) { pozycjaLeftRight_3 = pozycjaLeftRight_3 + LeftRightSpeed[2]; if (pozycjaLeftRight_3 > 100) { leftRight_3 = 0; } } else { pozycjaLeftPrawo_3 = pozycjaLeftPrawo_3 - leftRightSpeed[2]; if (pozycjaLeftRight_3 < 0) { leftRight_3 = 1; } } servoLeftRight_3.write(positionLeftRight_3); }
nieważna zmianaW górę3() {
if (upDown_3) { positionUpDown_3++; if (positionUpDown_3 > upDownMaxDegree[2]) { upDown_3 = 0; } } else { positionUpDown_3--; if (positionUpDown_3 < 1) { upDown_3 = 1; } } servoUpDown_3.write(positionUpDown_3); }
Licznik czasowyLeftRight3(100, zmieńLeftRight3);
Timer timerUpDown3(10, zmianaUpDown3);
pusta konfiguracja () {
// uruchom liczniki pogody timerWeatherForecast.start(); timerWeatherCurrent.start(); // Umieść inicjalizację jak pinMode i rozpocznij funkcje tutaj. // Ustaw serwomechanizm Micro ServoLeftRight_3.attach(D1); servoUpDown_3.attach(D0);
servoLeftRight_3.write(pozycjaLeftRight_3); //zainicjuj pozycję serwa
servoUpDown_3.write(positionUpDown_3); //zainicjuj pozycję serwa
timerLewoPrawo3.start();
timerUpDown3.start(); // Otwórz konsolę Serial.begin(9600); opóźnienie (2000); Serial.println("Cześć!"); // Zasubskrybuj webhooki get_weather5DayForecast i get_currentWeather Particle.subscribe("hook-response/get_weather5DayForecast2", gotWeather5DayForecast, MY_DEVICES); Particle.subscribe("hook-response/get_currentWeather2/0", gotCurrentWeatherData, MOJE_URZĄDZENIA); pobierzAktualnąPogodę(); getWeather5DayForecast(); }
void gotWeather5DayForecast(const char *event, const char *data)
{ allData5DaysPrognoza += dane; // zapisuje wszystkie dane w jednym ciągu. int allData5DaysForecastLen = allData5DaysForecast.length(); bufor znaków[allData5DaysForecastLen + 1]; allData5DaysForecast.toCharArray(bufor, allData5DaysForecastLen + 1); // utwórz bufor dla łańcucha int bufferLength = sizeof(buffer); DynamicJsonBuffer jsonBufferWeather(bufferLength); JsonObject& root = jsonBufferWeather.parseObject(bufor); //Serial.println(allData5DaysForecast); // Sprawdź, czy parsowanie się powiodło. if (!root.success()) { //Serial.println("Parsowanie prognozy pogody na 5 dni…BŁĄD!"); powrót; } int i = 1; JsonArray& lista = root["lista"]; for (JsonObject& currentObject: lista){ if (i < 3){ JsonObject& main = currentObject["main"]; temperatura pływaka = main["temp"]; int wilgotność = main["wilgotność"]; JsonObject& pogoda = obecnyObiekt["pogoda"][0]; const char* weatherInfo = pogoda["główna"]; pływająca prędkość wiatru = bieżącyObiekt["wiatr"]["prędkość"]; const char* znacznik czasu = bieżącyObiekt["dt_txt"]; int tempFah = przelicz naFahrenheita(temperatura); int servoMaxDegree = updateUpDown(tempFah); upDownMaxDegree = servoMaxDegree; int servoIncrement = updateleftRight(windSpeed); leftRightSpeed = servoIncrement; temperatureArray = tempFah; wilgotnośćArray = wilgotność; weatherArray = weatherInfo; windSpeedArray = windSpeed; tablica znaczników czasu = znacznik czasu; i++; } jeszcze{ przerwa; } } }
void gotCurrentWeatherData(const char *event, const char *data)
{ DynamicJsonBuffer jsonBufferWeather(bufferSizeCurrent); JsonObject& root = jsonBufferWeather.parseObject(dane); //Serial.println(dane); // Sprawdź, czy parsowanie się powiodło. if (!root.success()) { //Serial.println("Parsing dla aktualnej pogody…BŁĄD!"); powrót; } JsonObject& pogoda = root["pogoda"][0]; const char* weather_main = pogoda["główna"]; JsonObject& main = root["główny"]; float main_temp = main["temp"]; int główna_wilgotność = główna["wilgotność"]; float prędkość_wietrza = root["wiatr"]["prędkość"]; const char* znacznik czasu = root["dt_txt"]; int tempFah = konwertuj naFahrenheita(main_temp); int servoMaxDegree = updateUpDown(tempFah); upDownMaxDegree[0] = servoMaxDegree; int servoIncrement = updateleftRight(wind_speed); leftRightSpeed[0] = servoIncrement; weatherArray[0] = pogoda_główna; temperatureArray[0] = tempFah; wilgotnośćArray[0]= główna_wilgotność; windSpeedArray[0] = wind_speed; timestampArray[0] = znacznik czasu; }
int updateUpDown (wartość zmiennoprzecinkowa){
//Odwzoruj stopień na zakres [0, 180] float servoMaxDegree = temp * 45 / 31 + (990 / 31); Serial.print("nowy stopień serwo: "); Serial.println(servoMaxDegree); powrót servoMaxDegree; }
int updateleftRight(pływająca prędkość wiatru){
//Przypisz prędkość wiatru do zakresu [1, 100] float servoIncrement = windSpeed * 99 / 26 + 1; Serial.print("nowa wartość przyrostu serwa: "); Serial.println(servoPrzyrost); zwróć servoInkrement; }
int konwertuj na stopnie Fahrenheita(zmienna tempKel){
int tempFah = tempKel * 9,0 / 5,0 - 459,67; powrót tempFah; }
Zrobiłeś to! Udało Ci się przejść przez dział programowania projektu! Teraz upewnij się, że wykonałeś całe okablowanie i połączenia od serwomotorów i neopikseli do płytki stykowej i mikrokontrolerów. UWAGA: włóż dodatkowe kołki/pałeczki przez pionowe szczeliny w pudełkach, aby umożliwić ruchy ciała w lewo i w prawo. Drugi koniec powinien być połączony z ciałem smoka.
Krok 10: Ciesz się swoim smokiem
Gratulacje! Zbudowałeś od podstaw smoka Sine-ese! Teraz wszystko, co musisz zrobić, to usiąść wygodnie i cieszyć się nastrojowym wyświetlaczem!
UWAGA: Ten projekt został zbudowany jako część zajęć przez Joan Bemponga i Soundaryę Muthuvel. Stronę kursu można znaleźć tutaj.