Skocz do zawartości

HC-SR04 - Wielofunkcyjność programowa na podstawie czujnika odległości. Modyfikacja programu


Forseti

Pomocna odpowiedź

11 minut temu, _LM_ napisał:

Jak dla mnie kolejny warunek przeciw arduino.

Tyle że to nie jest wymysł Arduino a pewnego standardu, którego Arduino się trzyma (zresztą nie tylko Arduino).

A jaki Twoim zdaniem typ powinno zwracać millis()? Masz do dyspozycji albo uint16_t (czyli po minucie się przekręci), albo istniejący uint32_t. Poza tym kto Ci broni zrobić coś takiego:

uint16_t costam =  millis();

Cóż - jak to było z tym tancerzem i pewnymi częściami ciała? 😉

 

Link do komentarza
Share on other sites

1 minutę temu, ethanak napisał:

A jaki Twoim zdaniem typ powinno zwracać millis()?

A po co ta funkcja jak można to lepiej zrobić bezpośrednio na przerwaniach? Co jak będę potrzebował dziesięciu timerów programowych, mam zużyć 40B pamięci? O ile w Atmegach to jakoś ujdzie to w Attiny dość szybko zawali ram, już nie wspominając o tym że zapis/odczyt większych typów danych zajmuje również sporo czasu. To ja już wolę poświęcić te minutę na konfigurację i uruchomienie któregoś z timerów.

Link do komentarza
Share on other sites

4 minuty temu, _LM_ napisał:

A po co ta funkcja jak można to lepiej zrobić bezpośrednio na przerwaniach?

A czy millis() służy wyłącznie do zastępowania delaja przez już-nie-początkujących-jak-im-się-wydaje programistów? To przecież funkcja odmierzająca czas, owszem, można to zrobić na przerwaniach (tylko po jakiego grzyba, jeśli millis() już jest i działa właśnie na przerwaniach? swojego millisa będziesz pisać i pewnie będzie lepszy niż ten co jest?)

Takie typowe zastosowanie: czy minęło już ileś tam milisekund od zdarzenia X?

A pytanie "po co ta funkcja" kieruj do autorów Wiringa. Możesz ich nawet poinformować, że wymyśliłeś coś lepszego i powinni natychmiast usunąć millis() ze standardu.

 

Link do komentarza
Share on other sites

11 minut temu, _LM_ napisał:

O ile w Atmegach to jakoś ujdzie to w Attiny dość szybko zawali ram

Wiesz - programowanie ATtiny z bibliotekami Arduino to niespecjalnie dobry pomysł... W takim np. SDK to RPi Pico nie ma millis, jest za to odpowiednik micros i to 64-bitowy 😉 Mam się go pozbyć?

 

 

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

4 minuty temu, ethanak napisał:

W takim np. SDK to RPi Pico nie ma millis, jest za to odpowiednik micros i to 64-bitowy 😉 Mam się go pozbyć?

Panie kolego a czujesz różnicę pomiędzy mikrokontrolerem 32bitowym a piździkiem 8bit? 

 

5 minut temu, ethanak napisał:

Wiesz - programowanie ATtiny z bibliotekami Arduino to niespecjalnie dobry pomysł...

A jednak takie próby się pojawiają, ja nie oceniam czy to dobrze, jak ktoś lubi niech se używa.

11 minut temu, ethanak napisał:

To przecież funkcja odmierzająca czas, owszem, można to zrobić na przerwaniach (tylko po jakiego grzyba, jeśli millis() już jest i działa właśnie na przerwaniach? swojego millisa będziesz pisać i pewnie będzie lepszy niż ten co jest?)

A po to, że wiem po co i którego timera użyłem do wykonania tego czy innego zadania. I tak wiem, mogę sobie to sprawdzić w dokumentacji arduino.

Link do komentarza
Share on other sites

3 minuty temu, _LM_ napisał:

A po to, że wiem po co i którego timera użyłem do wykonania tego czy innego zadania.

Zdaje się że patrzysz na wszystko z punktu widzenia typu "ja robię takie rzeczy a nie inne" i w związku z tym uważasz, że co poniektóre funkcje są niepotrzebne bo ich nie używasz. Wyobraź sobie, że istnieje cała masa zastosowań w których owe funkcję potrzebne, i w których nikt nie zawraca sobie głowy jakimiś timerami (krórych albo się w owych zastosowaniach nie używa, albo po prostu używa się funkcji bibliotecznych które się owymi timerami zajmują).

