Danyeru Napisano Luty 15, 2023 Udostępnij Napisano Luty 15, 2023 (edytowany) Hej! Jeszcze jestem zielony, ale walczę. Moja wiedza to na razie kurs Arduino I i coś tam echem o millis. Jestem w trakcie modyfikacji robota z forbotowego kursu, oprócz zmian w budowie, wprowadzam też zmiany w programie. Jednym z założeń jest eliminacja wstrzymujących program delayów. Aktualnie pracuję nad sekcją jazdy autonomicznej. Popełniłem działający program z millisami, ale kolega @ethanak wskazał mi, że no nie do końca. Zatem, na początku kody z kursu (żeby w jednym miejscu było): Kontaktowe wykrywania/omijanie przeszkód: if (digitalRead(L_SIDE_SENSOR) == LOW) { //Jesli przeszkoda po lewej stronie //Jedz wstecz i wydawaj dzwiek leftMotor(-40); rightMotor(-40); digitalWrite(BUZZER, 1); delay(800); //Obrot w miejscu w prawo leftMotor(40); rightMotor(-40); digitalWrite(BUZZER, 0); delay(140); //Koniec warunku wracamy do jazdy prosto } if (digitalRead(R_SIDE_SENSOR) == LOW) { //Jesli przeszkoda po prawej stronie //Jedz wstecz i wydawaj dzwiek leftMotor(-40); rightMotor(-40); digitalWrite(BUZZER, 1); delay(800); //Obrot w miejscu w lewo leftMotor(-40); rightMotor(40); digitalWrite(BUZZER, 0); delay(140); //Koniec warunku wracamy do jazdy prosto } Wykrywanie przeszkód czujnikiem ultradźwiękowym: void loop() { //Czy wykryto przeszkode w zakresie 0-40 cm if (zmierzOdleglosc() > 40) { leftMotor(40); //Jesli nie, to jedz prosto rightMotor(40); } else { //Jesli przeszkoda stopMotors(); //Zatrzymaj robota serwo.write(20); //Skrec czujnikiem w prawo delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji //Sprawdz, czy po prawej stronie jest przeszkoda if (zmierzOdleglosc() > 40) { //Jesli jest pusto leftMotor(40); rightMotor(-40); delay(400); //Obracaj w prawo przez 400 ms } else { //Jeśli po prawej jest przeszkoda serwo.write(160); //Obroc czujnik w lewo delay(800); //Poczekaj 800ms dla ustabilizowania konstrukcji //Sprawdz, czy po lowej stronie jest przeszkoda if (zmierzOdleglosc() > 40) { //Jesli jest pusto leftMotor(-40); rightMotor(40); delay(400); //Obracaj w lewo przez 400 ms } else { //Jesli z przodu, z lewej i prawej jest przeszkoda digitalWrite(BUZZER, 1); delay(500); digitalWrite(BUZZER, 0); //Daj sygnal buzzerem } } //Po sprawdzeniu przeszkod po bokach //Ustaw czujnik prosto serwo.write(90); } //Opoznienie 100ms, ponieważ nie ma potrzeby sprawdzać przeszkod czesciej delay(100); } Aktualnie popełniłem taką funkcję, łączącą wykrywanie przeszkód przez krańcówki i sonar: void jazdaAuto() { //Funkcja jazdy autonomicznej ekspander.digitalWrite(LEDjazda, 1); unsigned long kontakt = 0; //Zmienne przechowująca czas startu unsigned long przeszkoda = 0; if (digitalRead(lewySensor) == LOW) { //Jeżeli przeszkoda po lewej zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms lewySilnik(-80); //Cofnij kawałek prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Cofaj przez 800 ms lewySilnik(80); //Skręć w prawo prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Skręcaj przez 800 ms zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms } if (digitalRead(prawySensor) == LOW) { //Jeżeli przeszkoda po prawej zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 ms lewySilnik(-80); //Cofnij kawałek prawySilnik(-80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Cofaj przez 800 ms lewySilnik(-80); //Skręć w lewo prawySilnik(80); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 800) {} //Skręć w lewo przez 800 ms zatrzymajSilniki(); kontakt = millis(); //Aktualizuj czas startu while (millis() - kontakt < 100) {} //Poczekaj 100 milisekund } if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(90); // To jedź prosto prawySilnik(90); } else { // Jeżeli wykryłeś przeszkodę serwo.attach(SERWO_PIN); // Podłącz serwo zatrzymajSilniki(); serwo.write(700); // Skręć czujnikiem w prawo przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; //Poczekaj 800 ms if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(70); // Skręcaj w prawo prawySilnik(-70); serwo.write(1400); // Ustaw serwo do pozycji domyślnej przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; // Skręcaj przez 800 ms serwo.detach(); // Odłącz serwo } else { // Jeżeli wykryłeś przeszkodę serwo.write(2100); // Skręć czujnikiem w lewo przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; //Poczekaj 800 ms if (sonarDystans() > 30) { // Jeżeli w odległości 30 cm nie ma przeszkody lewySilnik(-70); // Skręcaj w lewo prawySilnik(70); serwo.write(1400); // Ustaw serwo domyślnie przeszkoda = millis(); while(millis() - przeszkoda < 800) {}; // Skręcaj przez 800 ms serwo.detach(); // Odłącz serwo } else { // Jeżeli z każdej strony jest przeszkoda serwo.write(1400); // Ustaw serwo domyślnie digitalWrite(BUZZER, 1); // Daj sygnał buzzerem przeszkoda = millis(); while(millis() - przeszkoda < 500) {}; //Buzzer włączony przez 500 ms digitalWrite(BUZZER, 0); //Wyłącz buzzer serwo.detach(); //Odłącz serwo } } } przeszkoda = millis(); while (millis()-przeszkoda < 100) {} //Opóźnienie 100 ms dla wykrywania przeszkód } Edytowano Luty 15, 2023 przez Danyeru
Danyeru Luty 15, 2023 Autor tematu Udostępnij Luty 15, 2023 W międzyczasie popełniłem takiego potworka, ale po wykryciu przeszkody z przodu, obracał czujnik od razu w lewo i jak nie wykrył przeszkody, to ruszał do przodu nie odwracając czujnika. Wiem, że gdzieś dzwoni, ale nie do końca... void jazdaAuto(){ ekspander.digitalWrite(LEDjazda, 1); czasSonar = millis(); roznicaSonar = czasSonar - odmierzSonar; if (roznicaSonar >= 100UL) { odmierzSonar = czasSonar; if (sonar() > 30) { //Jeżeli w odległości 30 cm brak przeszkody lewySilnik(95); //Jedź prosto prawySilnik(95); } else { serwo.attach(SERWO_PIN); //Podłącz serwo zatrzymajSilniki(); serwo.write(25); //Spójrz w prawo czasPrawo = millis(); roznicaPrawo = czasPrawo - odmierzPrawo; if (roznicaPrawo >= 500UL) { odmierzPrawo = czasPrawo; if (sonar() > 30) { //Jeżeli w odległości 30 cm brak przeszkoday lewySilnik(70); //Skręć w prawo prawySilnik(-70); czasSkretP = millis(); roznicaSkretP = czasSkretP - odmierzSkretP; if (roznicaSkretP >= 1000UL){ odmierzSkretP = czasSkretP; zatrzymajSilniki(); serwo.write(85); //Ustaw serwo na wprost serwo.detach(); //Odłącz serwo } } else { serwo.write(155); //Spójrz w lewo czasLewo = millis(); roznicaLewo = czasLewo - odmierzLewo; if (roznicaLewo >= 500) { odmierzLewo = czasLewo; if (sonar() > 30){ //Jeżeli w odległości 30 cm brak przeszkody lewySilnik(-70); //Skręć w lewo prawySilnik(70); czasSkretL = millis(); roznicaSkretL = czasSkretL - odmierzSkretL; if (roznicaSkretL >= 1000UL){ odmierzSkretL = czasSkretL; zatrzymajSilniki(); serwo.write(85); //Ustaw serwo na wprost serwo.detach(); //Odłącz serwo } } else { serwo.write(85); //Ustaw serwo na wprost serwo.detach(); //Odłącz serwo digitalWrite(BUZZER,1); czasBuzzer = millis(); roznicaBuzzer = czasBuzzer - odmierzBuzzer; if (roznicaBuzzer >= 500UL){ odmierzBuzzer = czasBuzzer; digitalWrite(BUZZER,0); } } } } } } } if (digitalRead(lewySensor) == LOW) { //Jeżeli dotkniesz przeszkody po lewej zatrzymajSilniki(); czasLewyDotyk = millis(); roznicaLewyDotyk = czasLewyDotyk - odmierzLewyDotyk; if (roznicaLewyDotyk >= 100UL){ //Zatrzymaj się na 100 ms odmierzLewyDotyk = czasLewyDotyk; lewySilnik(-70); //Cofnij się kawałek prawySilnik(-70); czasLeweCofanie = millis(); roznicaLeweCofanie = czasLeweCofanie - odmierzLeweCofanie; if (roznicaLeweCofanie >= 500UL) { //Cofaj przez 500 ms odmierzLeweCofanie = czasLeweCofanie; lewySilnik(70); //Obracaj w prawo prawySilnik(-70); czasLewyObrot = millis(); roznicaLewyObrot = czasLewyObrot - odmierzLewyObrot; if (roznicaLewyObrot >= 1000UL){ //Obracaj przez sekundę odmierzLewyObrot = czasLewyObrot; zatrzymajSilniki(); } } } } if (digitalRead(prawySensor) == LOW) { //Jeżeli dotkniesz przeszkody po prawej zatrzymajSilniki(); czasPrawyDotyk = millis(); roznicaPrawyDotyk = czasPrawyDotyk - odmierzPrawyDotyk; if (roznicaPrawyDotyk >= 100UL){ //Zatrzymaj się na 100 ms odmierzPrawyDotyk = czasLewyDotyk; lewySilnik(-70); //Cofnij się kawałek prawySilnik(-70); czasPraweCofanie = millis(); roznicaPraweCofanie = czasPraweCofanie - odmierzPraweCofanie; if (roznicaPraweCofanie >= 500UL) { //Cofaj przez 500 ms odmierzPraweCofanie = czasPraweCofanie; lewySilnik(-70); //Obracaj w lewo prawySilnik(70); czasPrawyObrot = millis(); roznicaPrawyObrot = czasPrawyObrot - odmierzPrawyObrot; if (roznicaPrawyObrot >= 1000UL){ //Obracaj przez sekundę odmierzPrawyObrot = czasPrawyObrot; zatrzymajSilniki(); } } } } } DHT22 pracuje na millis i jest ok, ale nie potrafię się odnaleźć w nieco bardziej złożonym przypadku.
farmaceuta Luty 15, 2023 Udostępnij Luty 15, 2023 (edytowany) Ja bym to trochę zmienił i rozpisał maszynę stanów...millis() używasz tak często że być może lepsza opcja było by użycie funkcji... fun(last_time, 1000); bool fun(uint32_t & last, uint32_t interval) { if(millis() - last > interwal) { last = millis(); return true; } else { return false; } Edytowano Luty 16, 2023 przez farmaceuta 1
ethanak Luty 16, 2023 Udostępnij Luty 16, 2023 @farmaceuta bardzo fajny przykład (tylko zmień typ drugiego argumentu na uint32_t i popraw literówkę) @Danyeru problem w tym, że traktujesz "delay" jako jakiś strasznie fujasty wynalazek diabła i robisz własną konstrukcję... która w rzeczywistości robi dokładnie to samo tylko z mniejszą dokładnością (w folderze instalacyjnym Arduino masz gdzieś plik wiring.c i możesz zobaczyć jak działa ten "systemowy" delay. Uprzedzam: funkcja yield() nie robi nic) i jest dokładnie tak samo fujasta W swoim kodzie masz coś takiego: void loop() { zrób_coś(); zrób_coś_jeszcze(); poczekaj_chwilkę(); } Jeśli chcesz pozbyć się czekania, to raczej powinno być coś w stylu: void loop() { if (przyszedł_czas_na_zrobienie_czegoś()) zrób_coś(); if (przyszedł_czas_na_zrobienie_czegoś_jeszcze()) zrób_coś_jeszcze(); } Jeśli teraz owe "zróbcosie" potraktujesz tak samo, okaże się że nie masz żadnych opóźnień, ale za to wielce krzaczasty gąszcz ifów... ale właśnie dlatego wymyślono coś co się nazywa "maszyna stanów" i bardzo skutecznie eliminuje owe krzaki. Tak przy okazji: "automat skończony" i "maszyna stanów" to takie bardzo mądre nazwy, ale w rzeczywistości jest to całkiem proste i nie ma się czego obawiać. Na tym polega owo "przestawienie myślenia" o którym pisałem na czacie. Ale... jeśli nie skończyłeś całego kursu Arduino (a zdaje się że tylko pierwszą część) to lepiej skończ cały, bo takie przeskakiwanie do produ może być nieskuteczne. 1
Danyeru Luty 16, 2023 Autor tematu Udostępnij Luty 16, 2023 To nie jest tak, że skończyłem pierwszą część kursu i pozjadałem wszystkie rozumy, oczywiście będę kontynuował. Tutaj zrobiłem jeden skok do przodu przy okazji czujnika DHT. A, że przeglądając forum pod tematami pierwszej części kursu często widziałem w postach wypowiedzi typu "lepiej użyj millis, zainteresuj się millis", no to się zainteresowałem nieco ponad kursem, może nieco na wyrost. Robot oprócz jeżdżenia wysyła dane z czujnika i ma mieć konkretne sekwencje grup LED, zatem czy ten aktualny delay w manewrach nie wpłynie na te funkcje? Zatem dziękuję za wskazówki, zainteresuję się tą maszyną stanów i tym rozwiązaniem od Farmaceuty.
ethanak Luty 16, 2023 Udostępnij Luty 16, 2023 Delay won do kosza zanim nie przejdxiesz na esp. A to tego co chcesz właśnie są maszyny stanów (możesz ich mieć wiecej niż jedną).
Danyeru Luty 18, 2023 Autor tematu Udostępnij Luty 18, 2023 (edytowany) Dobra, idę uczyć się dalej, a póki co, ogarnąłem w ten sposób, dla sekcji z czujnikiem odległości: enum States { PROSTO, PATRZ_PRAWO, OBROT_PRAWO, PATRZ_LEWO, OBROT_LEWO, ALARM, ZATRZYMAJ, }; void jazdaAuto() { //Funkcja jazdy autonomicznej ekspander.digitalWrite(LEDjazda, 1); //Włącz LED informujący o jeździe autonomicznej static States obecnyStan = PROSTO; //Domyślny stan static unsigned long czasStanu = 0; //Zmienna dla timera const int doPrzeszkody = 20; //Odległość wykrywania przeszkody w cm switch (obecnyStan) { case PROSTO: if (sonarDystans() <= doPrzeszkody) { //Jeżeli w zadanej odległości jest przeszkoda obecnyStan = ZATRZYMAJ; //Przejdź do zatrzymania czasStanu = millis(); //Ustaw czas dla timera serwo.attach(SERWO_PIN); //Podłącz serwo } else { //Jedź prosto lewySilnik(90); prawySilnik(90); } break; case ZATRZYMAJ: zatrzymajSilniki(); if (millis() - czasStanu >= 500) { obecnyStan = PATRZ_PRAWO; //Przejdź do wykrywania przeszkody po prawej czasStanu = millis(); } break; case PATRZ_PRAWO: //Wykrywanie przeszkód po prawej serwo.write(25); //Ustw serwo w prawo if (millis() - czasStanu >= 200) { //Patrz przez 200 ms dla ustabilizowania serwa if (sonarDystans() > doPrzeszkody) { //Jeżeli nie ma przeszkód bliżej niż zadana odległość obecnyStan = OBROT_PRAWO; //Skręć w prawo czasStanu = millis(); //Ustaw czas dla timera } else { //Jeżeli jest przeszkoda obecnyStan = PATRZ_LEWO; //Przejdź do wykrywania przeszkody po lewej czasStanu = millis(); //Ustaw czas dla timera } } break; case OBROT_PRAWO: //Skręt w prawo lewySilnik(70); prawySilnik(-70); serwo.write(85); //Ustaw serwo na wprost if (millis() - czasStanu >= 800) { //Skręcaj przez 800 ms serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy na prosto czasStanu = millis(); //Uataw czas dla timera } break; case PATRZ_LEWO: //Wykrywanie przeszkód po lewej serwo.write(155); //Obróć serwo w lewo if (millis() - czasStanu >= 250) { //Patrz przez 200 ms dla ustabilizowania serwa if (sonarDystans() > doPrzeszkody) { //Jeżeli nie ma przeszkody w zadanej odległości obecnyStan = OBROT_LEWO; //Skręć w lewo czasStanu = millis(); //Ustaw czas dla timera } else { //Jeżeli jest przeszkoda obecnyStan = ALARM; //Włącz alarm czasStanu = millis(); //Ustaw czas dla timera } } break; case OBROT_LEWO: //Skręt w lewo lewySilnik(-70); prawySilnik(70); serwo.write(85); //Ustaw serwo na wprost if (millis() - czasStanu >= 800) { //Skręcaj przez 800 ms serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy prosto czasStanu = millis(); //Ustaw czas dla timera } break; case ALARM: serwo.write(85); //Ustaw serwo na wprost digitalWrite(BUZZER, 1); //Włącz buzzer if (millis() - czasStanu >= 500) { //Po upływie 500 ms digitalWrite(BUZZER, 0); //Wyłącz buzzer serwo.detach(); obecnyStan = PROSTO; //Przejdź do jazdy prosto czasStanu = millis(); //Ustaw czas dla timera } break; } Edytowano Luty 19, 2023 przez Danyeru
ethanak Luty 19, 2023 Udostępnij Luty 19, 2023 No i właśnie złapałeś o co chodzi.To co prawda jeszcze nie jest taki kod jak powinien być docelowo, ale zasada jest właśnie taka. 2
Pomocna odpowiedź
Bądź aktywny - zaloguj się lub utwórz konto!
Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony
Utwórz konto w ~20 sekund!
Zarejestruj nowe konto, to proste!
Zarejestruj się »Zaloguj się
Posiadasz własne konto? Użyj go!
Zaloguj się »