• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Niedokładność pomiarowa - problem z odczytywaniem impulsow
#1
Witam, projekt, którym aktualnie się zajmuje to skonstruowanie komputera pokładowego do mojego leciwego juz samochodu Opla Astry F z 97 roku. Moją główną potrzeba jest opracowanie układu który pokazywałby średnie spalanie, ale skoro będę to już robił wyposażę go w dodatkowe funkcje, prędkość, średnia prędkość, dystans, zasięg itp.

Problem z którym aktualnie się borykam wiąże się z pomiarem prędkości, który tak czy siak muszę mieć jeśli chce mieć pomiar spalania średniego czy też chwilowego. Układ jest podłączony do przewodu przesyłającego impulsy przebytej drogi (wzorowałem się na tym projekcie) do układu TID montowanego w oplach. W moim samochodzie na jeden obrót koła przypada 30 impulsów, obwód koła wynosi 1,78 [m], stad na 1 metr przypada 16,85 impulsu. Metodą pomiarową którą obrałem jest zliczanie impulsów w ciągu 1/2 [s], następnie podzielenie ilości przez 16,85, wtedy otrzymuje wynik w [m/(1/2)s], który przeliczam na [km/h]. Sposób ten sprawdza się, całkiem dokładnie, jednak do prędkości rzędu 90 [km/h], potem mimo tego, że auto przyśpiesza pozostaje mniej więcej na tym samym poziomie. Po pomiarach za pomocą monitora portu szeregowego wychodzi na to, że powyżej tej prędkości mój program nie jest w stanie zliczyć więcej impulsów.

Oto kod:
Kod:
#include <LiquidCrystal.h>
#include <Timers.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
Timers <2> timer;

int speedImpulsPin = 9;

int impulsCounter = 0;
bool impuls = true;
double impulsesInOneMeter = 16.85; // obwod kola wynosi 1.78m, na pelny obrot kola przypada 30 impulsow


void setup() {
 Serial.begin(9600);
 pinMode(speedImpulsPin, INPUT);
 
 lcd.begin(16,2);
 lcd.setCursor(0,0);
 lcd.print("ASTRA F    X14XE");
 delay(3000);
 lcd.clear();

 timer.attach(0,1,checkImpuls);
 timer.attach(1,500,calculateSpeed);
}

void checkImpuls() {
 bool voltage = digitalRead(speedImpulsPin);
 
 if(voltage == LOW && impuls == false) {
   impuls = true;
   impulsCounter++;
 }
 else if(voltage == HIGH && impuls == true)
   impuls = false;
}

void calculateSpeed() {
 double meters = impulsCounter / impulsesInOneMeter;
 
 Serial.print(impulsCounter);
 Serial.print(" imp");
 Serial.print("\t");
 
 impulsCounter = 0;
 int speedOfVehicle = meters * 72 / 10; //km/h (2*3600/1000) -> (72/10)
 
 //int speedOfVehicle = meters * 144 / 10; //km/h (4*3600/1000) -> (144/10)

 Serial.print(meters);
 Serial.print(" m/(1/2)s");
 Serial.print("\t");
 Serial.print(speedOfVehicle);
 Serial.println(" km/h");

 displaySpeed(speedOfVehicle);
}

void displaySpeed(int speedOfVehicle) {
 clearLine(0);
 lcd.setCursor(0,0);
 lcd.print("SPEED:");

 if(speedOfVehicle < 10)
   lcd.setCursor(10,0);
 else if(speedOfVehicle >=10 && speedOfVehicle < 100)
   lcd.setCursor(9,0);
 else if(speedOfVehicle >=100 && speedOfVehicle < 1000)
   lcd.setCursor(8,0);  

 lcd.print(speedOfVehicle);
 lcd.print(" KM/H");
}

void clearLine(int line) {
 lcd.setCursor(0,line);
 lcd.print("                ");
}

void loop() {
 timer.process();

}
Użyłem biblioteki Timers.h która znalazłem pod tym linkiem. Jak można zauważyć w 1 milisekundowym interwale zliczam impulsy, w półsekundowym interwale obliczam prędkość. 

Wydaje mi się, że program musiałby częściej sprawdzać impulsy, tylko jak to osiągnąć? Może ktoś zna inną metodę zliczania impulsów lub zaleca zastosowanie innej biblioteki? Za wszystkie rady, a także za konstruktywna krytykę będe niezmiernie wdzieczny Smile
 