Mówisz timery... a teraz wyobraź sobie, że chcesz przeportować swój niewątpliwie wspaniały program na inny mikrokontroler. Ile czasu zmarnujesz na nauczenie się jakich timerów możesz użyć np. w ESP-32? Ja jak chcę poznać ile czasu minęło od jakiegoś zdarzenia nie przejmuję się timerami (choćby z tego powodu, że te same programy uruchamiam często na małym Arduino, obu wersjach ESP czy Pico, a nawet na pececie czy pełnowymiarowym RPi) - tylko znajduję sobie funkcję z biblioteki. A czy to będzie millis, czy time_us_64, czy nawet gettimeofday - jedna chwała.

 

Link do komentarza
Share on other sites

A żebyś wiedział że na takim esp8266 chętnie używam bibliotek arduino(ESP32 czeka na swoją kolej). I owszem. Niema sensu uczyć się rejestrów takiego esp czy jakiegoś ARMa. Stwierdziłem wcześniej że używanie tych millis() ze względu na zajmowany rozmiar w mikrokontrolerach 8bit jest marnotrawieniem pamięci, było to moje spostrzeżenie wysnute "na gorąco" po tym, jak sprawdziłem na szybko jak to działa. I nadal tak uważam. Co innego mocniejsze jednostki. To oczywiste że bez wbudowanych bibliotek trudno byłoby ruszyć z miejsca.  Dobrze jednak wiedzieć co w krzemie piszczy.

Link do komentarza
Share on other sites

 int bleble = 0;

void DC_PRAWO() //Silniki skręc w prawo
{
  motor1.run(FORWARD);
  motor2.run(BACKWARD);
  bleble = 0;
  while(bleble <= 500) {
    bleble++;
    if (wcisniety guzik?) {
      bleble = 1000;
      }
  delay(1);
    }
  motor1.run(FORWARD);
  motor2.run(FORWARD);
}

void DC_LEWO() //Silniki skręc w lewo
{
  motor1.run(BACKWARD);
  motor2.run(FORWARD);
  bleble = 0;
  while(bleble <= 500) {
    bleble++;
    if (wcisniety guzik?) {
      bleble = 1000;
      }
  delay(1);
    }
  motor1.run(FORWARD);
  motor2.run(FORWARD);
}

Sprawdz narazie to czy dziala...wiem ze da sie inaczej, estetyczniej itp, no ale slabo mi glowa ostatnio dziala...heh🤕

Link do komentarza
Share on other sites

14 minut temu, farmaceuta napisał:

wiem ze da sie inaczej,

Ludzie, przestańcie takie potworki programopodobne płodzić, bo zamiast pomagać początkującemu robicie tylko galimatias!

Prosty fragment programu - przykładowa realizacja start/stop po naciśnięciu jednego guzika oraz  półsekundowego skrętu i jazdy dalej prosto po naciśnięciu drugiego guzika:

enum {
  STOIMY = 0,
  START,
  JEDZIEMY,
  ZATRZYMAJ,
  JEDZIEMY,
  ZAKRECAMY_W_PRAWO,
  ZAKRECAMY
  };

int stan;
uint32_t started;

void loop()
{
  guzik_w_prawo.update(); // coś wspominałęm o bounce2?
  guzik_start.update();
  
  // przyjmujemy polecenie
  
  if (guzik_w_prawo.fell()) {
    stan = ZAKRECAMY_W_PRAWO;
  }
  if (guzik_start.fell()) {
    if (stan != STOIMY) stan = ZATRZYMAJ;
    else stan = START;
  }
  //no i maszyna stanów
  
  switch (stan) {
    case STOIMY: // czekamy na coś
      break;

    case ZATRZYMAJ:
      motor1.stop();
      motor2.stop();
      stan = STOIMY;
      break;
      
    case START: // czyli robot ma ruszyć i jechać
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      stan = JEDZIEMY;
      break;
      
    case JEDZIEMY: // silnuki się kręcą, robot jedzie, my patrzymy, ogólnie sielanka
      break;
      
    case ZAKRECAMY_W_PRAWO: // dostaliśmy polecenie, będziemy skręcać!
      motor1.run(FORWARD);
      motor2.run(BACKWARD);
      started = millis(); // zapamiętujemy kiedy zaczęliśmy skręcać
      stan = ZAKRECAMY;
      break;
      
    case ZAKRECAMY: // nieważne w którą stronę
      if (millis() - started >= 500UL) { // funkcja millis() słuzy oczywiście do pomiaru czasu jak sama nazwa wskazuje
                                         //Większe lub równe, a nie równe, bo jakby było równe to moglibyśmy przegapić
        stan = START; // czyli wracamy do jazdy prosto
      }
      break;
  }
}
      

 

 

