Skocz do zawartości

Kurs Arduino - #9 - Czujnik odległości HC-SR04, funkcje


Pomocna odpowiedź

(edytowany)

Cześć,

Usiłuję wyrzeźbić prosty prędkościomierz na bazie HC-SR04 ale nie mogę zmusić go do działania. 

Algorytm jest oczywisty:

  1. wywołanie funkcji mierzącej odległość
  2. odczekanie krótkiej chwili
  3. ponowny pomiar
  4. Obliczenie różnicy obydwu wartości
  5. Przeliczenie na prędkość (m/s).

Problem polega na tym, że nie udaje mi dokonać dwóch pomiarów w jednej pętli. Zawsze jeden z pomiarów jest prawidłowy a drugi wynosi niezmiennie 0 (zazwyczaj ten drugi ale po wydłużeniu czasu odstępu czasowego drugi jest ok a pierwszy pokazuje 0). Próbowałem kombinować z odstępem czasowym pomiędzy obydwoma pomiarami, tworzyłem również bliźniaczą funkcję 

measure()

(tyle że inaczej nazwaną) sterującą czujnikiem aby każdy pomiar miał "swoją" ale i to nie pomogło. Pomożecie?

 

[code]
#define trig 5
#define echo 6
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 4, 7, 8, 12, 13, 9);

void setup() {
  //UART
  Serial.begin(9600);
  //Ustawienie trig i echo
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  //Ustawienie LCD
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Velocity:");
}

void loop() {
  //Odczyt 2 + ograniczenie wartosci 1
  float cm1 = measure();
  if (cm1 > 400) {
    cm1 = 400;
  }
  delay(1);
  //Odczyt 2 + ograniczenie wartosci
  float cm2 = measure();
  if (cm2 > 400) {
    cm2 = 400;
  }
  //Obliczenie prędkości
  float substract = (cm2 - cm1);
  float velocity = abs((substract * 1000) / 100);
  Serial.println(cm1);
  Serial.println(cm2);
  //Wyswietlenie predkosci na LCD
  lcd.setCursor(0, 1);
  lcd.print(velocity, 2);
  lcd.print(" m/s");
  lcd.print("    ");
}

float measure() {
  float echoread;
  // Start nadawanie
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  // Koniec nadawania

  //Odczyt
  echoread = pulseIn(echo, HIGH);
  // Przeliczenie na cm 
  float odo = echoread / 58; 
  return odo;
}


[/code]

 

Edytowano przez Wloczykij555

Spróbuj dać na koniec sekcji setup delay(30). Mnie czasem czujnik nie zalapywal od razu po włączeniu zasilania. Masz też dużo zmiennych typu float. Operacje na nich są dość długotrwałe. Może dla testu spróbuj cześć z nich zamienić na int. Wynik z funkcji pulseIn nie musi być float, nie dostaniesz tam przecież ułamków

(edytowany)

Niestety delay(30) nie pomógł. 

Co do zmiennych, to pierwotnie wszystkie były typu int i działo się dokładnie to samo. Chciałem uzyskać pomiar z dokładnością do 2 miejsc po przecinku więc przemianowałem wszystko na float. Co ciekawe, również wynik z pulsein też musi być float bo inaczej po podzieleniu przez 58 zaokrągla mi końcowy wynik funkcji ("odo") do liczby całkowitej (nawet jeśli tą ostatnią zmienną zadeklarowałem jako float).

 

Ogólnie wszystko wydaje się być ok, wartości na LCD są wyświetlane w oczekiwanym formacie, tyle że są nieprawidłowe.

 

EDIT

Zmodyfikowałem program tak, żeby pierwszy pomiar odbywał się z wywołania funkcji, a drugi był zintegrowany z loop() i dalej lipa. Poniżej wyniki odczytu obu wartości (na górze pierwsza, na dole druga).

 

#define trig 5
#define echo 6
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 4, 7, 8, 12, 13, 9);

void setup() {
  //UART
  Serial.begin(9600);
  //Ustawienie trig i echo
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  //Ustawienie LCD
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Velocity:");
  delay(30);
}

void loop() {
  //Odczyt 1 + ograniczenie wartosci 1
  float cm1 = measure();
  if (cm1 > 400) {
    cm1 = 400;
  }
  delay(1);
  
  //Odczyt 2 + ograniczenie wartosci 2

float echoread1;
  // Start nadawanie
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  // Koniec nadawania

  //Odczyt
  echoread1 = pulseIn(echo, HIGH);
  // Przeliczenie na cm 
  float cm2 = echoread1 / 58; 
  
//  float cm2 = measure();
  if (cm2 > 400) {
    cm2 = 400;
  }
  //Sprawdzenie odczytów przez UART
  Serial.println(cm1);
  Serial.println(cm2);
  Serial.println("");
  //Obliczenie prędkości
  float substract = (cm2 - cm1);
  float velocity = abs((substract * 1000) / 100);
  //Wyswietlenie predkosci na LCD
  lcd.setCursor(0, 1);
  lcd.print(velocity, 2);
  lcd.print(" m/s");
  lcd.print("    ");
}

float measure() {
  float echoread;
  // Start nadawanie
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  // Koniec nadawania

  //Odczyt
  echoread = pulseIn(echo, HIGH);
  // Przeliczenie na cm 
  float odo = echoread / 58; 
  return odo;
}

Przechwytywanie.thumb.PNG.3bcf25e49156480366cbae630f5c8abb.PNG

Edytowano przez Wloczykij555
1 godzinę temu, Wloczykij555 napisał:

Co ciekawe, również wynik z pulsein też musi być float bo inaczej po podzieleniu przez 58 zaokrągla mi końcowy wynik 

 

Poczytaj o "jawne rzutowanie"...bardzo przydatny temat jesli sa jakies "bledy" podczas dzielenia, mnozenia itp roznych typow i zapisywania wyniku do roznych typow...ogolnie chodzi o to ze wynik jest automatycznie rzutowany do najwiekszego typu lub do typu int...

W twoim pierwszym kodzie spróbuj dać opóźnienie po 2 pomiarze, bo po pierwszym dajesz 1ms a po drugim już nie. Kurcze tak na 1 rzut oka powinno działać, ale coś widać nie gra. Jak sobie nie poradzisz to jutro podłącze wieczorem ardu i wrzucę to co Ty masz. 

46 minut temu, farmaceuta napisał:

Poczytaj o "jawne rzutowanie"...bardzo przydatny temat jesli sa jakies "bledy" podczas dzielenia, mnozenia itp roznych typow i zapisywania wyniku do roznych typow...ogolnie chodzi o to ze wynik jest automatycznie rzutowany do najwiekszego typu lub do typu int...

Dzięki! Nowa wiedza wpadła 🙂

 

10 minut temu, Krawi92 napisał:

W twoim pierwszym kodzie spróbuj dać opóźnienie po 2 pomiarze, bo po pierwszym dajesz 1ms a po drugim już nie. Kurcze tak na 1 rzut oka powinno działać, ale coś widać nie gra. Jak sobie nie poradzisz to jutro podłącze wieczorem ardu i wrzucę to co Ty masz. 

Ok, chyba mam odpowiedź a brzmi ona - ten czujnik po prostu ssie 🙃 Dodałem delay() na końcu programu oraz wydłużyłem odstęp czasowy pomiędzy pomiarami i zaczęło trybić. Wygląda na to, że przy tak krótkich czasach załączania i wyłączania ten czujnik się po prostu nie wyrabiał. Na marginesie, LCD też do takich pomiarów się nie nadaje, bo przy szybkich zmianach wartości robi się nieczytelny (zbyt duża bezwładność pikseli). Poniżej finalny kod. Dziękuję za odzew 🙂

 

#define trig 5
#define echo 6
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 4, 7, 8, 12, 13, 9);

void setup() {
  //UART
  Serial.begin(9600);
  //Ustawienie trig i echo
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  //Ustawienie LCD
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Velocity:");
  delay(30);
}

void loop() {
  //Odczyt 1 + ograniczenie wartosci 1
  float cm1 = measure();
  if (cm1 > 400) {
    cm1 = 400;
  }
  delay(80);
  
  //Odczyt 2 + ograniczenie wartosci 2

  float cm2 = measure();
  if (cm2 > 400) {
    cm2 = 400;
  }
  //Obliczenie różnicy pomiarów
  float substract = (cm2 - cm1);
  
  // Odflitrowanie szumów
  if (substract < 0.15 && substract > -0.15){
    substract = 0;
  }
  
  //Obliczenie prędkosci
  float velocity = abs((substract * 12.5) / 100);

  //Wyswietlenie predkosci na LCD
  Serial.println(velocity, 2);
  lcd.setCursor(0, 1);
  lcd.print(velocity, 2);
  lcd.print(" m/s");
  lcd.print("    ");
  delay(80);
}

float measure() {
  int echoread;
  // Start nadawanie
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  // Koniec nadawania

  //Odczyt
  echoread = pulseIn(echo, HIGH);
  // Przeliczenie na cm 
  float odo = (float) echoread / 58; 
  return odo;
}

 

Problem tez troche polega na tym że to typowe programowanie liniowe oparte na delayach. Ja bym to postaral się zrobić na timerach programowych, aby nic nie blokowało programu. Te delaye też blokują wyświetlanie na lcd, które też wbrew pozorom nie jest bardzo szybkie i ma swoje ograniczenia. 

  • 4 miesiące później...
  • 1 miesiąc później...

Chciałem napisać funkcję w której wpisywanym argumentem było by wejście analogowe np. A0. Jaką zmienną jest A0? Int lub String nie dają rady. Proszę o pomoc.

@Macej98 A0 jest symbolem preprocesora. Nie możesz odwołać się do A0 jak do zmiennej, możesz tylko wpisać. Ale do argumentu funkcji przyjmującej int zadziała.

void loop() {
  temperatura(A5);
}
void temperatura (int pin){
    float pomiar_t = analogRead(pin);
    float temperatura= (pomiar_t* 0.12218964)- 20;
    Serial.println(temperatura);
    delay(1000);
}

Napisałem taką funkcję. Niestety nie działa. 

Nie pokazuje wyniku z czujnika temperatury podpiętego do pinu A5. Natomiast przy identycznym połączeniu, poniższy kod normalnie pokazuje wynik z czujnika temperatury podpiętego do pinu 5.

void loop() {
  float pomiar_t = analogRead(A5);
  float temperatura= (pomiar_t* 0.12218964)- 20;
  Serial.println(temperatura);
  delay(1000);
}

 

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ę »
×
×
  • Utwórz nowe...