Odpowiedź
#2
Zliczaj impulsy na przerwaniu INT lub PCINT. Tak spokojnie można zliczać 20..30k impulsów na sekundę przy użyciu AVR (ARMem zdecydowanie więcej). Możesz też użyć timera (np T2) i taktować go impulsami, które chcesz zliczać wtedy max to FclkCPU /2. czyli w przypadku Arduino na AVR 8MHz.
 
Odpowiedź
#3
Podejście do tematu jest nieprawidłowe. Załóżmy że chcesz zliczać ile razy sąsiad był u Ciebie w domu. Możesz zainstalować kamerkę i sprawdzać codziennie o 11 czy sąsiad jest - możesz akurat nie trafić i zliczanie będzie błędne, ilość za mała. Możesz sprawdzać co 1h, ale sąsiad może przyszedł i jeszcze nie wyszedł - zliczanie będzie za duże. Lepiej ustawić na furtce między posesjami czujnik i zliczać w określonym czasie ile razy wchodził?
Przykład jest na forum, tutaj będzie max 1000 impulsów/sekundę, wystarczy: https://forum.arduinopolska.pl/watek-fas...u-programu 08-08-2018, 16:07 gdzie był zmieniany stan zmiennej, ty ją sobie zwiększaj, zmień też w linijce attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING ); może też być RISING, adekwatnie do rezystorów podciągających wewnętrznego/zewnętrznego/rodzaju impulsu.
Jeśli impulsów jest mało to lepiej mierzyć czas między nimi, tutaj wg mnie będzie wystarczająco dokładnie mierząc ich liczbę/s.
Kolejna rzecz to double - jak używasz UNO to nie ma double, jest tylko float. Można mieć zdefiniowaną taką zmienną, ale to i tak jest float - wolne obliczenia, niedokładne, większy kod. Lepiej taką zmienną zwiększyć x100 i potem na końcu podzielić /100, ale wszystko robić w zmiennych całkowitych, najlepiej dodatnich jeśli nie spodziewasz się liczb ujemnych - typy uint8_t, uint16_t,uint32_t,uint64_t, im mniejszy typ tym lepiej. Zmienne całkowite są zwykle lepszym wyborem.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#4
(13-08-2018, 06:32)kaczakat napisał(a):  tak jest float - wolne obliczenia, niedokładne, większy kod.

Float to plaga Arduino. Jest nadużywane. Odnosze wrażenie jakby soft na Arduino pisali PCtowcy, który maja do dyspozycji FPU. Na wet na ARM unikam liczb zmiennoprzecinkowych, nawet jak mam FPU. Wtedy głównym powodem jest niedokładność obliczeń.
 
Odpowiedź
#5
Zastosowanie przerwań rozwiązało problem. Dzięki za pomoc Smile
 
Odpowiedź
#6
Co do podejścia do tematu, mam świadomość ze było nieprawidłowe, jednak nie znałem innego sposobu dlatego spytałem tutaj, otrzymałem odpowiedz wiec wszystko jest OK.

Co do float/double to postaram się zastąpić te typy zmiennych.
 
Odpowiedź
#7
(13-08-2018, 18:49)qbic napisał(a): Zastosowanie przerwań rozwiązało problem. Dzięki za pomoc Smile

Może nie do końca, jest pewna pułapka. Ujawni się w przypadku np jakiegoś uszkodzenia. Podaj na wejście zliczające przebieg np 1MHz i zobacz co się stanie. Gdy użyjesz timera do zliczania takiego problemu nie będziesz miał.
 
Odpowiedź
#8
To jest pułapka typu: "Weź Fiata 126p i wystartuj w wyścigach Formuły 1, jak rozpędzisz się do 300km/h, to zobaczysz pewien problem"? Bo sam jestem ciekawy, a nie zrobię sobie takiego testu...
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#9
(13-08-2018, 21:43)kaczakat napisał(a): To jest pułapka typu: "Weź Fiata 126p i wystartuj w wyścigach Formuły 1, jak rozpędzisz się do 300km/h, to zobaczysz pewien problem"? Bo sam jestem ciekawy, a nie zrobię sobie takiego testu...

Złe porównanie. Z powodu uszkodzenia wejście int moze zmieniać stan bardzo często. Co sie wtedy stanie? Co się dzieje, gdy uC ma zbyt częste przerwania? Można porównać do sytuacji gdy ustawione jest przerwanie INT od poziomu niskiego i na to wejście cały czas podawany jest stan niski. Co sie stanie?
Dobry program powinien byc przed tym zabezpieczony.
 
Odpowiedź
#10
Zapewne będzie cały czas przerwany Tongue
Jedyne co mi przychodzi na myśl to zabezpieczenie przed zbyt wysokimi częstotliwościami.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości