Przeszukaj forum
Pokazywanie wyników dla tagów 'arduino'.
Znaleziono 465 wyników
-
Witam, od jakiegoś czasu borykam się z problemem zapisu wartości wpisanej z klawiatury membranowej do zmiennej w programie. Potrzebuję do mojego małego programu aby wartość wpisana na klawiaturze zapisywała się w zmiennej dzięki czemu byłbym w stanie za pomocą tej wartości wysterować odpowiednią ilość kroków na silniku. Szukałem informacji na paru forach, lecz jedyne co udało mi się uzyskać, to podpowiedzi do tworzenia lub całe kody przystosowane do porównywania wartości wpisanych na klawiaturze do odgórnie ustalonej zmiennej. Miałby ktoś z was jakąś podpowiedź lub wątek który pomógłby mi coś z tym ruszyć? Kożystam z biblioteki Keypad.h Z góry dziękuje za pomoc
-
Drodzy koledzy chciałbym prosić o pomoc: Hobbistycznie buduje robota na wzór: W zasadzie interesuje mnie samo podwozie. Wydrukowałem i złożyłem wszystko w całość. Całość waży: 910g (podwozie, okablowanie, arduino uno, PCA9685, kabel do programowania) Zastosowałem: 1. Źródło energii ogniwa 3x 18650 4,2V DC 1200mA (waga: 150g - na tą chwile jest poza podwoziem) 2. 18x Servo MG-90S specyfikacja: 3. Płyta Arduino UNO 4. Kontroler PCA9685 nakładka na Arduino uno 5. Redukcja dla serv: 300W 20A DC-DC Buck Converter Step Down Module 6. Całość złożona: Na potrzeby startu: Arduino zasilone bateria 9V PCA9685 zasilone poprzez step down ustawiony na 5,5V Program: #include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // I2C 0x40 #define SERVOMIN 100 // 0 stopni #define SERVOMAX 600 // 180 stopni 400 - 90 stopni #define SERVO_1 0 #define SERVO_2 1 #define SERVO_3 2 #define SERVO_4 3 #define SERVO_5 4 #define SERVO_6 5 #define SERVO_7 6 #define SERVO_8 7 #define SERVO_9 8 #define SERVO_10 9 #define SERVO_11 10 #define SERVO_12 11 #define SERVO_13 12 #define SERVO_14 13 #define SERVO_15 14 #define SERVO_16 15 void setup() { pwm.begin(); pwm.setPWMFreq(60); delay(10); // pozycja startowa Noga 1 pwm.setPWM(SERVO_11, 0, 120); delay(250); pwm.setPWM(SERVO_12, 0, 490); delay(250); pwm.setPWM(SERVO_13, 0, 400); delay(250); // pozycja startowa Noga 3 pwm.setPWM(SERVO_1, 0, 350); delay(250); pwm.setPWM(SERVO_2, 0, 100); delay(250); pwm.setPWM(SERVO_3, 0, 150); delay(250); // pozycja startowa Noga 6 pwm.setPWM(SERVO_14, 0, 315); delay(250); pwm.setPWM(SERVO_15, 0, 600); delay(250); pwm.setPWM(SERVO_16, 0, 600); delay(250); // pozycja startowa Noga 4 pwm.setPWM(SERVO_4, 0, 370); delay(250); pwm.setPWM(SERVO_5, 0, 600); delay(250); pwm.setPWM(SERVO_6, 0, 575); delay(250); // pozycja startowa Noga 2 // pwm.setPWM(SERVO_4, 0, 370); // brak wolnego slota // delay(250); pwm.setPWM(SERVO_7, 0, 150); delay(250); pwm.setPWM(SERVO_8, 0, 100); delay(250); // pozycja startowa Noga 5 // pwm.setPWM(SERVO_4, 0, 370); // brak wolnego slota // delay(250); pwm.setPWM(SERVO_9, 0, 550); delay(250); pwm.setPWM(SERVO_10, 0, 450); delay(250); } Mój problem: Robot podczas zasilenia nie wstaje do końca mimo małej masy Teraz pytanie czy źle zasilam shield? Czy dałem za małe opóźnienie pomiędzy serwami podczas podnoszenia się do pozycji startowej i za dużo serw naraz pracuje? Kod działa poprawnie gdy nie ma obciążenia Proszę o sugestie z góry dziękuje
-
Czytak do ebooków (czyli epub to speech)
ethanak opublikował temat w Projekty - DIY w budowie (worklogi)
Pisałem niedawno, że marzyłem kiedyś i takim przenośnym urządzeniu, które czytałoby mi książki w czasie spaceru czy jazdy pociągiem. I to nie audiobooki, ale zwyczajne ebooki. Cóż - kilkanaście lat temu było to raczej mało realne. Minęły lata (kilkanaście jak wspomniałem), realia się zmieniły, i chociaż rzadziej wychodzę na spacery czy wsiadam do pociągu - postanowiłem zrealizować swoje marzenie. Co prawda jakieś pierwotne założenia sobie poczyniłem, jednak pozostały z nich tylko dwa: rozmiar nie przekraczający paczki papierosów i ESP32 WROVER jako serce urządzenia. Miałem w planach kartę microSD - ale po drodze stwierdziłem, że na moim ESP mam jakieś 8MB flasha do dyspozycji na FatFS, książka po skompresowaniu zajmuje nie więcej niż pół mega, czyli kilkanaście książek powinienem zmieścić bez dodatkowych urządzeń typu czytnik kart. Kilka problemów musiałem rozwiązać zanim zabrałem się do jakiejkolwiek roboty. Najważniejsza była klawiatura: musiała być intuicyjna (tak żebym nie musiał wyciągać urządzenia z kieszeni żeby znaleźć klawisz pauzy), a jednocześnie odporna na jakieś "samoczynne" wciskanie klawiszy w kieszeni. Postanowiłem umieścić ją razem z gniazdem słuchawek i wyłącznikiem na górnej (najkrótszej) ścianie obudowy; pozwoli to na bezwzrokowe obsługiwanie czytaka, a jednocześnie jest nikłe prawdopodobieństwo że klawisz sam się wciśnie. Trochę musiałem pokombinować z ilością klawiszy (początkowo miało ich być 13, ale po ograniczeniu do 9 okazało się, że wszystkie potrzebne funkcje są dostępne). Trochę kombinowania - i wyszło mi coś takiego: Dla porównania wielkości - moje pudełko na papierosy. Jest to oczywiście tylko próbny wydruk, ale wszystkie klawisze są wlutowane do płytki, a gniazdo słuchawek jest już na swoim miejscu. Drugą niemniej ważną sprawą był rozmiar aplikacji. Tego się obawiałem najbardziej - bo o ile tworząc microlenę mogłem sobie pozwolić na dość duże uproszczenia z uwagi na przewidywalność stosunkowo krótkich komunikatów (vide "poziomica") - o tyle tutaj musiałem zastosować pełne słowniki i wzorce rozpoznawania zwrotów. Dodatkowo microlena nie miała modułu rozpoznawania czasowników - tu musiałem go stworzyć praktycznie od nowa (wersja pecetowa korzysta albo z Morfologika, albo z wbudowanego kilkunastomegabajtowego słownika czasowników). I tu niespodzianka - wszystkie dane potrzebne do przetworzenia tekstu z książki na zapis fonetyczny zmieściły się w ok. 800 kB. Co prawda analizator morfologiczny nie jest tak dokładny jak w wersji PC, ale wystarczający aby nie było rażących błędów prozodii. Przynajmniej słuchając przez pół godziny przygód Anastazji Kamieńskiej nie zauważyłem błędów (poza kompletnie popsutą odmianą liczebników, ale to kwestia błędów w programie, a nie niewystarczających danych). Tak więc testowa aplikacja, zawierająca prowizoryczny serwer www (do uploadu i ogólnie manipulowania "księgozbiorem") oraz syntezator ma ok. 1.8 MB. Ponieważ nie przewiduję jakichś "flashożernych" procedur powinienem zejść poniżej 3 MB. Biorąc pod uwagę zajmujące nieco ponad 5 MB próbki głosu potrzebne Mbroli do syntezy - powinienem móc połowę z 16 MB pozostawić na FatFS. Opiszę jeszcze klawiaturę urządzenia (w trybie odtwarzania): Klawisze po lewej stronie (piątka): dwa klawisze regulacji głośności klawisz pauzy dwa klawisze regulacji prędkości Klawisze po prawej stronie (romb) która godzina/stan baterii (krótkie lub długie wciśnięcie) dwa klawisze przeskoku o zdanie/akapit w tył lub do przodu gdzie jestem? (tytuł, rozdział, akapit) W trybie pauzy można przeskoczyć o akapit lub rozdział lub (poprzez długie naciśnięcie klawisza "pauza") przejść do stanu "stop" (tu jeszcze nie mam opracowanego znaczenia klawiszy). Ponieważ urządzenie będzie miało wbudowany zegarek - wybrałem moduł zawierający pamięć EEPROM, w której mam zamiar trzymać zarówno wszystkie ustawienia programu, jak i informacje o aktualnie czytanej książce (rozdział/akapit/offset). Cóż - zobaczymy co będzie dalej 🙂 Na pewno opiszę efekty moich bojów z wbudowanymi w ROM funkcjami kompresji/dekompresji, muszę tylko doprowadzić ten fragment kodu do postaci umożliwiającej publiczne pokazanie go bez narażania się na inwektywy oraz skrobnąć parę słów opisu typu "dlaczego tak a nie inaczej". Aha: program jest pisany pod Arduino, tak że być może ktoś wykorzysta jakieś jego fragmenty. Postaram się publikować co ciekawsze kawałki. Jeśli ktoś miałby jakieś sugestie - jestem bardzo ciekaw, bo na tym etapie mogę jeszcze dużo zmienić. Stay tuned! -
Opisywałem kiedyś takie małe "coś" podłączone do RPi, które pełniło rolę dodatkowych klawiszy i LED do Octoprinta. To coś działało sobie bez problemu przez parę lat, okazało się niesamowicie przydatne, i pewnie bym nie wtykał palców do czegoś co działa gdyby bnie jeden drobiazg: potrzebowałem RPi w wersji co najmniej 3b. Jako że zakup RPi to na chwilę obecną temat raczej na opowiadanie SF, postanowiłem wyjąć z drukarki 3b+ i w jego miejsce podłączyć terminal Wyse.Miałem co prawda jeden "luźny" Zero W, ale ten podobno kaszle już przy prostym drukowaniu, a obsługa dwóch drukarek jednocześnie jest raczej poza jego możliwościami... Zainstalowałem Debiana, Octoprinta, skonfigurowałęm - ruszyło od strzału. Tylko problem: to swoje urządzenie podłączałem do GPIO, a terminal takowego nie posiada... Postanowiłem więc lekko przerobić program i zrobić nowe urządzenie. Po przeszukaniu szuflady okazało się, że mam do dyspozycji: Arduino Pro Mini (co prawda z upalonym jednym pinem, ale to akurat mały problem) Konwerter USB/UART na kabelku (coś takiego), który leżał sobie parę lat nieużywany Dwa wyświetlacze 4x7seg (z czego jeden okazał się bezużyteczny, bo nie wiem czemu nie chciał współpracować z Arduino, mimo że z ESP nie miał problemów) No i oczywiście jakieś pstryczki. Postanowiłem więc zagospodarować Arduino i konwerter. Na początek oczywiście konfiguracja konieczna do działania całości. Ponieważ obie drukarki mam na CH340, nusiałem trochę pokombinować z rozróżnianiem. Na szczęście zrobiłem to już wcześniej, tak że wystarczyło dodanie dwóch linijek do reguł udeva: ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idProduct}=="7523", ATTRS{idVendor}=="1a86", ATTRS{bcdDevice}=="0260", RUN+="/bin/systemctl kill -s USR1 watchprinter", SYMLINK+="ttyUSB98" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idProduct}=="7523", ATTRS{idVendor}=="1a86", ATTRS{bcdDevice}=="0254", RUN+="/bin/systemctl kill -s USR2 watchprinter", SYMLINK+="ttyUSB99" przy czym demon watchprinter (służący do poinformowania octoprinta, że drukarka została włączona) był prawie taki sam, jak poprzednio, z tą różnicą, że łączył się z jedną z dwóch instancji octoprinta. Ogólnie urządzenie wyszło mi nawet całkiem ładnie (przepraszam za jakość zdjęcia, ale moja komórka nie chciała mi złapać ostrości przy wyświetlaczu świecącym prosto w obiektyw). Przy okazji wyszło na to, że wystarczy mi jeden demon z programem (w starej wersji miałem dwa, jeden sterował diodami, drugi przyjmował polecenia od klawiszy). Ponieważ wyświetlacz daje dużo więcej możliwości, postanowiłem wyświetlić jakieś sensowne komunikaty: nc -- brak połączenia z demonem -- -- drukarka wyłączona IDLE - drukarka włączona, bezczynna HEAT - grzanie stołu/hontendu PAUS - wydruk wstrzymany (np. ręczna zmiana koloru filamentu) Cncl - wydruk anulowany Przy drukowaniu naprzemiennie wyświetlają się pozostały czas i procent wydruku. Klawisze realizują bardzo proste funkcje: PAU - spauzowanie wydruku PAU (long press) - wyłączenie silników RUN - wznowienie wydruku RUN (long press) - podłączenie drukarki do octoprinta (np. po restarcie octoprinta, gdy drukarka jest włączona). Załączam kody zarówno demonów watchprinter i octan, jak i szkic dla Arduino: octan.zip Jedna uwaga: co prawda urządzenie miało obsługiwać dwa wyświetlacze i cztery klawisze, ale z uwagi na posiadanie jednego sprawnego wyświetlacza część kodu pozostała w strefie pobożnych życzeń. Mam nadzieję jednak, że jeśli ktoś będzie chciał coś podobnego zrobić nie będzie mu to przeszkadzać (albo skontaktuje się z informacją, że bez wersji na dwie drukarki życie mu niemiłe i muszę brakującą część kodu dopisać) 🙂 Schematu nie podaję - miejsca podłączenia dwóch klawiszy i wyświetlacza można określić na podstawie pliku .ino (a do tego sprowadza się całość). Ogólnie mogę powiedzieć, że na Wyse Zx0D (2 GB RAM, 16 GB SDD) chodzi to lepiej niż na RPi (który miał czasami problemy z dogadaniem się z drukarką z przyczyny takiej, że miał problemy).
-
Dzisiaj znów coś software-only: biblioteczka do prostej komunikacji UDP, taka po prostu konsola udp. Działa na obu ESP. Na pececie do komunikacji można użyć netcata (Linux, cygwin, pewnie Mac też), załączonego programu ardumon.py (Linux), i prawdopodobnie Ncat (Windows, nie mam jak sprawdzić). Biblioteczka jeszcze nie skończona, ale obiecałem koledze @SOYER że wrzucę 🙂 Można zacząć testować ESPUdpConsole.zip - feedback mile widziany.
-
Witam Pisze ponieważ nie mogę poradzić sobie z błędem który dostaje podczas podłączania modułu bluetooth XM-15. Przeglądałem strony w poszukiwaniu jakieś pomocy nie udało mi się tego niestety znaleźć. Jestem nowy wiec odrazu rzuciłem się na głęboka wodę nie sprawdzając tego moduły. Konfiguracja polegała na tym że podłączyłem moduł do arduino i działało to ok. Podczas pisania programów miałem problem z uruchomieniem monitora portu szeregowego. Błąd mówił ze port jest zajęty. Zacząłem szukać po internecie co to może być i znalazłem ,że może to być poprostu złe dobrana prędkość. Więc spróbowałem ja zmieniać na 9600. Na forum jest pokazane jak zrobić to z modelem HC za pomocą polecenia AT. Napisane jest tam ze po wpisaniu AT powinno wyskoczyć " AT ok ". U mnie wyskakuje " Witaj AT ! ", pisałem jakiś prosty program który miał właśnie tak dziać, że pisze coś i on ma wyświetlać Witaj + "coś "+ !. Teraz napisałem prosty program aby wgl sprawdzić czy jakoś ten moduł mogę podłączyć i dostaje błąd problemu z wgrywaniem na płytkę. Wygląda on tak : avrdude: Version 6.3-20171130 Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/ Copyright (c) 2007-2014 Joerg Wunsch System wide configuration file is "C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.19.0_x86__mdqgnx93n4wtt\hardware\tools\avr/etc/avrdude.conf" Using Port : COM4 Using Programmer : arduino Overriding Baud Rate : 115200 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0xe2 avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0xe2 avrdude done. Thank you. Problem z wgrywaniem na płytkę. Program który wgrywam jest następujący : int data; void setup() { // put your setup code here, to run once: Serial.begin(115200); } void loop() { // put your main code here, to run repeatedly: data=Serial.read(); Serial.println(data); delay(200); } Jeśli odepnę wejścia TX, RX program działa normalnie i nie żadnego problemu. Po podłączeniu modułu tylko do zasilania i uruchomieniu terminala na telefonie po wpisaniu polecenie AT dostaje jakieś znaczki których nie można przeczytać. Używam Arduino Uno. Z góry przepraszam jeśli coś namieszałem jestem początkującym i to mój pierwszy problem którego nie mogę przejść. Proszę o pomoc
-
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:
-
Witam Mam pytanie odnośnie doboru części do robota. Sytuacja wygląda tak mam zakupione podwodzie do robota z kołami mecanum, silnikami DC z przekładnią jeden do 1:48, Napięcie zasilania 3V-6V, Pobór prądu 170 mA. W robocie mam zamiar użyć Arduino i sterować nim z telefonu przez Bluetooth. Pytanie pierwsze: Czy jeśli chce użyć sterowników L298N do sterowania silnikami to potrzebuję jakiś przetwornic step down, żeby nie spalić silników i sterowników, jeżeli wymagane źródło napięcia okazałoby się większe niż 6V? Pytanie drugie: Jakiego źródła zasilania najlepiej użyć do tego przedsięwzięcia? Pytanie Trzecie: Jakiego modułu Bluetooth użyć do tego najlepiej (chodzi mi o to żeby sterować silnikami z telefonu)? Widziałem że większość projektów z Arduino, bo korzysta z HC-05. Czy HC-05 to dobory wybór dla laika?
-
Bezprzewodowy czujnik poziomu węgla do zasobnika na ekogroszek
romeok01 opublikował temat w Projekty - DIY
Budowa tego projektu zaczęła się od tego, że znajomy zapytał, czy bym czegoś nie wymyślił, ponieważ on posiada w domu piec na ekogroszek z zasobnikiem na węgiel i czasem zapomina dosypywać węgla i gaśnie mu w piecu. Wykonałem więc nadajnik z ultradźwiękowym czujnikiem odległości HC-SR04 , który przekazuje dane do odbiornika bezprzewodowo za pomocą modułu nRF24L01. Gotowy odbiornik i nadajnik wygląda tak, jak na zdjęciu niżej. Do budowy wykorzystałem: Dwie sztuki Arduino Pro Mini 328 - 5V/16MHz Dwie sztuki moduł radiowy nRF24L01 Ultradźwiękowy czujnik odległości HC-SR04 Buzzer z generatorem 5V 12mm Zestaw diod LED 5mm Rezystory 100 ohm, 110 ohm i 190 ohm Dwie sztuki Stabilizator LDO 3,3V Dwie sztuki Kondensator elektrolityczny 10uF/50V Dwie sztuki Zasilacz impulsowy 5V / 1,2A Obudowy plastikowe Całość zmontowałem na płytkach z OSH Park MySensor 3.3V Pro Mini or 5V Pro Mini Diody LED i buzzer zamontowałem na płytce uniwersalnej. Schemat nadajnika. Schemat odbiornika. Kod programu Arduino nadajnika. #include <SPI.h> #include "RF24.h" int msg[1]; const uint64_t pipe = 0xF0F0F0F0A1LL; RF24 radio(9,10); #define trigPin 3 #define echoPin 4 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 radio.begin(); radio.openWritingPipe(pipe); radio.setPALevel(RF24_PA_MAX); //Maxymalna moc nadajnika } void loop(){ long czas, dystans; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); czas = pulseIn(echoPin, HIGH); dystans = czas / 58; Serial.print(dystans); Serial.println(" cm"); msg[0] = dystans; radio.write(msg, 1); // Wysylanie wartosci ze zmiennej msg delay(500); } Kod programu do odbiornika. #include <SPI.h> #include "RF24.h" const uint64_t pipe = 0xF0F0F0F0A1LL; RF24 radio(9,10); int msg[1]; void setup(){ //Serial.begin (9600); pinMode(3, OUTPUT); //led czerwona pinMode(4, OUTPUT); //led zolta pinMode(5, OUTPUT); //led pierwsza zielona pinMode(6, OUTPUT); //led druga zielona pinMode(7, OUTPUT); //led trzecia zielona pinMode(8, OUTPUT); // buzer radio.begin(); radio.openReadingPipe(1,pipe); radio.startListening(); } void loop(){ if(radio.available()){ radio.read(msg, 1); Serial.print(msg[0]); Serial.println(" cm"); if (msg[0] >= 57) { //odlegolsc max kiedy wlacza sie buzer digitalWrite(3, HIGH); digitalWrite(4, LOW); digitalWrite(5, LOW); digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(8, HIGH); delay(5000); digitalWrite(3, HIGH); digitalWrite(4, LOW); digitalWrite(5, LOW); digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(8, LOW); delay(1800000); } else { digitalWrite(3, HIGH); digitalWrite(4, HIGH); digitalWrite(5, HIGH); digitalWrite(6, HIGH); digitalWrite(7, HIGH); digitalWrite(8, LOW); } if (msg[0] >= 43 && msg[0] <57) { digitalWrite(3, HIGH); digitalWrite(4, HIGH); digitalWrite(5, LOW); digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(8, LOW); } if (msg[0] >= 29 && msg[0] < 43) { digitalWrite(3, HIGH); digitalWrite(4, HIGH); digitalWrite(5, HIGH); digitalWrite(6, LOW); digitalWrite(7, LOW); digitalWrite(8, LOW); } if (msg[0] >= 15 && msg[0] < 29) { digitalWrite(3, HIGH); digitalWrite(4, HIGH); digitalWrite(5, HIGH); digitalWrite(6, HIGH); digitalWrite(7, LOW); digitalWrite(8, LOW); } if (msg[0] >= 15 && msg[0] < 2) { digitalWrite(3, HIGH); digitalWrite(4, HIGH); digitalWrite(5, HIGH); digitalWrite(6, HIGH); digitalWrite(7, HIGH); digitalWrite(8, LOW); } } delay(500); } Kod programu odbiornika, jest napisany tak, że gdy poziom węgla spadnie do 57 cm od góry, włącza się buzer na 5 sekund i świeci czerwona dioda i jeżeli nie dosypiemy węgla, buzer włączy się znowu za pół godziny na 5 sekund, po dosypaniu węgla trzeba nacisnąć przycisk reset, który wyprowadziłem za pomocą przycisku na obudowie lub odczekać pół godziny. Zasobnik na węgiel wygląda tak. Zmontowany nadajnik z ultradźwiękowym czujnikiem odległości HC-SR04. Nadajnik jest zamontowany na górze metalowego zasobnika na węgiel, przed montażem zostały wywiercone 2 otwory w zasobniku, tak aby pasowały wystające okrągłe elementy czujnika HC-SR04. Zmontowany układ na płytce MySensors dostępnej w OSH Park, długość to około 10 cm. Ponieważ zastosowałem 5 diod, które informują o stanie węgla, to 57 cm podzieliłem na 4, co daje około 14 cm i gdy poziom węgla spadnie o 14 cm gasną kolejne diody, aż do 57 cm i wtedy świeci się czerwona dioda i włącza buzer na 5 sekund. Program możemy dowolnie modyfikować, aby dostosować do wysokości pojemnika na węgiel. Działanie całości widać na poniższym filmie. Całość działa już 2 lata bez awarii i na czas dosypywania ekogroszku, nadajnik jest zdejmowany i czasem przedmuchany z pyłu. -
Moje oświetlenie biurka (taśma ws2812b) mam podpięte według schematu jak wyżej do Arduino UNO (a raczej jakiś klon) + zewnętrzny zasilacz. Płytka jest podłączona przez kabel USB do komputera w celu sterowania oświetleniem przy pomocy Prismatik. Mam taki problem, że po wyłączeniu PC na porcie USB od Arduino na pinie Vcc mam cały czas +5V które idzie z zasilacza przez co na wszystkich portach USB komputera jest napięcie co powoduje podświetlanie się klawiatury, diody led na DACu itd., wiadomo o co chodzi. Czy można to napięcie jakoś odseparować? Na poprzednim komputerze pojawienie się tego napięcia powodowało dziwne zachowanie komputera, np. po wciśnięciu jakiegoś klawisza na klawiaturze potrafił się on zawiesić w systemie i wciskać przez kilka sekund lub nagłe spadki wydajności komputera (przycięcia w grach). Pomagało odłączenie zasilacza LED. Na nowym komputerze jest tylko problem ze świecącymi się diodami ale nie wiem czy to jest bezpieczne dla komputera skoro na starym działy się takie dziwne rzeczy.
-
Witam, jestem nowy na forum więc liczę na wyrozumiałość 🙂 Ogólnie chciałbym zacząć swoją przygodę z Arduino i mam następujace pytanie: Czy to co mam w koszyku (załącznik) jest zgodne z pierwszą częścią kursu (tzn. czy zawiera wszystko co potrzebne i pasuje to wszystko do siebie). Wiem, że pytanie należy do tych bardziej głupich no ale po prostu się nie znam (jeszcze) Pozdrawiam 😄
- 1 odpowiedź
-
Mam problem z dwoma silnikami pochodzącymi z drona. Silniki szczotkowe 3.7V, 0.1A połączone z kontrolerem L293D. Źródło zasilania 12V (8x AA1.5V). Moim celem było sterowanie prędkością silników za pomocą komunikacji bluetooth (zasilany z arduino 5v). Sam moduł udało się skutecznie podłączyć bez większych przesekód, lecz sterowanie silnikami okazało się już przeszkodą. Po podłączeniu do kontrolera dwóch silników na wyjściach zmierzyłem jakieś 2.5V przy PWM 255. Gdy odłączyłem jeden silnik było trochę lepiej lecz nadal nie było 3.7V. Kontroler został podłączany zgodnie ze schematem (kilka razy). Co wtakim wypadku trzeba poczynić? 2. Dodatkowe pytanie Przy okazji bawienia się silnikami wpadłem na pomysł zasilenia silnika przez stabilizator liniowy LM7805 po prawidłowym podłączeniu wszystkich elementów pomiar z silnika wskazywał 0.6V. Co się stało z resztą napięcia i co trzeba zrobić by otrzymać 3.7V?
-
Witam, od jakiegoś czasu próbuję zrobić generator sygnałów. Taki prosty generatorek do sygnału prostokątnego, trójkątnego i sinusoidalnego. Moim problemem jest załączenie bibliotek do programu aby ten działał poprawnie. Robię ten generator z poradnika, no dokładnie z dwóch, mianowicie poradnika https://www.instructables.com/DIY-FunctionWaveform-Generator/ oraz https://www.allaboutcircuits.com/projects/how-to-DIY-waveform-generator-analog-devices-ad9833-ATmega328p/. Ale dokładnie chce się skupić na tym pierwszym. Jest tam link do pobrania z kodem do arduino oraz 3 biblioteki(zamieszczę ten plik w załączniku). Od generatora przebiegów, od wyświetlacza LCD oraz od enkodera. I nie wiem jak je wgrać, bo chyba to powinienem zrobić. Pomyślałem wiec że z GitHuba pobiorę. W sumie to tylko dwie biblioteki musiałem dodać bo LCD już miałem. Jednak to nic nie dało dalej wyświetla mi się pewien błąd(zrobię screena i też dam w załączniku).Z takich innych rzeczy dodam jeszcze że kiedy otwieram plik wyskakuje mi dziwna ikonka, gdy kliknę "ok" program się otwiera i otwiera się też drugie dziwne okienko, gdy znów kliknę pole zaznaczone na niebiesko to okno programowania wydaje się działać normalnie. I cóż męczy mnie to strasznie bo ja tu chciałem sprawdzić program ewentualnie przerobić go pod mojego LCD(bo mam trochę innego) a tu takie coś. Będę niezmiernie wdzięczny za pomoc FXZ5055K06ZGL9U (4).rar
-
Nie mogę wgrać żadnego programu na płytkę. Najpierw ładuje się bardzo długo a potem wywala błąd avrdude: stk500_recv(): programmer is not responding i temu podobne zaczynające się na avrdude: . Wszystko szło bardzo dobrze robiłem już drugą część kursu arduino aż pewnego dnia nic nie mogę wgrać. próbowałem już zmiany kabla, prze instalowanie arduino, tak port jest wybrany dobry, uruchomienie arduino jako administrator i uruchomienie portu szeregowego (zawiesiło mi komputer i nie mogę teraz zamknąć tego okienka), przytrzymywanie przycisku reset podczas wgrywania na płytkę(zdaje się że wywaliło wtedy trochę inny błąd) mam podejrzenia co do botloadera ale na razie nie mam odpowiedniego kabla żeby wypalić na nowo proszę o pomoc bo zbliża się turniej robotyki a ja jestem z nie działającą płytką😧
- 54 odpowiedzi
-
- Arduino
- Arduino Uno
- (i 3 więcej)
-
Hej! Jeszcze jestem zielony, ale walczę. 😉 Moja wiedza to na razie kurs Arduino I i coś tam echem o millis. Jestem w trakcie modyfikacji robota z forbotowego kursu, oprócz zmian w budowie, wprowadzam też zmiany w programie. Jednym z założeń jest eliminacja wstrzymujących program delayów. Aktualnie pracuję nad sekcją jazdy autonomicznej. Popełniłem działający program z millisami, ale kolega @ethanak wskazał mi, że no nie do końca. 😉 Zatem, na początku kody z kursu (żeby w jednym miejscu było): Kontaktowe wykrywania/omijanie przeszkód: if (digitalRead(L_SIDE_SENSOR) == LOW) { //Jesli przeszkoda po lewej stronie //Jedz wstecz i wydawaj dzwiek leftMotor(-40); rightMotor(-40); digitalWrite(BUZZER, 1); delay(800); //Obrot w miejscu w prawo leftMotor(40); rightMotor(-40); digitalWrite(BUZZER, 0); delay(140); //Koniec warunku wracamy do jazdy prosto } if (digitalRead(R_SIDE_SENSOR) == LOW) { //Jesli przeszkoda po prawej stronie //Jedz wstecz i wydawaj dzwiek leftMotor(-40); rightMotor(-40); digitalWrite(BUZZER, 1); delay(800); //Obrot w miejscu w lewo leftMotor(-40); rightMotor(40); digitalWrite(BUZZER, 0); delay(140); //Koniec warunku wracamy do jazdy prosto } Wykrywanie przeszkód czujnikiem ultradźwiękowym: void loop() { //Czy wykryto przeszkode w zakresie 0-40 cm if (zmierzOdleglosc() > 40) { leftMotor(40); //Jesli nie, to jedz prosto rightMotor(40); } else { //Jesli przeszkoda stopMotors(); //Zatrzymaj robota serwo.write(20); //Skrec czujnikiem w prawo delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji //Sprawdz, czy po prawej stronie jest przeszkoda if (zmierzOdleglosc() > 40) { //Jesli jest pusto leftMotor(40); rightMotor(-40); delay(400); //Obracaj w prawo przez 400 ms } else { //Jeśli po prawej jest przeszkoda serwo.write(160); //Obroc czujnik w lewo delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji //Sprawdz, czy po lowej stronie jest przeszkoda if (zmierzOdleglosc() > 40) { //Jesli jest pusto leftMotor(-40); rightMotor(40); delay(400); //Obracaj w lewo przez 400 ms } else { //Jesli z przodu, z lewej i prawej jest przeszkoda digitalWrite(BUZZER, 1); delay(500); digitalWrite(BUZZER, 0); //Daj sygnal buzzerem } } //Po sprawdzeniu przeszkod po bokach //Ustaw czujnik prosto serwo.write(90); } //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej delay(100); } Aktualnie popełniłem taką funkcję, łączącą wykrywanie przeszkód przez krańcówki i sonar: void jazdaAuto() { //Funkcja jazdy autonomicznej ekspander.digitalWrite(LEDjazda, 1); unsigned long kontakt = 0; //Zmienne przechowująca czas startu unsigned long przeszkoda = 0; if (digitalRead(lewySensor) == LOW) { //Jeżeli przeszkoda po lewej zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms lewySilnik(-80); //Cofnij kawałek prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Cofaj przez 800 ms lewySilnik(80); //Skręć w prawo prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Skręcaj przez 800 ms zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms } if (digitalRead(prawySensor) == LOW) { //Jeżeli przeszkoda po prawej zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms lewySilnik(-80); //Cofnij kawałek prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Cofaj przez 800 ms lewySilnik(-80); //Skręć w lewo prawySilnik(80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Skręć w lewo przez 800 ms zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 milisekund } if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(90); // To jedź prosto prawySilnik(90); } else { // Jeżeli wykryłeś przeszkodę serwo.attach(SERWO_PIN); // Podłącz serwo zatrzymajSilniki(); serwo.write(700); // Skręć czujnikiem w prawo przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; //Poczekaj 800 ms if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(70); // Skręcaj w prawo prawySilnik(-70); serwo.write(1400); // Ustaw serwo do pozycji domyślnej przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; // Skręcaj przez 800 ms serwo.detach(); // Odłącz serwo } else { // Jeżeli wykryłeś przeszkodę serwo.write(2100); // Skręć czujnikiem w lewo przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; //Poczekaj 800 ms if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(-70); // Skręcaj w lewo prawySilnik(70); serwo.write(1400); // Ustaw serwo domyślnie przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; // Skręcaj przez 800 ms serwo.detach(); // Odłącz serwo } else { // Jeżeli z każdej strony jest przeszkoda serwo.write(1400); // Ustaw serwo domyślnie digitalWrite(BUZZER, 1); // Daj sygnał buzzerem przeszkoda = millis(); while(millis() - przeszkoda < 500) {}; //Buzzer włączony przez 500 ms digitalWrite(BUZZER, 0); //Wyłącz buzzer serwo.detach(); //Odłącz serwo } } } przeszkoda = millis(); while (millis()-przeszkoda < 100) {} //Opóźnienie 100 ms dla wykrywania przeszkód }
-
Od kilku dni próbuję zrobić projekt który używając diody IR po prostu wyśle dany kod i wyłączy telewizor. Od razu uprzedzam - jestem totalnie zielony w arduino, a szczególnie w podczerwień, ale bardzo zależy mi na tym projekcie. A więc korzystając z różnych poradników w necie odczytałem za pomocą odbiornika IR kod z przycisku off na pilocie. Jest to u mnie F708FB04. Chciałbym ten kod po prostu wysłać przez diodę IR do telewizora aby go wyłączyć. Wstawiam tu kod z którym próbowałem: #include <IRremote.h> IRsend irsend; void setup() { Serial.begin(9600); } void loop() { delay(5000); //Power// irsend.sendLG(0xF40BFB04, 32); //Power Code Serial.println("Power off"); delay(2000); } Telewizor najzwyczajniej nie reaguje, załączam zrzut schematu według którego podłączyłem diodę, rezystor to 100 ohm (nie miałem 100 więc połączyłem równolegle 2 x 200ohm) Proszę o pomoc, podejrzewam że problem jest po stronie kodu.
-
Cześć, z zawodu jestem alpinistą przemysłowym i pracując na konstrukcji (ścierając kurz ) z racji już średniego wieku stwierdziłem, że będzie mi łatwiej, przyjemniej i ciekawiej jeżeli pomogę sobie jakimś pojazdem zdalnie sterowanym :). W sprawach elektroniki jestem raczej zielony, ale zacząłem i w miarę upływu czasu okazuje się, że można, i jest jakiś mglista szansa, że mi się uda :). Mózgiem operacji jest płytka PWM UNO, pojazd gąsienicowy z 2-ma silnikami 12V(chińskimi-brak jakichkolwiek informacji o prądzie maksymalnym). Sterownik silników to L293d, moduł bluetooth to HC-05. Sterowanie z komórki. Pojazd ma się poruszać po wąskiej konstrukcji ~20cm szerokości, która nachylona jest pod kątem +-45 stopni do poziomu, dlatego używam też magnesu pod spodem oddalonego o jakieś 5 mm od "gruntu". Magnes powoduje, że będę potrzebował sporej mocy, żeby poruszać się łazikiem. I tak rzeczy, o których wiem, że nie są ok to : 1. Sterownik silników powinien być ( w mojej ocenie ) mocniejszy-choć ten się jeszcze nie spalił, ale nie chcę ryzykować i chciałbym kupić inny ( pytanie jaki?) 2. Moduł bluetooth powinien przechodzić przez około 3,5V, u mnie jest 5V, ale nic się nie dzieje. 3. Kod jest bardzo toporny i mi się nie podoba 🙂 ale póki mi działa też się tym nie przejmuję. Nie radzę sobie z : Sytuacją, w której z jakiegoś powodu tracę połączenie z łazikiem, nie chcę żeby stanął i się zrestartował. Chciałbym też zamontować prosty wskaźnik (czerwoną diodę) do sygnalizacji spadku napięcia poniżej pewnego progu (potencjometr dioda i rezystor wystarczą?) Zasilanie- póki co 2 akumulatory połączone szeregowo 7,4V x 2. Na jednym też działa. Chciałbym nie przesadzić, wiem że jest spadek napięcia na sterowniku ale nie wiem do jakiego napięcia mogę dojść (pewnie już przesadziłem :)) Wszelkie informację o kardynalnych i nie tylko, błędach oczywiście mile widziane- pamiętajcie także, że jestem
-
Cześć, niedawno zacząłem budowę łazika z napędem na 6 kół (każde z nich skrętne, stąd 6 serw), całość będzie drukowana w 3D i sterowana przez Arduino Uno. Podczas projektowania obwodu napotkałem problem dotyczący zasilania, poniżej wklejam schemat (bez połączenia przewodów sygnałowych do L298N). Silniki to mocniejsze odpowiedniki tych małych żółtych silników. Producent podaje napięcie 3V-6V (sam myślałem żeby je troszkę zwiększyć, ponieważ w moim układzie będą dość mocno obciążone) a pobór prądu to (przy zatrzymanym wale) do 1,2A. Dlatego wybrałem takie sterowniki. Serwa to Tower Pro MG90S (są to serwa typu micro). A do sterowania całością planuję użyć Arduino Uno. I tu pojawia się problem ponieważ L298N mają spadek napięcia 2V. Więc akumulator/bateria 6V odpada. Myślałem nad tym żeby serwa osobno były zasilane z 4x AA. A silniki z 6x AA. Tylko czy z takich 6 baterii można pobrać max ok. 7A. A z 4 do ok. 5. Do silników można było by użyć też jakiś ogniw, takich jak np. w bateriach do laptopów. Pozostaje jeszcze zasilanie Arduino. Jak wy byście to rozwiązali? Mnie najbardziej przekonują baterie. Z góry dziękuje za pomoc Filip
-
Podłączenie silnika krokowego i wyświetlacza LCD do Arduino
JakubKozak opublikował temat w Arduino i ESP
Mam pytanie dotyczące podłączenia wyświetlacza LCD i silnika krokowego. Czy mogę zasilać wyświetlacz LCD z 5v a silnik krokowy z Vin? Czy lepiej podłączyć baterie bezpośrednio do płytki stykowej a wyświetlacz LCD zasilać z portu usb? Nie do końca rozumiem jak działa Vin. -
Jakiś czas temu zakupiłem sobie ESP32 CAM, niestety nie umiałem dla niej znaleźć jakiegoś sensownego zastosowania. Przeleżała z pół roku a może i więcej, aż wpadłem na pomysł zrobienia foto-pułapki. I tak oto powstała: Po mojej posiadłości często biegają dzikie zwierzęta takie jak: sarny, bażanty, dziki i zające. Te ostatnie to raczej szkodniki ale lecimy z tematem dalej. Założenia: Zapis zdjęć na karcie SD Wysyłka zdjęć na FTP Wysyłka zdjęć na maila jakiś czujnik temperatury praca możliwie jak najdłużej z jednej baterii wspomaganej panelem PV Po ogarnięciu softu na biurku podłączeniu czujnika PIR wszystko ładnie działało. Za zasilanie odpowiada jedno ogniwo 18650, przetwornica podnosząca napięcie do 5V i mały panel PV 6V 167mA. Jak widać powyżej kamera jest przylepiona klejem dwuskładnikowym, tak by uniknąć uszkodzenia tasiemki. Wszystko zostało umieszczone w obudowie po NanoStation Loco M5. Która została dostosowana do zamontowania panelu PV, czujnika PIR oraz kamery. Poniżej etap pasowania elementów. Został również wydrukowany daszek oraz uchwyty dla szyby która osłania kamerę od deszczu. Obudowa Została dodatkowo pomalowana na czarno - ale chyba będę jej robić jakieś malowanie taktyczne, lub pójdzie w ruch “termoglut” i trzcina żeby się lepiej wtapiała w otoczenie. Pierwsze wyjście w teren i klapa, wszystkie zdjęcia były przejaśnione. Po kilku próbach okazało się że kamera potrzebuje 2s! aby dostosować czas ekspozycji, (lekka tragedia bo przy zajączkach to już go może dawno nie być w kadrze) oczywiście w warsztacie wszystko działało jak należy. Następnym nietrafionym pomysłem okazało się wysyłanie zdjęć na maila, trwa to stosunkowo długo a co za tym idzie zużycie energii jest większe, co doprowadziło do rozładowania baterii po 2 dniach. Konieczne było zrezygnowanie z wysyłki zdjęć na maila. W tej chwili kamera działa bez ładowania już 5 dni. Przykładowe zdjęcia z kamery poniżej: Trapi mnie jeszcze jeden problem mianowicie jeśli na zdjęciu jest więcej szczegółów np: cały kadr trzciny lub trawy, to obraz jest obcinany tak około 100-200px z dołu. Nie jest to chyba problem buforu w ESP bo przy kompresji ustawionej w sofcie na 10 zdjęcia zajmują 384KB jeśli zwiększę kompresje zdjęcia zajmują mniej a obraz i tak jest obcinany. Oprócz zdjęć wyzwalanych czujnikiem ruchu, procesor budzi się co 30 min wykonuje zdjęcie i wysyła je na FTP. To aby mieć pewność że bateria nie uległa rozładowaniu. A i jest jeszcze nieszczęsny czujnik temperatury DS18B20, nie było łatwo go tam upchać bo okazało się że wszystkie piny na płytce są wykorzystywane i jedyny wolny pin który mogę wykorzystać to pin serial RX, co niesie za sobą konieczność wypięcia czujnika w razie chęci przeprogramowania układu. Lista wykorzystanych elementów: ESP32-CAM AI-Thinker Przetwornica step-up 5V wraz z modułem ładowania ogniw 18650 Koszyk na ogniwo 18650 Czujnik PIR Mini panel PV 6V 167mA Antena 2.4 Ghz Podsumowując, działa aczkolwiek widać pewne ograniczenia tego układu chociażby czas jaki kamera potrzebuje na uruchomienie się. Z ciekawostek do ESP32 została podłączona zewnętrzna antena, gdzie przetestowany zasięg to około 200 m :), ale pewnie to też zasługa tego że łącze się do AP który mam wystawiony na dworze. Kodu programu pozwolę sobie w tej chwili nie udostępnić bo mam tam niezły bałagan, a jeszcze staram się uporać z obcinaniem fotek, za jakiś czas na pewno go zamieszczę.
-
Dzień dobry Nie będę zupełnie oryginalny i zrobiłem dwie stacje meteo. Chciałem poduczyć się trochę arduino i szukałem pomysłu na projekt przeglądając Botland znalazłem czujniki pyłu PM 2,5 i PM 10. Przez to, że temat smogu jest na czasie uznałem to za dobry pomysł by zweryfikować czy miejscowość w której mieszkam (wieś) jest od niego wolna. Zacząłem od kursów na Forbocie (vel wyświetlacz lcd) by załapać podstawy arduino i elektroniki. Były bardzo pomocne. Następnie chciałem przetestować niektóre czujniki i tak sprawdziłem Temperatura DS18B20 MCP9808 SHT 15 SHT 31 Wilgotność DHT 11 DHT 22 SHT 15 SHT 31 Przy wyborze też między innymi kierowałem się dokładnością pomiaru najlepiej ok 5% oraz możliwością pracy przy ujemnych temperaturach im mniej tym lepiej gdyż mrozy tu mogą sięgać -20C. Przy testowaniu tylko miałem problem z DHT11 i DHT22 - mianowicie nie podawał mi poprawnych danych (miałem obok kupny wilgotnościomierz i dane zupełnie nie pasowały do siebie ale opisałem to w innym poście na forum). Wybrałem MCP9808 gdyż uznałem, na czujnik temperatury gdyż wg moich obserwacji najlepiej się sprawdzał w różnych warunkach i wahaniach temperatury. Osobno tak samo wybrałem czujniki wilgotności tylko do tego celu tj. SHT31. Barometr widziałem, że polecany jest BMP180 więc na nim zostałem. Z programowaniem nie było problemu ze względu na biblioteki. Czujniki pyłu były małym wyzwaniem. Brak bibliotek. I śmigają na UART Trzeba operować na przykładowych kodach i rozumieć jak lecą bity. Ponadto trzeb zwracać uwagę na to że różne modele mogą mieć różny formę ramki danych przesyłanych. Przetestowałem 3 czujniki pyłu PMS5003 PMS5003 z detekcją formaldehydu Gravity Każdy z nich miał inaczej ramkę ukształtowaną. Ponadto czujniki zasilane są napięciem 5V a linia danych 3,3V Do tego należy dokupić konwerter poziomów logicznych by zadziałało to sprawnie. Do tego zestawu dokupiłem stacje meteo z wiatromierzem. Następnie chciałem aby stacja mogła być na zewnątrz i komunikować się z odbiornikiem w środku przez nRF24L01+. Warto brać moduł z zewnętrzną anteną oraz adapterem poprawia działanie modułu. Mając już na płytce w miarę temat ogarnięty chciałem najpierw testowo zrobić mobilny czujnik pyłu aby zrobić pierwsze przymiarki do lutowania i montażu. Lutowałem na płytkach prototypowych z cienkimi kablami. Nie był to dobry pomysł ale na daną chwilę dało się. Zamiast przylutowywać moduły na stałe lutowałem sloty do nich. Wolałem trochę poświęcić jakość wykonania na rzecz sytuacji w której mógłbym się pomylić. Nie mam rozlutotwnicy a standardowa lutownica i odsysacz słabo mi się sprawdzały. Specyfikacja mobilnego czujnika pyłu (główne moduły) Arduino Pro Mini 328 - 5V/16MHz SHT 15 (wilgotność i temperatura) PMS5003 (czujnik pyłu) Konwerter USB-UART FTDI FT232RL - gniazdo miniUSB (programator ew zasilanie poza bateryjne) Wyświetlacz LCD 4x20 znaków zielony Efekt był zadowalający wiec uznałem, że warto będzie spróbować wysyłać dane na stronę www. Do tego zadania zaprzęgłem malinkę z modułem nRF24L01+. Idea była taka aby: ->pomiar stacji ->wysłanie danych drogą radiową ->odebranie przez Ras Pi ->wysłanie danych na zewnętrzny bazę danych MySQL ->pobranie danych z bazy i wyświetlenie jej na stronie bazującej na wordpresie Główny problem był z liczbami zmiennoprzecinkowymi. Gdyż malinka odbiera surowe bity i nie chce ich prze konwertować na liczbę zmiennoprzecinkową. W każdym bądź razie wszelkie próby konwersji i operacji na bitach skończyły się komunikatem ze Python nie obsługuje przesunięć bitowych dla liczb zmiennoprzecinkowych. Do zastosowań domowych wystarczy mi pomiar do drugiego miejsca po przecinku (temperatura) więc po prostu każdą zmienna która miała część ułamkową mnożę na Arduino razy 100 i jak odbiorę na malince dzielę przez 100. O ile odbiór między arduino to linijka kodu to tu przy odbiorze suchej transmisji (już przy użyciu biblioteki ...... ) trzeba było bity ręcznie składać bo Arduino wysyła jedną zmienną w dwóch bajtach trzeba było używać operatorów bitowych by te bajty złączyć w jeden. Przed montażem należało wyznaczyć miejsce dla stacji. Z tego względu do stacji mobilnej dorzuciłem adapter NRF na który mogłem po prostu zamiennie testować wersje z zewnętrzną i wewnętrzną anteną. Syngał nadawał do malinki kolejne cyfry a obok miałem telefon z teamviwerem na którym patrzałem się co na konsoli wyświetliło. Jeśli był cykl 1 2 3 .... 11 12, tzn., że w miejscu w którym stałem jak nadawano cyfry 4 5 6 7 8 9 10 sygnał nie doszedł i nie należało go brać pod uwagę do montażu docelowej stacji meteo. Wiatromierz montowałem na chwycie antenowym. Średnica rur od stacji była mniejsza więc wkładając ją uzupełniłem całość pianką montażową by nie latało. Rezultat był taki, że moduł z wbudowaną anteną za oknem 3m tracił zasięg drugi miał sygnał spokojnie do ok 10m (nawet przez ściany). Po teście wysłania danych i odebrania jednej danej na wordpresie przytępiono do montażu stacji. Jej finalna konfiguracja to Arduino Pro Mini 328 - 5V/16MHz Konwerter USB-UART FTDI FT232RL - gniazdo miniUSB (programator i zasilanie) nRF24L01+ Stacja meteo dfrobot PMS5003 (czujnik pyłu) Gravity (czujnik pyłu) MCP9808 (temperatura) SHT 31 (wigotność) BMP180 (ciśnienie) Dorzuciłem dwa czujniki pyły by porównać ich działanie. Jako końcowy element została mi kwestia wyświetlenia danych na stronie www. Dzięki wtyczce do pisania skryptów php w wordpresie udało napisać moduł pobierania danych z bazy i jego wyświetlania. Wykresy były większym problemem. Darmowe wtyczki do wordpressa nie chcą pobierać danych z sql i są ciężko edytowalne preferują prace na .csv i najlepiej jakby je ręcznie przeładowywać. Finalnie użyłem do tego celu Google Charts (nota bene na których wiele darmowych wtyczek do wordpresa bazuje). Z racji, że nie jestem web-developerem było to moje pierwsze spotkanie z php oraz javascriptem na którym Google Charsty operują. Zmuszenie tego pracy odbyło się metodą prób i błędów ale efekt jest zadowalający. Mam wykresy z 24h, tygodnia i miesiąca. Problemy Kodowanie int w arduino i malince Ze względu za na sposób kodowania liczny int w pythonie ujemne wartości temperatury np -5C na arduino pokazywały na malince wartość 65531 C. Trzeba było dopisać fragment który usuwał ten błąd. Komunikacja L01+ Moduły te są bardzo wrażliwe na zmiany napięcia. Można do nich dokupić adapter do wpięcia który głównie ma stabilizator napięcia. Nawet nie zawsze on pomaga jeśli do niego pójdzie nie wystarczające napięcie. Widać to np. jak się rusza kable to migocze LED lub jest "ciut" jaśniejszy. Wtedy anteny nie mogą się dogadać. Potrafi się zdarzyć takie kuriozum, że w takiej sytuacji antena straci własny adres. Jeśli anteny nie są w stanie się dogadać należy bezwzględnie sprawdzić pewność zasilania. Błąd wysłania danych SQL Czasami kod w malince się zawiesi w oczekiwaniu na wysłanie danych do serwera SQL. Trudno mi powiedzieć jak dobrze temu zaradzić. Występuję to przy dłuższej pracy (tydzień, miesiąc) aczkolwiek jedyne co mi przychodzi do głowy to ustawić na Raspianie auto-restart systemu co 24h. Wycinanie dziur w plastikowej obudowie Próbowałem wycinać szlifierką modelarską ale zawsze plastik się topił. Po szperaniu w necie rozwiązaniem są albo nożyki do plastiku albo wycinarka włosowa do plastiku ale nie udało mi się tego przetestować. Niestety wycięcia wyglądają mało estetycznie ale trudno. Google Charts Przesyłanie danych z PHP do JavaScript tak aby Google bylo problemem. Wykresy nie łykną dowolnego formatu danych i nie wyświetlą błędy jeśli uznają, że format im nie pasuje. Co mógłbym zrobić inaczej? Gdybym miał robić update to zamiast komunikacji radiowej do malinki wydaje mi się bardziej rozsądne pójście w wyposażenie arduino w WIFI i wysyłanie bezpośrednio na serwer. Nie uczyniłem tak ze względu na to pisanie kodu komunikacji Arduino WIFI nie jest to pare linijek. Plus też kod do wysyłania do SQL który znalazłem też pewnie by zawierał trochę kodu. Więcej dłubania ale efekt powinien być bardziej zadowalający. Plany na przyszłość Jedyne co chce na dniach zrobić to poduczyć się Eagla i przenieść całość na płytkę drukowaną i zamówić ją np. JLCPCB. Wtedy wypnę moduły z tamtych płytek i przypnę je do zamówionej. Reasumując Stacja działa już ok 6 miesięcy. Bez problemowo. Jak widać na wykresie z ostatniego miesiąca (tj. 26.12.2018 - 25.12.2019), że normy dla smogu w mojej wsi były w paru dniach przekroczone (a mieszkam w centrum pomorskiego bez kopalni, ciężkiego przemysłu wokół). Gdyby dobrze opisać każdy etap pracy można by z tego zrobić osobny kurs 🙂 Poniżej kody źródłowe Arduino Ras PI Wordpress pobieranie suchych danych Wordpress pobieranie danych i osadzenie ich na Google Charts //Autor Bartosz Jakusz. Można wykorzystywać komercyjnie. Proszę tylko podać autora kodu #include <math.h> #include <Wire.h> #include <Arduino.h> #include <Adafruit_BMP085.h> #include <SoftwareSerial.h> #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include "Adafruit_SHT31.h" #include "Adafruit_MCP9808.h"7 #define dataSize 16 #define PMS5003BufferSize 40 #define dustGravityBufferSize 32 Adafruit_BMP085 bmp; Adafruit_MCP9808 tempsensor = Adafruit_MCP9808(); Adafruit_SHT31 sht31 = Adafruit_SHT31(); // software serial #2: RX = digital pin 8, TX = digital pin 9 SoftwareSerial Serial1(4, 5); SoftwareSerial Serial3(8, 9); SoftwareSerial Serial2(3, 2); RF24 radio(10, 14); // CE, CSN const byte address[6] = "00001"; char col; unsigned int dustSensor25 = 0,dustSensor10 = 0; unsigned int PMS = 0,PM10 = 0, formalin = 0,CR1 = 0,CR2 = 0; float PMSTemp = 0, PMSHigro = 0; bool readErr = false, readErr25 = false; int dustSensorReadError = 0; unsigned int higherBit = 0, LowerBit = 0; unsigned char buffer_RTT[40]={}; //Serial buffer; Received Data char meteoDatabuffer[35]; int measurments [dataSize]; void readPMS(); void readPM25(); void readDustSensorUARTData(SoftwareSerial S, unsigned char *bufferData, int bufferSize); unsigned int mergeBitsToInt(unsigned char *bufferData, int startBit, int stopBit); void clearBuffer(unsigned char *bufferData); void calculateControlSum(unsigned int &CR1Var, unsigned int &CR2Var, unsigned char *bufferData, int bufferSize); void encageDustSensorReadError(); void printUARTRecievedData(); void readMeteoStation(); int transCharToInt(char *_buffer,int _start,int _stop); //char to int) void sendData(); void printSendedData(); void printDataBySensor(); void setup() { Serial.begin(115000); Serial.println("start"); Serial1.begin(9600); Serial1.setTimeout(1500); delay(2000); Serial2.begin(9600); Serial2.setTimeout(1500); delay(1000); Serial3.begin(9600); Serial3.setTimeout(1500); radio.begin(); radio.setPALevel(RF24_PA_MAX); radio.setDataRate(RF24_1MBPS); radio.setChannel(0x76); radio.openWritingPipe(0xF0F0F0F0E1LL); radio.enableDynamicPayloads(); radio.stopListening(); if (!bmp.begin()) { while (1) {} } if (!tempsensor.begin()) { while (1); } if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr while (1) delay(1); } Serial.println("Zakończony Init"); delay(2000); } void loop() { readPMS(); readPM25(); readMeteoStation(); printDataBySensor(); if(readErr == false && readErr25 == false) { //Serial.println("Wysyłam dane"); sendData(); //Serial.print("Wysłano dane: "); } delay(1000); } void readPMS() { Serial.println("Czujnik pm5003"); readDustSensorUARTData(Serial1, buffer_RTT, PMS5003BufferSize); calculateControlSum(CR1, CR2, buffer_RTT, PMS5003BufferSize); if(CR1 == CR2 && CR1 != 0) //Check { PMS = mergeBitsToInt(buffer_RTT, 12, 13); PM10 = mergeBitsToInt(buffer_RTT, 14, 15); formalin = mergeBitsToInt(buffer_RTT, 28, 29); PMSTemp = mergeBitsToInt(buffer_RTT, 30, 31) / 10; PMSHigro = mergeBitsToInt(buffer_RTT, 32, 33) / 10; readErr = false; } else { PMS = 4321; PM10 = 4321; formalin = 4321; encageDustSensorReadError(); } clearBuffer(buffer_RTT); } void readPM25() { Serial.println("Czujnik p, 25"); readDustSensorUARTData(Serial3, buffer_RTT, dustGravityBufferSize); calculateControlSum(CR1, CR2, buffer_RTT, dustGravityBufferSize); if(CR1 == CR2 && CR1 != 0) //Check { dustSensor25 = mergeBitsToInt(buffer_RTT, 6, 7); dustSensor10 = mergeBitsToInt(buffer_RTT, 8, 9); readErr25 = false; } else { dustSensor25 = 4321; dustSensor10 = 4321; encageDustSensorReadError(); } clearBuffer(buffer_RTT); } void readDustSensorUARTData(SoftwareSerial S, unsigned char *bufferData, int bufferSize) { S.listen(); while(!S.available()); while(S.available()>0) //Data check: weather there is any Data in Serial1 { col =S.read(); delay(2); if (col == 0x42) { bufferData[0]=(char)col; col =S.read(); delay(2); if (col == 0x4d) { bufferData[1]=(char)col; for(int i = 2; i < bufferSize; i++) { col =S.read(); bufferData[i]=(char)col; delay(2); } break; } } S.flush(); } } unsigned int mergeBitsToInt(unsigned char *bufferData, int startBit, int stopBit) { higherBit = buffer_RTT[startBit]; //Read PM2.5 High 8-bit LowerBit = buffer_RTT[stopBit]; //Read PM2.5 Low 8-bit return (higherBit << 8) + LowerBit; } void clearBuffer(unsigned char *bufferData) { for(int i = 0; i < 40; i++) { bufferData[i] = 0; } delay(100); } void calculateControlSum(unsigned int &CR1Var, unsigned int &CR2Var, unsigned char *bufferData, int bufferSize) { CR1Var = 0; CR2Var = 0; CR1Var =(buffer_RTT[bufferSize - 2]<<8) + buffer_RTT[bufferSize - 1]; for(int i = 0; i < bufferSize - 2; i++) { CR2Var += bufferData[i]; } } void encageDustSensorReadError() { dustSensorReadError = dustSensorReadError + 1; readErr = true; readErr25 = true; Serial.print("Błąd odczytu: "); Serial.println(dustSensorReadError); //printUARTRecievedData(); } void readMeteoStation() { Serial.println("Stacja meteo nasłuchuje"); Serial2.listen(); while(!Serial2.available()); while(Serial2.available()>0) //Data check: weather there is any Data in Serial1 { Serial.println("Start meteo"); for (int index = 0;index < 35;index ++) { if(Serial2.available()) { meteoDatabuffer[index] = Serial2.read(); if (meteoDatabuffer[0] != 'c') { //Serial.println("Transmisja w toku meteo"); index = -1; } } else { index --; } } } Serial.println("Koniec"); } int transCharToInt(char *_buffer,int _start,int _stop) { //char to int) int result = 0; int num = _stop - _start + 1; int tempArr[num]; for (int indx = _start; indx <= _stop; indx++) { tempArr[indx - _start] = _buffer[indx] - '0'; result = 10 * result + tempArr[indx - _start]; } return result; } void sendData(){ for(int z = 0; z < dataSize; z++) { measurments[z] = -1000; } //Meteo station measurments[0] = (int)(transCharToInt(meteoDatabuffer,1,3)); //wind directoin measurments[1] = (int)(transCharToInt(meteoDatabuffer,28,32) / 10.00); //pressure //measurments[2] = (int)(((transCharToInt(meteoDatabuffer,13,15) - 32.00) * 5.00 / 9.00) * 100); //temp *C //measurments[3] = (int)((transCharToInt(meteoDatabuffer,25,26)) * 100); //higro %RH measurments[2] = (int)((transCharToInt(meteoDatabuffer,5,7) / 0.44704) * 100); //avg wind speed 1 min (m/s) measurments[3] = (int)((transCharToInt(meteoDatabuffer,9,11) / 0.44704) * 100); //max wind speed 5min (m/s) measurments[4] = (int)((transCharToInt(meteoDatabuffer, 17, 19) * 25.40 * 0.01) * 100); // rain 1 hour (mm) measurments[5] = (int)((transCharToInt(meteoDatabuffer, 21, 23) * 25.40 * 0.01) * 100); // rain 24 hour (mm) //MCP9008 measurments[6] = (int)(tempsensor.readTempC() * 100); //SHT31 measurments[7] = (int)(sht31.readHumidity() * 100); measurments[8] = (int) (sht31.readTemperature()* 100); //PMS5003 //measurments[11] = PMSTemp * 100; //measurments[12] = PMSHigro * 100; measurments[9] = PMS; measurments[10] = PM10; measurments[11] = formalin; //PM2,5 Gravity measurments[12] = dustSensor25; measurments[13] = dustSensor10; //BMP180 measurments[14] = bmp.readPressure() / 100; //measurments[19] = (int) (bmp.readTemperature() * 100); measurments[15] = 666; int testMe = 0; for(int k = 0; k < 15; k++) { testMe += measurments[k]; } Serial.print("PRZYKLADOWA CHECK SUMA: "); Serial.println(testMe); radio.write(&measurments, sizeof(measurments)); printSendedData(); } void printSendedData() { Serial.println("Wysłano następujące dane:"); for (int i = 0; i < dataSize; i++) { Serial.print(measurments[i]); Serial.print(" "); } Serial.println(); } void printUARTRecievedData() { byte b; for(int i=0;i<32;i++) { b = (byte)buffer_RTT[i]; //buffer_RTT[i] = 0; Serial.print(b, HEX); Serial.print(" "); } Serial.print("CR1: "); Serial.print(CR1); Serial.print(" = "); Serial.println(CR2); } void printDataBySensor() { Serial.println(); Serial.println("MCP9808: "); Serial.print("Temperatura: "); float c = tempsensor.readTempC(); Serial.print(c); Serial.println("*C"); Serial.println(); Serial.println("SHT31: "); Serial.print("Wilgotność: "); Serial.print(sht31.readHumidity()); Serial.println("%RH"); Serial.print("Temperatura: "); Serial.print(sht31.readTemperature()); Serial.println("*C"); Serial.println(); Serial.println("BMP180: "); Serial.print("Temperatura: "); float bmpTemp = bmp.readTemperature(); Serial.print(bmpTemp); Serial.println("*C"); Serial.print("Ciśnienie: "); Serial.print(bmp.readPressure() / 100); Serial.println("hPa"); Serial.print("Teoretyczna wysokość: "); Serial.print(bmp.readAltitude(101100)); Serial.println("m.n.p.m"); Serial.println(); Serial.println("PMS5003:"); Serial.print("PM 2,5: "); Serial.print(PMS); Serial.println(" /25 ug/m3 "); Serial.print("PM 10 : "); Serial.print(PM10); Serial.println(" /50 ug/m3 "); Serial.print("Formaldehyd : "); Serial.print(formalin); Serial.println(" ug/m3 "); Serial.print("Temperatura: "); Serial.print(PMSTemp); Serial.println("*C"); Serial.print("Wilgotność: "); Serial.print(PMSHigro); Serial.println("%RH"); Serial.println(); Serial.println("PM 2,5 GRAVITY:"); Serial.print("PM 2,5: "); Serial.print(dustSensor25); Serial.println(" /25 ug/m3 "); Serial.print("PM 10 : "); Serial.print(dustSensor10); Serial.println(" /50 ug/m3 "); Serial.println(); Serial.println("STACJA METEO: "); Serial.print("Temperatura: "); c = (transCharToInt(meteoDatabuffer,13,15) - 32.00) * 5.00 / 9.00; Serial.print(c); Serial.println("*C"); Serial.print("Wilgotnosc: "); float metHigro = transCharToInt(meteoDatabuffer,25,26); Serial.print(metHigro); Serial.println("%RH"); Serial.print("Cisnienie: "); float pp = transCharToInt(meteoDatabuffer,28,32) / 10.00; Serial.print(pp); Serial.println("hPa"); Serial.print("Predkośc wiatru: "); float w = transCharToInt(meteoDatabuffer,5,7) / 0.44704; Serial.print(w); Serial.println("m/s"); Serial.print(" "); w = w * 3.6; Serial.print(w); Serial.println("km/h"); Serial.print("Max Predkośc wiatru: "); float m = transCharToInt(meteoDatabuffer,9,11) / 0.44704; Serial.print(m); Serial.println("m/s (ostatnie 5 minut)"); Serial.print(" "); m = m * 3.6; Serial.print(m); Serial.println("km/h (ostatnie 5 minut)"); Serial.print("Kierunek wiatru: "); Serial.print(transCharToInt(meteoDatabuffer,1,3)); Serial.println("C"); Serial.print("Opad (1h): "); float rain1 = transCharToInt(meteoDatabuffer, 17, 19) * 25.40 * 0.01; Serial.print(rain1); Serial.println("mm"); Serial.print("Opad (24h): "); float rain24 = transCharToInt(meteoDatabuffer, 21, 23) * 25.40 * 0.01; Serial.print(rain24); Serial.println("mm"); Serial.println(); } #Autor Bartosz Jakusz. Można replikować nawet w celach komercyjnych. Tylko umieścić autora kodu. import RPi.GPIO as GPIO from lib_nrf24 import NRF24 import time import spidev import struct import os import mysql.connector from mysql.connector import errorcode from datetime import date, datetime, timedelta GPIO.setmode(GPIO.BCM) pipes = [[0xE8, 0xE8, 0xF0, 0xF0, 0xE1], [0xF0, 0xF0, 0xF0, 0xF0, 0xE1]] radio = NRF24(GPIO, spidev.SpiDev()) radio.begin(0, 17) radio.setPayloadSize(32) radio.setChannel(0x76) radio.setDataRate(NRF24.BR_1MBPS) radio.setPALevel(NRF24.PA_MAX) radio.setAutoAck(True) radio.enableDynamicPayloads() radio.enableAckPayload() i = 0 j = 0 sucRate = 0 errRate = 0 totalRec = 0 try: while True: radio.openReadingPipe(1, pipes[1]) #radio.printDetails() radio.startListening() print(" ") print(datetime.now()) radio.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) radio.print_address_register("TX_ADDR", NRF24.TX_ADDR) j = 0 while not radio.available(0): j = j + 1 receivedMessage = [] radio.read(receivedMessage, radio.getDynamicPayloadSize()) radio.stopListening() print("Received: {}".format(receivedMessage)) string = "" floatBytes = [] indx = 0 while indx < 4: floatBytes.append(0) indx = indx + 1 measurments = [] indx = 0 mIndx = 0 tmpStr= "" tmpIndx = 0 crc = 0 if not receivedMessage: print("pusto wywalam sie") else: for n in receivedMessage: #print(tmpIndx) tmpIndx = tmpIndx + 1 floatBytes.insert(indx, n) if(indx >= 1): b1 = floatBytes[0] b2 = floatBytes[1] host = 0 host = b2 host = host << 8 host = host | b1 if(mIndx == 6): print("trt {}".format(host)) if(host > 65536 / 2): host = (65536 - host) * (-1) print("trti {}".format(host)) tmpVar = host / 100 print("trtf {}".format(tmpVar)) elif(mIndx >= 2 and mIndx < 5 or mIndx >= 7 and mIndx <= 8): tmpVar = host / 100 else: tmpVar = host indx = 0 measurments.append(tmpVar) mIndx = mIndx + 1 else: indx = indx + 1 totalRec = totalRec + 1 print(" ") if(host == 666): sucRate = sucRate + 1 print("Odebrano z sukcesem {}/{} transmisji".format(sucRate, totalRec)) try: print("Zaczynamy łacznie z baza") cnx = mysql.connector.connect(host='00.00.00.00',database='db') cursor = cnx.cursor() print("Połączono z baza") #zapytania SQL add_probeTime = ("INSERT INTO MeasrumentDateTime" "(time, date)" "VALUES (%s, %s)") add_MCP8006 = ("INSERT INTO MCP8006 " "(temperature, MeasrumentDateTime_ID) " "VALUES (%(temperature)s, %(timeID)s)") add_SHT31 = ("INSERT INTO SHT31 " "(humidity, temperature, MeasrumentDateTime_ID) " "VALUES (%(humidity)s ,%(temperature)s, %(timeID)s)") add_BMP180 = ("INSERT INTO BMP180" "(pressure, MeasrumentDateTime_ID) " "VALUES (%(pressure)s, %(timeID)s)") add_PMS5003 = ("INSERT INTO PMS5003" "(pm25, pm10, formaldehyd, MeasrumentDateTime_ID) " "VALUES (%(pm25)s, %(pm10)s, %(formaldehyd)s,%(timeID)s)") add_PMGravity = ("INSERT INTO PM25" "(PM25, PM10, MeasrumentDateTime_ID) " "VALUES (%(pm25)s, %(pm10)s, %(timeID)s)") add_meteoSation = ("INSERT INTO MeteoStation" "(windDirection, avgWindSpeedPerMinute, avgWindSpeedPerFiveMinutes, rainfallOneHour, rainfal24Hours, pressure, MeasrumentDateTime_ID) " "VALUES (%(windDir)s, %(avgWind)s, %(maxWind)s, %(rain1h)s, %(rain24h)s, %(pressure)s, %(timeID)s)") #Dodaj obecna godzine currentTimeAndDate = datetime.now() formatted_time = currentTimeAndDate.strftime('%H:%M:%S') currentDate = datetime.now().date() toSendSampleDate = (formatted_time, currentDate) cursor.execute(add_probeTime, toSendSampleDate) sampleTimeID = cursor.lastrowid #Wyslij do bazy MySql dane czujnik temp MCP8006Data = { 'timeID' : sampleTimeID, 'temperature' : measurments[6], } cursor.execute(add_MCP8006, MCP8006Data) #Wyslij do bazy MySql dane higrometr SHT 31 SHT31Data = { 'timeID' : sampleTimeID, 'humidity' : measurments[7], 'temperature' : measurments[8], } cursor.execute(add_SHT31, SHT31Data) #Wyslij do bazy MySql dane barometr BMP180 BMP180Data = { 'timeID' : sampleTimeID, 'pressure' : measurments[14], } cursor.execute(add_BMP180, BMP180Data) #Wyslij do bazy MySql dane czujnik pylu PMS5003 PMS5003Data = { 'timeID' : sampleTimeID, 'pm25' : measurments[9], 'pm10' : measurments[10], 'formaldehyd' : measurments[11], } cursor.execute(add_PMS5003, PMS5003Data) #Wyslij do bazy MySql dane czujnik pylu PM 2,5 Gravity PMGravityData = { 'timeID' : sampleTimeID, 'pm25' : measurments[12], 'pm10' : measurments[13], } cursor.execute(add_PMGravity, PMGravityData) #Wyslij do bazy MySql dane stacja meteo metStationData = { 'timeID' : sampleTimeID, 'windDir' : measurments[0], 'avgWind' : measurments[2], 'maxWind' : measurments[3], 'rain1h' : measurments[4], 'rain24h' : measurments[5], 'pressure' : measurments[1], } cursor.execute(add_meteoSation, metStationData) print("Wysylanie danych na serwer") cnx.commit() cursor.close() print("Wyslano do bazy pomyslnie dane") except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: print("Something is wrong with your user name or password") elif err.errno == errorcode.ER_BAD_DB_ERROR: print("Database does not exist") else: print(err) else: cnx.close() time.sleep(14) else: print("BLAD TRANSMISJI: nie zgadza sie suma kontrolna") #errRate = errRate + 1 #print("Żle odebrano {}/{} transmisji".format(errRate, totalRec)) print(" ") print("------------------------------------------") #radio.closeReadingPipe(pipes[1]) #radio.stopListening() time.sleep(1) except KeyboardInterrupt: print(i) except: # this catches ALL other exceptions including errors. # You won't get any error messages for debugging # so only use it once your code is working print ("Other error or exception occurred!") finally: GPIO.cleanup() # this ensures a clean exit echo"Autor Bartosz Jakusz. Można wykorzystywać komercyjnie. Wsakazać tylko autora kodu. "; $mydb = new wpdb('usr_db','db','localhost'); $currentTime = $mydb->get_results("SELECT time, date FROM MeasrumentDateTime ORDER BY ID DESC LIMIT 1"); $tempData = $mydb->get_results("SELECT temperature FROM MCP8006, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $higroData = $mydb->get_results("SELECT humidity FROM SHT31, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $pressureData = $mydb->get_results("SELECT pressure FROM BMP180, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $pms5003Data = $mydb->get_results("SELECT pm25, pm10, formaldehyd FROM PMS5003, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $gravityData = $mydb->get_results("SELECT PM25, PM10 FROM PM25, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $metStationData = $mydb->get_results("SELECT windDirection, avgWindSpeedPerMinute, avgWindSpeedPerFiveMinutes, rainfallOneHour, rainfal24Hours FROM MeteoStation, MeasrumentDateTime WHERE MeasrumentDateTime_ID = MeasrumentDateTime.ID ORDER BY MeasrumentDateTime.ID DESC LIMIT 1"); $avgkmPerHour = $metStationData[0]->avgWindSpeedPerMinute * 3.6; $maxkmPerHour = $metStationData[0]->avgWindSpeedPerFiveMinutes * 3.6; echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Ostatni pomiar z: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>".$currentTime[0]->time." </th>"; echo"<th>".$currentTime[0]->date." </th>"; echo"</tr>"; echo"</table>"; echo "<br>"; echo "<br>"; $dir = $metStationData[0]->windDirection; $dirName = ""; if ($dir < 45) { $dirName = "Północny"; } elseif ($dir >= 45 or $dir < 90 ) { $dirName = "Północno-Wschodni"; } elseif ($dir >= 90 or $dir < 135 ) { $dirName = "Wschodni"; } elseif ($dir >= 135 or $dir < 180 ) { $dirName = "Południowo-Wschodni"; } elseif ($dir >= 180 or $dir < 225 ) { $dirName = "Południowy"; } elseif ($dir >= 225 or $dir < 270 ) { $dirName = "Południowo-Zachodni"; } elseif ($dir >= 270 or $dir < 315 ) { $dirName = "Zachodni"; } else { $dirName = "Północno-Zachodni"; } echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Temperatura: </th>"; echo"<th>".$tempData[0]->temperature."*C </th>"; echo"</tr>"; echo"<tr>"; echo"<th>Wilgotność: </th>"; echo"<th>".$higroData[0]->humidity."%RH </th>"; echo"</tr>"; echo"<tr>"; echo"<th>Ciśnienie: </th>"; echo"<th>".$pressureData[0]->pressure."hPa </th>"; echo"</tr>"; echo"</table>"; echo "<br>"; echo "<br>"; echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Czystość powietrza: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PM 2,5 - norma 25ug/m3: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PMS5003: </th>"; echo"<th>".$pms5003Data[0]->pm25."ug/m3</th>"; echo"</tr>"; echo"<tr>"; echo"<th>Gravity: </th>"; echo"<th>".$gravityData[0]->PM25."ug/m3</th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>PM 10 - norma 50ug/m3</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PMS5003: </th>"; echo"<th>".$pms5003Data[0]->pm10."ug/m3 </th>"; echo"</tr>"; echo"<tr>"; echo"<th>Gravity: </th>"; echo"<th>".$gravityData[0]->PM10."ug/m3 </th>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>Formaldehyd</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>PMS5003: </th>"; echo"<th>".$pms5003Data[0]->formaldehyd."ug/m3 </th>"; echo"</tr>"; echo"</table>"; echo "<br>"; echo "<br>"; echo "<table>"; echo"<col width=50%>"; echo"<tr>"; echo"<th>Stacja Meteo: </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>Kierunek Wiatru: </th>"; echo"<th>".$dirName."</th>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"<tr>"; echo"<th>Średnia prędkość wiatru (ostatnia minuta): </th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$metStationData[0]->avgWindSpeedPerMinute."m/s</th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$avgkmPerHour."km/h</th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>Max prędkość wiatru (ostatnie 5 min)</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$metStationData[0]->avgWindSpeedPerFiveMinutes."m/s</th>"; echo"</tr>"; echo"<tr>"; echo"<th> </th>"; echo"<th>".$maxkmPerHour."km/h</th>"; echo"</tr>"; echo"<tr>"; echo"<th><br></th>"; echo"<th><br></th>"; echo"</tr>"; echo"</tr>"; echo"<tr>"; echo"<th>Opad atmosferyczny</th>"; echo"<th></th>"; echo"</tr>"; echo"<tr>"; echo"<th>Ostatnia godzina: </th>"; echo"<th>".$metStationData[0]->rainfallOneHour."mm</th>"; echo"</tr>"; echo"<tr>"; echo"<th>Ostatnia doba: </th>"; echo"<th>".$metStationData[0]->rainfal24Hours."mm </th>"; echo"</tr>"; echo"</table>"; echo"Autor Bartosz Jakusz. Można wykorzystywać komercyjnie. Wsakazać tylko autora kodu. "; $mydb = new wpdb('usr_db','db','localhost'); $pm25DataPMS5003 = $mydb->get_results("SELECT time, date, round(avg(pm25), 0) as pm25PMSMonth FROM PMS5003, MeasrumentDateTime WHERE TIMESTAMP(date, time) > NOW() - INTERVAL 1 MONTH and MeasrumentDateTime_ID = MeasrumentDateTime.ID group by DAY(TIMESTAMP(date, time)) ORDER BY MeasrumentDateTime.ID"); $pm25DataGravity = $mydb->get_results("SELECT time, date, round(avg(PM25.PM25),0) as pm25GravMonth FROM PM25, MeasrumentDateTime WHERE TIMESTAMP(date, time) > NOW() - INTERVAL 1 MONTH and MeasrumentDateTime_ID = MeasrumentDateTime.ID group by DAY(TIMESTAMP(date, time)) ORDER BY MeasrumentDateTime.ID"); $tmpPM25 = []; $i = 0; $someRandData = 25; foreach ($pm25DataGravity as $obj) : array_push($tmpPM25, array(substr((string)$obj->date,5)." ".substr((string)$obj->time,0,-9), (float)$obj->pm25GravMonth, (float)$pm25DataPMS5003[$i]->pm25PMSMonth, (float)$someRandData )); $i++; endforeach; echo"<div id='pm25ChartMonth'></div>"; ?> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> var pm25 = <?php echo json_encode($tmpPM25); ?>; google.charts.load('current', {packages: ['corechart', 'line']}); google.charts.setOnLoadCallback(drawBasic); function drawBasic() { var data = new google.visualization.DataTable(); data.addColumn('string', 'Last Hour'); data.addColumn('number', 'Gravity'); data.addColumn('number', 'PMS5003'); data.addColumn('number', 'Norma'); data.addRows(pm25); var options = { 'title':'Zaniczyszczenie PM 2,5 ostatni miesiąc', 'curveType': 'function', hAxis: { title: 'Godzina' }, vAxis: { title: 'um/m3' }, height: 500 }; var chart = new google.visualization.LineChart(document.getElementById('pm25ChartMonth')); chart.draw(data, options); } </script>
- 5 odpowiedzi
-
- 5
-
-
-
- Arduino
- Raspberry Pi
-
(i 3 więcej)
Tagi:
-
cześć, potrzebuje pomocy z programem do sterowania rębaka no stress. Większość kodu zrobiłem lecz coś nie działa program i nie mam pomysłu co jest nie tak. program ten ma za zadanie po wykryciu 3000 obrotów RPM włączyć przekaźnik sterowania silnikiem do przodu, lecz gdy obroty spadną do 1000 ma on włączyć na 0,5s przekaźnik silnika do tyłu i go zatrzymać. Po osiągnięciu obrotów 3000 ma on od nowa uruchomić silnik do przodu. pin awaria - wyłącznik bezpieczeństwa(wyłącza oba silniki) zmienna walek - włączanie wyłączanie silnika do przodu prowizorycznie RPM zmieniam wartością zmiennej //#define czujnik 2 // - w projekcie obrotomierz jest jako RPM //#define walek 6 //(OPCJONALNIE) czy jest wlaczony walek #define awaria 5 // wyłącza posów #define cewkaPrzod 3 // przekaznik wlaczajacy posow w przod #define cewkaTyl 4 // przekaznik wlaczajacy posow w tyl int RPM = 3001; int a = 0; bool walek; void setup(){ //pinMode(czujnik, INPUT_PULLUP); //pinMode(walek, INPUT_PULLUP); // wlaczyc jesli jest czujnik wałka pinMode(awaria, INPUT_PULLUP); pinMode(cewkaPrzod, OUTPUT); pinMode(cewkaTyl, OUTPUT); } void loop(){ walek = false; if(walek == true){ digitalWrite(cewkaPrzod, HIGH); } if(walek == false){ digitalWrite(cewkaPrzod, LOW); } walek = false; digitalWrite(cewkaTyl, LOW); //digitalWrite(cewkaPrzod, LOW); while(digitalRead(awaria) == HIGH){ if(a == 0 && RPM < 1000) { walek = false; digitalWrite(cewkaTyl, HIGH); delay(500); digitalWrite(cewkaTyl, LOW); a = a + 1; } if(RPM > 3000){ walek = true; a = 0; } } }
- 6 odpowiedzi
-
- Arduino
- Arduino IDE
-
(i 2 więcej)
Tagi:
-
Witam, mam mały problem z programem na arduino z wzmacniaczem. Chciałem zrobić układ wyjściowy 0-10V proporcjonalny do temperatury o zakresie 17 do 22 stopni celsjusza. Napięcie na układzie wyjściowym miało być proporcjonalne do temperatury czyli, temperatura 17 stopni to napięcie na wyjściu 10V i odwrotnie. Problem polega na tym, że po podłączeniu wzmacniacza i dopisaniu dla niego programu wyświetlana na LCD (z konwerterem I2C) temperatura zaczęła wariować. Bez wzmacniacza wszystko było w porządku. przesyłam program oraz na szybko schemat. Z góry dziękuje za pomoc.
-
Oglądając zestaw arduino uno zastanawia mnie jedna kwestia, dlaczego jest po 5 szt diod koloru czerwonego, żółtego i zielonego a niebieska tylko jedna? Czy chodzi może o koszt i wyprodukowanie niebieskiej diody jest o wiele droższe?
-
Dzisiaj nieco odpoczynku od elektroniki. Ale oczywiście o ile ta cała kabelkologia jest niezmiernie ważna i ważne jest urządzenie sobie warsztatu - to samo można powiedzieć o "warsztacie programisty", czyli zorganizowaniu tak stanowiska, aby można było skupić się na tym co najważniejsze: tworzeniu kodu. Wrzucam to jako worklog, bo kilka spraw jest jeszcze nie do końca rozwiązanych (m.in. użycie esptool-ftdi, na czym bardzo mi zależy), ale w tej postaci jaka jest program jest absolutnie używalny i spełnia swoją funkcję. Na potrzebę powstania tego programu złożyło się kilka czynników. Przede wszystkim w większości do programowania swoich ESP używam frameworku Arduino, a Arduino IDE z różnych przyczyn uważam za mało używalne. Poza tym także nie przepadam za pisaniem Makefile (chociaż po napisaniu bardzo lubię używać make). Postanowiłem więc zrobić sobie wrapper do arduino-cli. Wrapper działa na Linuksie, ale nie widzę przeszkód w uruchomieniu go na Macu czy nawet na Windows, potrzebne by były jedynie niewielkie zmiany. Przede wszystkim musiałem zrobić to, czego mi a Arduino IDE brakuje - czyli oddzielna konfiguracja dla każdego szkicu. Postanowiłem pójść jeszcze dalej: ponieważ zdarza mi się ten sam program uruchamiać na kilku różnych architekturach, założyłem możliwość istnienia kilku wariantów konfiguracji dla każdego szkicu i zabrałem się do roboty. Ponieważ znałem już strukturę plików boards.txt i platform.txt poszło dość szybko - i w relatywnie krótkim czasie miałem już gotowy konfigurator. Oczywiście zanim cokolwiek się zrobi trzeba dodać nowy wariant. Po wciśnięciu klawisza "Nowa" ukazuje się okno tworzenia wariantu: Jak widać jest to podobne do menu wyboru płytki w Arduino IDE, dochodzi jedynie pole "Nazwa", pozwalające na nadanie wariantowi jakiejś łatwej do zapamiętania nazwy. Po utworzeniu wariantu można zabrać się do konfiguracji. I tu znów wzorowałem się na menu Arduino IDE - wszystkie parametry są widoczne na liście, a aktywacja wiersza (czyli dwuklik albo wciśnięcie Enter) powoduje pojawienie się możliwości wyboru predefiniowanej opcji: Jak widać, na razie różnice w stosunku do IDE są niewielkie, ale następną rzeczą, która w IDE jest dla mnie szalenie niewygodna, jest wybór portu do uploadu. Przede wszystkim - nasze systemy operacyjne przyporządkowują numer portu do urządzenia w sposób raczej losowy. Odłączenie i ponowne podłączenie płytki skutkować może np. zmianą portu z ttyUSB0 ma ttyUSB1, co potrafi trochę krwi napsuć. Dość dawno jednak stworzyłem prosty system detekcji portu, i zastosowanie go tutaj było oczywiste. Po prostu podaję jaki to ma być typ portu (do wyboru ttyS, ttyUSB i ttyACM) i/lub nazwę pod jaką zgłasza się podłączone urządzenie. Program szukając portu przeszukuje tylko te o zadeklarowanym typie, ewentualnie sprawdzając, czy nazwa odczytana z urządzenia zawiera w sobie wyszukany string. W ten sposób np. uploader dostaje informację że ma się połączyć na tym a nie innym porcie. Ten sposób działa u mnie już od ok. dwóch lat i jeszcze mnie nie zawiódł. W programie wprowadziłem jeszcze jedną zmianę: jeśli nazwa rozpoczyna się od VID:PID (np. "2341:0043 Uno R3") będzie wyszukiwane urządzenie odpowiadające odczytanym z USB wartościom VendorID i ProductID. Również nazwa w przypadku urządzeń USB będzie (o ile to mozliwe) pochodzić z oficjalnego wykazu. Następną sprawą jest ustawienie adresu i hasła OTA. O ile w IDE konieczne jest, aby urządzenie było włączone w czasie ustawiania portu, o tyle tu takiej konieczności nie ma: mogę albo skorzystać z listy urządzeń wykrytych przez zeroconf (przy czym mogę sobie zapisać albo nazwę, albo adres IP) albo podać te dane ręcznie (jeśli je znam). Poza tym mój program zapamiętuje hasło, co bywa wygodne (szczególnie w porównaniu do IDE w wersji 2.x). I ostatnia rzecz: użycie zewnętrznego programu do uploadu. Może to być np. program obsługi jakiegoś programatora, albo (jak w moim przypadku, co postaram się pokazać przy najbliższym DIY) skrypt wysyłający skompilowany plik do maszyny, do której podłączona jest płytka. W sumie okno konfiguratora uploadu wygląda tak: Istnieje również możliwość dodania dodatkowych parametrów do kompilacji. Dla architektury AVR można włączyć pełną wersję sprintf (tzn. taką, która pozwala na wypisywanie floatów). Można również dodać dowolną ilość definicji, które w programie będą traktowane jako dodatkowe linie #define. Poziom szczegółowości ostrzeżeń działa nieco inaczej niż w IDE: dla platform, dla których automatycznie dodawane jest -Werror przy wyświetlaniu wszystkich ostrzeżeń parametr ów nie jest dodawany automatycznie, można go dodać zaznaczając odpowiednie pole. W ten sposób można bez zbytniej ekwilibrystyki kompilować programy np. na ESP32 z wyświetlaniem wszystkich ostrzeżeń (w IDE przy takim przełączeniu kompilator odmawia kompilacji bibliotek które generują jakieś ostrzeżenia, choćby nawet nie miały wpływu na ich działanie): I to już cały konfigurator. Teraz wystarczy zapisać całą konfigurację (przycisk "Zapisz" lub "Zapisz i zakończ"). Jako domyślny zostanie wpisany wariant aktualnie wskazany na liście. No, ale konfigurator to nie wszystko - warto by było mieć coś, co z tego konfiguratora korzysta. Postanowiłem stworzyć jedno polecenie, które zależnie od podanych opcji będzie robiło różne czynności. Jako że najważniejszym poleceniem jest "help", tak wygląda wynik jego działania (i kilku następnych): Pisząc program natknąłem się na kilka nieprzyjemnych niespodzianek związanych z arduino-cli. Początkowo najbardziej naturalne wydało mi się umieszczenie katalogów build i cache wewnątrz katalogu szkicu. Stosowałem to już wcześniej używając arduino-builder i make, tak więc wydało mi się to najlepszym i w dodatku sprawdzonym rozwiązaniem. A guzik... arduino-cli bardzo grzecznie kompilował program, ale tylko raz. Ki diabeł? No tak, zajrzenie na githuba do issues wszystko wyjaśniło. Jest to stary, szacowny błąd z długą brodą, polegający na tym, że arduino-cli uważa pliku w katalogu build za pliki żródłowe, i próbuje je jeszcze raz skompilować (co się oczywiście nie udaje). W związku z tym preniosłem owe katalogi do /tmp, jakoś w miarę sensownie je ponazywałem i zadziałało... No prawie, a jak wiadomo - prawie robi wielką różnicę. Otóż plik konfiguracji (w formacie json) zapisywany jest w katalogu szkicu (no bo gdzie miałby być zapisany) z rozszerzeniem .json - a to też zmyliło arduino-cli które koniecznie chciało go skompilować. Zmiana rozszerzenia na .cfg skutecznie oduczyła arduino-cli nadmiernej gorliwości i wszystko ładnie ruszyło... Z jednym wyjątkiem: uploadu przez OTA. Podobno arduinio-cli to potrafi (w końcu jakoś IDE w wersji 2.x daje sobie z tym radę, aczkolwiek nie tak do końca). Postanowiłem więc darować sobie sprawdzanie i upload OTA rozwiązać "ręcznie". Jako że jak dla mnie dotyczy to tylko ESP, zaprzągłęm do pracy parser konfiguracji arduino (który i tak jest częścią programu), i dopisałem kilka linijek. Co prawda w tej postaci upload OTA możliwy jest wyłącznie dla ESP32 i ESP8266, ale po pierwsze nie mam innych mikrokontrolerów dla których mógłbym to wykorzystać, po drugie dopisanie kolejnych architektur to kwestia kliku minut, a po trzecie wszystko można załatwić możliwością uploadu przez zewnętrzne polecenie. Aha, no i najważniejsze: może autorzy arduino-cli jakoś w końcu uporają się z implementacją obsługi OTA 🙂 No cóż - chciałbym powiedzieć że to wszystko, ale już słyszę narzekania: linia poleceń? Ajaj, przecież to takie trudne, lepiej sobie kliknąć w jakieś menu w aplikacji! A da się. Porządne edytory (np. Geany) mają możliwość skonfigurowania zewnętrznych poleceń. Dla przykładu rozwiązanie wyklikane dla plików *.ino wygląda w Geany tak: No i na koniec kwestia instalacji. Najpierw musimy upewnić się, czy mamy potrzebne biblioteki i programy współpracujące:Python, gobject-introspection i gtk3 najprawdopodobniej już mamy; można to łatwo sprawdzić uruchamiając konsolę python3 i wpisując polecenia importu Gtk3: $ python3 Python 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gi >>> gi.require_version('Gtk', '3.0') >>> from gi.repository import Gtk >>> Jeśli nie było błędu wszystko jest w porządku; w przeciwnym razie należy sprawdzić w dokumentacji swojej dystrybucji. Dodatkowo potrzebny będzie pakiet zeroconf i usb.ids. Jeśli ich nie będzie, pakiet zeroconf można zainstalować z githuba, a plik usb.ids można ściągnąć z internetu i umieścić gdziekolwiek wskazując ścieżkę we właściwym miejscu w pliku arduports.py w linii zawierającej polecenie: f=open('/var/lib/usbutils/usb.ids','rb') No i ostatnie najważniejsze: arduino-cli. Możemy zainstalować z githuba, lub użyć wersji zawartej w Arduino-IDE 2.x. Ważne, aby znalazło się w ścieżce wskazanej przez $PATH! Właściwy program instalujemy oczywiście z poziomu użytkownika, a nie roota! W tym celu musimy znać katalog, w którym możemy umieścić polecenia. Dla Linuksów będą to najprawdopodobniej ~/bin lub ~/.local/bin - można to sprawdzić poleceniem: echo $PATH Załóżmy że jest to katalog ~/bin. Plik pyrduino.tgz umieszczamy tam, gdzie nie powinien się zgubić (np. w katalogu domowym) i wykonujemy kolejno polecenia: tar -xzf pyrduino.tgz cd pyrduino-src chmod 755 ardu.py ln -sf $(pwd)/ardu.py ~/bin/arducfg ln -sf $(pwd)/ardu.py ~/bin/ardu I to wszystko. Możemy teraz wejść do katalogu szkicu i pobawić się poleceniami arducfg i ardu. Na koniec jedna uwaga: o ile polecenie arducfg musi pozostać takie a nie inne (można to zmienić w pliku ardu.py), o tyle zamiast nazwy ardu możemy użyć dowolnej, która nam się podoba. I jeszcze jedno: jak wspominałem na początku, da się to pewnie zainstalować na Macu (z niewielkimi zmianami) i na Windows (z większymi zmianami). Gdyby komuś się to udało - proszę o danie znać w komentarzu; może komuś się przyda! Do ściągnięcia: pyrduino.tgz I tak już całkiem na zakończenie dla miłośników make - krótki przykład: BINARY=$(shell ardu -show | grep -P '^Build\s+=' | tr -d " " | cut -d= -f2) $(BINARY): *.ino ardu PHONY: flash flash: $(BINARY) ardu -V -flash PHONY:ota ota: $(BINARY) ardu -ota PHONY:clean clean: ardu -clean Prawda, że proste?