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 - roboty
    • Projekty - DIY
    • Projekty - DIY (początkujący)
    • Projekty - 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
    • Kosz

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


Znaleziono 353 wyników

  1. Witam forumowiczów, jestem w trakcie tworzenia pracy inżynierskiej i jako temat mam "Czujnik jakości powietrza" oparty o Arduino. Dostępne mam następujące czujniki: gazu (MQ-2, MQ-3, MQ-5, MQ-135), temperatury (BME280) oraz cząstek stałych (PMS7003). W planach mam jeszcze zakup modułu WiFi, żeby móc przesłać i wyświetlać dane mobilnie. Całość będzie oparta o płytkę Maker Uno. W planach nie mam korzystać z każdego elementu z listy, a prawdopodobnie skupię się na dwóch czujnikach gazu (najpewniej z czujnika MQ-2 oraz MQ-135), czujniku temperatury oraz cząstek stałych wraz z modułem wifi. Pierwsze podłączenia i testy czujników są już za mną poza czujnikiem pyłu. W tym momencie staram się zrozumieć i znaleźć sposób na kalibrację MQ-2. Chodzi mi zarówno od strony technicznej (zrozumienie wykresów z dokumentacji) jak i od strony praktycznej. Oczywiście, jeśli ktoś ma chęci i czas to nie pogardziłbym pomocą w tej materii. Poza tym udało mi się znaleźć jakiś kod do kalibracji, który w większości rozumiem, poza niektórymi zmiennymi. Pozdrawiam
  2. 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:
  3. Witam, zaznaczam, że jestem dość zielony w tych sprawach, ale chciałbym dowiedzieć się czy jest możliwość podłączenia trzech lub więcej czujników gazu MQ, a jeśli tak to w jaki sposób jest możliwość złożenia tego. Z tego co szukałem informacji odnośnie podstawowych układów to widziałem, że każdy podłącza czujniki te pod piny A5, A4 (SDA, SDL) lub bezpośrednio pod SDA, SDL na Arduino Uno/Maker Uno. Pozdrawiam serdecznie.
  4. Dzień dobry Wszystkim! Tak w skrócie, mój robot ma się poruszać po wyznaczonej ścieżce i robić mapę otoczenia wraz z pokazywaniem swojej pozycji. Mam problem z komunikacją, HC-06 mam podłączony do Arduino Mega 2560 przez RX,TX. Wysyłam dane z czujników optycznych odnośnie pozycji (pozycja już wyliczana w Arduino). Przesyłam 2 zmienne po sobie x1, y1. Arduino łączy się w 1-2 sekundy z moim telefonem, na telefonie używam Serial Bluetooth Terminal i odczyty z Arduino sa odbierane bez problemu (wysyłam około 4-6 danych/sekundę). Podczas łączenia się z komputerem trwa to 30sekund, a czasem 1-2minuty. Po stronie PC mam Bluetootha 4.0 Asusa USB-BT400 (pisze że jest kompatybilny z wersjami 2.0, 2.1, 3.0 no i 4.0... jest BLE (Low Energy). Używam do tego skryptu napisanego w Matlabie. Ta część odpowiada za samo połączenie. Działa gdyż w ustawieniach windowsa w sekcji bluetooth widzę HC-06 i mam sparowane i połączone. delete(instrfind) %zamkniecie otwartych portow w Matlabie clear all instrhwinfo('Bluetooth','HC-06') bt = Bluetooth('HC-06', 1) fopen(bt); Kolejna część kodu zajmuje się odczytem przesyłanych danych i prostym rysowaniem. tic; figure(1); x=0; xn=0; y=0; yn=0; while (true) x=fscanf(bt,'%f'); %odczyt impulsow z lewego kola y=fscanf(bt,'%f'); %odczyt impulsow z prawego kola xn=xn+x; yn=yn+y; plot(xn,yn,'black*') axis auto hold on end Dodam że czasem działa, ale głownie mam błąd z przekroczeniem czasu. Co może być przyczyną że jest taki problem z połączeniem? Poniżej screen z 2 kółek... Dzisiaj udało mi się nawiązać tylko 2 razy połączenie, a z telefonem śmiga. Tylko że na telefonie nie mam takich możliwości z odbieraniem danych i rysowaniem ich. A może jest jakaś apka na androida co by mi rysowała położenie mojego robota? Na koniec kod z Arduino. Trzymanie się lini i sterowanie silnikami wykonuje na niezależnym Arduino Nano. Próbowałem wykonywać i śledzenie linii, PID'a i odczyt z enkoderów, a także obsługę 3 czujników HC-SR04 na jednej platformie Arduino MEga2560, ale nie ogarniał (a może to mój nie zoptymalizowany kod?). Robiłem to przerwaniach, wątkach itd. Stanęło na 2 Arduino jak teraz, choć zastanawiam się nad platformą ESP32, nie wiem czy by nie było łatwiej. Proszę o pomoc. //czujniki lini #define L2_LINE_SENSOR A0 #define R2_LINE_SENSOR A1 //czujniki szczelinowe #define L_SZCZ 2 #define P_SZCZ 3 //silniki #define LMOTOR 9 #define RMOTOR 8 #define IN1 4 #define IN2 5 #define IN3 6 #define IN4 7 //czujniki ultradzwiekowe #define SechoHSCR04 51 #define StrigHSCR04 49 #define PechoHSCR04 50 #define PtrigHSCR04 48 #define LechoHSCR04 42 #define LtrigHSCR04 40 #include <Stream.h> #include <SoftwareSerial.h> SoftwareSerial mySerial(17, 16); // RX, TX #include <Wire.h> #include <Timers.h>//watki Timers<1>akcja;//watki volatile float impL=0, impP=0, vx1=0, vy1=0; //"impL","impP"-impulsy z enkoderow; float x1=0, y1=0, r=3.25, teta=0, tetaKat=0, tetaV=0, d=6.5, l=0, L=13.30, dystansL=0, dystansP=0, dystansS=0; //"r"-promien kola; "L"-odleglosc pomiedzy kolami mierzona od osi kola int licznik=0; int blad=0, g=200, vstart=40, pochodna=0, poprzedni=0, calka=0, PID=0; //"g"-granica widzialnosci czarnej lini; "vstart"-predkosc stala float Kp=8, Kd=0.1, Ki=0.4; //nastawy regulatora PID float Ldystans=0, Sdystans=0, Pdystans=0; float doMetra=0, prawo90=0; unsigned long s=0, start=0, time=0, aktualnyCzas=0, zapamietanyCzas=0, roznicaCzasu=0;//timery String inString = ""; void setup() { //Zasilanie +++ pinMode (47, OUTPUT);//ultradzwiekowy srodek digitalWrite(47, HIGH); pinMode (46, OUTPUT);//ultradzwiekowy prawy digitalWrite(46, HIGH); pinMode (38, OUTPUT);//ultradzwiekowy lewy digitalWrite(38, HIGH); pinMode (22, OUTPUT);//szczelinowy prawy digitalWrite(22, HIGH); pinMode (23, OUTPUT);//szczelinowy lewy digitalWrite(23, HIGH); //Masa --- pinMode (53, OUTPUT);//ultradzwiekowy srodek digitalWrite(53, LOW); pinMode (52, OUTPUT);//ultradzwiekowy prawy digitalWrite(52, LOW); pinMode (44, OUTPUT);//ultradzwiekowy lewy digitalWrite(44, LOW); //--------------Czujniki optyczne pinMode(L_SZCZ, INPUT); pinMode(P_SZCZ, INPUT); l=d*PI; //Silniki pinMode (LMOTOR, OUTPUT);//lewy pinMode (IN1, OUTPUT);//przod pinMode (IN2, OUTPUT);//tyl pinMode (RMOTOR, OUTPUT);//prawy pinMode (IN3, OUTPUT);//przod pinMode (IN4, OUTPUT);//tyl analogWrite(LMOTOR, 0); //Ustawienie predkosci digitalWrite(IN1, HIGH); //Kierunek: do przodu digitalWrite(IN2, LOW); //Kierunek: do tylu analogWrite(RMOTOR, 0); //Ustawienie predkosci digitalWrite(IN3, HIGH); //Kierunek: do przodu digitalWrite(IN4, LOW); //Kierunek: do tylu //Czujniki odbiciowe pinMode(R2_LINE_SENSOR, INPUT); pinMode(L2_LINE_SENSOR, INPUT); //Czujniki ultradzwiekowe pinMode(SechoHSCR04, INPUT); pinMode(StrigHSCR04, OUTPUT); pinMode(LechoHSCR04, INPUT); pinMode(LtrigHSCR04, OUTPUT); pinMode(PechoHSCR04, INPUT); pinMode(PtrigHSCR04, OUTPUT); mySerial.begin(9600); Serial.begin(9600); s=millis(); start=millis(); time = millis(); //------------Watki------------ //akcja.attach(0, 50, wysylanie); akcja.attach(0, 250, pozycja); //akcja.attach(1, 980, hcsr04lewy); //akcja.attach(2, 990, hcsr04srodek); //akcja.attach(3, 1000, hcsr04prawy); //akcja.attach(4, 2000, stopMotors); //--------------Przerwania na enkoderach kol--------------------- attachInterrupt(digitalPinToInterrupt(2), enkoderL, LOW); attachInterrupt(digitalPinToInterrupt(3), enkoderP, LOW); } //******************************************** //*****************FUNKCJE******************** //******************************************** //-----------------Wysylanie pozycji z arduinoNano przez BT void wysylanie() { if (Serial.available() > 0) { int inChar = Serial.read(); if (inChar != '\n') { inString += (char)inChar; } else { Serial.println(inString.toFloat()); inString = ""; } } } //----------------Enkodery kol void enkoderL() { if ((millis() - time) > 5) impL++; time = millis(); } void enkoderP() { if ((millis() - time) > 5) impP++; time = millis(); } //----------------Pozycja pojazdu void pozycja() { //droga przejechana przez kazde z kol dystansL=(impL/20)*l; dystansP=(impP/20)*l; //kata o jaki obrocil sie robot tetaKat=tetaKat+((dystansP-dystansL)/L); //pozycja dystansS=(dystansP+dystansL)/2; x1=dystansS*(cos(tetaKat)); y1=dystansS*(sin(tetaKat)); //Serial.print("x1: "); mySerial.println(x1); //Serial.print("y1: "); mySerial.println(y1); //reset licznikow impL=0; impP=0; } //---------------Jazda prosto 1 metr void jedenMetr () { if (doMetra<100) { dystansL=(impL/20)*l; dystansP=(impP/20)*l; dystansS=(dystansP+dystansL)/2; analogWrite(RMOTOR, 70); //Ustawienie predkosci digitalWrite(IN3, HIGH); //Kierunek: do przodu analogWrite(LMOTOR, 70); //Ustawienie predkosci digitalWrite(IN1, HIGH); //Kierunek: do przodu doMetra=dystansS+doMetra; //reset licznikow impL=0; impP=0; Serial.println(doMetra); } else if (doMetra>=100) { analogWrite(RMOTOR, 0); //Ustawienie predkosci digitalWrite(IN3, LOW); //Kierunek: do przodu analogWrite(LMOTOR, 0); //Ustawienie predkosci digitalWrite(IN1, LOW); //Kierunek: do przodu } } //---------------Skręt w prawo 90 stopni void wPrawo90 () { if (prawo90<20.88) { dystansL=(impL/20)*l; analogWrite(RMOTOR, 0); //Ustawienie predkosci digitalWrite(IN3, LOW); //Kierunek: do przodu analogWrite(LMOTOR, 70); //Ustawienie predkosci digitalWrite(IN1, HIGH); //Kierunek: do przodu prawo90=dystansL+prawo90; //reset licznikow impL=0; impP=0; Serial.println(prawo90); } else if (prawo90>=20.88) { analogWrite(LMOTOR, 0); //Ustawienie predkosci analogWrite(RMOTOR, 0); //Ustawienie predkosci digitalWrite(IN1, LOW); digitalWrite(IN3, LOW); } } //---------------Pomiar odleglosci czujnika srodkowego void hcsr04srodek () { float czas; digitalWrite(StrigHSCR04, LOW); delayMicroseconds(2); digitalWrite(StrigHSCR04, HIGH); delayMicroseconds(10); digitalWrite(StrigHSCR04, LOW); czas = pulseIn(SechoHSCR04, HIGH); Sdystans = (czas / 58); //delay(1000); //Serial.print("\nOdleglosc-srodek: "); mySerial.println(Sdystans); } //---------------Pomiar odleglosci czujnika lewego void hcsr04lewy () { float czas; digitalWrite(LtrigHSCR04, LOW); delayMicroseconds(2); digitalWrite(LtrigHSCR04, HIGH); delayMicroseconds(10); digitalWrite(LtrigHSCR04, LOW); czas = pulseIn(LechoHSCR04, HIGH); Ldystans = (czas / 58); //delay(1000); //Serial.print("\nOdleglosc-lewy: "); mySerial.println(Ldystans); } //---------------Pomiar odleglosci czujnika prawego void hcsr04prawy () { float czas; digitalWrite(PtrigHSCR04, LOW); delayMicroseconds(2); digitalWrite(PtrigHSCR04, HIGH); delayMicroseconds(10); digitalWrite(PtrigHSCR04, LOW); czas = pulseIn(PechoHSCR04, HIGH); Pdystans = (czas / 58); //delay(1000); //Serial.print("\nOdleglosc-prawy: "); mySerial.println(Pdystans); } //---------------------Wyliczenie bledu int error () { if (analogRead(L2_LINE_SENSOR) < g && analogRead(R2_LINE_SENSOR) < g) { //nie widza lini blad=1; } else if (analogRead(L2_LINE_SENSOR) > g && analogRead(R2_LINE_SENSOR) < g) { //lewy widzi linie blad=2; } else if (analogRead(L2_LINE_SENSOR) < g && analogRead(R2_LINE_SENSOR) > g) { //prawy widzi linie blad=-2; } //Serial.print("blad: "); //Serial.println(blad); return blad; } //-----------------------------PID void regPID () { pochodna=blad-poprzedni; poprzedni=blad-poprzedni; calka=constrain(calka+blad, -50, 50); PID=round(abs((Kp*blad)+(Kd*pochodna)+(Ki*calka))); //Serial.print("PID: "); //Serial.println(PID); if (blad == 1) {//jazda prosto leftMotor(vstart); rightMotor(vstart); } else if (blad == 2) { //lewy widzi linie leftMotor(vstart-PID); rightMotor(vstart+PID); } else if (blad == -2) { //prawy widzi linie leftMotor(vstart+PID); rightMotor(vstart-PID); } } //-------------------Sterowanie silnikami void leftMotor(int V) { if (V>0) { //V=constrain(V, 0, 256); analogWrite(LMOTOR, V); //Ustawienie predkosci digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); } else { //stop //V=abs(V); analogWrite(LMOTOR, 0); //Ustawienie predkosci digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); } } void rightMotor(int V) { if (V>0) { //V=constrain(V, 0, 256); analogWrite(RMOTOR, V); //Ustawienie predkosci digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); } else { //stop //V=abs(V); analogWrite(RMOTOR, 0); //Ustawienie predkosci digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); } } void stopMotors() { analogWrite(LMOTOR, 0); //Ustawienie predkosci analogWrite(RMOTOR, 0); //Ustawienie predkosci digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); delay(1000); } //--------------PETLA GLOWNA-------------- void loop() { //jedenMetr(); //wPrawo90(); //akcja.process(); //aktualnyCzas = millis(); //roznicaCzasu = aktualnyCzas - zapamietanyCzas; //error(); //regPID(); delay(200); pozycja(); //if (roznicaCzasu >= 250UL) { //zapamietanyCzas = aktualnyCzas; //pozycja(); //hcsr04lewy(); //hcsr04srodek(); //hcsr04prawy(); //} /* float czas=millis(); Serial.println(analogRead(R2_LINE_SENSOR)); delay(1000); Serial.print(" , "); Serial.println(czas/1000); */ }
  5. AJAX umożliwia przekazywanie danych pomiędzy klientem a serwerem WWW bez konieczności przeładowania strony. Dodając do tego timer w JavaScript możemy uzyskać świeże dane na stronie generowanej przez ESP8266. Na początek stwórzmy w PHP najprostszą stronę WWW prezentującą aktualną godzinę pobieraną z serwera (nie "JavaScriptovy" czas z przeglądarki - w końcu docelowo chcemy pobierać dane z czujników podłączonych do "serwera WWW" postawionego na ESP8266): <? if ($_REQUEST["time"]) { echo date("G:i:s"); exit; } ?> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>AJAX test</title> </head> <body> <span id="time"></span> <script> myTimer(); var myVar = setInterval(myTimer, 1000); function myTimer() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("time").innerHTML = this.responseText; } }; xhttp.open("GET", "test.php?time=1", true); xhttp.send(); } </script> </body> </html> Timer co sekundę przywołuje funkcję myTimer(); var myVar = setInterval(myTimer, 1000); a ta pobiera zawartość podstrony test.php?time=1 i wstawia ją do elementu o nazwie "time" (document.getElementById("time").innerHTML = this.responseText;). Mamy tu tylko jeden przekazywany parametr. Co zrobić, by aktualizować kilka różnych wartości? Przywykłem do podstrony przekazującej parametry rozdzielone znakiem ; (odczyt1;odczyt2;odczyt3). Dzięki JavaScriptowej funkcji split możemy podzielić taki ciąg znaków na tablice, a potem przydzielić jej części do elementów SPAN o określonym ID. <? if ($_REQUEST["time"]) { echo date("d.m.y;G:i:s"); exit; } ?> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>AJAX test</title> </head> <body> Date: <span id="date"></span><br> Time: <span id="time"></span> <script> myTimer(); var myVar = setInterval(myTimer, 1000); function myTimer() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var str = this.responseText; var values = str.split(";"); document.getElementById("date").innerHTML = values[0]; document.getElementById("time").innerHTML = values[1]; } }; xhttp.open("GET", "test.php?time=1", true); xhttp.send(); } </script> </body> </html> Działa! PHP po zainstalowania serwera np NGINX możemy uruchomić na Raspberry Pi. W połączeniu (komenda system()) z zewnętrznym skryptem Python lub programem w C korzystającym z WiringPi otrzymamy stronę z odczytami czujników hostowaną na Raspberry Pi! Spróbujmy wreszcie zaprogramować mikrokontroler ESP8266. Podłączmy najpierw czujnik BME280. /* I2C D4 - SCL D3 - SDA */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> char* ssid = "Weather"; //const char *password = ""; ESP8266WebServer server(80); Adafruit_BME280 bme; void setup() { Serial.begin(9600); Wire.begin(D3, D4); Wire.setClock(100000); if (!bme.begin(0x76)) //changed from default I2C adress 0x77 { Serial.println("Nie odnaleziono czujnika BMP085 / BMP180"); while (1) { } } IPAddress apIP(192, 168, 1, 1); WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // WiFi.softAP(ssid, password); WiFi.softAP(ssid); server.on("/", handleRoot); server.on("/sensors", handleSensors); server.begin(); } void loop() { server.handleClient(); } void handleRoot() { String content = "<html> <head><title>Weather</title></head><body>"; content += "<DIV style=\"display:table; font-size: large;\"><DIV style=\"border-style: solid;\">BME280:<BR>Temperature: <span id=\"tempBME\"></span>C<br>Humidity: <span id=\"humBME\"></span>%<br>Pressure: <span id=\"presBME\"></span>Pa<br></DIV>"; content += "<script>myTimer();var myVar = setInterval(myTimer, 1000);function myTimer() {var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var str = this.responseText; var values = str.split(\";\"); document.getElementById(\"tempBME\").innerHTML = values[0]; document.getElementById(\"humBME\").innerHTML = values[1]; document.getElementById(\"presBME\").innerHTML = values[2];} }; xhttp.open(\"GET\", \"sensors\", true); xhttp.send();}</script>"; content += "</body></html>"; server.send(200, "text/html", content); } void handleSensors() { String content = String(bme.readTemperature()) + ";" + String(bme.readHumidity()) + ";" + String((int)bme.readPressure()) + ";"; server.send(200, "text/html", content); } Rozdzielanie danych przecinkiem czy średnikiem nie jest sposobem "zbyt profesjonalnym". Przy dużej ilości zmiennych łatwo też o pomyłkę. Dlatego lepiej wtedy stosować bardziej odpowiednie formaty danych: JSON czy XML. Ze względu na "bliskość" JSON z JavaScript skupię się tylko na nim. Gotowa biblioteka ArduinoJson wygeneruje dane za nas. Więcej informacji znajdziemy w rozdziale Serialize with ArduinoJson dokumentacji technicznej. /* I2C D4 - SCL D3 - SDA */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> #include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson char* ssid = "Weather"; //const char *password = ""; ESP8266WebServer server(80); Adafruit_BME280 bme; void setup() { Serial.begin(9600); Wire.begin(D3, D4); Wire.setClock(100000); if (!bme.begin(0x76)) //changed from default I2C adress 0x77 { Serial.println("Nie odnaleziono czujnika BMP085 / BMP180"); while (1) { } } IPAddress apIP(192, 168, 1, 1); WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // WiFi.softAP(ssid, password); WiFi.softAP(ssid); server.on("/", handleRoot); server.on("/sensors", handleSensors); server.begin(); } void loop() { server.handleClient(); } void handleRoot() { String content = "<html> <head><title>Weather</title></head><body>"; content += "<DIV style=\"display:table; font-size: large;\"><DIV style=\"border-style: solid;\">BME280:<BR>Temperature: <span id=\"tempBME\"></span>C<br>Humidity: <span id=\"humBME\"></span>%<br>Pressure: <span id=\"presBME\"></span>Pa<br></DIV>"; content += "<script>myTimer();var myVar = setInterval(myTimer, 1000);function myTimer() {var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var str = this.responseText; var values = JSON.parse(str); document.getElementById(\"tempBME\").innerHTML = values.temp; document.getElementById(\"humBME\").innerHTML = values.hum; document.getElementById(\"presBME\").innerHTML = values.press;} }; xhttp.open(\"GET\", \"sensors\", true); xhttp.send();}</script>"; content += "</body></html>"; server.send(200, "text/html", content); } void handleSensors() { String content; StaticJsonBuffer<400> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); root["temp"] = bme.readTemperature(); root["hum"] = bme.readHumidity(); root["press"] = (int)bme.readPressure(); root.printTo(content); server.send(200, "text/html", content); } Strona prezentować się będzie tak samo jak poprzednio. Zyskamy za to wygodny i czytelny sposób dopisywania nowych danych root["temp"] = bme.readTemperature(); oraz ich odczytywania w kodzie źródłowym strony: document.getElementById(\"tempBME\").innerHTML = values.temp; Nie przejmujemy się już numeracją elementów długiej tablicy. Sytuację możemy też odwrócić tworząc stronę WWW, której formularz sterować będzie pracą naszego fizycznego urządzenia. Oczywiście nadal niekonieczne będzie przeładowanie strony, by wysłać dane. #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> char* ssid = "Weather"; //const char *password = ""; int ledValue = 0; ESP8266WebServer server(80); void setup() { Serial.begin(9600); IPAddress apIP(192, 168, 1, 1); WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // WiFi.softAP(ssid, password); WiFi.softAP(ssid); server.on("/", handleRoot); server.begin(); pinMode(D1, OUTPUT); analogWriteRange(100); //http://esp8266.github.io/Arduino/versions/2.0.0/doc/reference.html analogWriteFreq(500); } void loop() { server.handleClient(); analogWrite(D1, ledValue); } void handleRoot() { if (server.hasArg("ledVal") && server.arg("ledVal").toInt() >= 0 && server.arg("ledVal").toInt() <= 100) { ledValue = server.arg("ledVal").toInt(); Serial.print("ledVal "); Serial.println(ledValue); server.send(200, "text/html", ""); return; } //https://www.w3schools.com/howto/howto_js_rangeslider.asp //https://stackoverflow.com/questions/9713058/send-post-data-using-xmlhttprequest String content = "<!DOCTYPE html>" "<html>" "<head>" "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">" "<title>Luminosity setter</title>" "<style>" ".slidecontainer {" "width: 1024px;" "margin: 0 auto;" "text-align: center;" "}" ".slider {" " -webkit-appearance: none;" " width: 100%;" " height: 25px;" " background: #d3d3d3;" " outline: none;" " opacity: 0.7;" " -webkit-transition: .2s;" " transition: opacity .2s;" // " margin-left: 20px;" // " margin-right: 20px;" "}" ".slider:hover {" " opacity: 1;" "}" ".slider::-webkit-slider-thumb {" " -webkit-appearance: none;" " appearance: none;" " width: 25px;" " height: 25px;" " background: #4CAF50;" " cursor: pointer;" "}" ".slider::-moz-range-thumb {" " width: 25px;" " height: 25px;" " background: #4CAF50;" " cursor: pointer;" "}" "</style>" "</head>" "<body>" "<div class=\"slidecontainer\">" " <input type=\"range\" min=\"0\" max=\"100\" value=\"" + String(ledValue) + "\" class=\"slider\" id=\"myRange\">" " <p>Value: <span id=\"demo\"></span>%</p>" "</div>" "<script>" "document.getElementById(\"demo\").innerHTML = document.getElementById(\"myRange\").value;" "document.getElementById(\"myRange\").oninput = function() {" " document.getElementById(\"demo\").innerHTML = this.value;" "var data = new FormData();" "data.append('ledVal', this.value);" "var xhr = new XMLHttpRequest();" "xhr.open('POST', '/', true);" "xhr.onload = function () {" " console.log(this.responseText);" "};" "xhr.send(data);" "}" "</script>" "</body>" "</html>"; server.send(200, "text/html", content); } W tym przypadku przesunięcie suwaka na stronie sterującej wywoła natychmiastową zmianę jasności diody LED podłączonej odpowiednim rezystorem do pinu D1.
  6. Witam, zbudowałem lampkę nocną krok po kroku z tym filmem: Wszystko byłoby w porządku gdyby nie jedna bardzo uciążliwa rzecz. Można za pomocą biblioteki FastLED i gotowego kodu zmieniać tylko efekty świecenia tej lampki (po wpięciu do prądu lampka od razu świeci). Chciałbym więc dodać włączenie i wyłączenie jej z tym że mam do dyspozycji tylko 1 przycisk monostabilny. Najprościej oczywiście byłoby dodać 2 przycisk, który będzie wpięty do obwodu zasilania ale nie wierzę że nie idzie tego rozwiązać w kodzie programu. Mam już nawet pewną koncepcję ale jestem amatorem więc kompletnie nie wiem jak powiązać tą bibliotekę z takim rozwiązaniem (https://www.youtube.com/watch?v=IsDzxtaZCoI) czyli długością wciśnięcia przycisku.(np żeby włączyć lampkę trzymamy 3 sekundy wciśnięty przycisk, żeby zmienić program klikamy szybko raz, a żeby wyłączyć znowu trzymamy 3s). Z góry dziękuję za odpowiedź
  7. Już wcześniej pisałem na forum o mojej szklarni. Więc podpiąłem wszystko (2 linijki diód(10),termometr cyfrowy,wyświetlacz,fotorezystor, buzzer, czujnik wilgotności,pompę 12v, wentylator 12v)i nie działa. Do zasilania Arduino używam Stabilizowanego zasilacza sieciowego - dogniazdkowego 230 V AC. Napięcie wyjściowe wynosi 12 V DC. Prąd wyjściowy: 1,5 A - 2 A. Podpiąłem do gniazdka i jak wszystko na raz jest włączone to przestaje działać (chyba, że podepnę arduino także do komputera). Stabilizator napięcia na arduino się grzeje. Proszę o pomoc.
  8. Ech, miało być dużo wcześniej... Niestety okazało się, że co prawda pandemia zmusiła mnie (a właściwie nas, bo moją kochaną też) do siedzenia w domu, ale dodała mi (nam) tyle roboty, że nie bardzo miałem czas na ukończenie projektu. W każdym razie mam zaszczyt wreszcie przedstawić dyplomowaną wiedźmę, pannę (z gatunku tych starszych) Wolhę Nikołajewnę Androinę (dla znajomych Wonia, dla dalszych znajomych mlle Wonia). I od razu wyjaśnienie: tak, mimo wyglądu jest to skończony projekt. Podobnie jak Maestro Zitaurus, Wonia to konstrukcja lalki. Wszelkie włosy, ubrania to zupełnie inna historia: po pierwsze lalkę można ubrać i ucharakteryzować różnie; raz może być złą czarownicą - innym razem dobrą babcią... po drugie pracownie krawieckie są na razie niedostępne i nic nie zapowiada, aby w najbliższej przyszłości coś się zmieniło. Ale zacznę od początku. Wspomniany już Ziutek co prawda sprawdził się na scenie, ale kilka "drobiazgów" znakomicie utrudniało animację. Mechaniczny (bezpośredni) napęd głowy nie pozwolił na wygodne umieszczenie joysticka, a umieszczenie przycisku sterowania dłonią na rękojeści czempuritu bardzo skutecznie uniemożliwiło animację obu rąk jednocześnie. Konstrukcja dłoni też pozostawiała wiele do życzenia - umieszczenie serwomechanizmu w przedramieniu co prawda pozwoliło na zastosowanie typowego SG90, ale przeniesienie napędu na palce było zbyt skomplikowane. Postanowiłem więc skonstruować następną jawajkę - tym razem pozbawioną tych wad. Na pierwszy ogień poszła konstrukcja dłoni. Kiedyś kupiłem na próbę subminiaturowe serwa PowerHD 1370A - okazało się, że świetnie nadają się do tego typu konstrukcji. Są ciche, pobierają niewiele prądu, a rachityczny moment nie przeszkadza przy pracy praktycznie bez obciążenia (dłonie i oczy). Poza tym niewielkie wymiary pozwoliły na umieszczenie serwa bezpośrednio w dłoni i osadzenie palców bezpośrednio na orczyku serwa. Większy problem miałem z opracowaniem napędu głowy. Tym razem postanowiłem, że napęd będzie całkowicie elektryczny i sterowany wyłącznie joystickiem. Dodatkowo chciałem spróbować typowej dla animatroniki konstrukcji umożliwiającej przechyły głowy nie tylko w przód, ale również na boki. Niestety - narzucające się rozwiązanie z przegubami kulowymi (takimi jak stosowanie w drążkach kierowniczych pojazdów RC) było niemożliwe do zrealizowania; dostępne w handlu były po prostu za duże, a samodzielne ich wykonanie w domowych warunkach nie wchodziło w grę. Zrobiłem kilka prób, ale okazało się, że w wykonanych na drukarce przegubach luzy są zbyt duże, aby umożliwić jakikolwiek sensowny ruch - szczególnie w lalce, która wierci się i skacze na wszystkie strony. Już miałem zrezygnować z przechyłów na boki i zastosować sprawdzony sposób z przechyłem tylko w przód... ale w międzyczasie kupiłem zupełnie w innym celu komplet różnych sprężynek. Spróbowałem więc rozwiązania, gdzie sprężyna ściąga głowę do neutralnego położenia, a serwomechanizmy pracują jedynie w trybie pociągania za drążek. I to mnie uratowało - luzy są skutecznie kasowane przez sprężynę, a za napęd mogły posłużyć takie same serwa, jak w dłoniach. Obrót głowy zrealizowałem za pomocą jeszcze jednego takiego samego serwa przekładni zębatej. Jako że podstawowe sprawy z mechaniki miałem już rozwiązane, przyszła kolej na elektronikę. Tym razem lalka powinna działać w dwóch trybach: pierwszy to bezpośrednie sterowanie za pomocą joysticka i przełączników na rękojeści lalki, drugi to typowy w konstrukcjach Hensona sposób animacji przez dwie osoby: pierwsza robi to bezpośrednio w typowy dla jawajki sposób, druga (pomocnik) zdalnie steruje głową i zamykaniem dłoni. Jako głowny kontroler posłużył mi Arduino Pro Mini sterujący bezpośrednio serwami, do komunikacji ze zdalnym manipulatorem użyłem modułów nRF24L01+. Rękojeść jest tym razem pionowa, wewnątrz ukryte są Arduino, transceiver i przetwornica zasilająca elektronikę. Również w rękojeści znajduje się joystick sterujący głową, klawisze dłoni oraz przełącznik sterowania oczami. Klawisze dłoni mają różną wysokość ułatwiającą oddzielne manipulowanie dłońmi jednym palcem, przełącznik oczu został umieszczony tak, aby małym palcem można było bez problemu skierować wzrok lalki w odpowiednią stronę. Rękojeść jest dopasowana do konkretnej osoby - stąd widoczne na filmie trudności w animacji (film nagrywałem sam, a rozstaw joysticka i przycisków po prostu nie pasuje do mojej dłoni). Ponieważ musiałem zrealizować sterowanie trzema serwami za pomocą pojedynczego dwuwymiarowego joysticka, musiałem użyć pewnego tricku. Przesunięcie joysticka w dół powoduje skłon główy do przodu, przesunięcie na boki obrót, przy czym pochylenie głowy na bok realizowane jest przez jednoczesne przesunięcie joysticka w bok i w dół. Co prawda przy takim sterowaniu nie jest możliwe pochylenie głowy na bok bez obrócenia jej, ale taki taki efekt można uzyskać poprzez zaangażowanie drugiego animatora-pomocnika (zdalne sterowanie pozwala na dowolne ustawienie głowy). I tu ciekawostka. Któryś z kolei raz składając rękojeść omyłkowo przekręciłem joystick o 90°. I to był strzał w dziesiątkę: przy takim układzie można osiągnąć dużo większą precyzję w sterowaniu głową. Kontrola ruchu kciuka w linii prostopadłej do palców (a więc równoległej do osi rękojeści) jest dokładniejsza, a ta dokładność jest potrzebna przede wszystkim przy obrocie głowy. No i oczywiście musiałem popełnić jeden błąd - zasilanie. Początkowo zakładałem akumulator LiPo 2000 mAh i moduł przetwornicy MT3608. Wszystko pięknie działało dopóki nie poskładałem tego do kupy... okazało się, że zestaw akumulator-przetwornica nie wyrabia się szczególnie przy starcie urządzenia. Co prawda układ bardzo ładbnie startował przy odłączonych serwach, ich podłączenie już po starcie umożliwiało dalszą pracę ale i tak Arduino działał niestabilnie, a przy uruchomieniu wszystkich serw układ potrafił się zresetować. Wybrałem więc rozwiązanie najprostsze: zastosowałem dwie przetwornice (oddzielna na elektronikę, oddzielna na serwa) i największy akumulator LiPo z oferty Botlandu. Ustawienie drugiej przetwornicy na 6V pomogło przy okazji serwomechanizmom. Na załączonych zdjęciach widoczne są obie przetwornice - jedna w rękojeści do zasilania elektroniki, druga z tyłu lalki pod akumulatorem (do serw). Teraz przyszła kolej na sterownik dla pomocnika. W teorii urządzenie jest proste - Arduino, transceiver (tu użyłem wersji z anteną) kilka klawiszy, joystick... no i właśnie na joysticku się zaciąłem. Próbowałem różnych mocowań potencjometrów, ale urządzenie wychodziło mi jakieś wielkie i nieporęczne, poza tym operowanie czymś takim było piekielnie niewygodne. Chciałem sobie uprościć robotę, kupić zwykły joystick analogowy od peceta i na nim zamontować trzeci potencjometr - niestety, nie mogłem trafić na żadną sensowną ofertę w sieci. W końcu gdzieś na Thingiverse znalazłem szkic podobnej konstrukcji, no i po paru godzinach spędzonych nad OpenSCAD-em miałem gotowy projekt: Ostatecznie całość wygląda tak jak poniżej na zdjęciu. A, i jak zwykle jakiś błąd musiałem popełnić. Skorzystałem tu z gotowej obudowy Kradexu, wymierzyłem, znalazłem akumulator który się tam mieści i... zamawiając go w Botlandzie kliknąłem na sąsiedni link. Stąd takie dziwne umieszczenie akumulatora na zewnątrz - po prostu ten model nie zmieścił się w obudowie I tyle miałem przed pandemią. Co więc tak opóźniło opublikowanie projektu? Otóż zarówno w lalce, jak i w sterowniku zrezygnowałem z wbudowania ładowarki. Ponieważ oba akumulatory mają identyczne złącza JST, postanowiłem zrobić uniwersalną ładowarkę z możliwością przełączania prądu ładowania. Ustrojstwo niesamowicie proste: w zwykłym module TP4056 usunąłem rezystor 1.2k i w miejsce tego podłączyłem drabinkę z kilku rezystorów oraz przełącznik obrotowy, a do wyjścia podłączyłem gniazdo JST. Niestety, przed pandemią nie zdążyłem zmontować ładowarki, a nie mogłem przecież opisać niekompletnego urządzenia! Jeśli kogoś to interesuje, zamieszczam kody lalki i sterownika: lalka.zip O ile kod lalki jest dość typowy, to w kodzie sterownika zastosowałem pewien trick którego nie widziałem na razie w żadnych konstrukcjach - diodę sygnalizującą połączenie radiowe z lalką. Może się komuś przyda... Schematów nie zamieszczam, bo w rzeczywistości oba urządzenia (sterownik i lalka) to płytka Arduino z podłączonymi do odpowiednich pinów transceiverem, przyciskami, diodami i tak dalej, a cała pinologia jest zamieszczona w źródłach. Na koniec wyjaśnienie - skąd akurat takie imię? Miłośnicy fantasy pewnie już wiedzą o kogo chodzi, ale na wszelki wypadek podaję link do książki
  9. Nie wiem czy można to nazwać pełnoprawnym DIY ale dzisiaj zaprezentuję drugie życie robota z kursu budowy robotów. Komentarz dla czepialskich: tak, mogę tego robota nazwać robotem ponieważ jest wyposażony w akcelerometr który jest pewnego rodzaju czujnikiem. Wykorzystałem tą konstrukcję, ponieważ chciałem zrobić coś małego co będzie mogło jeździć po całym domu z kamerką. Najpierw omówimy sobie co było gotowe a później co dodałem albo zmieniłem. Cała konstrukcja, Arduino i shield forbota przez cały czas były na swoim miejscu nic w tej kwestii nie ruszałem (oprócz przylutowania paru kabelków do shielda, i wkręcenia wyższych dystansów pod Arduino). Natomiast ze zmian jest jedna ale za to ważna sprawa jaką jest zasilanie. W oryginalnym robocie całość była zasilana z 6 paluszków AA co daje razem 9 woltów (1,5V * 6 = 9V) . Wady takiego rozwiązania były dwie - brak możliwości ponownego naładowania i zajmowały sporo miejsca. Pozbyłem się problemu i zamieniłem na 2 akumulatorki 18650 co daje 8.4 woltów (4.2V * 2 = 8,4V). Ale ktoś może powiedzieć zaraz zaraz, ale 2 takie akumulatorki 18650 wcale nie zajmują jakoś mniej miejsca i w ogóle to 8.4 V to nie za mało ? I ma rację bo przy 8.4V mogłem jeździć niecałe dwie minuty (to wszystko wina malinki) dlatego dodałem przetwornicę step- up która podnosi napięcie do 10V. Wracając do kwestii zajmowanego miejsca przez baterie to może faktycznie 18650 nie zajmuje mniej miejsca objętościowo ale za to kształtem idealnie wpasowały się pod przestrzeń między podwoziem a Arduino. Swoją drogą, gdybym nie odkrył tego miejsca to ten projekt by nie powstał. To tyle ze zmian teraz czas na dodatki. Najważniejszym dodatkiem jest mój samodzielnie zlutowany shield na shielda, może śmiesznie to brzmi ale tak właśnie jest. Zawiera on: moduł radiowy nRF24l01 który odpowiada za sterowanie wszystkim, akcelerometr MPU6050 który daje możliwość cieszyć się w miarę prostą jazdą do przodu, wyprowadzenia na 2 serwa które pozwalają poruszać kamerą aby uzyskać większy kąt widzenia, tranzystor do którego podpięte są 2 ledy 1w każda. Drugim dodatkiem jest Raspberry Pi 4B razem z kamerką . Tak zdaję sobie sprawę że rpi 4 to overkill do takiego projektu, zajmuje połowę platformy i potrafi zużywać więcej prądu niż cała reszta robota. Ale po prostu nie mam nic innego pod ręką. Teraz powiem kilka słów o poszczególnych funkcjach i podzespołach (jeśli można tak to nazwać). Zasilanie - nie będę się już powtarzał ale dla tych co jeszcze się nie domyślili dopowiem tylko że malinka jest zasilana przez przetwornicę step-down ( 8.4V przetwarza na 5V) Sterowanie - jak już mówiłem za sterowanie odpowiada nRF24l01, jako transmitera używam własnoręcznie zlutowanego pilota którego używałem już w moich poprzednich projektach i o dziwo cały czas jest sprawny. Na razie pilot ma 10 kanałów z czego 8 używam w tym robocie. Krótka rozpiska co obsługuje poszczególny kanał: lewy joystick góra dół - jazda przód tył, lewy joystick lewo prawo - obrót lewo prawo, prawy joystick góra dół - ruch kamerą góra dół, prawy joystick lewo prawo - ruch kamerą lewo prawo, potencjometr - trymer (albo jakoś tak, nie wiem jak to się pisze) do kamery lewo prawo, chodzi o taki minimalny ruch serwem który pomaga ustawić kamerę w miarę prosto, środkowy(pod nrf'em) toggle switch - włącza funkcję w miarę prostej jazdy do przodu, prawy toggle switch - światła on/off, przycisk w lewym joysticku - włącza buzzer (ten wbudowany w forbotowego shielda). Akcelerometr - sprawił mi najwięcej problemów, a właściwie to program którego nie umiałem poprawnie napisać. Okej przyznam się że funkcji przetwarzającej dane z akcelerometru nie napisałem w pełni samodzielnie. Działa to tak że program odczytuje przyspieszenie w osi Z i w zależności od tej danej steruje prędkością poszczególnych silników. Kamera - podłączona do RPI 4B przekazuje obraz przez Wi-Fi w sieci WLAN . Ja siedząc przy komputerze widzę ten obraz z programu VNC. Oczywiście najpierw muszę wywołać jakąś komendę którą się z wami podzielę, może ktoś skorzysta: raspivid -o -t 0 -w 800 -h 400 -rot 180 -fps 30 Ta część też zajęła mi trochę czasu. Chciałem żeby opóźnienie obrazu nie przekraczało 200ms więc przekopywałem internet żeby znaleźć jak streamować obraz za pomocą netcata. Niestety nie udało się znaleźć żadnego właściwego poradnika. Po dłuższym czasie poszukiwań znalazłem tą komendę która pozwoliła mi streamować obraz z kamery na naprawdę sensownym opóźnieniu (postaram się później podesłać filmik w komentarzu). Wady - oczywiście, tak jak wszystko na tym świecie robot ma wady i to nie jedną, a kilka: środek ciężkości - można głównym ciężarem są akumulatorki które są położone z tyłu co znacznie przesuwa środek ciężkości (czerwony - gdzie jest, zielony - gdzie powinien być), Raspberry Pi 4B - zajmuje za dużo miejsca i pobiera za dużo prądu, Zasilanie - pomimo że je zmieniłem to nadal 18650 nie są najlepszym rozwiązaniem. Na końcu zamieszczę jeszcze filmik pokazujący moc akcelerometru, ruch kamery i jazdę po dywanie.
  10. Jeszcze jeden mały projekt z diodami RGB. Jest to mała lampka nocna zrobiona dla mojej córki. Sprzęt Lampka posiada pięć diod WS2811, pokrętło z przyciskiem i jeszcze jeden przycisk, wszystko polutowane na płytce uniwersalnej. Procesorem jest Seeeduino Xiao (czyli najtańsze co znalazłem niewymagające budowania programatora i innych takich rzeczy których nie mam ochoty robić), przyklejone do płytki taśmą dwustronną Dorzuciłem też rezystor i kondensator, tak jak sugerowali w opisie diod. Gałka jest zrobiona z sugru. No i obudowa ze sklejki 3mm. Jakbym miał drukarkę 3D to być może obudowę bym wydrukował, ale nie mam, a uważam że efekt nie jest najgorszy. Oprogramowanie Lampka ma kilka trybów pracy: W trybie podstawowym wszystkie diody świecą na ten sam kolor, gałką wybiera się kolor (hue) oraz jasność (naciśnięcie gałki przełącza pomiędzy tymi dwoma parametrami). Jest też trzeci parametr, określający saturation tak z grubsza, żeby go regulować trzeba długo nacisnąć gałkę. Regulacja jasności próbuje na mniej więcej odwzorować postrzeganie jasności przez człowieka, czyli nie jest liniowa od 0 do 255 (w przestrzeni RGB), tylko im niższa, tym wolniej zmienia jasność, a przy bardzo niskich ustawieniach jasność jest ułamkowa, przykładowo jasność 2.4 uzyskuję świecąc dwiema diodami z jasnością 3 i trzema z jasnością 2. Więcej o charakterystyce w sekcji poniżej. Tryb automatycznego przyciemniania - podobny jak poprzedni, ale jasność diod samoistnie maleje, z założenia w takim tempie jak oko dostosowuje się do ciemności. Ten tryb służy do włączenia zaraz po zgaszeniu światła. Tryb tęczy - po diodach przesuwa się cyklicznie "tęcza" hue. W tym trybie można regulować czterema parametrami: jasnością, szybkością przesuwania, saturation oraz rozpiętością. Ten ostatni parametr określa jaką długość łuku hue pokazują diody w każdym momencie. W ustawieniu maksymalnym (zdjęcie powyżej) suma kolorów diod jest zawsze biała, co widać dobrze gdy patrzy się na sufit pokoju - jego kolor się nie zmienia, natomiast przy niskich ustawieniach jest istna dyskoteka, bo wszystkie diody mają w danym momencie podobny kolor, ale zmienny w czasie. Sumowanie RGB (pierwsze zdjęcie poniżej): pierwsza dioda świeci na czerwono, druga na zielono a trzecia na niebiesko, reguluje się niezależnie siłą każdej z nich, a ostatnia świeci sumą tych kolorów. Sygnalizator świetlny, przełącza kolejno światła, samoistnie albo po naciśnięciu przycisku. Wyłączona. Tryby przełącza się przytrzymując dodatkowy guzik i kręcąc gałką. Samo sterowanie diod wygląda (mniej więcej) następująco: WS2812::WS2812(byte pin): pin(pin), portGroup(digitalPinToPort(pin)), pinBitMask(digitalPinToBitMask(pin)){ pinMode(this->pin,OUTPUT); } void WS2812::writeLEDs(const std::vector<RGB>& leds){ noInterrupts(); for(auto led=leds.begin();led!=leds.end();led++) writeLED(*led); interrupts(); } void WS2812::writeLED(const RGB& led){ this->writeByte(led.r); this->writeByte(led.g); this->writeByte(led.b); } void WS2812::writeByte(byte b){ writeBit(b&0x80); writeBit(b&0x40); writeBit(b&0x20); writeBit(b&0x10); writeBit(b&0x08); writeBit(b&0x04); writeBit(b&0x02); writeBit(b&0x01); } void WS2812::writeBit(byte b){ if(b) write1(); else write0(); } void WS2812::write0(){ up(); up(); down(); down(); } void WS2812::write1(){ up(); up(); up(); up(); down(); } void WS2812::up(){ portGroup->OUTSET.reg=pinBitMask; } void WS2812::down(){ portGroup->OUTCLR.reg=pinBitMask; } Uwagi: Muszę używać OUTSET i OUTCLR, bo digitalWrite jest za wolne. Liczba powtórzeń w write0 i write1 została wyznaczona eksperymentalnie, z użyciem oscyloskopu. Mógłbym zamiast powtarzać funkcję dodać tam jakąś dobrze skalibrowaną pustą pętlę wykonującą się n razy, ale tak mi było prościej i jest dostatecznie dobrze. Charakterystyka diod Tak jak wspomniałem, chciałem, żeby regulacja jasności wyglądała na liniową, co jak wiadomo oznacza, że taka nie jest. Robiłem sporo pomiarów jasności diod i długo się grzebałem w excelu, i ustaliłem taką oto funkcję przeliczającą level od 0 do 50 na jasność od 0 do 1 (przeliczaną następnie już liniowo na wartości RGB: float levelToLight(float level){ if(level<=15) return max(78e-5*level,0); if(level<=34) return 22e-4*pow(1.117,level); return min(55e-6*pow(1.221,level)+47e-3,1); } Nie żebym sądził, że się komuś ta funkcja przyda ale w każdym razie działa dość dobrze. Dzięki temu, że do 15 jest liniowa, od RGB(0,0,0) do RGB(3,3,3) ustawia się jasność z dokładnością do 0.2/255, co się w sam raz tłumaczy na wzmacnianie kolejno diod w trybie podstawowym. Powyżej 15 zmiany są coraz szybsze, na przykład przy wartości 16 trzy diody świecą RGB(3,3,3) a dwie RGB(4,4,4), a przy 17 już tylko jedna RGB(3,3,3) a cztery RGB(4,4,4) - oczywiście jeśli aktualnie wybranym kolorem jest biały. Niestety, dla wartości RGB 1 i 2 diody zachowują się ekstremalnie nieliniowo, mianowicie przy wartości 1 świeci tylko składowa G, a R oraz B w ogóle nie świecą, a z kolei przy wartości 2, G chyba świeci tak samo jak przy 1, a R i B robią się dużo jaśniejsze, przy czym R jaśniejsza od B. Na ostatnim zdjęciu widać też, że są różnice pomiędzy samymi diodami, mimo że były kupione razem - druga i czwarta wydają się bardziej czerwone. Wszystkie anomalie występują tylko przy niskich wartościach, przy wysokich świecą równo, albo w każdym razie gołym okiem nie widać między nimi różnicy. Ogólnie w porównaniu z diodami użytymi w tym projekcie, te tutaj dla niskich jasności są po prostu tragiczne - ale na lampkę dla dziecka nadają się w sam raz Ale w niektórych trybach, na przykład tęczy, nie pozwalam na zbytnie obniżenie jasności, bo efekt przestaje dobrze wyglądać.
  11. Chciałem podzielić się z wami jak powstała moja mała instalacja fotowoltaiczna oraz przedstawić system monitorowania. Ale od początku, aby móc zasilać wszystkie urządzenia w mojej domowej serwerowni konieczna była modyfikacja zasilania tak aby wszystkie sprzęty były zasilane z jednego źródła. Postanowiłem postawić na instalację 24V z przetwornicami stepdown do 12V. Dlaczego 24V a nie 12V? mniejsze prądy pakiet 7s ogniw 18650 w pełni pokrywa się z zakresem napięć akumulatorów kwasowych/żelowych więc można wykorzystać standardowy/tani kontroler do paneli PV możliwość zbudowania taniej baterii z ogniw 18650 niektóre urządzenia w mojej serwerowni były przystosowane już do napięcia 24V teraz kilka suchych danych: ilość paneli PV 3 szt. moc paneli 3x180Wp szacowana pojemność baterii 100Ah pobór mocy urządzeń dzień 80W, w nocy 100W - spowodowane tym że działa tam również monitoring więc podczerwień w kamerach pobiera w nocy 20W czyli jakieś 0,8A więcej. Instalacja w lato uruchamia się około godziny 8 ładuje baterie i na bieżąco zużywa energię z słońca, po zachodzie słońca całość pracuje do godziny 7-8 następnego dnia. Czyli w pogodne dni letnie 24h mogę pracować z energii słonecznej. Gdy akumulatory rozładują się do napięcia 21.2V sterownik odcina zasilanie, a wszystkie urządzenia zaczynają pracować z zasilacza, na którym mam ustawione napięcie 20V. Przełączanie jeśli tak to można nazwać zrealizowane jest na 2 diodach. Przedstawię ilość urządzeń które zasilam bo jest tego dość sporo: Switch DES-3028 Mikrotik 750GR3 Mikrotik 750R2 AP Tp-link 1043ND AP Ubnt Bullet M2 5 szt ESP8266 - przeznaczenie różne od sterownika pieca do sterowania bramą wjazdową Raspberry Pi NAS Zyxel NSA310 rejestrator Dahua 8 kamer Stacja meteo na Arduino Nano Nazbierało się tego dość sporo. Jak już wspomniałem energię gromadzę w 4 pakietach z ogniw 18650. Dwa z nich to pakiety 7s7p, jeden 7s14p oraz jeden 6s6p. Dlaczego tak, niestety przy samych pakietach 7s zdarzało się że przy głębokim rozładowaniu BMSy odłączały pakiety. Niestety mój sterownik z automatycznym wyborem napięcia akumulatorów następnego dnia włączał się z ustawieniami 12V. Aby temu zapobiec zbudowałem pakiet 6s, gdzie zakres pracy takiego pakietu to od 16.8V od 25.2V. Teraz wszyscy złapią się za głowę i powiedzą to co ten słynny kot na memie (Andrzej to .... ) Spokojnie tak wiem 7s to zakres od 19.6V do 29.4V. BMS w pakiecie 6s bardzo dobrze pilnuje aby nie przeładować ogniw, powyżej maksymalnego napięcia pakiet jest odłączany i w tym momencie ładowane są tylko pakiety 7s. Przewidziałem również prowizoryczny “system gaśniczy”, składający się z kuli gaśniczej, która podczas kontaktu z ogniem rozpyla 1.3 kg proszku. Wszystko zamknięte jest w szafie rack 5U, więc w razie pożaru kula powinna sobie poradzić. Opis jak są zbudowane moje baterie znajdziecie w osobnym poście bo ta historia jest również ciekawa, link tutaj. Jeszcze fotka z montażu skrzyni, jak widać baterie siedzą w dodatkowej skrzynce z grubej blachy. Do monitorowania ilości wytworzonego prądu oraz napięć na akumulatorach wykorzystuję EPS8266 oraz 3 szt. ACS712 podłączone do ADS1115, wszystkie dane zbieram w systemie Domoticz czyli: napięcie na pakietach prąd pakietów prąd wytworzony prąd zużyty licznik produkcji licznik zużycia A przy pomocy Grafany prezentuje je tak: Ważny szczegół, połączenia między ACS712 a ADS1115 warto polutować, bo inaczej mogą występować dziwne wahania prądów. Monitoruje dodatkowo temperaturę pakietów oraz szafy. Temperatura pakietów nie przekracza 30st podczas końcowego etapu ładowania/rozładowywania, a w samej szafie maksymalnie odnotowałem 25st. Jak widać zastosowałem też bezpieczniki 10A na pakiety 7s, 4A na pakiet 6s oraz 16A na panele PV. Cała elektronika zamontowana jest na listwie din a do sterownika dołożyłem z tyłu radiator oraz wentylator który załączany jest termistorem przy 50st. Teraz zapewne omówię najciekawszą sprawę jaka jest opłacalność. Zwrot z inwestycji w same panele, sterownik, bezpieczniki powinien zwrócić się po 24 miesiącach. (tak to wyliczyłem nie pamiętam jak ale chcę w to wierzyć ;) ) Nie liczę tu ceny ogniw bo pochodzą z odzysku i czasu jaki poświęciłem na budowę. Jest jeszcze jeden ważny aspekt, zmniejszyło mi się obciążenie UPSa więc w razie zaniku zasilania cały pozostały sprzęt w domu popracuje dłużej. Oprócz tej mini instalacji PV mam też instalacje z inwerterem 5.5kW, więc tą instalacje traktuję jako ciekawostkę. Jeszcze bym zapomniał, jeśli znajdą się zainteresowani kodem źródłowym to chętnie udostępnię, tylko jak zawsze muszę znaleźć czas aby go posprzątać i porobić komentarze
  12. Witam aktualnie razem z synem pracujemy nad lampką DIV (Led Cubes 4x4x4) Docelowo lampka ma mieć możliwość ustalenia do 10 różnych trybów wyświetlania, dodatkowo planujemy aby tryb wyświetlania był możliwy do zaprogramowania przez terminal Bluetooth z odpowiednią komendą (np. "set 1 0x0000x0660x0660x0000\n0x9009x0000x0000x9009\n") W tym celu przygotowałem stronę z wykorzystaniem obiektów Canvas JS, co pozwala na przygotowanie programu dla animacji (po klatkowej Cubs) i zabawę z lampką uprzyjemni. W załączniku ‘led_prog.zip’ kod strony do pobrania dla chętnych. Podczas projektu pojawił się problem z wyświetlaniem warstw diodów led, ze względu że diody w warstwie są podłączone do jednej masy, oczywiste jest że będzie problem z wyświetlaniem na różnych warstwach z różnym stanie Led np. W1 pali się W2 nie pali się. Problem rozwiązany został programowo , kolejne warstwy Led są wyświetlane w odstępie 2 milisekund dzięki czemu otrzymujemy złudzenie że cała kostka Led (klatka Led) jest aktywna w tym samym czasie. Dla rozjaśnienia poniżej kod programu. void loop() { aktualnyCzas = millis(); roznicaCzasu = aktualnyCzas - zapamietanyCzas; for (int i = 0; i < 4; i++) { DrawLayer(i); } if (roznicaCzasu >= AnimationRefresh) { zapamietanyCzas = aktualnyCzas; if (AnimationIndex<IndexK[AnimationSelect]) AnimationIndex++; else AnimationIndex=0; } } //rysujemy animacje dla odpowiedniej warstwy (i numer warstwy) void DrawLayer(int i) { unsigned int animation=ReadData(AnimationSelect,i); digitalWrite( LAYER_1, 0 ); digitalWrite( LAYER_2, 0 ); digitalWrite( LAYER_3, 0 ); digitalWrite( LAYER_4, 0 ); byte rows =ReadRows(animation,1); digitalWrite( LED_1, ReadLed(rows,1)); digitalWrite( LED_2, ReadLed(rows,2)); digitalWrite( LED_3, ReadLed(rows,3)); digitalWrite( LED_4, ReadLed(rows,4)); rows =ReadRows(animation,2); digitalWrite( LED_5, ReadLed(rows,1)); digitalWrite( LED_6, ReadLed(rows,2)); digitalWrite( LED_7, ReadLed(rows,3)); digitalWrite( LED_8, ReadLed(rows,4)); rows =ReadRows(animation,3); digitalWrite( LED_9, ReadLed(rows,1)); digitalWrite( LED_10, ReadLed(rows,2)); digitalWrite( LED_11, ReadLed(rows,3)); digitalWrite( LED_12, ReadLed(rows,4)); rows =ReadRows(animation,4); digitalWrite( LED_13, ReadLed(rows,1)); digitalWrite( LED_14, ReadLed(rows,2)); digitalWrite( LED_15, ReadLed(rows,3)); digitalWrite( LED_16, ReadLed(rows,4)); if (i==0) digitalWrite( LAYER_1, 255); else if (i==1) digitalWrite( LAYER_2, 255); else if (i==2) digitalWrite( LAYER_3, 255); else if (i==3) digitalWrite( LAYER_4, 255); delay(2); //wymagany w celu przedłurzenia czasu wyswietlania jednej warstwy 2 milisekundy } //PINY na ARDUINO #define LED_1 0 #define LED_2 1 #define LED_3 2 #define LED_4 3 #define LED_5 4 #define LED_6 5 #define LED_7 6 #define LED_8 7 #define LED_9 8 #define LED_10 9 #define LED_11 10 #define LED_12 11 #define LED_13 12 #define LED_14 13 #define LED_15 A4 #define LED_16 A5 //piny odwierzające kolejne warstwy animacji #define LAYER_1 A0 #define LAYER_2 A1 #define LAYER_3 A2 #define LAYER_4 A3 #include <stdlib.h> int PROGRAMSIZE = 10; //masymalny rozmiar animacji int PROGRAMMAX = 10; //masymalna liczba możliwych programuw do zaprogramowania //Bufor dla pamieci danych //jednka klataka zajmujew 2 bajty x 4 warstwy = 8 bajtów + 1 bajt index klatki = 9 bajtów unsigned int PROGRAM[10][4][10]; //900 bajtów unsigned IndexK[10]; int AnimationRefresh=1000; int AnimationSelect=0; //index wybranego programu int AnimationIndex=0; //index wybranej klatki w programie unsigned long aktualnyCzas = 0; unsigned long zapamietanyCzas = 0; unsigned long roznicaCzasu = 0; void ClearLed() { digitalWrite( LED_1, LOW ); digitalWrite( LED_2, LOW ); digitalWrite( LED_3, LOW ); digitalWrite( LED_4, LOW ); digitalWrite( LED_5, LOW ); digitalWrite( LED_6, LOW ); digitalWrite( LED_7, LOW ); digitalWrite( LED_8, LOW ); digitalWrite( LED_9, LOW ); digitalWrite( LED_10, LOW ); digitalWrite( LED_11, LOW ); digitalWrite( LED_12, LOW ); digitalWrite( LED_13, LOW ); digitalWrite( LED_14, LOW ); digitalWrite( LED_15, LOW ); digitalWrite( LED_16, LOW ); } void setup() { pinMode( LED_1, OUTPUT ); digitalWrite( LED_1, HIGH ); pinMode( LED_2, OUTPUT ); digitalWrite( LED_2, HIGH ); pinMode( LED_3, OUTPUT ); digitalWrite( LED_3, HIGH ); pinMode( LED_4, OUTPUT ); digitalWrite( LED_4, HIGH ); pinMode( LED_5, OUTPUT ); digitalWrite( LED_5, HIGH ); pinMode( LED_6, OUTPUT ); digitalWrite( LED_6, HIGH ); pinMode( LED_7, OUTPUT ); digitalWrite( LED_7, HIGH ); pinMode( LED_8, OUTPUT ); digitalWrite( LED_8, HIGH ); pinMode( LED_9, OUTPUT ); digitalWrite( LED_9, HIGH ); pinMode( LED_10, OUTPUT ); digitalWrite( LED_10, HIGH ); pinMode( LED_11, OUTPUT ); digitalWrite( LED_11, HIGH ); pinMode( LED_12, OUTPUT ); digitalWrite( LED_12, HIGH ); pinMode( LED_13, OUTPUT ); digitalWrite( LED_13, HIGH ); pinMode( LED_14, OUTPUT ); digitalWrite( LED_14, HIGH ); pinMode( LED_15, OUTPUT ); digitalWrite( LED_15, HIGH ); pinMode( LED_16, OUTPUT ); digitalWrite( LED_16, HIGH ); pinMode( LAYER_1, OUTPUT ); digitalWrite( LAYER_1, LOW ); pinMode( LAYER_2, OUTPUT ); digitalWrite( LAYER_2, LOW ); pinMode( LAYER_3, OUTPUT ); digitalWrite( LAYER_3, LOW ); pinMode( LAYER_4, OUTPUT ); digitalWrite( LAYER_4, LOW ); ClearLed(); AnimationRefresh=1000; AnimationIndex=0; AnimationSelect=0; for (int io=0;io<PROGRAMMAX;io++) ClearProgram(io); InsertAnimation(AnimationSelect,"0xFFFFx0000xFFFFx0000\n0x0000xFFFFx0000xFFFF\n"); InsertAnimation(1,"0x0000x0660x0660x0000\n0x9009x0000x0000x9009\n"); InsertAnimation(2,"0x8421x8421x8421x8421\n0x0C30x0C30x0C30x0C30\n0x03C0x03C0x03C0x03C0\n0x1248x1248x1248x1248\n0x2244x2244x2244x2244\n0x4422x4422x4422x4422\n"); InsertAnimation(3,"0xFFFFxFFFFx0660x0660\n"); AnimationSelect=1; } void ClearProgram(int nr) { for (int i=0;i<PROGRAMSIZE;i++) { PROGRAM[nr][0][i]=0x0000; PROGRAM[nr][1][i]=0x0000; PROGRAM[nr][2][i]=0x0000; PROGRAM[nr][3][i]=0x0000; } } String getValue(String data, char separator, int index) { int found = 0; int strIndex[] = { 0, -1 }; int maxIndex = data.length() - 1; for (int i = 0; i <= maxIndex && found <= index; i++) { if (data.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; } unsigned int toLayer(String value) { char ssid_array[5]; value.toCharArray(ssid_array, 5); long decimal_answer = strtol(ssid_array, NULL, 16); return decimal_answer; } void InsertAnimation(int nr,String value) { unsigned long vauleWord=0; ClearProgram(nr); int indexFream=0; PROGRAM[AnimationSelect]; for (int index=0;index<PROGRAMSIZE;index++) { int indexLayr=1; String objFream = getValue(value,'\n',index); if (objFream=="") break; String objLayr = getValue(objFream,'0x',indexLayr); //1 vauleWord = toLayer(objLayr); PROGRAM[nr][0][index] = vauleWord; indexLayr++; objLayr = getValue(objFream,'0x',indexLayr); //2 vauleWord = toLayer(objLayr); PROGRAM[nr][1][index] = vauleWord; indexLayr++; objLayr = getValue(objFream,'0x',indexLayr); //3 vauleWord = toLayer(objLayr); PROGRAM[nr][2][index] = vauleWord; indexLayr++; objLayr = getValue(objFream,'0x',indexLayr); //4 vauleWord = toLayer(objLayr); PROGRAM[nr][3][index] = vauleWord; indexFream++; } IndexK[nr]=indexFream-1; } //pobieramy odpowiednia klatkę animacji //NR - NMERA AKTUANIE WYBRANEJ ANIMACJI //index - INDEKS OKRESLAJACY AKTUALNY NUMER WYSWIETLANEJ KLATKI unsigned int ReadData(int nr,int i) { unsigned int aut=0x0000; aut = PROGRAM[nr][i][AnimationIndex]; return aut; } //pobieramy dane dla odpowiedniej warstwy - wiersz led byte ReadRows(unsigned int dane,int nrL) { switch (nrL) { case 1: return (0xF000 & dane) >> 12; case 2: return (0x0F00 & dane) >> 8; case 3: return (0x00F0 & dane) >> 4; case 4: return (0x000F & dane) ; default: return 0x0; } } //pobermy dane dla odpowiedniego led w wierszu bool ReadLed(byte dane,int nrLed) { switch (nrLed) { case 4: return (0b0001 & dane)>0; case 3: return (0b0010 & dane)>0; case 2: return (0b0100 & dane)>0; case 1: return (0b1000 & dane)>0; default: return false; } } Aktualnie zastanawiam się co wykorzystać w celu zwiększenia ilości pionów dla Arduino , Chodzi o fakt że Ledy są zasilane bezpośrednio z pionów cyfrowych Arduino (+) i zależy mi aby moc Ledów nie uległy zmianie (aby świeciły równomiernie). Proszę o sugestię… led_prog.zip filmy.zip
  13. Witam chciał bym zaprezentować , drugą "lepszą wersję " kierownicy do komputera opartej na Arduino Leonardo. Film pokazujący jak dziala kierownica i Force Feedback: Jest to wersja elektronicznie taka sama jak poprzednia, wszystko opisane wcześniej link do poprzedniej tutaj : W tej wersji zmieniłem obudowę na znacznie mniejszą , lżejszą , łatwa do zamocowania przy stole, biurku itp. Obudowa została wykorzystana z kupionej przeze mnie za 50 zł kierownicy Logitech Formula Force Ex o obrocie 180* i Force Feedback. Dzięki temu że kierownica miała już przekładnie i ogólnie jest prosta w budowie , bardzo łatwo i tanio można ją przerobić tak aby miala kąt skrętu taki jak ustawimy sobie w programie np 720*,900* i Force Feedback do tego kąta obrotu. Tutaj link do gotowego software na Arduino Leonardo , od razu mówię że na Arduino Uno nie zadziała , link do pobrania w opisie filmu: Ja zrobiłem to tak: Na początku przez środek starej przekładni , dodałem pręt gwintowany o średnicy 10mm ,do którego z jednej strony mocowana jest kierownica, a z drugiej enkoder z drukarki canon ip2770. Aby zamocować enkoder musiałem wyciąć dziure jak widać na zdjęciu poniżej : Aby enkoder nie tarł o blat , dodałem plastikowe podkładki : A tak wygląda już gotowa sama kierownica: Wyjścia enkodera i do silnika , zostały przerobione na standardowych wyjściach które były w kierownicy i wchodzą do dodatkowej skrzynki w której znajduje się reszta elektroniki czyli w sumie tylko Arduino Leonardo i sterownik silników BTS7960: Jeszcze pedal box został przerobiony na taki aby miał 3 jednakowe pedały więc musiałem dokupić drugie takie same i wyciąć jeden i dokleić tak jak na zcjeciach . Schemat podłączenia wszystkiego w linku do wcześniejszej wersji. Efekt końcowy (pedały jeszcze stare): To by było na tyle , jeśli czegoś ktoś potrzebuje , śmiało pisać
  14. Witam, Jestem amatorem. Buduję szklarnię kontrolowaną Arduino i chciałbym, żeby się w niej znajdował: czujnik temperatury czujnik światła wentylator 3pin do 12v pompa 6v czujnik wilgotności gleby pasek LED wyświetlacz dioda LED przycisk buzzer wszystko podpiąłem tylko nie umiem kontrolować wentylatora 3-pinowego i pompy. Zależy mi na tym, żeby wszystko było wpięte w jedno gniazdko, ewentualnie również w baterię 9v. Do zasilania Arduino używam Stabilizowanego zasilacza sieciowego - dogniazdkowego 230 V AC. Napięcie wyjściowe wynosi 12 V DC. Prąd wyjściowy: 1,5 A - 2 A. Proszę o radę.
  15. Jako, że jestem wielkim fanem gier komputerowych to nieuniknione było to, że w pewnym momencie spróbuję w jakiś sposób połączyć swoje zainteresowanie elektroniką oraz grami. W taki sposób narodził się pomysł na projekt, który przyjął nazwę "Fly And Shoot". Projekt złożony jest z dwóch części: Programistyczna - stworzenie samej aplikacji oraz gry. Postawiłem tutaj na prostotę i postanowiłem zrobić grę, w której lecąc statkiem kosmicznym musimy omijać/zestrzeliwać nadlatujące asteroidy. Taki typ gry wydał mi się idealny aby można było z nią połączyć drugą część projektu czyli część: Elektroniczna - polegająca na stworzeniu pada dzięki któremu będzie można sterować statkiem. W tym przypadku aby sterowanie nie okazało się banalne, postanowiłem, że pad będzie opierał się na akcelerometrze, a sterować będzie można wychylając go w odpowiednie strony. Tak o to prezentowała się koncepcja mojej gry: PAD DO GRY Do stworzenia pada postanowiłem użyć dwóch głównych komponentów: akcelerometru MMA7660FC oraz mikrokontrolera Arduino Nano v3. Założenie było proste: akcelerometr analizuje swoje wychylenie i przesyła zebrane dane do Arduino poprzez protokół I2C, następnie Arduino serializuje dane w odpowiedni format i przesyła je poprzez UART do komputera, w którym to dalsze działanie przejmuje aplikacja. Dodatkowym elementem, który postanowiłem jeszcze dodać był zwykły przycisk, który potem mógłbym wykorzystać np. do odczytu strzału. Na podstawie powyższych założeń stworzyłem schemat elektroniczny pada: Na podstawie schematu złożyłem układ na płytce stykowej: Na początku miał to być tylko prototyp, jednak okazał się on na tyle wygodny do trzymania, iż uznałem że nie ma sensu specjalnie lutować tych kilku komponentów. Osobiście uznałem, że kanciasty prostokątny kształt nadaje padowi trochę retro stylu, w szczególności jeśli ktoś kiedyś miał styczność z NESem : Oczywiście można było wszystko schować w jakąś kanciastą obudowę, jednak nie mam jeszcze doświadczenia z takimi rzeczami, więc stworzenie ślicznych obudów do wszystkich moich projektów zostawiam na przyszłość. Na podstawie dokumentacji akcelerometru oraz biblioteki Wire.h dla Arduino napisałem mały program, który łączył się z modułem, a następnie odczytywał zwracane dane i konwertował je na stopnie. Na jego podstawie mogłem potwierdzić działanie modułu: Kolejnym krokiem stało się przesłanie danych do komputera. Uznałem, że najlepszym sposobem będzie połączenie wszystkich danych w tzw. "ramkę" i przesłanie jej w całości do komputera. Moja ramka przyjęła następującą postać: Tworząc ramkę na początku umieszcza się nagłówek, który pozwala aplikacji odbierającej dane rozpoznać, że to właśnie z nią ma do czynienia. W kolejnych polach umieściłem dane, które chciałem przesłać: 'accX' i 'accY' oznaczające wychylenie akcelerometru/pada w osi X oraz Y (pominąłem Z, ponieważ było one zbędne w przypadku mojej gry) oraz 's' mówiące o tym czy wciśnięty został przycisk. Na końcu ramki umieszczone zostało pole na sumę kontrolną CRC8. Po co? W moim przypadku głównie w celu edukacyjnym, jednak na pewno jest ono przydatne w bardziej krytycznych węzłach komunikacyjnych, gdyż zapewnia integralność danych. W skrócie działa to tak, że na podstawie wszystkich wysyłanych danych mikrokontroler oblicza sumę kontrolną i przesyła ją razem z danymi. Następnie program, który odbiera dane ponownie na ich podstawie oblicza sumę kontrolną takim samym algorytmem i porównuje ją z sumą kontrolną, którą uzyskał razem z danymi - jeśli się zgadzają oznacza to, że przesłane dane nie zostały zakłamane i są prawdziwe. W tym momencie konieczne stało się przejście do drugiego etapu projektu, czyli aplikacji. APLIKACJA Z GRĄ Na początku postanowiłem stworzyć graficzny projekt aplikacji oraz gry. Poszczególne elementy, które sobie wymyśliłem wyglądają następująco: Do stworzenia aplikacji z grą postanowiłem użyć środowiska Qt: czemu akurat Qt? Bo nigdy wcześniej nie miałem z nim styczności, a chciałem je poznać . Na początku bardzo pomocny okazał się Kurs Qt z Forbota - to właśnie on pomógł mi stworzyć pierwsze okna i zaimplementować połączenie i komunikację z Arduino: W dalszej części postanowiłem najpierw zająć się oknem z wykresami, aby mieć pewność, że dane które odczytuje mają sens. W tym celu musiałem zaimplementować funkcje, które odczytywały moją ramkę danych i sprawdzały ich integralność. Następnie stworzyłem wykresy za pomocą narzędzi udostępnianych przez Qt: Po potwierdzeniu, że wszystkie dane są odczytywane poprawnie przyszedł czas na stworzenie gry. W pierwszej kolejności stworzyłem scenę, na której umieściłem obrazek gracza i stworzyłem możliwość jego poruszania. Uzyskanie satysfakcjonującego efektu nie było zbyt proste. Testowałem różne rozwiązania, aż w końcu mój wybór stanął na funkcji y = 2*sqrt(x) [y - prędkość gracza, x - wychylenie akcelerometru]. Użycie takiej funkcji do konwersji wychyleń akcelerometru na prędkość gracza pozwoliło mi uzyskać szybką reakcję w przypadku małych wychyleń przy jednoczesnym ograniczeniu maksymalnej prędkości w przypadku dużych wychyleń. W kolejnym kroku stworzyłem kilka obrazków dla przeszkód (aby miały różne wielkości) i napisałem funkcję, która tworzyła je w losowych miejscach ponad górną krawędzią ekranu. Nadanie im prędkości w dół wywołało iluzję poruszania się statku gracza. Następnie zaimplementowałem wykrywanie kolizji obiektów i tym samym dodałem system żyć oraz punktów dla gracza: Przy okazji stworzyłem jeszcze obiekt odpowiadający za pocisk, który potrafił niszczyć nadlatujące przeszkody. Na końcu dodałem okienko końca gry w przypadku utraty wszystkich żyć, które pozwalało na jej restart: Po stwierdzeniu, że wszystko działa jak należy nadszedł czas na ostatni krok: upiększenia graficzne. Do tej pory wszystkie elementy były tylko prowizorycznymi kształtami. Jako, że nie mam wielkiego talentu artystycznego, to postanowiłem poszukać darmowych paczek obrazków w internecie. Po znalezieniu zestawu obrazków użyłem ich do stworzenia prostych animacji, które zaimplementowałem w grze. Efekt końcowy wygląda następująco: PODSUMOWANIE Projekt nauczył mnie sporo o tworzeniu aplikacji z użyciem Qt. Wykorzystanie elektroniki do stworzenia kontrolera do gry dodatkowo umiliło naukę - w szczególności, że efekt końcowy wyszedł całkiem nieźle. Nie jest to gra na długie godziny, ale potrafiła zatrzymać na odrobinę czasu wszystkich, którym dałem wypróbować swój kontroler. Na koniec dorzucam link do repozytorium: https://github.com/Wirgiliusz/FlyAndShoot oraz filmik prezentujący działanie gry wraz z padem:
  16. Cześć. W ramach projektu wymyśliłem sobie układ do sterowania wewnętrzną roletą w pokoju. Całość ma być kontrolowana przez ATmega328, ruch ma się odbywać między wyłącznikami krańcowymi, sterowanie pilotem / telefonem. Niestety kompletnie nie znam się na silnikach i nie wiem na ile mocny napęd jest mi potrzebny. Czy mógłbym prosić o podanie mi jakiegoś wzoru / skrótu myślowego, który pomoże dobrać mi moc silnika? Chciałbym użyć najprostszego silnika DC i umiejscowić go na dole łańcuszka poruszającego całością . Roleta ma wymiary 80x150 cm i waży ~1 kg.
  17. Witam wszystkich czytelników. Zainspirowałem się w wakacje postem użytkownika @Krzysiek97, który przedstawił swoją kierownice do gier na bazie arduino leonardo: Kierownica PC - wersja 2. Z racji tego że lubię grać w gry wyścigowe i symulatory postanowiłem zbudować własną kierownicę z dodatkowymi akcesoriami. Nie chciałem przerabiać starej gotowej kierownicy do komputera, więc wpadłem na pomysł aby zbudować całe stanowisko. Materiał o tym stanowisku/ projekcie znajduję się na moim kanale na YT do którego was zapraszam Kierownica do komputera na bazie arduino Chciałem aby w tym stanowisko znajdowała się kierownica o kącie obrotu 900 stopni, sprzęgło, gaz, hamulec, 8 biegów + wsteczny (8 biegów ponieważ tyle mają niektóre samochody np. w Forza Horizon 4), hamulec ręczny, 2 joystiki (do sterowania maszynami w Farming Simualtor), button matrix 4x5 = 20 przycisków (przypisanych do rożnych akcji w grach) i zegary do wyświetlania prędkości i obrotów. Tak więc gdzieś w połowie lipca zacząłem szukać potrzebne części. Pierwszym problemem z którym się spotkałem była niewystarczająca ilość wejść w arduino leonardo. Ktoś na tym forum podsunął mi płytki Nucleo 64 na STM32, obawiałem się jednak czy programy które wcześniej znalazłem w internecie będą z nimi współpracować. Bawiłem się naco wcześniej arduino lecz nucleo nie stąd moja niepewność ponieważ zaczynałem dopiero wtedy zabawę z tym wszystkim. Zdecydowałem się jednak zostać przy arduino i zakupiłem 3 płytki, po jednej dla każdego programu który obsługuję inną część stanowiska, ponieważ i tak nie ma prgoramu który ogarnie wszystkie moje rzeczy na raz. A więc tak: Arduino Leonardo - program EMC Utility Lite (z początku korzystałem z RFR Whell Configuration elcz sprawiał on problemy) - obsługuję kierownicę, pedały, hamulec ręczny - Link do programu EMC, Jak zainstalować program Pierwsze Arduino Pro Micro - program MMJoy2 - obsługuję button matrix i 2 joysticki - Link do programu MMJoy2, Jak zainstalować program Drugie Arduino Pro Micro - program SimHub - obsługuję zegary/wyświetlacze - Link do programu SimHub Zamówiłem też 20 guzików (push button) 10 styczników krańcowych 2 Joysticki 2 wyświetlacze Tm1638, 1 wyświetlacz Max7219 (zamówiłem też sterownik silnika BTS7960 lecz na razie nie zakładałem FFB). Rzeczy które miałem w domu to: 2 potencjometry 10k Ohm, stycznik krańcowy ls-11s, kable kawałki plastiku, materiału i gumy. Za postawę stanowiska posłużyła mi deska rozdzielcza i fotel od mazdy mx-5 i kierownica od mazdy 626. Całość jest przyspawana do rurki i przykręcona do euro palety. Z racji tego że deska pochodzi z anglika to nie mogłem zamontować zwykłych zegarów w miejscu poduszki pasażera. Zamieszczam tutaj schematy podłączeń danych elementów: Drugim problemem który chce tu opisać, było przeniesienie/ zczytanie obrotu z kierownicy do arduino. Na początku chciałem wykorzystać enkoder optyczny z swojej starej drukarki, lecz gubił się on często i nie działał dokładnie, więc kupiłem enkoder inkrementalny 600ppr. Nie będę się już tak rozpisywał co jak i gdzie jest skręcone dlatego wszystko pokazane i omówione jest w filmiku do którego link jest na początku posta. Więc to jest dodatkowy materiał dla ciekawych. Podsumowując: koszt budowy stanowiska zamknął się dla mnie w kwocie 300zl, czas realizacji od pierwszego pomysłu do zbudowania całości i upewnienia się że wszystko jest sprawne to 6 miesięcy. Tak oto prezentuję się kierownica i jej działanie w grze Forza Horizon 4 Na koniec pytanie głownie do administratora, czy i kiedy będzie znowu dostępny konkurs Opisz elektroniczne DIY i odbierz 50 zł rabatu do Botland?
  18. 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ę.
  19. Witam, jestem nowy w świecie arduino i chciałem spróbować napisać swój własny kod który wykryje drgania i pokaże je na wyświetlaczu 16x2. Płytka: Arduino UNO System: W10 Detektor drgań: SW-520D Wyświetlacz: HD44780 Występuje problem gdzie pokazuje mi komunikat "expected unqualified-id before 'else' " i nie wiem gdzie zrobiłem coś źle. #include <LiquidCrystal.h> LiquidCrystal lcd(2, 3, 4, 5, 6, 7); void setup() { pinMode(A5, OUTPUT); pinMode(A0, INPUT_PULLUP); } void loop() { if (digitalRead(A0) == LOW); { noTone(A5); lcd.begin(16, 2); lcd.setCursor(0, 0); lcd.print("Wszystko ok."); } } else { tone(A5,1000); lcd.begin(16, 2); lcd.setCursor(0, 0); lcd.print("Wykryto"); lcd.setCursor(0 , 2); lcd.print("drgania!"); } Z góry dziękuje za pomoc :)
  20. Sprzęt Lubię stary sprzęt, nie tylko komputerowy. Zdobyłem starą tarczę telefoniczną, wyczyściłem styki i uformowałem różne elementy które się pogięły, a następnie postanowiłem zrobić z tego klawiaturę. Przykleiłem na spodzie tarczy Seeeduino Xiao (taśmą dwustronną), wylutowałem oryginalny sznur i dodałem trzy przewody, starając się zresztą użyć tych samych kolorów, które były tam oryginalnie, chociaż wątpię czy jest na to jakiś ustalony standard. Sprzęt nie był wygodny do trzymania i łatwo było przypadkowo palcem zablokować mechanizm, więc złożyłem małe pudełko ze sklejki. (Na wszelki wypadek wyjaśnię jak się używa takiej tarczy. Żeby wybrać jakąś cyfrę, wkłada się palec w odpowiednią dziurę w tarczy, a następnie obraca tarczę w kierunku ruchu wskazówek zegara aż do momentu gdy palec zatrzyma się na tej metalowej blaszce. Tarcza, puszczona, wraca do położenia początkowego, w międzyczasie wykręcając numer w trybie pulsowym, czyli rozwierając i zwierając przewody, którymi telefon połączony jest z centralą.) Oprogramowanie Ustaliłem eksperymentalnie (z pomocą mojej pokazywaczki Hantek, która do tego celu była w sam raz) jakie sygnały nadaje tarcza. Otóż normalnie pin czerwony nie jest zwarty z żółtym, ale jeśli tarcza jest przynajmniej trochę obrócona, to się zwierają. Natomiast pin zielony jest normalnie zwarty z czerwonym, natomiast w czasie gdy tarcza się cofa, to to coś na wierzchu tej mniejszej zębatki rozwiera je i zwiera. Tych "pulsów" jest mianowicie tyle, z jakiej cyfry tarcza wraca (10 dla cyfry 0). Odczytanie wybranej na tarczy cyfry jest więc dość proste, na przykład tak: void setup() { pinMode(PIN_YELLOW,INPUT_PULLUP); pinMode(PIN_GREEN,INPUT_PULLUP); pinMode(PIN_RED,OUTPUT); digitalWrite(PIN_RED,LOW); } void dialledDigit(int d){ // Cyfra wybrana } void loop() { if(digitalRead(PIN_YELLOW)==LOW){ int p=0; byte prevG=LOW; delay(20); while(digitalRead(PIN_YELLOW)==LOW){ byte g=digitalRead(PIN_GREEN); if(g>prevG) p++; prevG=g; digitalWrite(LED_BUILTIN,!g); delay(10); } digitalWrite(LED_BUILTIN,HIGH); if(p) dialledDigit(p%10); } delay(5); } Najprostsze co można dalej zrobić, to użyć funkcji z Keyboard.h i wysyłać wybrane cyfry, ale taka klawiatura potrafi wpisywać tylko cyfry, a to trochę mało. Dlatego doimplementowałem tryb ASCII, który działa tak, że wybiera się kolejne cyfry kodu ASCII znaku, który chce się wpisać. Czyli żeby napisać 'A' (=65), trzeba wybrać 6 a potem 5. Większość kodów dwucyfrowych łatwo odróżnić od trzycyfrowych - wiadomo, że 65 nie jest początkiem trzycyfrowej liczby, bo maksymalna wartość kodu to 255. Natomiast kody poniżej 26 trzeba poprzedzić zerem. To jednak nadal za mało, bo chciałem również móc przytrzymywać klawisze, na przykład do tego, żeby pisać polskie litery z prawym altem, a także do innych operacji na przykład na tekście. Dlatego dodałem jeszcze następujące funkcje: Kod poprzedzony przez 00 oznacza, że klawisz należy przytrzymać. Gdy później wybrany zostanie dowolny kod bez 00, to ten klawisz zostanie puszczony. Kod poprzedzony przez 0000 oznacza, że klawisz należy przytrzymać, i trzymać tak długo, aż ponownie zostanie wybrany jego kod. Tryby zmienia się generując większą niż 10 liczbę pulsów. Żeby to osiągnąć, należy naciągnąć tarczę, potem pozwolić jej się cofnąć, ale tylko częściowo, i naciągnąć ponownie. W ten sposób liczba pulsów w czasie, gdy pin czerwony jest zwarty z żółtym, może być dowolnie duża. Efekt (oglądać z włączonymi napisami!): Łatwiej mi było nagrać klawiaturę podłączoną do telefonu niż do komputera, działa oczywiście tak samo. Można też oczywiście użyć tarczy do... wybierania numeru, wystarczy uruchomić aplikację telefonu Możliwe zastosowania projektu No cóż... Jak się można domyślić, ta klawiatura nie jest specjalnie ergonomiczna i nie ma prawdziwego zastosowania. Natomiast można by było wykorzystać taką tarczę jako część większego projektu, na przykład zamka szyfrowego.
  21. Jakiś czas temu postanowiłem zbudować zegarek z jakimś termometrem i od razu zabrałem się do roboty dopiero później dodałem do niego buzzer by mógł służyć też w razie potrzeby za budzik. Do budowy wykorzystałem zegar czasu rzeczywistego ds1307, arduino nano, wyświetlacz lcd 2x16 wraz z konwerterem I2C, przetwornicę step up na 5v, akumulator li-ion, termometr dht11 oraz moduł ładowania. Z racji , że nie posiadam drukarki 3d a nie chciało mi się wykonywać całej obudowy zegarka ze sklejki postanowiłem użyć plastikowego opakowania znalezionego u siebie w pokoju przy okazji postanowiłem zużyć trochę elementów odlutowanych z różnych elektro śmieci. Zdjęcia: Jak widać na jednym z zdjęć postanowiłem wykorzystać ds1307 w wersji modułu do przylutowania nie zaś płytki z modułem ponieważ chciałem wypróbować wyjście tego układu(na filmie wykorzystałem je do migania diodą podczas alarmu).Przetwornica z kolei była niezbędna do działania wyświetlacza który bez tych 5v miał tak słabe podświetlenie że niewiele było widać a buzzer ukryłem pod mikrokontrolerem. Jeśli chodzi o montaż to większość trzyma się na śrubach poza przetwornicą i modułem ładowanie które przymocowałem klejem na gorąco oraz przyciskami które są zamontowane na wcisk. Jeden włącza cały zegarek drugi wyłącza alarm. Film: Na filmie uchwyciłem moment aktywacji alarmu. Zegarek najlepiej wygląda kiedy jest ciemno wtedy właśnie najlepsze wrażenie sprawia dioda która oświetla od wewnątrz plątaninę kabli znajdującą się wewnątrz. Co do kodu to jest on tak prosty jak się da z po za tym korzystałem z bibliotek: Wire, DHT, LiquidCrystal_I2C, DS1307. Szczególnie warto wspomnieć o tej ostatniej nad wyraz wygodna oferująca funkcje sterowania wyjściem zegara i dostępu do wewnętrznej wbudowanej w zegar pamięci przygotowana przez jarzebskiego jak toś będzie chciał to wystarczy po prostu wpisać w wyszukiwarkę i wyskoczy na pierwszym miejscu.
  22. Często wykorzystuje w swoich projektach bluetooth który przynajmniej dla mnie jest najprostszą i najlepszą formą komunikacji na małe odległości. Stąd też wpadłem na pomysł wykonania małego pilota bluetooth mniej więcej takiej wielkości żeby zmieścił się w całości w ręce i można go było obsłużyć jedną ręką. A że lubię nowości to postanowiłem wykorzystać moduł digispark z mikrokontrolerem Attiny85 które wydawało mi się najlepsze pod względem wielkości jednak nie wiedziałem wtedy jeszcze że nie posiada ona uartu który był nie zbędny do komunikacji przy pomocy modułu hc-05. Po za tym do budowy pilota wykorzystałem jeszcze obudowę kradex z47u, przyciski, joystick, akumulator Li-pol, oraz przetwornicę step-up. Zdjęcia: Trudnością którą napotkałem w trakcie budowy okazał się brak pinów portu szeregowego na szczęście rozwiązanie okazało się proste a była nim biblioteka SoftwareSerial która pozwala na symulowanie portu szeregowego na dowolnych pinach. Po za tym problemem okazał się brak miejsca który zmusił mnie do wystawienia akumulatora na zewnątrz konstrukcji a nie tak jak początkowo planowałem ukryć go wewnątrz . Kod: #include <SoftwareSerial.h>//RX, TX SoftwareSerial sserial(0,1); int a1 = 0; int a2 = 0; int a3 = 0; int a4 = 0; void setup() { sserial.begin(9600); sserial.println("test"); } void loop() { a1 = analogRead(A2);//2 od góry a2 = analogRead(A3);//3 od góry a3 = digitalRead(2);//3 od dołu a4 = digitalRead(0);// 1 od dołu if((a1 > 250)&&(a1<850)){ if((a2 > 250)&&(a2<800)){ sserial.println("u"); delay(100); } } if(a1 > 850){ sserial.println("q"); delay(100); }if(a1 < 250){ sserial.println("w"); delay(100); }if(a2 > 800){ sserial.println("e"); delay(200); }if(a2 < 250){ sserial.println("r"); delay(100); }if(a3 == HIGH){ sserial.println("t"); delay(100); }if(a4 == LOW){ sserial.println("y"); delay(100); } } Film: Przepraszam za słabą jakość filmu ale niestety aparat w telefonie nie pozwala na nagrywanie w lepszej jakości. Po za tym na filmie widać to że robot nie zawsze reaguje na polecanie ale to już było wynikiem wyładowującego się akumulatora. Starałem się by pilot był jak najmniejszy, możliwy do obsługi za pomocą jednej ręki a przy tym w miarę wygodny by dłuższa obsługa nie męczyła ręki .To rozwiązanie ma też jednak swoje wady na przykład nie ma możliwości by obsługiwać nim coś bardziej skomplikowanego niż coś co wymagało by więcej niż jednego joysticka(np. robot z chwytakiem, dron)
  23. witam mam na sprzedaż kilka , kilkanaście elementów sprzedam wszystko w bardzo okazyjnej cenie , taniej niż z Chin :) Podaję linki tych produktów, oraz link do olx ( kilka aukcji) proszę się nie opierać na tamtych cenach wszystko do dogadania) https://kamami.pl/esp8266/574128-plytka-rozwojowa-d1-mini-v3-wifi-esp8266.html https://www.banggood.com/pl/Geekcreit-D1-Mini-16-Pro-16-Module-+-ESP8266-Series-WiFi-Wireless-Antenna-p-1144951.html?gmcCountry=PL&currency=PLN&createTmp=1&utm_source=googleshopping&utm_medium=cpc_bgs&utm_content=sxxx&utm_campaign=ssc-pl-all-newcustom-0904&gclid=EAIaIQobChMIq-Xlv8Sb7AIVWeDtCh2xgw00EAYYBSABEgI2C_D_BwE&cur_warehouse=CN https://pl.banggood.com/DC-Power-Shield-V1_0_0-For-D1-Mini-Development-Board-p-1160039.html?cur_warehouse=CN https://www.banggood.com/Geekcreit-AM2302-DHT22-Temperature-And-Humidity-Sensor-Module-Geekcreit-for-Arduino-products-that-work-with-official-Arduino-boards-p-937403.html?rmmds=detail-left-hotproducts__3&cur_warehouse=CN https://botland.com.pl/pl/przekazniki/8228-modul-przekaznika-1-kanal-styki-10a250vac-cewka-5v-5903351241229.html?gclid=EAIaIQobChMI_JrJkMib7AIVheJ3Ch38cQCdEAYYBCABEgI_OvD_BwE
  24. Autonomiczny robot mobilny z nawigacją GSP W życiu każdego studenta przychodzi monet, kiedy musi się spiąć i zrobić pracę inżynierską. Jako, że większość proponowanych tematów przez uczelnię nie wpadło w obszar moich zainteresowań, a już od jakiegoś czasu chciałem „pobawić się” w budowę robota z GPS to właśnie taki temat zaproponowałem promotorowi i bez problemów został zaakceptowany (kierunek – AiR). Potem jak się okazało nie był to do końca dobry pomysł z uwagi na problemu w testowaniu GPS – testy przypadły głównie na styczeń – a więc w tym roku deszcze itp. a nawigację trzeba jednak testować na dworze. To tyle tytułem wstępu a teraz do bardziej praktycznych zagadnień. Robot z założenie miał być 2 kołowy + jedno koło wleczone, posiadać moduł bluetooth do wstępnej kalibracji i wpisywaniu współrzędnych, sterowany za pomocą Arduino Nano (w tym przypadku klon), a jego zmysłami poznawania świata miał być: moduł GPS Neo-6m, magnetometr oraz 3 czujniki ultradźwiekowe z przodu do wykrywania przeszkód. Przeszukałem pełno gotowych platform mobilnych ale żadna mi do końca nie pasowała, a że od niedawna byłem właścicielem drukarki 3D to postanowiłem zaprojektować własną i wydrukować z PLA. Projekt owej platformy zrobiłem w środowisku CAD w programie Solid Edge i wyglądał tak jak poniżej. Składa się z 2 platform oraz miejsca na czujniki ultradźwiękowe: dolna na arduino, sterownik i akumulator, a górna na pozostałe podzespoły. Jak widać pokusiłem się o zamodelowanie również felg do już gotowych kół – okazało się że mają efekt „ósemkowania” co uniemożliwiało prostą jazdę. Koło wleczone zastąpiłem jednak Ball Caster'em, ponieważ te które użyłem miało straszne luzy i również powodowało samoczynną jazdę po łuku. A tak prezentuje się już wydrukowana i złożona platforma: Jako że wszystko było zamodelowane w CAD’zie to mogłem porobić rysunki złożeniowe rodem jak z sklepów meblowych (może projektowanie mechaniczne to dobry pomysł na artykuł ) Kolejnym krokiem było zrobienie elektroniki. Aby wyglądało to w miarę estetyczniej to pokusiłem się o zrobienie płytki PCB – projekt w KiCad'zie a potem termotransferem na laminat (tam gdzie Arduino to płytka dwustronna, a tam gdzie moduły jedno) Jeszcze tylko zasilanie – Li-Pol 2s firmy Redox (pomocny w ogarnięciu tego tematu był artykuł na Forbocie – wielkie dzięki za kompendium wiedzy w pigułce) i możemy zaczynać programować – a to dla mnie było największym wyzwaniem. Wrzuciłbym kod ale to jest 700 linijek napisanych raczej łopatologicznie więc tylko ja się w nim odnajduję Jak byście mieli jakieś pytania odnośnie działania jakiejś części to podrzucę i postaram się wyjaśnić. Jako, że byłem na AiR no to fajnie by było wrzucić jakiś nawet prosty regulator – zdecydowałem się na Proporcjonalny a układ regulacji wygląda następująco: (KSN – kompensacja strefy nieczułości) Działał on dosyć dobrze, im robot "był dalej" od zadanego kontu tym szybciej obracał się a im bliżej tym zwalniał, zaś przeregulowanie było znikome. Gotowy robot prezentuje się tak: Niestety wszystko nie było takie piękne i proste, a to niektóre napotkane problemy Magnetometr praktycznie nie działał. Wskazywał azymut w przedziale może z 0-15o. Powodem było pole magnetyczne wytwarzane przez magnesy silników. Google jednak nie znały odpowiedzi co zrobić z tym faktem więc testowałem po kolei różne warianty i tak o to idealnym rozwiązaniem okazało się umieszczenie silników w stalowe rurki. Z powody złych warunków na dworze testowanie robota nie było zawsze możliwe. Arduino też nie wyrabiał jak dostawał tyle danych (GPS okazał się bardzo obciążający – w momencie kiedy dostawał pakiet danych to Ardu zaczęło wariować). GPS i bluetooth nie mogły działać w tym samym momencie więc nie miałem możliwości zdalnie dowiedzenia się co robot w danej chwili „miał na myśli”. Generalnie to wszystko działało ale osobno: jak testowałem unikanie przeszkód i ustawianie się na dany kąt to była gitara. Dołożyłem do tego GPS to raz działało a raz nie – jak wspomniałem po dostaniu pakietu danych zaczynał wariować przez chwilę. W planach mam zamianę Ardu na STM32 i spróbowanie ponownie ruszyć temat. Dodatkowo napisałem prostą aplikację w C#, która komunikowała się z robotem przez bluetooth i można było łatwiej testować podzespoły i wprowadzać współrzędne. Praca została obroniona na 5 więc było warto poświęcić nad tym dużo czasu. Zapraszam do komentowania
  25. Cześć, zbliża się nowy rok akademicki i przez to będę miał mniej czasu na konstruowanie, dlatego jeszcze zanim zaczną się pierwsze laboratoria online chciałem zbudować coś prostego, co nie zajęłoby zbyt wiele czasu, a i dawało satysfakcję. Postawiłem na budowę line follower'a, ponieważ - co wielu z Was może zdziwić - jeszcze nigdy nie robiłem robota tej klasy. W internecie oczywiście jest wiele tutoriali poświęconych budowie podobnych pojazdów, jednak uznałem, że dużo więcej wyciągnę z nauki działania czujników zbliżeniowych oraz samodzielnego skonstruowania i zaprogramowania robota. Elektronika Sercem robota jest stara dobra płytka Arduino Uno, natomiast jako sterownika silników użyłem rozszerzenia Ardumoto od SparkFun. Czujniki to popularne TCRT5000 z potencjometrem do regulacji czujności. Jako zasilania używam 4 baterii AA zapakowanych do koszyka z włącznikiem. Mechanika Podwozie składa się z płytki wyciętej z 3 mm spienionego PCV, dwóch silników Dagu DG01D-L z przekładnią 48:1, które były w zestawie z płytką Ardumoto oraz kulki podporowej dla stabilizacji. Kod Jestem dość zielony jeśli chodzi o programowanie, więc działanie kodu jest dość proste. Arduino odczytuje sygnał cyfrowy z czujników zbliżeniowych, a następnie z pomocą instrukcji warunkowej decyduje, który silnik uruchomić. Poniżej wrzucam kilka fotek, filmik oraz kod. Mam nadzieję, że nie jest to projekt zbyt banalny na tutejsze standardy . Swoją drogą mogę polecić budowę takiego robota dla początkujących, ponieważ mimo swojej prostoty daje sporo satysfakcji. const int pinIRdL = 8; const int pinIRdR = 7; int wartoscL = 0; int wartoscR = 0; #define CW 0 #define CCW 1 #define MOTOR_A 0 #define MOTOR_B 1 #define trigPin 8 #define echoPin 9 const byte PWMA = 3; // PWM control (speed) for motor A const byte PWMB = 11; // PWM control (speed) for motor B const byte DIRA = 12; // Direction control for motor A const byte DIRB = 13; // Direction control for motor B void setup() { pinMode(pinIRdL, INPUT); pinMode(pinIRdR, INPUT); } void loop() { if(wartoscL == 1 && wartoscR == 0) { driveArdumoto(MOTOR_A, CW, 90); stopArdumoto(MOTOR_B); delay(10); } else if(wartoscR == 1 && wartoscL == 0) { driveArdumoto(MOTOR_B, CCW, 90); stopArdumoto(MOTOR_A); delay(10); } else if(wartoscL == 0 && wartoscR == 0) { driveArdumoto(MOTOR_A, CW, 90); driveArdumoto(MOTOR_B, CCW, 90); } else if(wartoscL == 1 && wartoscL == 1) { stopArdumoto(MOTOR_A); stopArdumoto(MOTOR_B); } wartoscL = digitalRead(pinIRdL); wartoscR = digitalRead(pinIRdR); } void driveArdumoto(byte motor, byte dir, byte spd) { if (motor == MOTOR_A) { digitalWrite(DIRA, dir); analogWrite(PWMA, spd); } else if (motor == MOTOR_B) { digitalWrite(DIRB, dir); analogWrite(PWMB, spd); } } void stopArdumoto(byte motor) { driveArdumoto(motor, 0, 0); } void setupArdumoto() { pinMode(PWMA, OUTPUT); pinMode(PWMB, OUTPUT); pinMode(DIRA, OUTPUT); pinMode(DIRB, OUTPUT); digitalWrite(PWMA, LOW); digitalWrite(PWMB, LOW); digitalWrite(DIRA, LOW); digitalWrite(DIRB, LOW); } Filmik
×
×
  • Utwórz nowe...