Skocz do zawartości

Osobne obrotomierze na arduino


walekmocy

Pomocna odpowiedź

Witam. Zabawę z Arduino zacząłem od niedawna i jestem w tym temacie zielony(ale coraz mniej).

Muszę zrobić licznik który będzie pokazywał

1. Prędkość jazdy

2. Liczbę obrotów na minutę silnika

3. Liczbę obrotów na minutę wałka

Czujniki to hallotrony zlokalizowane

1. przy przednim kole

2. przy wentylatorze

3. przy wale

na których przymocowane zostaną magnesy

Do tej pory udało mi się zaprogramować arduino uno dla jednego czujnika na tzw. przerwaniach.

#include <LiquidCrystal.h>
LiquidCrystal lcd(4, 5, 9, 10, 11, 12);
volatile float time = 0;
volatile float time_last = 0;

void setup()
{
attachInterrupt(0, fan_interrupt, FALLING);
 lcd.begin(16, 2);
}
void loop()
{
 int rpm = 0;
 while(1){    
 delay(400);
 lcd.setCursor(0, 1);
 lcd.print(rpm);   
 if(time > 0)
 {
  rpm = 60*(1000000/(time));    
 }
}
}
void fan_interrupt()
{
  time = (micros() - time_last); 
  time_last = micros();
}

Problem zaczyna się kiedy próbuję dodać kolejny czujnik, bo moimo że sygnał odbiera tylko jeden to na drugim wartości też się zmieniają. A poza tym chyba nie tędy droga skoro pinów do przerwań jest w uno tylko dwa.

Proszę o pomoc. Każda wskazówka i rada będzie dla mnie cenna za co z góry dziękuję.

Link do komentarza
Share on other sites

Przede wszystkim napisz o jakich wielkościach mówimy. Jakie są minimalne i maksymalne prędkości obrotowe tych wszystkich wałków, kół i wentylatorów oraz ile impulsów dostajesz z jednego obrotu na każdym z czujników. Jak krótkie to są impulsy tj. np. jaką część obrotu zajmują lub ile mikro/milisekund można się w najgorszym wypadku (najkrótszym) spodziewać? Ile tych zespołów wałek-koło-wentylator chcesz docelowo obsługiwać jednym procesorem? Jak często chcesz mieć nowe wyniki? To tylko wyświetlacz dla człowieka (3 pomiary/s powinno wystarczyć) czy jakaś pętla regulacji? Czy ten procesor będzie robił jeszcze coś o czym nam nie powiedziałeś?

Od tego wszystkiego zależy sposób realizacji. Zastanawiałeś się nad tym?

Link do komentarza
Share on other sites

@marek1707 : jeden czujnik będzie mierzył obroty wałka który maksymalnie osiąga 540 obr/min, natomiast drugi obroty koła jezdnego czyli jakieś max 330 obr/min, które przeliczane byłyby na km/h. Docelowo ma byc jeszcze trzeci mierzący obroty silnika do max 2600 obr/min.

Wyniki mają się jedynie wyświetlać na wyświetlaczu lcd, w późniejszym czasie może przedstawiane byłyby za pomocą wskazówki albo zapalających się diód led.

Czas obrotu to w najkrótszym przypadku 23 milisekundy, a w najdłuzszym 4000 milisekund (4sekundy).

Znalazłem coś takiego i zwyczajnie przerobiłem na swoje potrzeby dodając narazie jeszcze jeden licznik z przeliczaniem obrotów na prędkość(nie ma tego tutaj)

Kod pochodzi z tej strony

https://sites.google.com/site/measuringstuff/more-sensor-examples

Problemem jest mała dokładność- duże uogólnienie wyników i wolne działanie. Zminiałem oczywiście czas pojedynczej próby itp. ale dalej to samo. Przypominam ze jestem zielony.

/*
 RPM meter code (tested on device rotating at 10,000 rpm) 
 rev.001
 * using a hall effect sensor
 http://www.adafruit.com/index.php?main_page=product_info&cPath=35&products_id=158
 * using a parallel LCD with
 LiquidCrystal Library
 http://www.ladyada.net/learn/lcd/charlcd.html
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 with pins 7,8,9,10,11,12
*/

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7,8,9,10,11,12);
// read the hall effect sensor on pin 2
const int hallPin=2;
const unsigned long sampleTime=1000;
const int maxRPM = 10200; 

void setup() 
{
 pinMode(hallPin,INPUT);
 Serial.begin(9600);
 // set up the LCD's number of rows and columns: 
 lcd.begin(16, 2);
 // Print a message to the LCD.
 lcd.print("initializing");
 delay(1000);
 lcd.clear();
}

void loop() 
{
 delay(100);
 int rpm=getRPM();
 lcd.clear();
 displayRPM(rpm);
 displayBar(rpm);
}

int getRPM()
{
 // sample for sampleTime in millisecs
 int kount=0;
 boolean kflag=LOW;
 unsigned long currentTime=0;
 unsigned long startTime=millis();
 while (currentTime<=sampleTime)
 {
   if (digitalRead(hallPin)==HIGH)
   {
     kflag=HIGH;
   }
   if (digitalRead(hallPin)==LOW && kflag==HIGH)
   {
     kount++;
     kflag=LOW;
   }
   currentTime=millis()-startTime;
 }
 int kount2rpm = int(60000./float(sampleTime))*kount;
 return kount2rpm;
}

void displayRPM(int rpm) 
{
 lcd.clear();
 // set the cursor to column 0, line 1
 lcd.setCursor(0, 0); 
 // print the number of seconds since reset:
 lcd.print(rpm,DEC);
 lcd.setCursor(7,0);
 lcd.print("RPM");
}

void displayBar(int rpm)
{
 int numOfBars=map(rpm,0,maxRPM,0,15);
 lcd.setCursor(0,1);
 if (rpm!=0)
 {
 for (int i=0; i<=numOfBars; i++)
  {
       lcd.setCursor(i,1);
       lcd.write(1023);
     }
 }
} 
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

Jak piszesz - modyfikowałeś program więc zapewne rozumiesz jak on działa. Przez sekundę (nie wiem jak u Ciebie) zlicza impulsy z czujnika. Potem prosty wzór i jest wynik w rpm. Czego oczekujesz? Jeśli rozumiesz zasadę to widzisz, że nic tu po nas. Skrócisz czas to wyniki będą częstsze, ale dokładność spadnie. Wydłużysz czas do np. 5 czy 10s - dokładność będzie dużo lepsza (5 lub 10 razy), ale czas reakcji wskaźnika wydłuży się chyba nieakceptowalnie. To normalny dylemat takich pomiarów. Jeżeli te trzy czujniki o których piszesz są jakoś połączone kinematycznie przez przekładnię o stałym przełożeniu, najsensowniej jest mierzyć ten najszybszy, bo masz najwięcej impulsów i prędkość obrotową mierzysz najdokładniej. Prędkości reszty możesz chyba policzyć z parametrów przekładni?

W przypadku skrajnie małych obrotów, porównywalnych co do rzędu wielkości z okresem pomiaru zaczynasz mieć ogromny błąd - to jasne. Jeżeli w ciągu sekundy zliczysz 2 albo 3 impulsy to wcale nie znaczy, że prędkość zmieniła się ze 120 do 180rpm tylko to, że "okienko" pomiarowe raz "złapało" 2 a innym razem 3 impulsy o być może stałej częstotliwości. Zastanów się nad przechodzeniem - poniżej jakiejś prędkości obrotowej - na pomiar okresu. Wtedy, gdy wykryjesz przykładowo <200rpm zaczynasz mierzyć ile czasu upływa od jednego impulsu czujnika do drugiego. Przeliczasz to innym wzorem (wymyśl go 🙂 ) i masz wyniki w rpm i dokładniej i częściej. Gdy prędkość znowu rośnie i czasy stają się za krótkie by je dokładnie mierzyć w Arduino, znów przechodzisz na stały czas pomiaru i zliczanie liczby impulsów. Tak działa wiele mierników rpm - gdy zakres obrotów jest tak szeroki nie masz szans zrobić tego dobrze jednym sposobem.

Acha, procesor w Arduino ma specjalne wejście (niestety tylko jedno) do bardzo precyzyjnego, sprzętowego pomiaru okresu impulsów. Gdybyś swój czujnik podpiął do niego, mógłbyś mierzyć odstęp między impulsami z bardzo dużą precyzją w szerokim zakresie prędkości obrotowych: od np. 100000 do 250rpm. Ale tylko jeden czujnik, niestety ATmega328 nie została zbyt bogato wyposażona w rozbudowane sprzętowe timery i w takich przypadkach możliwości cudownego Arduino po prostu niewystarczają 🙁

Choć moim zdaniem opisana wcześniej metoda "podwójna" powinna się sprawdzić, nawet dla kilku czujników podpiętych jednocześnie do zwykłych wejść. Zamiast odczytu funkcji milis(), do pomiaru czasu zliczania powinieneś jednak użyć timera 1 - szybciej się sprawdza flagę niż woła funkcję systemową, więc dużo bardziej precyzyjnie.

Link do komentarza
Share on other sites