Link do komentarza
Share on other sites

2 godziny temu, _LM_ napisał:

Niema sensu uczyć się rejestrów takiego esp czy jakiegoś ARMa.

Dlaczego nie ma sensu uczyć się działania na rejestrach w układach ARM? O esp nie pytam, bo nie używam, ale w przypadku ARM trochę mnie zaskoczyło takie stwierdzenie.

Link do komentarza
Share on other sites

(edytowany)

Po przeanalizowaniu Waszych sugestii zacząłem równolegle rozwiązywać swój problem na własną rękę (wywaliłem delaye() ). Sądzę, że jestem relatywnie bliski rozwiązania problemu. 

Okroiłem program do samej obsługi serva (cel edukacyjny). Kod robi to co chcę. Przełącza się microswitchem pomiędzy Programami (1,2,3). Servo reaguje na zbliżenie do czujnika <15cm ale... no właśnie. Kod się realizuje tylko gdy dystans jest <15cm. W momencie gdy ten dystans się zwiększy kod się zatrzymuje. Nie wiem jak sobie z tym poradzić.  Chcę aby jeśli dystans jest mniejszy niż 15cm to ma być wykonany cały kod (LEWO/PRAWO) bezwzględnie od kolejnego pomiaru. Jak go zmusić do tego bez delay()? 😕

Jakieś sugestie?  Nie chciałbym znów przewracać do góry nogami kodu. 

/*Robot omijający przszkody - oparty o L293D Motor Driver Shield
   oraz czujnik odległości HC-SR04
   Napęd - 2x silniki DC 3-6V
   Serwomechanizm SG-90
   Włączany microswitchem
   dioda LED sygnalizacyjna stan pracy - Wolne miganie Program_1, Szybkie Program_2, Ciągłe STOP
   Opcja rozbudowy o sterowanie BT i modułem HC-05
*/

//Biblioteki
#include <NewPing.h> //Wczytanie Biblioteki NewPing dla HC-SR04
#include <Servo.h>  //Wczytanie Biblioteki Servo dla SG-90

//Definicje
#define LED_1 A4 //LED 1 
#define Przycisk_1 A5 //Microswitch_1

//Sensor HC-SR04
#define TRIG_PIN A0 //Wejście wyzwalające Trigger - pomiar odległości
#define ECHO_PIN A1 //Wyjście ECHO - odczyt odległości
#define MAX_DISTANCE 200 //Maksymalny dystans dla czujnika HC-SR04 - od tej wartości reaguje robot

//Ustawienia i przypisania

NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); //Przypisanie zmiennych z define

//Wyjście serwomechanizm

Servo moje_servo;   //Obiekt dający możliwość odwołania się do serwa o nazwie moje_servo

boolean F1 = true, F2 = true, F3 = true, F4 = true; //Flagi dla serva umożliwiające wykonanie kodu z użyciem millis
boolean Sonar = true; //Flaga dla sonar


int dystans = 100; //Ustawienie dystansu dla moje_servo - int distance = 100;
int stanLED1 = LOW; //Przypisanie stanu LED 1 do zmiennej int - Zapamiętanie stanu LED

int dystansR = 0; //Ustawienie dystansu w Prawo
int dystansL = 0; //Ustawienie dystansu w Lewo

uint8_t tryb_program = 0; //Zmienna trybu programu

//Ustawienia do millis()
unsigned long aktualnyCzas = 0 ; //Czas, który jest zliczany - ciągle rośnie - Wartość od której odejmujemy zapamiętany czas!!!
unsigned long zapamietanyCzas_LED1 = 0; //Czas, który był zapamiętany w ostatnim obiegu pętli dla LED1
unsigned long zapamietanyCzas_Servo1 = 0; //Czas, który był zapamiętany w ostatnim obiegu pętli dla silnika Serva 1 - obrót prawo/lewo
unsigned long zapamietanyCzas_Sonar = 0; //Czas, który był zapamiętany w ostatnim obiegu pętli dla czujnika HC-SR04

unsigned long miganie_LED1 = 500; //Interwał migania LED1 - Program_1
unsigned long miganie_LED2 = 100; //Interwał migania LED1 - Program_2

//▼▼▼▼▼▼▼▼▼▼▼▼▼PRZYPISANIE RUCHÓW ROOTA▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼

int patrz_PRAWO() //Ustawienie serwa - do patrzenia w prawo - int lookRight()

{
  if ((aktualnyCzas - zapamietanyCzas_Servo1 >= 500UL && F1))
  {
    F1 = false;
    moje_servo.write(50); //Ustawienie kąt 50°
    int dystans = readPing();
    zapamietanyCzas_Servo1 = aktualnyCzas;

  }
  if ((aktualnyCzas - zapamietanyCzas_Servo1 >= 1000UL && F2))
  {
    F2 = false;
    moje_servo.write(115); //Ustawienie kąt 115°
    int dystans = readPing();
  }
}
int patrz_LEWO() //Ustawienie serwa - do patrzenia w lewo - org int lookLeft()
{
  if ((aktualnyCzas - zapamietanyCzas_Servo1 >= 500UL && F3))
  {
    F3 = false;
    moje_servo.write(170); //Ustawienie kąt 170°
    int dystans = readPing();
  }
  if ((aktualnyCzas - zapamietanyCzas_Servo1 >= 1000UL && F4))
  {
    F4 = false;
    moje_servo.write(115); //Ustawienie kąt 115°
    int dystans = readPing();
    zapamietanyCzas_Servo1 = aktualnyCzas;
    F1 = true;
    F2 = true;
    F3 = true;
    F4 = true;
    return dystans;
  }
}

int readPing() //Ustawienie odległości w cm dla czujnika HC-SR04
{
  if ((aktualnyCzas - zapamietanyCzas_Sonar >= 70UL && Sonar))
  {
    Sonar = false;
    int cm = sonar.ping_cm(); //zwraca dystans w cm
    if (cm == 0)
    {
      cm = 250; //do sprawdzenia odległość- czemu aż 250cm ?
    }
    Sonar = true;
    return cm;

  }
}
//▼▼▼▼▼▼▼▼▼▼▼▼▼POCZĄTEK PROGRAMU▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼

void setup() {

  Serial.begin(9600);

  //Startowe ustawienie serva

  moje_servo.attach(10); /*Serwomechanizm podłączony do pinu 10 - obsługiwane PINY 9 i 10.
  Dla Sheilda L293D kolejno 9=Servo_1, 10=Servo 2 -sygnały sterujące*/
  moje_servo.write(115); //Ustawienie pozycji serva na 115°

  //Wyprowadzenie przycisków
  pinMode(Przycisk_1, INPUT_PULLUP); //Wejście przycisku 1 w trybie PULLUP

  //Wyprowadzenia LED
  pinMode(LED_1, OUTPUT);

  //Ustawienie wyjściowego stanu LED
  digitalWrite(LED_1, LOW); //Stan diody LED1 - wyłączona

  //Ustawienie wyjściowe dla millis() - zerowanie liczenia
  aktualnyCzas = millis();
}

void loop() {

  aktualnyCzas = millis(); //Ustawienie wyjściowe dla millis()

  if (!digitalRead(Przycisk_1)) tryb_program++; //Jeśli ostatni stan był wyłączony i aktualny stan jest włączony to:

  switch (tryb_program % 4)  {

    //Modulo - reszta z dzielenia przez 4 - bo 3 programy

    case 1:
      //Miganie LED_1 Wolne miganie Program_1
      if (aktualnyCzas - zapamietanyCzas_LED1 >= miganie_LED1) {
        stanLED1 = !stanLED1;
        digitalWrite(LED_1, stanLED1);
        zapamietanyCzas_LED1 = aktualnyCzas;  //zapamiętaj aktualny czas
      }
      if (dystans <= 15) //jeśli dystans mniejszy od 15cm Patrz_Prawo->Patrz_lewo
      {
        dystansR = patrz_PRAWO();
        dystansL = patrz_LEWO();
      }
      Serial.println(dystans);
      dystans = readPing();
      break;
    case 2:
      //Miganie LED_1 Szybkie miganie Program_2
      if (aktualnyCzas - zapamietanyCzas_LED1 >= miganie_LED2) {
        stanLED1 = !stanLED1;
        digitalWrite(LED_1, stanLED1);
        moje_servo.write(60); //Tylko przykład
        zapamietanyCzas_LED1 = aktualnyCzas;  //zapamiętaj aktualny czas
      }
      break;
    case 3:
      //Tutaj będzie stan OFF
      //Miganie LED_1 Szybkie miganie Program_3
      if (aktualnyCzas - zapamietanyCzas_LED1 >= 50) {
        stanLED1 = !stanLED1;
        digitalWrite(LED_1, stanLED1);

        zapamietanyCzas_LED1 = aktualnyCzas;  //zapamiętaj aktualny czas

      }
      break;
  }

  while (!digitalRead(Przycisk_1));
  delay(50);
}

Oczywiście w każdej wolnej chwili staram się dokształcać ale idzie to powoli. Dzięki za cierpliwość.

PS. Obudowa robota jest gotowa pod kątem mechanicznym 🙂 Męczę tylko logikę. 

Edytowano przez Forseti
Link do komentarza
Share on other sites

10 minut temu, Forseti napisał:

Chcę aby jeśli dystans jest mniejszy niż 15cm to ma być wykonany cały kod (LEWO/PRAWO) bezwzględnie od kolejnego pomiaru. Jak go zmusić do tego bez delay()?

Coś takiego:

W stanie JAZDA jeśli dystans jest mniejszy od 15, zapamiętujesz czas, uruchamiasz silniki czy serwa czy co tam do LEWOi  przełączasz stan maszyny np. na LEWO_BLISKO

W stanie LEWO_BLISKO sprawdzasz, czy czas minął. Jeśli tak, uruchamiasz silniki/serwo/cokolwiek do PRAWO, zapamiętujesz czas i przełączasz stan maszyny np. do PRAWO_BLISKO.

W stanie PRAWO_BLISKO sprawdzasz czy minął czas. Jeśli tak, robisz coś co kończy sekwencję (np. ustawiasz serwo PROSTO,) i przełączasz stan maszyny np. na ROZEJRZALEM_SIE.

W stanie ROZEJRZALEM_SIE decydujesz, co robić dalej (np skręcić tam gdzie jest miejsce albo się cofnąć).

Aha, jeszcze jedno:

Odczytujesz odległość raz na początku pętli, w ostateczności od razu po wejściu do odpowiedniej gałęzi case maszyny stanu czy przy okazji zmiany stanu w ramach przygotowania do następnej czynności. Nigdy w żadnym innym miejscu.

Może być?

16 minut temu, Forseti napisał:

Nie chciałbym znów przewracać do góry nogami kodu. 

Wiesz - program nad którym siedzę osiągnął 5000 linii kodu, a parę takich bardziej grubaśnych funkcji kilka razy już wędrowało do kosza. I nie, nie jest to bardzo duży program, tylko niemiłosiernie pokiełbaszony 🙂 Niestety - czasem przewrócenie wszystkiego do góry nogami ma sens. W sumie w większości przypadków napisanie kawałka kodu od zera będzie szybsze niż próba ratowania kodu który jest źle zaprojektowany.

Tak że nie bój się kosza na śmieci - nie gryzie.

 

Link do komentarza
Share on other sites

2 minuty temu, _LM_ napisał:

można ulepszyć stosując wskaźniki na funkcje zamiast switch

Gdzie tu ulepszenie? Można pewnie zastosować parę konstrukcji których kolega wątkotwórca nie zna (i może niech się na razie nauczy jednego a nie fafnastu rzeczy na raz), a znalazłoby się pewnie i parę takich o których i Ty nie słyszałeś 😉 Sprawdź sobie przy okazji co oznacza skrót KISS.

2 minuty temu, _LM_ napisał:

czekam aż @ethanakpokaże jak powinna wyglądać maszyna stanów z prawdziwego zdarzenia

Na pewno nie tak jak sobie wyobrażasz. A pokazywać nie mam zamiaru - w sieci jest multum przykładów.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

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