Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'arduino'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino i ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - DIY
    • Projekty - DIY roboty
    • Projekty - DIY (mini)
    • Projekty - DIY (początkujący)
    • Projekty - DIY w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie

Kategorie

  • Quizy o elektronice
  • Quizy do kursu elektroniki I
  • Quizy do kursu elektroniki II
  • Quizy do kursów Arduino
  • Quizy do kursu STM32L4
  • Quizy do pozostałych kursów

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Imię


Strona

  1. Przychodzę z pewnym problemem z którym borykam się już od jakiegoś czasu, związanym z mobilnym robotem. Ma to być robot wyposażony w wiele czujników, w tym: 4 czujniki odległości HC-SR04P, listwa z czujnikami odbiciowymi QTR-8A, IMU ICM-20948, 4 przyciski ("ala czujniki dotyku"), LIDAR, kamera, enkodery kwadraturowe. Do odbierania danych z czujników oraz do sterowania silnikami chcę wykorzystać Arduino Mega lub giga r1(niby jest szybyszy ale nie wykorzystuje się jego potencjału jak ię tworzy kod na arduino ide). Dane z Arduino będą przekazywane poprzez kabel usb do Raspberry Pi 4, na którym będzie ROS, oraz do którego podłączone będą LIDAR i kamera. Mam problem głównie z doborem silników do tego robota z powodu konieczności wyposażenia każdego silnika w enkoder. Wszystkie silniki, na jakie natrafiłem, były wyposażone w enkodery inkrementalne (co wymaga 2 pinów do obsługi jednego enkodera). Z tego, co sprawdziłem, aby obsłużyć enkodery, potrzebne są przerwania a arduino potrzebuję czasu aby wszystkie obsłużyć. Poniżej znajduje się kod, który napisałem, aby pomóc sobie przy doborze silników . Orientacyjna masa robota będzie wynosić około 6 kg(dla 4 kół), a koła, które chcę wykorzystać, mają średnicę 10 cm. Ilość kół wpłynie na moment potrzebny do silnika oraz ilość enkoderów. Ma być to robot autonomiczny a więc jeśli zastosuję 4 silniki, zamierzam użyć kół mecanum; jeśli 2, to zwykłe koła i jedno z przodu swobodne; jeśli 3, to koła omnikierunkowe. Dla 4 zwykłych kół nie znalazłem macierzy. #include <stdio.h> int main() { // Deklaracja zmiennych double V, M, N, X=1.5 /* odwrotnosc sprawnosci */, D, g=9.81, u=0.9 /* wspolczynik tarcia */, a=1 /* przyspieszenie liniowe */, t, O; // Wprowadzanie wartości zmiennych printf("Podaj wartość M: "); // masa scanf("%lf", &M); printf("Podaj wartość N: "); // Ilosc kol scanf("%lf", &N); printf("Podaj wartość D :"); // Srednica kola scanf("%lf", &D); printf("Podaj wartość V: "); // Predkosc liniowa scanf("%lf", &V); // Obliczenia zgodnie z podanymi wzorami t = (X * (((u * M * g) + (M * a)) * D) / (2*N)) * 10.19716; // Wymagany moment(z przelicznkiem z Nm na kgfcm) O = X*(2 * V / D) * 9.5493; // Predkosc obrotowa(z przelicznikiem z rad/s na rpm) // Wyświetlenie wyników printf("Wartość t wynosi: %lf\n", t); printf("Wartość O wynosi: %lf\n", O); return 0; } W kodzie nie uwzględniłem kąta równi pochyłej bo robot ma się poruszać po płaskiej powierzchni.Mam także wątpliwości co do współczynnika tarcia, - czy mam wziąć pod uwagę tarcie toczene, czy statyczne.Jeżeli macie także jakieś porady do innych rzeczy związanych z tym robotem będe wdzięczny za podpowiedź i pomoc.
  2. Dzień dobry, problem taki jak w tytule. Jeszcze do niedawna wszystko było w porządku i działało. Przez ostatni miesiąc arduino stało nieużywane, aż do dzisiaj, kiedy przyszedł mi zestaw kursu Arduino II z forbota. W zestawie jest zawarty zasilacz sieciowy - podłączyłem go do płytki, była wtedy też podłączona do komputera przez USB (nie jestem pewny czy była wtedy widoczna, nie sprawdzałem ani nic nie uploadowałem). Niestety w tym momencie oderwałem się i tak podłączoną płytkę zostawiłem na jakąś godzinę / dwie. Po powrocie była gorąca, a tak konkretniej to główny mikrokontroler - praktycznie się poparzyłem po dotknięciu go. Rozłączyłem wszystko i zostawiłem na kilka godzin. Teraz (już bez zasilacza sieciowego, tylko przez połączenie usb do komputera) próbowałem zuploadować jakiś banalny program, ale wyskakuje następujący błąd: No i faktycznie, w IDE arduino nie są widoczne żadne porty, nie wykrywa płytki. Oto co próbowałem robić: - Sprawdzałem czy płytka jest widoczna w menedżerze urządzeń - nie jest. - Podpinałem do innych portów USB w komputerze (wszystkie działają dla innych urządzeń) - brak rezultatu - Zwarcie resetu do masy na płytce i ponowne jej podłączenie - dalej nic - Reinstall Arduino IDE - bez skutku Czyżby płytka faktycznie się uszkodziła? Jeśli tak to z jakiej racji? Napięcie na zasilaczu to prawidłowe ok. 12V, nawet sprawdzone multimetrem. Żaden program nie był wtedy wgrany na płytkę. Jeszcze na końcu dodam, że po podłączeniu płytki do komputera świeci się dioda ON oraz obie diody: RX i TX. Po ponownym podłączeniu płytki do zasilacza, nagrzewa się do poziomu gdzie nie da się utrzymać na nim palca w około 30 sekund. Będę wdzięczny za wszelkie wskazówki i odpowiedzi. Pozdrawiam.
  3. Witam serdecznie ponownie, Udało mi się ukończyć poprzedni projekcik - SDK + alarm, więc przyszła kolej na kolejny. Celem projektu jest dobrze znana automatyczna pompa wody, która będzie mierzyć poziom wilgotności gleby. Jeśli chodzi o stronę programowalną to pestka, ale z kolei mam niepewność względem podłączenia. Na schemacie poniżej został stworzony układ w jaki połączyłem elementy, i chciałem zapytać czy jest to poprawne podłączenie, czy nie brakuje tutaj jakiegoś elementu. Na forum gdzieś znalazłem schemat podłączenia, ale była tam zainstalowana pompka bodajże 6V, która zasilało się baterią. Tutaj mam zasilacz 240/12V, 2,5A oraz pompkę 12V z poborem 300 mA więc jest w miarę podobnie. Pomiędzy zasilaczem a przekaźnikiem wstawiłem przełącznik i wpiąłem go do wejścia COM, a przewód zasilający(+) z pompki do NO. Problem mi przysporzyło zrozumienie działania przekaźnika, i jeżeli dobrze rozumiem działa to w ten sposób, że jeżeli obwód przechodzi przez wejście NO, to pompka uruchomi się dopiero wtedy gdy przez przekaźnik poleci napięcie z Arduino(sygnał sterujący), a NC jest to obwód który działa od razu w momencie otrzymania zasilania z sieci(nie wymaga sygnału sterującego). Czy ten wywód jest poprawny? Ponownie mam nadzieję, że temat w dobrym miejscu, Z góry dziękuje za odpowiedzi, pozdrawiam.
  4. Witam serdecznie, Jest to mój pierwszy post pewnie i błachy ale szukajką nie znalazłem. Czy do portów 0 oraz 1 na Arduino Uno. Mogę wpiąć wyjścia echo oraz Trig z HC SR04 ? , lub wpiąć to do wyjść analogowych A0-A5?. Buduje maly zamek do drzwi, po naciśnięciu przycisku obraca się serwo, zapala czerwona diodę oraz wyświetla napis zamknięte. I to działa. Jednocześnie gdy drzwi będą zamknięte, dalmierz zmierzy odległość od drzwi i jeżeli będzie ona mniejsza niż ustawione 2cm to również akcja z serwo i wyświetlaczem się wykona. Sęk w tym że brakuje mi dwóch wejść. Został mi wolny jeden port cyfrowy(8) oraz 0 i 1. Jeżeli temat w złym miejscu to z góry przepraszam.
  5. Mam problem z podłączeniem do arduino mega modułu HC-06, w moim układzie mam 2 silniki i jeszcze będę musiał dodać 6 serwomechanizmów co zajmie mi wszystkie piny PWM a mój moduł bluetooth z jakiegoś powodu działa tylko na pinach 2-13. Jak to naprawić? #include <SoftwareSerial.h> #define BT_TX 0 #define BT_RX 1 SoftwareSerial bt(BT_TX, BT_RX); char x; void setup() { dht.begin(); pinMode(2,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(7,OUTPUT); bt.begin(9600); } void loop() { digitalWrite(3,255); digitalWrite(6,255); if(bt.available()){ x = bt.read(); bt.println(x); } if(x == 'B'){ digitalWrite(4,HIGH); digitalWrite(5,HIGH); } else if(x == 'F'){ digitalWrite(2,HIGH); digitalWrite(7,HIGH); } else if(x == 'L'){ digitalWrite(2,HIGH); digitalWrite(5,HIGH); } else if(x == 'R'){ digitalWrite(7,HIGH); digitalWrite(4,HIGH); } else if(x == 'S'){ digitalWrite(2,LOW); digitalWrite(4,LOW); digitalWrite(5,LOW); digitalWrite(7,LOW); } delay(100); }
  6. Cześć, przedstawiam projekt dla fanów drinków dla których zachowanie proporcji jest niezmiernie istotne. Postanowiłem, że robot będzie nalewał trzy różne substancje (jak na domowego barmana w zupełności wystarczy). Wykorzystałem w tym celu pompki membranowe, które są stosunkowo tanie, jednak warto użyć zaworów zwrotnych przy każdym z węży ponieważ "na postoju" nie są szczelne i ciecze powoli kapią z dysz robota. Przy innym projekcie zdarzyło mi się, że pompka była nieszczelna, więc w tym zamontowałem je w miejscu w którym ewentualny wyciek nie narobi szkód. We wcześniejszych konstrukcjach ustawiałem lanie zależne od zadanego czasu, jednak po testach (wspierając się wagą kuchenną) stwierdziłem, że odmierzane wartości nie są powtarzalne. Wtedy postanowiłem dodać wbudowaną wagę. Użyłem belki tensometrycznej do 1kg oraz wzmacniacza HX711. Robot zasilany jest zasilaczem wtykowym 12V a jego serce to Arduino Mega - ze względu na zapotrzebowanie na dużą liczbę wejść/wyjść. Do sterowania pompek użyłem gotowego Shielda - sterownika L293D – może sterować czterema silnikami DC i zajmuje mało miejsca w obudowie, a chciałem żeby konstrukcja była zwarta i jak najmniejsza. Początkowo użyłem wyświetlacza 2x16, jednak wyświetlane dane nie były tak przejrzyste, jakbym tego chciał więc zamontowałem wyświetlacz 4x16. Teraz każdy składnik ma swoją nieskróconą nazwę i ma swoją osobną linijkę. Wartości danych substancji ustawia się przy pomocy trzech potencjometrów. Wyskalowałem wartość każdego od 0 do 150g. W przypadku przekroczenia sumy trzech substancji powyżej 250g, zamontowane diody RGB świecą na czerwono (jest to tylko sygnał ostrzegawczy, nie blokuje nalewania). Diody te również „ubarwiają” proces tworzenia drinka (efekt widoczny na załączonym filmie). Po ustawieniu ulubionych proporcji wciskamy START i nalewanie odbywa się automatycznie, przed nalaniem każdego składnika waga samoczynnie się taruje. Można również korzystać z manualnego nalewania oraz tarowania, gdy stworzony drink nie spełnia wszystkich wymagań. Obudowę wydrukowałem na drukarce 3D. Składa się z wielu elementów, żeby był łatwiejszy dostęp do podzespołów oraz żeby pojedynczy wydruk krócej się drukował. Umieściłem z jednej strony okno rewizyjne żeby móc się w razie potrzeby podłączyć do Arduino. Części których użyłem do budowy robota: Arduino ATmega2560 - 1szt. wyświetlacz LCD 4x20 - Niebieski - ze sterownikiem kompatybilnym z HD44780 - QC2004A konwerter I2C do wyświetlacza LCD HD44780 wzmacniacz do belki tensometrycznej HX711 - 1szt. belka tensometryczna 1kg - 1szt pompa do cieczy 12V 110l/h - 7mm – 3szt moduł sterownika silnika L293 UNO MEGA shield - 1szt moduł diody RGB 5V - 2szt, wtyk DC 2,1/5,5mm z zaciskami skręcanymi – 1szt. gniazdo DC 2,1/5,5 do obudowy plastikowe -1szt. zasilacz wtyczkowy UMEC impulsowy 12V 30W 2,5A - 1szt. przełącznik kołyskowy 15x10mm – 1 szt przewody połączeniowe przycisk podświetlany - 1szt. przycisk okrągły monostabilny chwilowy czerwony - 4szt. potencjometr liniowy 1K – 3szt. .zawór zwrotny - 3szt. wężyk silikonowy 1,5m Oto kod, z którym się najdłużej męczyłem, ale działa 😉 #include <HX711.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <AFMotor.h> #define I2C_ADDR 0x3F #define start 52 #define manpom1 50 #define manpom2 46 #define manpom3 44 #define tara 48 #define redl 24 #define bluel 22 #define greenl 26 #define redr 30 #define bluer 28 #define greenr 32 HX711 waga; LiquidCrystal_I2C lcd(I2C_ADDR, 2, 1, 0, 4, 5, 6, 7); int led = 13; float ciezar; int ml1 = 0; int ml2 = 0; int ml3 = 0; int czasMigania = 250; int predkoscNalewania = 200; char odczyt[8]; AF_DCMotor pompa1 (3); AF_DCMotor pompa2 (2); AF_DCMotor pompa3 (1); void setup() { Serial.begin(9600); pinMode(start, INPUT_PULLUP); pinMode(manpom1, INPUT_PULLUP); pinMode(manpom2, INPUT_PULLUP); pinMode(manpom3, INPUT_PULLUP); pinMode(tara, INPUT_PULLUP); pinMode(redl, OUTPUT); pinMode(bluel, OUTPUT); pinMode(greenl, OUTPUT); pinMode(redr, OUTPUT); pinMode(bluer, OUTPUT); pinMode(greenr, OUTPUT); lcd.begin(20, 4); lcd.setBacklightPin(3, POSITIVE); digitalWrite(led, HIGH); lcd.setBacklight(HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Witaj!"); lcd.setCursor(0, 1); lcd.print("Chlapnij sobie!"); lcd.setCursor(13, 3); lcd.print("Kasztan"); delay(1000); pinMode(led, OUTPUT); waga.begin(A1, A2); waga.set_scale(419341.0 / 200.0); waga.tare(5); pompa1.setSpeed(predkoscNalewania); pompa2.setSpeed(predkoscNalewania); pompa3.setSpeed(predkoscNalewania); } void loop() { pomiar(); ekran(); if ((ml1 + ml2 + ml3) > 250) { czerwona(); delay(500); ciemno (); } else { ciemno(); } if (digitalRead(start) == LOW) { waga.tare(); ekran(); Serial.println("zeruje"); if (ml1 >= 0) { waga.tare(10); pomiar(); ekran(); Serial.println("nalewam promile"); while (ciezar <= ml1) { pomiar(); ekran(); pompa1.run(FORWARD); led1(); } pompa1.run(RELEASE); Serial.println("promile przerwa"); delay(100); if (ml2 >= 0) { waga.tare(10); pomiar(); ekran(); Serial.println("nalewam rozcienczacz"); while (ciezar <= ml2) { pomiar(); ekran(); pompa2.run(FORWARD); led2(); } pompa2.run(RELEASE); Serial.println("rozcienczacz przerwa"); delay(100); if (ml3 >= 0) { waga.tare(10); pomiar(); ekran(); Serial.println("nalewam kwas"); while (ciezar <= ml3) { pomiar(); ekran(); pompa3.run(FORWARD); led3(); } pompa3.run(RELEASE); Serial.println("kwaas przerwa"); delay(100); } } } waga.tare(); pomiar(); kolorowo(); ciemno(); } if (digitalRead(manpom1) == LOW) { pompa1.run(FORWARD); led1(); } else { pompa1.run(RELEASE); } if (digitalRead(manpom2) == LOW) { pompa2.run(FORWARD); led2(); } else { pompa2.run(RELEASE); } if (digitalRead(manpom3) == LOW) { pompa3.run(FORWARD); led3(); } else { pompa3.run(RELEASE); } if (digitalRead(tara) == LOW) { waga.tare(10); } } void pomiar() { ml1 = analogRead(A5); ml1 = map(ml1, 1020, 0, 0, 150); ml2 = analogRead(A4); ml2 = map(ml2, 1020, 0, 0, 150); ml3 = analogRead(A3); ml3 = map(ml3, 1020, 0, 0, 150); ciezar = waga.get_units(); dtostrf(ciezar, 5, 0, odczyt); } void ekran() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("1.Alkohol:"); lcd.print(ml1); lcd.setCursor(0, 1); lcd.print("2.Dodatek:"); lcd.print(ml2); lcd.setCursor(0, 2); lcd.print("3.Kwas:"); lcd.print(ml3); lcd.setCursor(0, 3); lcd.print("Waga:"); lcd.print(odczyt); lcd.print("g"); Serial.println(ml1); Serial.println(ciezar); } void ciemno() { digitalWrite(redl, LOW); digitalWrite(greenl, LOW); digitalWrite(bluel, LOW); digitalWrite(redr, LOW); digitalWrite(greenr, LOW); digitalWrite(bluer, LOW); } void czerwona () { digitalWrite(redl, HIGH); digitalWrite(greenl, LOW); digitalWrite(bluel, LOW); digitalWrite(redr, HIGH); digitalWrite(greenr, LOW); digitalWrite(bluer, LOW); } void zielona () { digitalWrite(redl, LOW); digitalWrite(greenl, HIGH); digitalWrite(bluel, LOW); digitalWrite(redr, LOW); digitalWrite(greenr, HIGH); digitalWrite(bluer, LOW); } void niebieska () { digitalWrite(redl, LOW); digitalWrite(greenl, LOW); digitalWrite(bluel, HIGH); digitalWrite(redr, LOW); digitalWrite(greenr, LOW); digitalWrite(bluer, HIGH); } void kolorowo () { digitalWrite(redl, HIGH); delay(czasMigania); digitalWrite(greenl, HIGH); delay(czasMigania); digitalWrite(bluel, HIGH); delay(czasMigania); digitalWrite(redr, HIGH); delay(czasMigania); digitalWrite(greenr, HIGH); delay(czasMigania); digitalWrite(bluer, HIGH); delay(czasMigania); delay(500); } void led1 () { digitalWrite(redl, HIGH); digitalWrite(greenl, HIGH); digitalWrite(bluel, LOW); digitalWrite(redr, HIGH); digitalWrite(greenr, HIGH); digitalWrite(bluer, LOW); } void led2 () { digitalWrite(redl, LOW); digitalWrite(greenl, HIGH); digitalWrite(bluel, HIGH); digitalWrite(redr, LOW); digitalWrite(greenr, HIGH); digitalWrite(bluer, HIGH); } void led3 () { digitalWrite(redl, HIGH); digitalWrite(greenl, LOW); digitalWrite(bluel, HIGH); digitalWrite(redr, HIGH); digitalWrite(greenr, LOW); digitalWrite(bluer, HIGH); } Link do filmu:
  7. Cześć, na wstępie zaznaczę, że dopiero zaczynam i jestem całkowicie zielony jeśli chodzi o elektronikę. Szukając pomysłu na prezent dla drugiej połówki znalazłem coś takiego [LINK] i postanowiłem, że zrobię swoją własną wersje tylko przy wykorzystaniu Arduino Nano i programowalnych ledów. Chciałbym żeby całość była zasilana bateriami - i tutaj jest główny powód pisania tego postu, bo nie do końca wiem jak to wszystko połączyć. Zaznaczę, że do zasilenia będzie ok. 7-8 ledów. Lepiej użyć baterii 1.5V i przetwornicy step-up, czy baterii 9V i podpiąć się po prostu do pinu VIN? Jeśli istnieją inne opcje to proszę dajcie znać. Zależy mi żeby układ był jak najbardziej oszczędny i optymalny żeby nie trzeba było często wymieniać baterii 😄 Pozdrawiam serdecznie.
  8. Witam, założyłem wcześniej wątek, o tym. Dziękuję @farmaceuta @ethanak @SOYER i innym za tłumaczenie, o co chodziło z else/if'ami, ale nadal nie wiem, kiedy ich użyć. Czy ktoś dałby mi jakieś przykłady, czy coś innego. Nadal nie wiem, w jakich przypadkach ich użyć. Bardzo proszę o wytłumaczenie.
  9. Dobra a więc tak robie swój pierwszy projekt czyli mój gameboy i żeby jakoś zasilić arduino kupiłem baterie lipo 1000mah 3,7v i moduł solar charger shield od seeed naładowałem baterie i podłączyłem moduł do arduino wgrałem kod na gameboya i włączyłem zasilanie a dioda na arduino sie zaswieciła na zielono lecz arduino nie wykonuje kodu czy ktoś może mi coś poradzić?
  10. Witam, czy ktoś mógłby wytłumaczyć mi, o co chodzi z else if'ami? Zastosowałem je w moim robocie, ale nie do końca wiem, czym one się różnią od zwykłych, osobnych if'ów. Chciałbym również się dowiedzieć, kiedy je wykorzystywać. Z góry dzięki 😄
  11. Cześć, zbudowałem robota kroczącego składającego się z 12 serw. 4x serwo typu medium (Power HD HD-1160A z plastikowymi przekładniami) i 8x serwo typu micro (MG-90S z metalowymi przekładniami), serwa zasilane są battery Packiem (4x bateria AA 1,5V) 6V oraz Arduino mega, które zasilam 5V. Po wykonaniu dwóch kroków robot się zapada i serwa medium się wyłączają (serwa umieszczone na ramie robota) a serwa micro działają i wykonują dalsze ruchy nogi. Podejrzewam, że problem leży przy zasilaniu robota, battery pack dodaje masy do robota i może być niezbyt optymalnym źródłem prądu. Po podłączeniu woltomierza, miernik pokazywał ~5V zamiast wymaganego 6V. Drugim problemem mogą być serwera medium, jakich używam, przy 6V ruch obrotowy serwa wynosi 2,7 kg*cm a serwa micro nogi mają 2,2 kg*cm również przy 6V. Po ściągnięciu battery packa, robot działał dobrze do pewnego momentu, gdy się zawalił, serwa przestały być „naprężone” co wynikało by z braku odpowiedniego zasilania. Czy ktoś z Was wie, gdzie może leżeć przyczyna problemu? Z góry dziękuje. Film z działania robota oraz zdjęcie nogi w załącznkiu poniżej:
  12. Od dawna interesowały mnie pomiary warunków meteorologicznych w mojej miejscowości, pierwsza stacja meteorologiczna, którą zbudowałem około roku 2010, wykonana była na mikrokontrolerze Atmega32. Do komunikacji z światem wykorzystywała moduł LAN Wiznet 7010a. Stacja ta była oprogramowana w języku BASCOM. Projekt który chcę zaprezentować dzisiaj działa już od roku 2018 i został oprogramowany w środowisku Arduino. Stacja została podzielona na 2 moduły, pierwszy pomiarowy oparty jest na klonie Arduino Nano oraz drugi odbiorczy którego sercem jest ESP8266 NodeMCU v3, służy on również do wyświetlania aktualnych pomiarów na wyświetlaczu LED dot matrix o wymiarach 8x56 punktów. Na pracach stolarskich się nie będziemy skupiać napiszę tylko że klatka meteorologiczna została wykonana z drewna sosnowego i umieszczona na wysokości 2 m. Moduł Pomiarowy Czujniki jakie zastosowałem to dwie sztuki DS18B20 pierwszy zajmuje się pomiarem temperatury przy gruncie na wysokości 5cm, drugi pełni rolę zapasowego czujnika temperatury na wypadek uszkodzenia się głównego czujnika BME280. Do pomiaru prędkości wiatru wykorzystuję wiatromierz firmy Maplin na jeden obrót wiatromierza przypadają 2 impulsy z kontaktronu który jest w nim zamontowany, producent dostarcza również odpowiedni wzór według którego można obliczyć rpm oraz prędkość wiatru w km/h. Dane mierzone przez wiatromierz możemy podzielić na dwie wartości, pierwsza to chwilowa prędkość, druga prędkość w porywach, aby uśrednić wartości mierzone program zlicza impulsy z 5s a następnie dokonuje odpowiednich obliczeń. Zebrane dane przesyłane są do drugiego urządzenia poprzez moduły radiowe które działają na częstotliwości 433,92 MHz. W tym celu zastosowana została biblioteka RCSwitch. Każda mierzona wartość jest wysyłana jako osobna transmisja. aby rozróżnić pomiary z konkretnych czujników mierzona wartość mnożona jest przez 100 a następnie dodawana jest liczba 100 000 dla pierwszego czujnika, 200 000 dla drugiego itd. Przykład kodu który realizuje tę funkcję poniżej: // temperatura sensor BME codetosend = temp * 100 + (1 * 100000); mySwitch.send(codetosend, 24); // wilgotnosc sensor BME codetosend = hum * 100 + (2 * 100000); mySwitch.send(codetosend, 24); Moduł Wewnętrzny Obudowa, która idealnie nadawała się do implementacji wewnętrznego modułu pochodzi z tunera IPTV Motorola VIP1910-9. Przedni panel został wykonany z ciemnego półprzepuszczalnego plastiku który idealnie nadaje się do umieszczenia w nim wyświetlacza. Sercem urządzenia jest układ ESP8266. "Moduł wewnętrzny" został również wyposażony w czujnik temperatury oraz wilgotności DHT22, dodatkowo w celu prezentacji zmierzonych wartości dołączone zostało 7 szt. modułów wyświetlacza LED dot matrix z układem MAX7219. Do obsługi tej matrycy zastosowałem bibliotekę Max72xxPanel.h która współpracuje z biblioteką Adafruit_GFX.h w ten sposób nie byłem zmuszony implementować do rozwiązania własnych czcionek. Matryca ta oprócz modułowej konstrukcji umożliwia również sterowaniem jasnością podświetlania, w tym celu aby uprzyjemnić użytkowanie w porach nocnych odbiornik został wyposażony w fotorezystor dzięki któremu potrafi określić natężenie oświetlenia otoczenia i odpowiednie ustawienie podświetlenia. Na wyświetlaczu w pierwszej kolejności wyświetlam aktualną godzinę oraz temperaturę wewnątrz pomieszczenia oraz wilgotność, po około jednej minucie wyświetlane są informacje odczytane z stacji meteo czyli temperatura wilgotność i ciśnienie, postanowiłem nie wyświetlać tutaj informacji dotyczących prędkości wiatru oraz temperatury przy gruncie. Decyzję tą podjąłem na podstawie użytkowania innego podobnego rozwiązania, akurat jak chcemy odczytać godzinę to wyświetlane są inne informacje. Dodatkowo w godzinach nocnych, które zostały ustawione w sztywnych ramach czasowych między 21:00 a 7:00 informacje odczytane z stacji meteo zostały okrojone tylko do temperatury. W projekcie zostały zastosowane 2 rodzaje animacji pierwsza z nich, przesuwa tekst z prawej strony wyświetlacza na lewą, z możliwością zatrzymania w interesujących momentach. Drugi rodzaj to pionowa animacja. Mikrokontroler również poprzez protokół NTP i bibliotekę time.h pobiera aktualną godzinę i datę. Za odbiór danych z pierwszego układu odpowiedzialny jest moduł radiowy którego obsługą tak jak w poprzednim module zajmuje się biblioteka RCswitch. Poniżej fragment programu który demonstruje w jaki sposób odbierane i dekodowane są dane: rc = mySwitch.getReceivedValue(); // czujnik temperatury powietrza BME280 if (abs(rc)>=50000&& abs(rc)<150000) { rc=(rc-100000)/100; if (rc > -50 and rc < 60) { temp1 = rc; Serial.print("Czujnik BME280 - temperatura: \t"); Serial.println(rc); matrix.drawPixel(55,0,1); matrix.write(); } } // czujnik wilgotności BME280 if (abs(rc)>=150000 && abs(rc)<250000) { rc=(rc-200000)/100; if (rc > 5 and rc <= 100) { hum = rc; Serial.print("Czujnik BME280 - wilgotnowsc: \t"); Serial.println(rc); matrix.drawPixel(55,1,1); matrix.write(); } } Dzięki zastosowaniu zewnętrznej anteny oraz odbiornika opartego na superheterodynie, zasięg w otwartym terenie to około 250 m. Po odebraniu danych z pierwszego układu poprzez moduł radiowy następuje przekazanie ich do serwera z systemem Domoticz. Domoticz to bardzo lekki system automatyki domowej, który pozwala monitorować i konfigurować różne urządzenia, przełączniki, czujniki takie jak temperatura, opady deszczu, wiatr, promieniowanie ultrafioletowe (UV), zużycie energii elektrycznej, zużycie gazu, zużycie wody i wiele więcej. Wykresy dostępne są również na stronie www http://meteo.palowice.net Poniżej film z działania odbiornika, smużenie animacji które występuje na filmiku ludzie oko nie rejestruje. Gdyby kogoś interesował kod to również zamieszczam: meteo.zip
  13. Zapraszam do "blogowania" nowych / mniej znanych mikrokontrolerów, które można programować z poziomu Arduino / PlatformIO. W80x - chińska podróbka... chińskiego ESP32. Również oparta na rdzeniu XT804. Wersja W801 ma WiFi i Bluetooth, W806 jest "bezradiowa". Chyba jedyną przewagą nad ESP32 jest nieco niższa cena - poniżej 14zł z przesyłką z Aliexpress. https://github.com/board707/w80x_arduino Boards Manager URL: https://raw.githubusercontent.com/board707/w80x_arduino/hal-v0.6.0/package_w80x_test_index.json LGT8F328P - bezczelna, chińska aluzja do Atmega328P. Parametry podobne, chyba nawet pin compatible, z niewielkimi poprawkami względem pierwowzoru. Wyróżnia go m.in. selekcja zegara 1, 2, 4, 8, 12, 16 oraz 32 Mhz z poziomu Arduino (co pozwala dopasować wydajność i pobór prądu do zastosowań), 12-bitowe ADC (zamiast 10), wbudowany DAC. Toolchain wydaje się być w pełni użyteczny, zwłaszcza przy prostych projektach (używam od paru lat w stacji lutowniczej DIY). https://github.com/dbuezas/lgt8fx Boards Manager URL: https://raw.githubusercontent.com/dbuezas/lgt8fx/master/package_lgt8fx_index.json CH32 RISC-V MCUs Get Official Arduino Support CH32V003 - Test i recenzja https://github.com/openwch/arduino_core_ch32 Boards Manager URL: https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json https://github.com/AlexanderMandera/arduino-wch32v003 Boards Manager URL: https://alexandermandera.github.io/arduino-wch32v003/package_ch32v003_index.json CH582F - toolchain chyba nie jest zbyt aktywnie rozwijany. https://github.com/ElectronicCats/arduino-wch58x Ze względu na gorsze wsparcie i w niektórych przypadkach toolchain na bardzo wczesnym etapie, na początku lepiej wybrać sprawdzone ESP8266, ESP32, RP2040, STM32. Z "dziwactw", najciekawsze wydają mi się moduły w stylu Arduino Pro Mini - LGT8F328P SSOP20, WeAct CH32V003F4U6. Zapewniają nieco więcej możliwości od Pro Mini (choć jest jeszcze zmniejszony klon Raspberry Pi Pico - RP2040-Zero).
  14. chcąc programować mikrokontrolery avr, ale niestety mój programator nie jest zbyt dobry dokładnie usbasp. Słyszałem o możliwości programowania tych mikrokontrolerów za pomocą arduino ale nie wiem jak to zrobić
  15. W tym projekcie chciałbym opisać krok po kroku proces podłączenia licznika samochodowego od Forda Galaxy do naszego Arduino. Potrzebne elementy: Zasilacz 12V Arduino Przewody męsko-żeńskie Licznik samochodowy Zestaw wskaźników od Forda Galaxy posiada 2 wtyczki - czerwoną oraz czarną. Nas w tym projekcie interesuje tylko czerwona wtyczka gdyż znajdują się w niej piny zasilające oraz dostarczające dane do silników krokowych w liczniku. Najpierw zajmijmy się zasilaniem. Do pinu 3 oraz do pinu 4 na liczniku wpinamy 2 przewody i podłączamy je do minusa na naszym zasilaczu a kolejne 2 przewody wpięte w pin 14 oraz w pin 15 podłączamy do +. Jako zasilacz może nam posłużyć zwykły zasilacz komputerowy kub jakikolwiek o napięciu 12V. Dalej zajmijmy się podłączeniem silniczków od wskazówek. obrotomierz - 10 pin prędkościomierz - 27 pin wskaźnik poziomu paliwa - 21 pin wskaźnik temperatury cieczy - 23 pin (pin 1 jest w lewym dolnym rogu wtyczki) Następnie przewody te wpinamy w wejścia cyfrowe do Arduino. W moim przypadku obrotomierz wpiąłem w wejście oznaczone 2, prędkościomierz w wejście nr 3, wskaźnik poziomu paliwa 4 a temp. cieczy w wejście 5. Jeżeli po podpięciu zasilania licznik zadziała (wskazówki ustawią się w położeniu 0 oraz włączy się podświetlenie) to możemy przejść do konfiguracji. Pobieramy oprogramowanie SimHub i instalujemy je. Po uruchomieniu programu przechodzimy do zakładki Arduino a następnie klikamy na zakładkę "My hardware". Wybieramy "Single Arduino" i klikamy "Open arduino setup tool". Następnie definiujemy w jakie wejścia wpięliśmy nasze wskaźniki. Wybieramy z jakiego arduino korzystamy (w moim przypadku jest to UNO) oraz wybieramy port komunikacyjny. Gdy wszystko mamy już zrobione klikamy Upload to arduino i czekamy aż program zostanie wgrany na Arduino. Jeżeli program wgrał się poprawnie przechodzimy do zakładki "Gauges" i kalibrujemy nasz licznik. Wartości liczbowe są indywidualne dla każdego licznika ale to co musimy ustawić do każdego licznika to MAX Tachometer RPM na 7 (jeżeli zakres na tarczy obrotomierza jest inny to podajemy maksymalną liczbę, jeśli jest to 5 to podajemy 5) oraz tachometer cylinders na 6. Warto zaznaczyć opcję "Always use tachometer full range" jednak jeśli sprawia ona problemy możemy ją wyłączyć. Resztę wartości musimy ustawić tak, żeby wskazówka poprawnie wskazywała położenie min i max. Niestety nie ma uniwersalnych wartości i prędkościomierz u mnie wskazuje poprawnie 240 km/h przy wartości 222 (speedo gauge maximum output) jednak w innym liczniku może być to wartość ciut większa lub mniejsza. Na samym końcu wybieramy grę w którą chcemy zagrać z zakładki "Games". Następnie uruchamiamy naszą grę i cieszymy się rozgrywką z naszym licznikiem. Ktoś mi może powiedzieć "Przecież można napisać kod", zgodzę się z tym tylko ja gram od ETS 2 przez Dirt 4 na Forzie kończąc. O wiele łatwiej jest jednym kliknięciem zmienić grę w simhubie niż pisać osobny kod eksportujący dane z telemetrii do Arduino. Jeżeli ktoś potrzebuje tylko licznika do jednej gry to ma to sens jednak w moim przypadku mija się to z celem. Koszt takiego licznika może zamknąć się w okolicach 50 zł. Możemy wykorzystać klona arduino (klon nano możemy kupić za mniej niż 15zł), a licznik możemy znaleźć na portalach aukcyjnych za ok 20zł. Jest to niedrogi i fajny bajer a na dodatek jest bardzo praktyczny. Poniżej znajdują się zdjęcia i gif pokazujący pracę urządzenia.
  16. Cześć. 🙂 Przedstawiam wam Small Autonomous Amateur Rover "Romek" - czyli owoc mojej, z założenia kosmetycznej, metamorfozy robota, którego można poznać w jednym z forbotowych kursów. (A ponieważ robiłem tylko w wolnych chwilach, których wielu nie mam, to niczym ciąża - zacząłem z końcem listopada, mamy narodziny z końcem sierpnia). Krótki zarys historyczny: Kilka lat temu miałem fazę, zakupiłem w Botlandzie kilka zestawów do kursów oraz tu i ówdzie trochę rzeczy do szuflady "przydasiów". Życie jednak weryfikuje i przez kilka lat zbierało kurz, aż w zeszłym roku przeszedłem w końcu kurs budowy robotów i kurs Arduino poziom I. Jednak chciałem przede wszystkim sterować robotem przez BT, do tego chciałem pozbyć się w jakiś sposób wężykowania. Odnalazłem info, że komunikacja z BT to w zasadzie komunikacja przez port szeregowy - zapiąłem HC-05, zainstalowałem aplikację Bluetooth RC Car i napisałem switch case pod dane wysyłane z tej apki. Pierwsza rozbudowa "forbociaka" - moduł HC-05 i konwerter poziomów logicznych. Robot jeździł sterowany przez BT i tyle. Podjąłem decyzję, że dokonam modyfikacji zarówno w kodzie, jak i wyglądzie - z tym ostatnim poszedł też warunek, tylko rzeczy z szuflady, żadnych nowych inwestycji - własny czelendż ruszył. Posiadałem podwozie typu T100, które miało silniki z enkoderami - pomyślałem, że super, bo te silniczki z kursu to mogłyby mieć problem z ruszeniem cięższej konstrukcji, ponadto różny typ osi sprawił, że nawet nie próbowałem z nimi rzeźbić. Początkowa radość minęła wraz z przeczytaniem specyfikacji - maksymalny prąd pracy dołączonych silników to 4,5A, zdecydowanie za dużo na shield od Forbota. Przekopywałem szufladę dalej, znalazłem w niej silniczki N20, ale to maluszki, no i oś za mała. Znalazłem także silniki DFRobot o odpowiedniej osi i punktach montażowych. Przeczytałem notę - 7,5V, prąd pracy 50mA, maks. prąd 600 mA, przekładnia 99:1 - zostały wybrane. Nie chciałem mieć elektroniki na zewnątrz, więc potrzeba było też obudowy. Na wstępie wybrałem Kradex Z125 na body i Kradex Z130 na czujnik odległości. Jednak wraz z rozbudową, wybrana obudowa okazała się za ciasna - ledwo się zamykała, a nie założyłem jeszcze wszystkiego, co chciałem. Dodatkowo chciałem odzyskać pewne piny Arduino, które zajmował shield, a których nie potrzebowałem (przycisk i odbiornik IR). Podjąłem decyzję o zmianie obudowy - miałem jeszcze Kradex Z112, która była szersza i nieco wyższa. Poprzednia obudowa wchodziła pomiędzy gąsienice, przy tej musiałem zastosować dystanse, żeby zamocować budę do podwozia i nie kolidować z gąsienicami. Dodałem płaski koszyk na 6 baterii AA, krańcówki dla jazdy autonomicznej, połączone po dwie równolegle - żeby pokryć jak najwięcej czoła i jednocześnie nie odchylać blaszek pod dużym kątem i nie dodawać wąsów z trytytek - i wyłącznik kołyskowy, żeby załączać zasilanie z zewnątrz. Kanapkę Arduino+shield rozdzieliłem i połączyłem je przewodami, odzyskując wspomniane wcześniej piny cyfrowe 2 i 3 oraz uzyskując dostęp do pinu 3,3 V. Obudowę przed dalszymi pracami pomalowałem. Żeby robot nie był tylko sterowanym autkiem, dodałem oczywiście czujnik odległości HC04-SR, czujnik temperatury i wilgotności DHT22 oraz dzielnik napięcia - zbudowany z rezystora 510k i dwóch 68k - dla pomiaru napięcia baterii. Profesjonalny dzielnik amatorski. 😉 Na koniec dodałem LED-y w oprawkach. 4 białe jako światła czołowe, każdy z rezystorem 1k. 2 zielone i 2 czerwone jako światła pozycyjne/nawigacyjne - również z rezystorami 1k. 2 żółte drogowe (już nie żółte, jeszcze nie pomarańczowe) jako światła ostrzegawcze, oczywiście z rezystorami 1k. 1 niebieski jako światło sygnalizujące jazdę autonomiczną, z rezystorem 330 Ohm. Niebieski LED jest zasilany i załączany bezpośrednio z Arduino. Pozostałe LED-y zasilane są z baterii i załączane przez tranzystory NPN BC548. Ostatecznie wyszło trochę makaronu z przewodów, ale nie jest ciasno, obudowa zamyka się dobrze, a ja mam w razie W spis przewodów, a te z górnej części, które są wpięte w Arduino są także opisane na wtykach. :) Ponieważ żółte ledy miałem tylko typu clear i ich światło było widoczne tylko na wprost soczewki, dodałem dyfuzory zrobione ze... słomki. 😄 Romek po montażu waży ok. 1290 g i prezentuje się tak: Oprogramowanie: Założyłem, że chcę się pozbyć delay(), żeby nie kolidować z DHT oraz żeby robot reagował natychmiast na polecenia. Czasami musiałem się naklikać zanim robot zareagował. Czujnik odległości był jedną z prostszych rzeczy. Zastosowałem bibliotekę New Ping, dla której utworzyłem obiekt: NewPing sonar(trigPin, echoPin, MAX_DISTANCE); Sama funkcja wygląda tak: int sonarDystans() { int dystans = sonar.ping_cm(); // Wykonanie pomiaru i zapisanie wyniku w zmiennej distance w centymetrach return dystans; } A jej wykorzystanie na przykład tak: if (sonarDystans() <= doPrzeszkody) { //Jeżeli w zadanej odległości jest przeszkoda obecnyStan = ZATRZYMAJ; //Przejdź do zatrzymania czasStanu = millis(); //Ustaw czas dla timera serwo.attach(SERWO_PIN); //Podłącz serwo } Najwięcej problemów miałem z przepisaniem logiki jazdy autonomicznej. Poziom mojej wiedzy to kurs robota, kurs Arduino I i na coś tam liźnięte o DHT i millisach. Tutaj nawet zatrudniłem forumowiczów do pomocy: Ostatecznie oryginalną logikę wymieniłem na maszynę stanów, gdzie w danym stanie wywołuję funkcję, a dopiero w funkcji mam opisane zachowanie robota. switch (obecnyStan) { case PROSTO: prosto(); break; case ZATRZYMAJ: zatrzymaj(); break; void zatrzymaj() { zatrzymajSilniki(); if (millis() - czasStanu >= 500UL) { //Odczekaj zadany czas obecnyStan = PATRZ_PRAWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } } W przypadku krańcówek musiałem dodać flagę dla kolizji, gdyż bez tego po wjechaniu w przeszkodę robot się zatrzymywał. Zapewne zanim zdążył przejść dalej program ponownie docierał do miejsca, gdzie natrafiał co zrobić po załączeniu krańcówki. Dodanie flagi sprawiło, że problem zniknął. boolean kolizjaPrawo = false; if (digitalRead(prawySensor) == LOW && kolizjaPrawo==0) { //Jeżeli przeszkoda po prawej kolizjaPrawo = 1; obecnyStan = COFAJ_PRAWY; czasStanu = millis(); } void cofajPrawy() { lewySilnik(-70); prawySilnik(-70); if (millis() - czasStanu >= 800UL) { obecnyStan = ZATRZYMAJ2; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); kolizjaPrawo = 0; } } Samo wejście w jazdę autonomiczną również realizowane jest zmianą flagi. W switch case dle odczytu z seriala/BT poczyniłem toggleswitch. case 'A': jazdaAutonomiczna = !jazdaAutonomiczna; if (!jazdaAutonomiczna) { zatrzymajSilniki(); ekspander.digitalWrite(LEDjazda, 0); serwo.detach(); } break; Nie ukrywam, że obsługę DHT podejrzałem w drugiej części kursu do Arduino, zanim tam dotrę, ale jak już wiemy, unikam delay(). Na podstawie obsługi czujnika z kursu i tego co wiem o millisach, napisałem funkcję po swojemu. Dodałem też korektę odczytów, gdyż względem czujnika referencyjnego temperatura była zawyżana o wilgotność zaniżana. Najpierw próbowałem korekty procentowej, ale ostatecznie wprowadziłem sztywną korektę. Względem czujnika referencyjnego odczyty nie odbiegają o więcej niż 0,5 stopnia i 0,5%. W tym miejscu dodałem także odczyt z ADC, gdzie doprowadziłem wyjście z dzielnika napięcia dla baterii. Dla napięcia baterii 9,66 V napięcie doprowadzone z dzielnika wynosiło ok. 0,95 V. Po wstępnym obliczeniu mnożnika, ostateczną wartość dobrałem empirycznie. Rozbieżność nie przekracza 0,1 V, średnio jest to 0,06 V. W funkcji tej następuje także wysyłanie danych na serial. void humitemp () { //Funkcja czujnika DHT22 i pomiar napięcia float wilgotnosc = dht.getHumidity(); //Pobierz info o wilgotności do zmiennej float temperatura = dht.getTemperature(); //Pobierz info o temperaturze do zmiennej float wilgKorekta = wilgotnosc + 1.11; //Korekta dla odczytu wilgotności float tempKorekta = temperatura - 2.35; //Korekta odczytu temperatury int adc_val = analogRead(bateria); //Odczytaj wartość ADC float Ubat = adc_val * 0.0485340314; //Wylicz wartość napięcia czasDHT = millis(); //Pobierz aktualny czas Arduino roznicaDHT = czasDHT - odmierzDHT; if (roznicaDHT >= 2000UL) { //Jeżeli różnica wyniesie 2000 ms lub więcej odmierzDHT = czasDHT; //Zapisz aktualny czas arduino do zmiennej if (dht.getStatusString() == "OK") { //Jeżeli czujnik zwróci wartość ok, wykonaj poniższe Serial.print(tempKorekta); Serial.print(" °C"); Serial.print("|"); Serial.print(wilgKorekta); Serial.print(" %"); Serial.print("|"); Serial.print(Ubat); Serial.println(" V"); } } } Wspomniałem wcześniej, że odzyskałem niektóre piny z Arduino. Zależało mi zwłaszcza na pinie PWM dla świateł pozycyjnych. W prototypie używałem pinu ekspandera w trybie włącz-wyłącz, a pulsowanie osiągałem przez zastosowany kondensator, jednak nie dawało to pełnej kontroli. Uwolniony pin PWM wykorzystałem właśnie do świateł pozycyjnych. Zmienna kierunek ma wartość 1 lub -1, zatem wartość PWM jest zwiększana lub zmniejszana. Kiedy wartość PWM osiąga 0 lub 255 wartość zmiennej kierunek zostaje przemnożona przez -1 powodując zmianę jej wartości na przeciwną. void swiatlaPuls() { aktualnyCzasPWM = millis(); // Obsługa narastania i opadania PWM if (aktualnyCzasPWM - poprzedniCzasPWM >= interwalZmianyPWM) { poprzedniCzasPWM = aktualnyCzasPWM; wartoscPWM += kierunek; //Zmniana wartości PWM zależna od wartości kiereunku if (wartoscPWM >= 255 || wartoscPWM <= 0) { if (aktualnyCzasPWM - poprzedniCzasAnimacji >= interwalZmianyKierunku) { poprzedniCzasAnimacji = aktualnyCzasPWM; kierunek *= -1; // Zmiana kierunku narastania/opadania } } analogWrite(pulsLED, wartoscPWM); } } Dla świateł ostrzegawczych chciałem osiągnąć efekt szybkich mignięć wplecionych we włączanie i wyłączanie (włącz, zapulsuj, wyłącz, powtórz). Pożądane zachowanie uzyskałem stosując switch case i zmienną dla licznika i zmieniając zachowanie świateł w zależności od jej wartości. void swiatlaStrobo() { czasLEDstrobo = millis(); switch(licznikStrobo) { case 0: digitalWrite(stroboLED, 1); if (czasLEDstrobo - czasStrobo >= 700UL) { digitalWrite(stroboLED, 0); czasStrobo = czasLEDstrobo; licznikStrobo ++; } break; case 13: digitalWrite(stroboLED, 0); if (czasLEDstrobo - czasStrobo >= 500UL) { digitalWrite(stroboLED, 0); licznikStrobo ++; } break; default: if (czasLEDstrobo - czasStrobo >= 50UL) { czasStrobo = czasLEDstrobo; stanStrobo = !stanStrobo; digitalWrite(stroboLED, stanStrobo); licznikStrobo ++; } break; } if (licznikStrobo > 13) { licznikStrobo = 0; } } Na koniec moja świeżynka. Poznałem operator trójargumentowy, zauważyłem, że dla mnie - tego amatora przed monitorem - działa podobnie do if else, zatem przepisałem logikę odpowiedzialną za silniki. Dotychczas używałem oryginalnej z kursu, po poznaniu tego operatora powstało coś takiego: void lewySilnik (int VL) { if (VL == 0) return; //Jeżeli wartość VL jest równa zero to nie wykonuj funkcji int kierunekLewySilnik = (VL > 0) ? 0 : 1; //Jeżeli wartość VL jest większa od 0 to ustaw wartość 0 (jazda do przodu), jeżeli mniej to ustaw 1 (do tyłu) int vlMap = map(abs(VL), 0, 100, 0, PWM_MAX); //Przemapuj zakres PWM do zakresu 0-100, dla ujemnego VL zwróć wartość absolutną digitalWrite(L_DIR, kierunekLewySilnik); //Jazda do przodu, albo do tyłu :) analogWrite(L_PWM, vlMap); //Ustaw zadaną prędkość } Komunikacja - software: Robot jest częściowo zgodny z aplikacją o której wspomniałem na początku (sterowanie, załączanie świateł co drugi kllik), ale gotowa apka nie do końca spełnia moje oczekiwania. Można też sterować przez aplikację typu BT serial monitor, ale to też nie do końca to - choć tutaj już odbieram dane. Postanowiłem wyrzeźbić - to dobre słowo - aplikację w APP Inventorze. O ile w sekcji bloczkowej jakoś to poszło, to graficznie naprawdę była to rzeźba. Predefiniowane rozdzielczości są przedpotopowe, a i responsive nie do końca daje to, czego człowiek oczekuje. Ale, potrzebowałem jednej apki, więc postanowiłem się przemęczyć, zamiast podejmować naukę tworzenia od podstaw w jakimś ludzkim środowisku. W pierwszej wersji odbierałem temperaturę i wilgotność, napis "connect" był tylko etykietą. W drugiej odbieram jeszcze wartość napięcia. Przyciski kierunkowe to przód, tyłu, obroty w miejscu w prawo, w lewo. Dodatkowo w narożnikach przyciski przywołują jazdę po łuku w daną stronę (prawy przód, lewy tył itp). Przycisk H wyzwala impuls buzzerem. Przycisk Światła uruchamia światła. Zmienna w robocie sprawia, że po kolei uruchamiane są: światła pozycyjne i ostrzegawcze, z drugim wywołaniem dochodzą światła frontowe, z trzecim wywołaniem gaszone są pozycyjne i ostrzegawcze, pozostają frontowe. Czwarte wywołanie resetuje zmienną i gasi wszystkie światła. Przycisk Auto włącza lub wyłącza tryb jazdy autonomicznej. Podsumowanie Zdaję sobie sprawę, że kod nie jest idealny, zwłaszcza, że wiele rzeczy znałem po łebkach, niektórych uczyłem się w trakcie. Ale jestem zadowolony - coś, co miało być tylko dodaniem sterowania BT zmieniło się w duży jak dla mnie projekt, który robiony po godzinach ostatecznie działa. 😄 Co dalej? Wyciągnę zasilanie jakoś zasilanie na zewnątrz. Zastosowana obudowa sprawia, że aby ją odkręcić, muszę ściągać gąsienice w celu uzyskania dostępu do śrub. To ze zwykłej wymiany baterii, czy przyszłych zmian w oprogramowaniu, zamienia rutynę w procedurę. 😉 W drugiej części kursu Arduino widziałem czujnik ruchu, więc pewnie też go jakoś zatrudnię - zamysł taki, że w trybie auto będzie sobie oczekiwał i uruchamiał jazdę po wykryciu ruchu. A ponieważ szuflada zawiera jeszcze jednego HC-05, jakiegoś klona Nano i wyświetlacz OLED, mam w planie zrobić sprzętowy kontroler dla tego robota. 😄 Co to za antenka? To tylko ozdoba - zabieram Romka ze sobą na ERC w tym roku - będzie maskotką. 😄 Jaki koszt konwersji? Dla mnie żaden, jeżeli uznajemy, że co w szufladzie to 0 zł. Jeżeli ktoś by chciał iść w moje ślady, to myślę, że kilka stówek. Podwozie jest najdroższe. Ale jak już ktoś ma wydawać pieniądze na konwersję, to lepiej na budowę od podstaw i zrezygnować z tego shielda, na rzecz sterownika, który uciągnie silniki 4,5A - wtedy nie trzeba szukać silników, które ogarnie shield i parę zł zostaje. 😉 Osobiście, gdyby nie postanowienie zrobienia tego bez dodatkowych nakładów, to pewnie też bym dokupił kilka rzeczy, rezygnując z shielda forbotowego, ale czelendż to czelendż. Dotarłeś tutaj? No to zobacz krótki filmik. 🙂 Podjazd miał nachylenie ok. 30 stopni. A tutaj cały potworek 😅 //Załączenie bibliotek #include "DHT.h" //Czujnik temperatury i wilgotności #include "Servo.h" #include "Adafruit_MCP23008.h" //Ekspander portów #include <NewPing.h> //Obsługa HC-SR04 //Ekspander Adafruit_MCP23008 ekspander; //Deklaracje i zmienne dla DHT i pomiaru napięcia #define DHT22_PIN 7 //Pin sygnału z DHT DHT dht; //Utworzenie obiektu dla czujnika #define bateria A3 unsigned long czasDHT = 0; unsigned long odmierzDHT = 0; unsigned long roznicaDHT = 0; //Deklaracje serwomechanizmu Servo serwo; #define SERWO_PIN 11 //Pin sygnału sterującego PWM int idle = 84; //Neutralna pozycja dla serwa //Deklaracje mostek H #define L_PWM 5 //Pin prędkości lewego silnika #define L_DIR 4 //Pin kierunku lewego silnika #define R_PWM 6 //Pin prędkości prawego silnika #define R_DIR 9 //Pin kierunku prawego silnika #define PWM_MAX 210 //Maksymalne wypełnienie dla silnika 7,5V przy zasilaniu 9V //Deklaracje i definicje do obsługi buzzera #define BUZZER 10 unsigned long aktualnyCzasBuzzer = 0; unsigned long czasStartuBuzzer = 0; unsigned long czasTrwaniaBuzzer = 200; // Czas trwania impulsu w milisekundach boolean buzzerON = false; //Deklaracje i zmienne czujnika odległości i wykrywania przeszkód #define LEDjazda 0 //LED informujący o jeździe autonomicznej na 0 pinie ekspandera!!! #define lewySensor A0 //Krańcówka po lewej #define prawySensor A1 //Krańcówka po prawej #define trigPin 12 //Pin nadawczy (szary) #define echoPin 13 //Pin odbiorczy (biały) #define MAX_DISTANCE 200 // Maksymalny zasięg w centymetrach NewPing sonar(trigPin, echoPin, MAX_DISTANCE); //Inicjalizacja obiektu sonar z użyciem biblioteki NewPing const int doPrzeszkody = 25; //Odległość wykrywania przeszkody w cm //Wyliczenie stanów dla jazdy autonomicznej enum States { PROSTO, PATRZ_PRAWO, OBROT_PRAWO, PATRZ_LEWO, OBROT_LEWO, ZATRZYMAJ, ZATRZYMAJ2, COFAJ, COFAJ_LEWY, COFAJ_PRAWY, }; boolean jazdaAutonomiczna = false; boolean kolizjaPrawo = false; boolean kolizjaLewo = false; static States obecnyStan = PROSTO; //Domyślny stan unsigned long czasStanu = 0; //Zmienna dla timera stanu unsigned long czasDotyku = 0; //Zmienna dla timera krańcówek static unsigned long czasObrotu = 1100; //Zmienna dla czasu trwania obrotu //Definicje i zmienne dla świateł #define frontLED 1 //LEDy frontowe na 1 pinie ekspandera!!! #define stroboLED 2 #define pulsLED 3 int trybLED = 0; unsigned long czasStrobo = 0; unsigned long czasLEDstrobo = 0; int stanStrobo = 0; int licznikStrobo = 0; int stanPuls = 0; unsigned long poprzedniCzasPWM = 0; unsigned long poprzedniCzasAnimacji = 0; int wartoscPWM = 0; int kierunek = 1; // 1 - narastanie, -1 - opadanie unsigned long interwalZmianyPWM = 10; unsigned long interwalZmianyKierunku = 750; unsigned long aktualnyCzasPWM = 0; void setup() { //Konfiguracja ekspandera ekspander.begin(); ekspander.pinMode(LEDjazda, OUTPUT); //Konfiguracja świateł ekspander.digitalWrite(LEDjazda, LOW); pinMode(stroboLED, OUTPUT); digitalWrite(stroboLED, stanStrobo); pinMode(pulsLED, OUTPUT); analogWrite(pulsLED, stanPuls); ekspander.pinMode(frontLED, OUTPUT); ekspander.digitalWrite(frontLED, LOW); //Konfiguracja pinów mostka H pinMode(L_DIR, OUTPUT); pinMode(L_PWM, OUTPUT); pinMode(R_DIR, OUTPUT); pinMode(R_PWM, OUTPUT); //Konfiguracja pozostałych elementów pinMode(bateria, INPUT); //Odczyt ADC dla pomiaru napięcia baterii pinMode(lewySensor, INPUT_PULLUP); pinMode(prawySensor, INPUT_PULLUP); Serial.begin(9600); //Uruchomienie sprzętowej komunikacji UART dht.setup(DHT22_PIN); //Podłączenie czujnika do zadeklarowanego pinu serwo.attach(SERWO_PIN); //Podłączenie serwa do zadeklarowanego pinu serwo.write(idle); //Ustawienie serwa w domyślnej pozycji delay(200); //Opóźnienie dla ustabilizowania i przeczekania stanów nieustalonych serwo.detach(); //Odłączenie serwa //Konfiguracja buzzera i info o zakończeniu setupu pinMode(BUZZER, OUTPUT); digitalWrite(BUZZER, 1); ekspander.digitalWrite(LEDjazda, 1); delay(100); digitalWrite(BUZZER, 0); ekspander.digitalWrite(LEDjazda, 0); delay(100); digitalWrite(BUZZER, 1); ekspander.digitalWrite(LEDjazda, 1); delay(100); digitalWrite(BUZZER, 0); ekspander.digitalWrite(LEDjazda, 0); delay(100); } void loop() { humitemp(); //Wykonuj funkcje DHT if(jazdaAutonomiczna) { jazdaAuto(); } switch (trybLED) { case 0: analogWrite(pulsLED, 0); digitalWrite(stroboLED, 0); ekspander.digitalWrite(frontLED, 0); break; case 1: swiatlaPuls(); swiatlaStrobo(); ekspander.digitalWrite(frontLED, 0); break; case 2: swiatlaPuls(); swiatlaStrobo(); swiatlaFront(); break; case 3: analogWrite(pulsLED, 0); digitalWrite(stroboLED, 0); swiatlaFront(); break; case 4: trybLED = 0; break; } if (buzzerON) { klakson(); } if (Serial.available() > 0) { //Jeżeli są dostępne dane BT char jazda = Serial.read(); //Odczytaj te dane i przypisz do zmiennej switch(jazda) { //Wykonaj case zgodnie z odebranymi danymi case 'F': //Do przodu lewySilnik(95); prawySilnik(95); break; case 'B': //Do tyłu lewySilnik(-95); prawySilnik(-95); break; case 'S': //Zatrzymaj zatrzymajSilniki(); break; case 'L': //Obrót w lewo lewySilnik(-80); prawySilnik(80); break; case 'R': //Obrót w prawo lewySilnik(80); prawySilnik(-80); break; case 'G': //Lewy łuk do przodu lewySilnik(60); prawySilnik(95); break; case 'I': //Prawy łuk do przodu lewySilnik(95); prawySilnik(60); break; case 'H': //Lewy łuk do tyłu lewySilnik(-60); prawySilnik(-95); break; case 'J': //Prawy łuk do tyłu lewySilnik(-95); prawySilnik(-60); break; case 'V': //Impuls buzzerem buzzerON = !buzzerON; czasStartuBuzzer = millis(); break; case 'X': trybLED++; break; case 'A': jazdaAutonomiczna = !jazdaAutonomiczna; if (!jazdaAutonomiczna) { zatrzymajSilniki(); ekspander.digitalWrite(LEDjazda, 0); serwo.detach(); } break; } } } void lewySilnik (int VL) { if (VL == 0) return; //Jeżeli wartość VL jest równa zero to nie wykonuj funkcji int kierunekLewySilnik = (VL > 0) ? 0 : 1; //Jeżeli wartość VL jest większa od 0 to ustaw wartość 0 (jazda do przodu), jeżeli mniej to ustaw 1 (do tyłu) int vlMap = map(abs(VL), 0, 100, 0, PWM_MAX); //Przemapuj zakres PWM do zakresu 0-100, dla ujemnego VL zwróć wartość absolutną digitalWrite(L_DIR, kierunekLewySilnik); //Jazda do przodu, albo do tyłu :) analogWrite(L_PWM, vlMap); //Ustaw zadaną prędkość } void prawySilnik (int VR) { if (VR == 0) return; //Jeżeli wartość VL jest równa zero to nie wykonuj funkcji int kierunekLewySilnik = (VR > 0) ? 1 : 0; //Jeżeli wartość VR jest większa od 0 to ustaw wartość 1 (jazda do przodu), jeżeli mniej to ustaw 0 (do tyłu) int vrMap = map(abs(VR), 0, 100, 0, PWM_MAX); //Przemapuj zakres PWM do zakresu 0-100 digitalWrite(R_DIR, kierunekLewySilnik); //Jazda do przodu, albo do tyłu :) analogWrite(R_PWM, vrMap); //Ustaw zadaną prędkość } void zatrzymajSilniki() { analogWrite(L_PWM, 0); //Zatrzymaj lewy silnik analogWrite(R_PWM, 0); //Zatrzymaj prawy silnik } void humitemp () { //Funkcja czujnika DHT22 i pomiar napięcia float wilgotnosc = dht.getHumidity(); //Pobierz info o wilgotności do zmiennej float temperatura = dht.getTemperature(); //Pobierz info o temperaturze do zmiennej float wilgKorekta = wilgotnosc + 1.11; //Procentowa korekta dla odczytu wilgotności float tempKorekta = temperatura - 2.35; //Korekta odczytu temperatury int adc_val = analogRead(bateria); //Odczytaj wartość ADC float Ubat = adc_val * 0.0485340314; //Wylicz wartość napięcia czasDHT = millis(); //Pobierz aktualny czas Arduino roznicaDHT = czasDHT - odmierzDHT; if (roznicaDHT >= 2000UL) { //Jeżeli różnica wyniesie 2000 ms lub więcej odmierzDHT = czasDHT; //Zapisz aktualny czas arduino do zmiennej if (dht.getStatusString() == "OK") { //Jeżeli czujnik zwróci wartość ok, wykonaj poniższe Serial.print(tempKorekta); Serial.print(" °C"); Serial.print("|"); Serial.print(wilgKorekta); Serial.print(" %"); Serial.print("|"); Serial.print(Ubat); Serial.println(" V"); } } } int sonarDystans() { int dystans = sonar.ping_cm(); // Wykonanie pomiaru i zapisanie wyniku w zmiennej distance w centymetrach return dystans; } void swiatlaPuls() { aktualnyCzasPWM = millis(); // Obsługa narastania i opadania PWM if (aktualnyCzasPWM - poprzedniCzasPWM >= interwalZmianyPWM) { poprzedniCzasPWM = aktualnyCzasPWM; wartoscPWM += kierunek; //Zmniana wartości PWM zależna od wartości kiereunku if (wartoscPWM >= 255 || wartoscPWM <= 0) { if (aktualnyCzasPWM - poprzedniCzasAnimacji >= interwalZmianyKierunku) { poprzedniCzasAnimacji = aktualnyCzasPWM; kierunek *= -1; // Zmiana kierunku narastania/opadania } } analogWrite(pulsLED, wartoscPWM); } } void swiatlaStrobo() { czasLEDstrobo = millis(); switch(licznikStrobo) { case 0: digitalWrite(stroboLED, 1); if (czasLEDstrobo - czasStrobo >= 700UL) { digitalWrite(stroboLED, 0); czasStrobo = czasLEDstrobo; licznikStrobo ++; } break; case 13: digitalWrite(stroboLED, 0); if (czasLEDstrobo - czasStrobo >= 500UL) { digitalWrite(stroboLED, 0); licznikStrobo ++; } break; default: if (czasLEDstrobo - czasStrobo >= 50UL) { czasStrobo = czasLEDstrobo; stanStrobo = !stanStrobo; digitalWrite(stroboLED, stanStrobo); licznikStrobo ++; } break; } if (licznikStrobo > 13) { licznikStrobo = 0; } } void swiatlaFront() { ekspander.digitalWrite(frontLED, 1); } void jazdaAuto() { //Funkcja jazdy autonomicznej ekspander.digitalWrite(LEDjazda, 1); //Włącz LED informujący o jeździe autonomicznej switch (obecnyStan) { case PROSTO: prosto(); break; case ZATRZYMAJ: zatrzymaj(); break; case ZATRZYMAJ2: zatrzymaj2(); break; case PATRZ_PRAWO: //Wykrywanie przeszkód po prawej patrzPrawo(); break; case OBROT_PRAWO: //Skręt w prawo obrotPrawo(); break; case PATRZ_LEWO: //Wykrywanie przeszkód po lewej patrzLewo(); break; case OBROT_LEWO: //Skręt w lewo obrotLewo(); break; case COFAJ: cofaj(); break; case COFAJ_LEWY: cofajLewy(); break; case COFAJ_PRAWY: cofajPrawy(); break; } if (digitalRead(lewySensor) == LOW && kolizjaLewo==0) { //Jeżeli przeszkoda po lewej kolizjaLewo = 1; obecnyStan = COFAJ_LEWY; czasStanu = millis(); } if (digitalRead(prawySensor) == LOW && kolizjaPrawo==0) { //Jeżeli przeszkoda po prawej kolizjaPrawo = 1; obecnyStan = COFAJ_PRAWY; czasStanu = millis(); } } void prosto() { if (sonarDystans() <= doPrzeszkody) { //Jeżeli w zadanej odległości jest przeszkoda obecnyStan = ZATRZYMAJ; //Przejdź do zatrzymania czasStanu = millis(); //Ustaw czas dla timera serwo.attach(SERWO_PIN); //Podłącz serwo } else { //Jedź prosto lewySilnik(90); prawySilnik(90); } } void zatrzymaj() { zatrzymajSilniki(); if (millis() - czasStanu >= 500UL) { //Odczekaj zadany czas obecnyStan = PATRZ_PRAWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } } void zatrzymaj2() { zatrzymajSilniki(); if (millis() - czasStanu >= 500UL) { obecnyStan = PATRZ_LEWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } } void patrzPrawo() { serwo.write(25); //Ustw serwo w prawo if (millis() - czasStanu >= 400UL) { //Patrz przez zadany czas dla ustabilizowania serwa if (sonarDystans() > doPrzeszkody) { //Jeżeli nie ma przeszkód bliżej niż zadana odległość obecnyStan = OBROT_PRAWO; //Skręć w prawo czasStanu = millis(); //Ustaw czas dla timera } else { //Jeżeli jest przeszkoda obecnyStan = PATRZ_LEWO; //Przejdź do wykrywania przeszkody po lewej czasStanu = millis(); //Ustaw czas dla timera } } } void obrotPrawo() { lewySilnik(70); prawySilnik(-70); serwo.write(idle); //Ustaw serwo na wprost if (millis() - czasStanu >= czasObrotu) { //Skręcaj przez zadany czas serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy na prosto czasStanu = millis(); //Ustaw czas dla timera } } void patrzLewo() { serwo.write(155); //Obróć serwo w lewo if (millis() - czasStanu >= 450UL) { //Patrz przez zadany czas dla ustabilizowania serwa if (sonarDystans() > doPrzeszkody) { //Jeżeli nie ma przeszkody w zadanej odległości obecnyStan = OBROT_LEWO; //Skręć w lewo czasStanu = millis(); //Ustaw czas dla timera } else { //Jeżeli jest przeszkoda obecnyStan = COFAJ; //Włącz alarm czasStanu = millis(); //Ustaw czas dla timera } } } void obrotLewo() { lewySilnik(-70); prawySilnik(70); serwo.write(idle); //Ustaw serwo na wprost if (millis() - czasStanu >= czasObrotu) { //Skręcaj przez zadany czas serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy prosto czasStanu = millis(); //Ustaw czas dla timera } } void cofaj() { serwo.write(idle); //Ustaw serwo na wprost lewySilnik(-80); //cofaj prawySilnik(-80); if (millis() - czasStanu >= 800UL) { //Po upływie zadanego czasu zatrzymajSilniki(); //Zatrzymaj się obecnyStan = ZATRZYMAJ; //Przejdź do jazdy prosto czasStanu = millis(); //Ustaw czas dla timera } } void cofajLewy() { lewySilnik(-70); prawySilnik(-70); if (millis() - czasStanu >= 800UL) { obecnyStan = ZATRZYMAJ; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); kolizjaLewo = 0; } } void cofajPrawy() { lewySilnik(-70); prawySilnik(-70); if (millis() - czasStanu >= 800UL) { obecnyStan = ZATRZYMAJ2; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); kolizjaPrawo = 0; } } void klakson() { aktualnyCzasBuzzer = millis(); if (aktualnyCzasBuzzer - czasStartuBuzzer < czasTrwaniaBuzzer) { digitalWrite(BUZZER, HIGH); } else { digitalWrite(BUZZER, LOW); buzzerON = false; } }
  17. Czego dowiesz się z tego artykułu? Każdy to robi, natomiast prawie nikt nie zwraca na to uwagi. Nawet czytając ten tekst, organizm czytelnika wykonuje ściśle określoną listę kroków, która pozwala mu na zrozumienie czytanego tekstu. Algorytm to uporządkowany zbiór zadań, które wykonuje się w celu rozwiązania problemu. Czytając poniższy tekst zrozumiesz, że algorytmy są związane z praktycznie wszystkim co robisz na co dzień. Wprowadzę Cię do zapisu algorytmów. W artykule przedstawiono również 2 proste algorytmy zapisane w formie programu dla Arduino. Algorytmy w codziennym życiu. Załóżmy, że chcielibyśmy upiec ciasto, tak jak robiła to nasza babcia, która kierowała się konkretnym przepisem. Zaglądamy do jej zeszytu i czytamy, że potrzebujemy jajka, mąkę, masło i inne składniki. Pierwszym krokiem jest pokrojenie masła. Drugi to dodanie mąki, proszku do pieczenia, cukru i masła do miski. Po kolejnych 10 krokach wyciągamy pyszne ciasto z piekarnika i po ostygnięciu delektujemy się nim. Postępujemy tutaj według jasno określonej listy zadań, którą wymyśliła nasza babcia i dzięki której możemy osiągnąć pożądany cel. Po zjedzeniu ciasta wychodzimy na spotkanie z naszym znajomym. Nasz kolega mieszka na 1 piętrze, a winda nie działa, więc kierujemy się na schody. Wchodzimy na pierwszy stopień i weryfikujemy, czy jesteśmy na 1. piętrze. Jeżeli nie, to wchodzimy o 1 stopień wyżej i powtarzamy to, dopóki nie znajdziemy się na docelowym piętrze. W tym przypadku nasze postępowanie jest wyrażone za pomocą powtarzających się czynności, które kończymy, gdy założony przez nas warunek się spełni. Oczywiście w takich sytuacjach postępujemy automatycznie, ale warto było o tym wspomnieć, bo są to życiowe przykłady algorytmów - przepisów, które prowadzą do rozwiązania problemu, np. upieczenia ciasta, lub wejścia na 1. piętro. Mówimy o algorytmie, gdy jest on: poprawny - działa, jednoznaczny - daje ten sam wynik przy takich samych danych, skończony - nie działa w nieskończoność, efektywny - wykonuje się w sensownym czasie. Trzeba pamiętać, że algorytm ≠ program. Jeżeli algorytm jest zapisany językiem programowania, to wtedy możemy mówić o programie. Zapis algorytmów i przykłady Pamiętaj, że bardzo złym pomysłem jest zapisywanie algorytmów jako jakąś opowieść, bo może to zaburzać interpretację ich działania. Dobrym zwyczajem jest zapisywanie ich technikami, które zostały przedstawione poniżej. Lista kroków Najprostszą i najbardziej naturalną techniką jest zapis algorytmu w postaci ponumerowanych punktów, w których wypisujemy po kolei, co robimy. Zależnie od sytuacji, kroki można pomijać lub do nich wracać. Uproszczony algorytm wykonania ciasta. Autor nie ponosi odpowiedzialności za korzystanie z tego przepisu! pokrój 100 g zimnego masła na małe kosteczki dodaj do miski: 200 g szklanki mąki, pokrojone masło, 13 g proszku do pieczenia, 26 g cukru i rozbite jajko bez skorupki zmieszaj porządnie zawartość miski ciasto włóż do lodówki po 15 minutach wyciągnij ciasto piekarnik nagrzej do 180 stopni Celsjusza wypełnij formę ciastem i dodaj owoce włóż do piekarnika blachę z ciastem na 50 minut sprawdź czy gotowe. Jeżeli tak to przejdź do kroku 12. W przeciwnym razie przejdź do kroku 10 poczekaj minutę przejdź do kroku 9 wyjmij ciasto i daj mu ostygnąć zakończ algorytm Powyższy algorytm jest uproszczeniem. Bezmyślne kierowanie się nim może skutkować tym. Jesteśmy ludźmi i raczej każdy rozumie zwrot dodaj cukier. Algorytm wchodzenia po schodach: sprawdź czy wszedłeś na docelowe piętro. Jeżeli tak, to przejdź do kroku 4. W przeciwnym razie przejdź do następnego kroku wejdź o jeden stopień do góry przejdź do kroku 1 zakończ algorytm W powyższych algorytmach pojawiają się instrukcje warunkowe (jeżeli) i pętle (jeżeli… przejdź do kroku poprzedniego) - jedne z najważniejszych zagadnień programowania. Instrukcją warunkową nazywamy fragment programu, który praktycznie odpowiada na pytanie w formie: tak/nie, prawda/fałsz, 1/0. Na podstawie odpowiedzi może wykonywać jakąś czynność. Pętla to fragment kodu, który powtarza się, jeżeli warunek przypisany do tej pętli jest spełniony. W kolejnych przykładach będę posługiwał się tylko algorytmem wchodzenia po schodach, bo jest on krótki i wystarczy do wyjaśnienia innych technik zapisywania algorytmów. Pseudokod Jak sama nazwa wskazuje, jest to symbolicznie zapisany kod, który w dużej mierze zachowuje zasady języków programowania. W tym artykule wykorzystamy zasady, które opisano w tym dokumencie. Należy pamiętać, że nie istnieje oficjalny standard dla pseudokodu i to jest tylko szkolny przykład. Operacje matematyczne dodawanie – + odejmowanie – - mnożenie – • dzielenie – / dzielenie całkowite – div reszta z dzielenia – mod Przypisanie wartości do zmiennej a ← 3 Instrukcja warunkowa jeżeli a = 3 wykonuj a ← 0 w przeciwnym razie a ← 1 Operatory porównania większe - > większe równe - ≥ mniejsze - < mniejsze równe - ≤ równe - = nierówne - ≠ Operatory logiczne AND - i OR - lub Pętle dopóki a < 10 wykonuj a ← a + 1 lub dla i = 1, 2, 3, … 10 wykonuj a ← a + 1 lub wykonuj a ← a + 1 dopóki a < 10 Przedstawmy teraz algorytm wchodzenia po schodach w postaci pseudokodu. Musimy założyć pewne uproszczenia i dodatki: z góry wiemy ile dane schody mają stopni wejście na stopień traktujemy jako dodanie 1 do zmiennej wskazującej aktualny stopień gdy będziemy na środkowym stopniu to powiemy “połowa za mną…” po wejściu na piętro jesteśmy bardzo szczęśliwi, że nasz algorytm działa, więc mówimy “jestem na piętrze!” wprowadź liczbaStopni aktualnyStopien ← 0 dopóki aktualnyStopien < liczbaStopni wykonuj aktualnyStopien ← aktualnyStopien + 1 jeżeli aktualnyStopien = liczbaStopni div 2 wypisz “Połowa za mną…” wypisz “Jestem na piętrze!” Zapisując algorytm w pseudokodzie, pamiętaj, żeby stosować wcięcia do operacji, które dotyczą użytej wcześniej instrukcji, takiej jak instrukcja warunkowa. Zapewni to czytelność i poprawne działanie kodu, ponieważ pseudokod bazuje na wcięciach. Pseudokod zapewnia szybki zapis algorytmu i możliwość łatwego przekonwertowania go na język programowania. Schemat blokowy W tej technice używamy bloków o konkretnym kształcie, aby wskazać różne instrukcje algorytmu. Podstawowe kształty: owal - miejsce rozpoczęcia/zakończenia algorytmu prostokąt - operacje na zmiennych romb - instrukcja warunkowa równoległobok - wprowadzenie/wypisanie danych I tak jak poprzednio, algorytm wchodzenia po schodach: Dla czytelności polecam wejść w pełny obraz. Schemat blokowy czyta się od punktu START i podąża się zgodnie ze strzałkami, wykonując wszystkie operacje zawarte w mijanych blokach. Spróbuj przeanalizować powyższy algorytm! Dzięki schematowi blokowemu będziesz mógł przedstawić swoje algorytmiczne pomysły w czytelny i klarowny sposób. Należy pamiętać, że schemat blokowy dobrze sprawdza się w algorytmach mniejszych rozmiarów. Spróbuj sobie wyobrazić, co by było, gdyby na schemacie znajdowało się 100 różnych bloków i byłoby między nimi dużo połączeń… Język programowania Wcześniejsze techniki zapisu algorytmów są stosowane do ich przedstawienia w sposób symboliczny. Komputer to maszyna i potrzebuje konkretnych instrukcji, dlatego stosuje się języki programowania, które są jednoznaczne i precyzyjne. Mówiąc chcę dodać dwie liczby trzeba jeszcze sprecyzować, jakie mają wartości, jakiego są typu, gdzie będzie przechowywany wynik itp. Każdy język charakteryzuje się składnią i semantyką, czyli sposobem, w jaki programy napisane w danym języku są konstruowane i interpretowane przez komputer. Składnia odnosi się do struktury i zapisu gramatycznego kodu, czyli do tego, jakie konstrukcje i polecenia są akceptowane w danym języku. Z kolei semantyka odnosi się do znaczenia tych konstrukcji oraz sposobu, w jaki są one rozumiane i wykonane przez interpreter lub kompilator. Poniżej znajduje się zapis algorytmu wchodzenia po schodach w języku C. #include <stdio.h> int main() { int iloscStopni = 10; int aktualnyStopien = 0; while (aktualnyStopien < iloscStopni) { aktualnyStopien = aktualnyStopien + 1; if (aktualnyStopien == iloscStopni / 2) { printf("Polowa za mna!\n"); } } printf("Jestem na pietrze!\n"); return 0; } Tutaj warto zaznaczyć jak korzysta się z funkcji. Nazwę możesz kojarzyć z matematyki, gdzie występuje funkcja f(x). Dokładnie w ten sam sposób działają funkcje w programowaniu. Wywołując ją podajesz jej nazwę i w nawiasach argumenty, które zostaną wykorzystane do pewnych operacji. Funkcja może zwracać pewną wartość lub nie. Np. funkcja printf() nic nie zwraca, ale wypisuje napis w konsoli. Jeżeli zwraca to musimy podać zmienną przechowującą wartość wyniku. Na początku programu musimy pobrać bibliotekę, w której znajdują się funkcje, których będziemy używali w programie. Za to odpowiada pierwsza linijka - #include <stdio.h>. W C operacje pisze się między nawiasami klamrowymi, które oznaczają początek i koniec danej instrukcji. W tym przypadku cały program jest zapisany w funkcji głównej main(), która zawsze się wykonuje przy uruchomieniu programu. Na końcu każdej operacji musi wystąpić średnik! Żeby nie komplikować kodu pobraniem wartości założyłem, że wiemy od samego początku, ile jest stopni na schodach, dlatego równocześnie z deklaracją, że będzie to zmienna stałoprzecinkowa int, przypisujemy jej wartość 10: int iloscStopni = 10;. while() to pętla odpowiadająca pętli dopóki w pseudokodzie. W nawiasach wpisujemy warunek wykonania się kolejnego kroku pętli. Funkcja printf() wyświetla napis zawarty w nawiasach, w cudzysłowie. Porównaj kod zapisany pseudokodem z tym w C. Jestem pewny, że dostrzeżesz podobieństwa. Algorytmika w Arduino Należy pamiętać, że programy, które piszemy na Arduino, działają w nieskończonej pętli. Procesory, mikrokontrolery i inne sterowniki są projektowane tak, aby mogły działać cały czas. Z tego powodu programy w Arduino wykonują się w dwóch funkcjach - setup() i loop(). Dodatkowo warto zaznaczyć, że język wykorzystywany w Arduino IDE jest praktycznie językiem programowania C++. setup() wykonuje się tylko i wyłącznie raz przy starcie całego programu. Używamy tej funkcji, żeby rozpocząć pewne procesy lub ustawić wejścia i wyjścia na odpowiednie tryby. Stąd jej nazwa, która przetłumaczona na j. polski brzmi konfiguracja. Konfigurujemy i przygotowujemy środowisko na późniejsze etapy wykonywania programu. loop() wykonuje się po zakończeniu funkcji setup i działa w pętli - wykonuje się cały czas. Tutaj umieszczamy operacje związane z np. sterowaniem i przechwytywaniem informacji. Przykładowe algorytmy na Arduino Blink Na początku zajmiemy się miganiem diodą LED. Nie musisz nic pisać, aby skorzystać z tego programu! Włącz Arduino IDE -> kliknij zakładkę File -> Examples -> 01.Basics -> Blink. Otworzy się nowe okienko z programem Blink. Zauważysz dużo komentarzy, które są poprzedzone dwoma myślnikami, lub znakami /* i zakończone */. Możesz je usunąć. Zostanie poniższy kod: void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); } pinMode() ustawia wybrany pin na wejście lub wyjście. Przyjmuje dwa argumenty - numer pinu i wybranie trybu. Arduino ma wbudowaną stałą, która wskazuje na pin wbudowanej w płytkę diody, więc to będzie nasz pierwszy argument. Drugim będzie OUTPUT, czyli ustawienie pinu na wyjście. Ta funkcja wykona się tylko raz, bo znajduje się w setup(). W funkcji loop() jako pierwszy krok ustawiamy pin LEDa na stan wysoki (zapali się) funkcją digitalWrite(), podając pin tej diody i argument HIGH oznaczający stan wysoki. Funkcja delay() powoduje czekanie programu. Wartość w nawiasach to długość czasu w milisekundach. Potem wyłączamy diodę, czekamy sekundę. Funkcja loop() wykonuje się od nowa. Czy jesteś w stanie zapisać algorytm migania diodą w postaci schematu blokowego? Czytanie przycisku Poniżej znajduje się program do zapalania lampki, gdy wciśnięty jest przycisk na pinie 7. Spróbuj go przeanalizować i pochwal się w komentarzu, jak działa! Dodatkowo w ramach ćwiczenia, polecam zapisać go w postaci pseudokodu. Kilka podpowiedzi: zmienne i stałe można deklarować poza głównymi funkcjami. Można wtedy się do nich odwołać w każdym miejscu w programie #define oznacza deklarację stałej, której nie zmienia się przez cały program. Symbolicznie stałe zapisuje się wielkimi literami digitalRead() czyta i zwraca stan, który aktualnie jest na pinie funkcja else() wykonuje się wtedy, gdy instrukcja warunkowa zwróciła fałsz #define PIN_LED 8 #define PIN_BUTTON 7 int buttonState = 0; void setup() { pinMode(PIN_LED, OUTPUT); pinMode(PIN_BUTTON, INPUT); } void loop() { buttonState = digitalRead(PIN_BUTTON); if (buttonState == HIGH) { digitalWrite(PIN_LED, HIGH); } else { digitalWrite(PIN_LED, LOW); } } Podsumowanie Znajomość pojęcia algorytm to kluczowa umiejętność w świecie programowania. Jeśli zaczynasz pisać kod na platformę Arduino, to warto zgłębić tę tematykę. Nie ograniczaj się tylko do zapisu algorytmów - zrozum, jak działają i jak możesz je wykorzystać w praktyce. Gorąco polecam skorzystać z kursu Arduino na Forbocie, abyś mógł szybko przekuć swoją wiedzę na konkretne projekty.
  18. Cześć, może komuś by się chciało napisać coś na temat pisania bibliotek do Arduino? Temat nie poruszany a potrzebny. Baaaaaardzo potrzebny 😁
  19. Cześć, pewnego razu na spotkaniu ze znajomymi okazało się, że na hasło „polej” nikt nie zareagował. Wtedy zrodził się pomysł, aby zaradzić takim przykrym sytuacjom w przyszłości postanowiłem stworzyć robota do nalewania alkoholi wysokoprocentowych. Z założenia robot miał nalewać alkohol do każdego kieliszka jaki się postawi oraz miał być zasilany przy pomocy baterii. Pierwsze prototypy zawierały prostą elektronikę opartą na czujnikach i przekaźnikach – jestem laikiem oraz samoukiem w kwestiach elektroniki. Projekty nie spełniały oczekiwań, ponieważ w normalnym użytkowaniu zawodziły. Około rok temu natknąłem się na Arduino i zacząłem pogłębiać swoją wiedzę w tym kierunku. Wydruki 3D wykonałem na swojej drukarce. Robot spełnił założenia. Poprzez zastosowanie czujnika ultradźwiękowego jest w stanie nalać do każdego kieliszka, a potencjometrem można ustawić ilość nalewanej wódki w zakresie około 10 - 50ml. Do zasilania użyłem 8 akumulatorów AA. Wykonałem obudowę z kilku elementów żeby mieć lepszy dostęp do podzespołów. Rynienka na pompce została stworzona po zalaniu układu... z wyciekiem sobie poradziłem ale dla pewności została 😉 Części których użyłem do budowy: Płytka stykowa 170 pól - 1 szt Stabilizator L7805CV 5V 1,5A – 1 szt Ultradźwiękowy czujnik odległości HC-SR04 2-200cm – 1szt Potencjometr liniowy 1K – 1 szt Wtyk DC 2,1/5,5mm z zaciskami skręcanymi – 1 szt Pompa membranowa - silnik R385+ - 12V - 3W - mini pompa wodna – 1szt Moduł sterownika L298N do silników DC – 1 szt Przełącznik kołyskowy 15x10mm – 1 szt Koszyk na baterie 8xAA (R6) – 1 szt Arduino Nano – 1 szt Uniwersalny Proto Shield do Arduino Nano – 1 szt Serwo TowerPro MG-995 – 1szt. Zawór zwrotny – 2szt. Moduł dioda LED RGB 5050 wspólna katoda – 1 szt. Magnesy neodymowe 10x5 – 8 szt Przycisk monostabilny – 1 szt. Rurka sylikonowa – 0,5m Rezystory Przewody połączeniowe Aby "polewacz" był mobilny jego elementy zaprojektowałem tak, aby zmieściły się w drewnianej skrzyni 30x20x15cm.
  20. Cześć wszystkim, Ostatnio zainteresowałem się pewnym zjawiskiem fizycznym, polegającym na możliwości wykorzystania dźwięku do gaszenia ognia [link] [link]. Postanowiłem samemu zbudować podobne urządzenie, jednak podczas doboru elementów natrafiłem na pewne problemy, których niestety sam nie potrafię rozwiązać. 1. Schemat urządzenia 2. Zasada działania urządzenia Chciałbym, aby zaprojektowane urządzenie, za pomocą głośnika (generowanej fali akustycznej) było w stanie zgasić np. płomień zapalonej świeczki typu tealight [link] czy ogień z podpalonego denaturatu, wypełniającego pojemnik po wyżej wspomnianej świeczce. Z tego względu podstawą takiego urządzenia musi być odpowiedni głośnik. Uważam, że dobrym wyborem okaże się głośnik o impedancji 8 Ω, głośności 91 dB i mocy maksymalnej 200 W. Dzięki temu będę miał zapas na wykonywanie coraz to bardziej skomplikowanych eksperymentów, z możliwością podnoszenia poprzeczki. Owszem zapaloną świeczkę można po prostu zdmuchnąć ale trzeba od czegoś zacząć 😉 [link]. Również zdaję sobie sprawę, że do uzyskania takiego zjawiska potrzebuję odpowiedniej częstotliwości fali akustycznej oraz poziomu natężenia dźwięku. Precyzyjną częstotliwość fali akustycznej mogę wygenerować dzięki Arduino Uno oraz funkcji tone() [link], zaś kontrolę nad poziom natężenia dźwięku uzyskam dzięki wzmacniaczowi z wbudowanym potencjometrem [link]. Idąc dalej wzmacniacz potrzebuje zasilania od 6 V do 12 V. Większe napięcie przy stałej impedancji zapewnia większe natężenie. Większe natężenie to większa moc głośnika. Rozwiązaniem okaże się tutaj moduł z tranzystorem [link] pozwalający na włączanie urządzeń wymagających zasilania od 5 V do 15 V. Co więcej uchronię Arduino Uno przed natężeniem większym niż 20 mA. Wybrałem taki moduł z serii Grove, ponieważ posiadam nakładkę Grove Base Shield v2 [link] rozszerzającą możliwości pinów Arduino Uno oraz dysponuję wyświetlaczem LCD 2 x 16 [link] tej samej firmy, na którym wyświetlałbym daną częstotliwość fali akustycznej oraz poziom natężenia dźwięku. Co więcej planuję dokupić 2 przyciski, dzięki którym sterowałbym częstotliwością fali akustycznej generowanej przez Arduino (zmniejszenie częstotliwości / zwiększenie częstotliwości) [link]. Całość planuję zasilić akumulatorem 12 V ; 1,2 Ah, w połączeniu z przełącznikiem ON/OFF i stabilizatorem LM7805 [link] odpowiadającym za dostarczenie bezpiecznego napięcia 5 V do Arduino wraz z dwoma kondensatorami 1000 μF ; 25 V, których zadaniem jest eliminacja zakłóceń i zapewnienie prawidłowej pracy układu. Zasilanie do Arduino zapewnię poprzez wtyk DC [link]. 3. Problem do rozwiązania Mam nadzieję, że udało mi się zrozumiale wytłumaczyć planowany sposób działania urządzenia. Poniżej zapisałem pytania, na które niestety sam nie potrafię odpowiedzieć, a są według mnie kluczowe do poprawnego zadziałania prototypu: Czy mój tok rozumowania jest prawidłowy? Czy może coś mi umknęło? Czy przedstawiony schemat zakłada poprawne połączenia wejść / wyjść komponentów urządzenia? Czy zasilanie 12 V w połączeniu ze stabilizatorem okaże się wystarczające do uruchomienia głośnika, nie uszkadzając przy tym Arduino? Czy głośnik w połączeniu ze wzmacniaczem będzie generował dźwięk? Czy może czegoś brakuje? Z góry dziękuję za poświęcony czas i pomoc! 😊
  21. Już myślałem, że mam ogarnięty temat RS-485. Jednak nie i znów potrzebuję pomocy. Czy są jakieś zasady / dobre praktyki, które należy stosować do obsługi komunikacji dwukierunkowej w trybie half duplex? Ew. ktoś to robił i może mi pomóc z moją aplikacją (np. jakiś wieczorny calll?) Aktualnie robię w miarę prosty układ obsługujący komunikację RS-485, wykorzystując 2 płytki: UNO R4 i GIGA. Całość ma działać tak: 1. (działa) Wciskam przycisk podpięty do UNO. UNO wysyła komunikat do GIGA. Kod: void sendReadMessage(int command) { char message[BatteryMonitor_Message_Lenght]; int commandValueParameter = 1; //wg przykładów z instrukcji urządzenia każdy read wysyła wartość = 1. int checksum = getChecksum(commandValueParameter); sprintf(message, ":R%02i=%i,%i,%i,\r\n", command, batteryMonitorParameters.deviceAddress, checksum, commandValueParameter); //Active HIGH for Driver Input Enable; Active LOW for Receiver Output Enable. digitalWrite(receiverOutputEnablePinNumber, HIGH); batteryMonitorSerialDevice->print(message); batteryMonitorSerialDevice->flush(); delay(WaitTimeAfterSend); //Active HIGH for Driver Input Enable; Active LOW for Receiver Output Enable. digitalWrite(receiverOutputEnablePinNumber, LOW); } W klasie instancją której operuję jest definicja zmiennej: Stream* batteryMonitorSerialDevice; a przy inicjowaniu podpinam pod nią Serial1 na którym jest poprawnie wpięty konwerter RS-485. 2. (działa) GIGA odbiera i prasuje komunikat. W zależności od treści otrzymanego i przetworzonego komunikatu ustala odpowiedź do wysyłki. Kod: void loop() { returnMessage = ""; switch (readMessage()) { case 0: { returnMessage = ":r00=1,47,1120,100,101,\r\n"; break; } case 50: { returnMessage = ":r50=2,215,2056,200,5408,4592,9437,14353,134,0,0,0,162,30682,\r\n"; break; } default: break; } if (returnMessage.length() > 0) { sendMessage(returnMessage); } delay(100); } int readMessage() { String returnMessage_local = ""; char message[BatteryMonitor_Message_Lenght]; int startIndex = 0; int endIndex = 0; bool receivedFullMessage = false; bool receivedMessage = false; int index = 0; while (Serial1.available() > 0) { message[index] = Serial1.read(); receivedMessage = true; if (message[index] == '\n') { receivedFullMessage = true; break; } index++; } if (receivedMessage and receivedFullMessage) { //parsuję wiadomość i szukam interesującego mnie kodu operacji for (int i = 0; i <= index; i++) { if (message[i] == 'R') { startIndex = i + 1; } if (message[i] == '=') { endIndex = i - 1; i = index + 1; //leave the loop } } for (int i = startIndex; i <= endIndex; i++) { returnMessage_local += message[i]; } if (returnMessage_local == "") { return -1; } else { return returnMessage_local.toInt(); //kod operacji } } return -1; } 3. (zaczynają się problemy) GIGA wysyła komunikat po RS-485. Nie mam żadnych oznak niepoprawnego działania. Kod: void sendMessage(String message) { message.toCharArray(messageToSend, BatteryMonitor_Message_Lenght); digitalWrite(ReceiverOutputEnablePinNumber, HIGH); for (int i = 0; i < message.length(); i++) { Serial1.write(messageToSend[i]); } Serial1.flush(); delay(100); digitalWrite(ReceiverOutputEnablePinNumber, LOW); } 4. (nie działa) UNO czeka na przychodzący komunikat. Jeżeli coś się pojawia to odbiera i wyświetla na serial (USB). Niestety przy kolejnych naciśnięciach przycisku albo nic nie odbiera, albo odbiera śmieci. Ani razu nie dotarła wiadomość zwrócona przez GIGA. void loop() { if (digitalRead(5) == LOW) { //Jeśli przycisk jest wciśnięty readBasicInformation(); SerialDebug_BM_BasicInformation(); //na potrzeby debugowania wyświetla otrzymane informacje na Serial / USB } delay(150); } void readBasicInformation() { char returnMessage[140]; String complexField = ""; char nextCharacter; int index = 0; //funkcja wysyłania z pkt 1 – ta działająca. Na wejściu kod operacji sendReadMessage(BatteryMonitor_Functions_ReadBasicInfo); //wiadomości są zakończone dwoma znakami: \r\n int tmpTimeout = 0; //czekam na wiadomość. Aby nie zawiesić aplikacji symulacja timeout w oczekiwaniu na komunikat. Kod do refactoringu while (batteryMonitorSerialDevice->available() <=0 && tmpTimeout <=30) { delay(150); tmpTimeout++; } //odczyt znak po znaku i wyświetlanie na Serial w celu debugowania while (batteryMonitorSerialDevice->available() > 0) { //tu dostaję śmieci lub nic nie dostaję…. returnMessage[index] = batteryMonitorSerialDevice->read(); Serial.print(returnMessage[index]); index++; } //odczyt wyświetlanie na Serial w celu debugowania Serial.print("Return message full: "); Serial.println(returnMessage); } Co mogę robić źle?
  22. Uczę się używania Arduino i gdy podłączyłem całość wyskakuje mi błąd, co musze zrobic? Szkic używa 1144 bajtów (3%) pamięci programu. Maksimum to 30720 bajtów. Zmienne globalne używają 13 bajtów (0%) pamięci dynamicznej, pozostawiając 2035 bajtów dla zmiennych lokalnych. Maksimum to 2048 bajtów. avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0xde avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0xde Failed uploading: uploading error: exit status 1
  23. Witam. Gdy robię schemat załączony na obrazku i załączam poniższy kod, serwomechanizm działa przez jakiś czas, ale po czasie się wyłącza, a stabilizator się przegrzewa tak, że ledwo co mogę go dotknąć. Wie ktoś, czy powinno tak być, a jeśli nie, to czym to może być spowodowane i jak można temu zaradzić? #include <Servo.h> //Biblioteka odpowiedzialna za serwa Servo serwomechanizm; //Tworzymy obiekt, dzięki któremu możemy odwołać się do serwa void setup() { serwomechanizm.attach(9); //Serwomechanizm podłączony do pinu 9 } void loop() { serwomechanizm.write(0); delay(1000); serwomechanizm.write(120); //Wykonaj ruch delay(1000); serwomechanizm.write(40); delay(1000); }
  24. Dz ień dobry🙂Chciałbym się dowiedzieć czy mogę zasilać z baterii 9V plytkę arduino UNO i silniki 5V? Robięaktualnie projekt z dwoma silnikami i plytka arduino, chcę to zasilac z jednej bateri 9V i chcę to zrobić tak że podłączę do bateri plytkę i stabilizatory napięcia ktore z 9v beda robic 5v (dla silnikow) a stabilizatory do tranzystorow a tranzystory do plytki i silnikow. (Bede sterował napieciemdla silnikow poprzez płytkę) 😀
  25. Dopiero zaczynam z arduino i nie wiem gdzie mam tu błąd. Chcę podłączyć dalmierz ultradźwiękowy brzęczyk i leda który się zaświeci gdy coś się ruszy #define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Pin, do którego podłączymy trig jako wyjście pinMode(echoPin, INPUT); //a echo, jako wejście pinMode(2, OUTPUT); //Wyjście dla buzzera pinMode(4, OUTPUT); } void loop() { zakres(10, 25); //Włącz alarm, jeśli w odległości od 10 do 25 cm od czujnika jest przeszkoda delay(100); } int zmierzOdleglosc() { long czas, dystans; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); czas = pulseIn(echoPin, HIGH); dystans = czas / 58; return dystans; } void zakres(int a, int b) { int jakDaleko = zmierzOdleglosc(); if ((jakDaleko > a) && (jakDaleko < b)) { digitalWrite(2, HIGH); //Włączamy buzzer } else { digitalWrite(2, LOW); //Wyłączamy buzzer, gdy obiekt poza zakresem } void zakres(int a, int b) { int jakDaleko = zmierzOdleglosc(); if ((jakDaleko > a) && (jakDaleko < b)) { digitalWrite(4, HIGH); } else { digitalWrite(4, LOW); } }
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.