walekmocy, Jeśli można wiedzieć do jakiego ciągnika chcesz wprowadzić takie udoskonalenia? Tak jak pisał Marek obroty silnika mógł byś mierzyć i z tego obliczyć prędkość WOM. Tylko została by do pomiaru prędkość kół, tutaj w zależności od biegu te prędkości są różne.

Link do komentarza
Share on other sites

Zastanawiam się czy nie lepiej byłoby zamienić millis na micros, czy by wtedy zyskało na dokładności...

@marek1707 niestety obliczanie obrotów z przekładni jest niemożliwe, wałek pracuje w trybie obrotów niezależnych, a koło przednie jezdne nie ma poślizgu więc i tutaj podawanie prędkości w zależności od obrotów bądź przełożenia nie dało by rady.

@piter161 do ciągnika ursus c 330, stary licznik uległ uszkodzeniu na ślimaku w silniku i naprawa wymagała by rozpołowienia ciągnika.

Tutaj mój przerobiony kod. Wszystko działało w miarę spoko, z opóźnieniem i sporym błędem ale a ciężkich warunkach uszkodził się wyświetlacz lcd- świecą wszystkie piksele za wyjątkiem połowy dwóch.

#include <LiquidCrystal.h>

LiquidCrystal lcd(4,5,9,10,11,12);
const int hallPin=A0;
const int spedPin=A1;
const unsigned long sampleTime=2000;
const unsigned long sampleTimes=4000;
const int maxRPM = 3000; 
volatile float sped;

void setup() 
{
 pinMode(hallPin,INPUT);
 pinMode(spedPin,INPUT);
 Serial.begin(9600);
 // set up the LCD's number of rows and columns: 
 lcd.begin(16, 2);
 // Print a message to the LCD.
 lcd.print("START");
 delay(1000);
 lcd.clear();
}

void loop() 
{
 delay(100);
 int rpm=getRPM();
 int spe=getSPED();
 lcd.clear();
 displayRPM(rpm);
 displayBar(rpm);
 sped=spe*1,32;
 sped=sped/10;
}
int getRPM()
{
 int kount=0;
 boolean kflag=LOW;
 unsigned long currentTime=0;
 unsigned long startTime=millis();
 while (currentTime<=sampleTime)
 {
   if (digitalRead(hallPin)==HIGH)
   {
     kflag=HIGH;
   }
   if (digitalRead(hallPin)==LOW && kflag==HIGH)
   {
     kount++;
     kflag=LOW;
   }
   currentTime=millis()-startTime;
 }
 int kount2rpm = int(60000/float(sampleTime))*kount;
 return kount2rpm;
}
int getSPED()
{
 int kounts=0;
 boolean kflags=LOW;
 unsigned long currentTimes=0;
 unsigned long startTimes=millis();
 while (currentTimes<=sampleTimes)
 {
   if (digitalRead(spedPin)==HIGH)
   {
     kflags=HIGH;
   }
   if (digitalRead(spedPin)==LOW && kflags==HIGH)
   {
     kounts++;
     kflags=LOW;
   }
   currentTimes=millis()-startTimes;
 }
 float kount2rpms = float(60000/float(sampleTimes))*kounts;
 return kount2rpms;
}  
void displayRPM(int rpm) 
{
 lcd.clear();
 // set the cursor to column 0, line 1
 lcd.setCursor(0, 0); 
 // print the number of seconds since reset:
 lcd.print(rpm,DEC);
 lcd.setCursor(5,0);
 lcd.print("RPM");
 lcd.setCursor(13,0);
 lcd.print("KMH");
 lcd.setCursor(12,1);
 lcd.print(sped);
}
void displayBar(int rpm)
{
 int numOfBars=map(rpm,0,maxRPM,0,15);
 lcd.setCursor(0,1);
 if (rpm!=0)
 {
 for (int i=0; i<=numOfBars; i++)
  {
       lcd.setCursor(i,1);
       lcd.write(1023);
     }
 }
} 
Link do komentarza
Share on other sites

Czyli znów brutalna siła pokonała czystą sztukę 🙁

Elektronika używana w polu (tutaj: dosłownie 🙂 ) musi być naprawdę dobrze przygotowana. Czasem pochłania to dużo więcej czasu i wysiłku niż zrobienie samych bebechów.

Będziesz próbował kolejnego podejścia? Co w tym było nie tak? Piszesz o dużych błędach. Wyjaśnij dokładniej czego oczekujesz, bo zasady i ograniczenia obu metod pomiaru są chyba oczywiste. Czy to w nich upatrujesz problemów, czy raczej problem może leżeć w zakłóceniach i np. niedobrym kondycjonowaniu sygnałów na drodze od czujnika do wejścia procesora?

Link do komentarza
Share on other sites

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...

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.