Transoptor szczelinowy (czujnik szczelinowy)

Słowem wstępu…

Nasz Fi-Bot’owy zespół wciąż pracuje nad swoimi pojazdami. Podzieleni w pary wciąż ulepszamy swoje maszyny dodając kolejne części i klepiąc nowe linijki kodu.

Tym razem przyszedł czas na rozwiązanie problemu zliczania obrotów kół, tak aby można było lepiej sprawdzać i kontrolować prędkość naszego pojazdu.

Z pomocą przyszedł nam właśnie…

Transoptor Szczelinowy

Jak działa to wspaniałe urządzenie? (już wcześniej się bawiliśmy takim modułem – wyznaczając wartość przyspieszenia ziemskiego).

Na samym początku potrzebowaliśmy kółka zębatego (poniżej: wydrukowane w 3D), które ma dokładnie 16 ząbków i które umieszczamy na osi obrotowej naszego koła(silniczek ma wał obrotowy po dwóch stronach). Następnie zamontowaliśmy czujnik szczelinowy tak, aby kółko zębate znajdowało się między nim.

Poniżej wykorzystałem moje ponad przeciętne zdolności artystyczne aby lepiej Wam to zobrazować. Kółko obracając się raz po raz przesłania wiązkę światła emitowanego z transoptora (a dokładniej z diody) i sygnał ten nie trafia do bramki – mamy stan wysoki (logiczną jedynkę), pokazuje to górny rysunek (lewa strona), albo przepuszcza wiązkę i mamy wówczas stan nisko (czyli zero, prawy obrazek). Obracając się mamy szereg stanów wysokich i niskich na wyjściu z transoptora.

Transoptor szczelinowy mówiąc łopatologicznie sprawdza czy między nim coś jest, lub nie ma. Jeżeli nasze koło się obraca, a razem z nim oś wraz z zębatką – czujnik szczelinowy jest w stanie odczytać:

  • czy między nim jest ząbek koła – i zwrócić 1
  • czy też ząbka niema – i zwrócić 0

Łatwo możemy więc wywnioskować że jeden obrót koła to „przejście” transoptora po 16 ząbkach koła zębatego.

Niestety nasze urządzenie nie odczyta zmiany stanów w czujniku w ten sposób:

101010101010101010

ponieważ urządzenie to nadaje nam z prędkością nawet do kilku tysięcy stanów na sekundę (w zależności od modelu), więc Arduino odczytywać będzie to mniej więcej tak:

0000000000011111111111111100000000000000111111111111111111111100000000

gdzie '1′ oczywiście znaczy, że w danej chwili ząbek jest między szczeliną, a '0′ że go nie ma.

Tak więc do zliczania obrotów musieliśmy napisać swój program. Na tym zakończy się teoria a zacznie się…

 

Transoptor w praktyce

Jeżeli chodzi o podłączenie modułu do Arduino to nie sprawia to większych trudności. Zasilanie modułu podpinamy pod pin z napięciem 5V, uziemienie do GND, natomiast ostatni kabelek wędruje pod wybrany przez nas pin cyfrowy. W moim przypadku był to pin z numerem 7.

Przejdźmy więc do pisania kodu 😉

Oczywiście pomysłów na rozwiązanie tego problemu jak i wykonanie i działanie samego programu było kilka, ja zamieszczam pod spodem swoją wersje.

void setup() {
  pinMode(7,INPUT);
  Serial.begin(9600);
}

bool zn;
bool temp=0;
int rotates=0;
int indents=0;

void loop() {
  zn = digitalRead(7);
  if(zn>temp)
  {
    indents++;
    temp=zn;
    Serial.print(rotates);
    Serial.print(" rotates ");
    Serial.print(indents);
    Serial.println(" indents");
  }
  else
  {
    temp=zn;
  }
  if(indents==16)
  {
    rotates++;
    indents=0;
  }
}

Na początku:

  1. w funkcji setup ustawiamy tryb wybranego przez nas pinu na input – czyli tryb wejścia, ponieważ dane będą wchodzić przez niego do naszego Arduino. Robimy to za pomocą funkcji pinMode(7, INPUT)
  2. uruchamiamy komunikacje szeregową z komputerem za pomocą funkcji Serial.begin(9600) – to właśnie na naszym monitorze będziemy odczytywać liczbę obrotów koła

Zanim jeszcze wejdziemy do naszej głównej pętli wprowadziłem potrzebne zmienne:

  1. bool zn – zmienna zn (od słowa znak) będzie przechowywać aktualny stan podawany przez czujnik. Typ zmiennych 'bool’ nadaje się do tego idealnie bo przechowuje On tylko 1 lub 0 – inaczej prawda lub fałsz.
  2. bool temp – zmienna temp (od słowa ang. temporary – tymczasowy) będzie zmienną pomocniczą. Na początku musimy przypisać jej wartość '0′, jednak jej działanie opiszę dokładniej później.
  3. int rotates – zmienna rotates (od słowa ang. rotations – obroty) jak sama nazwa wskazuje będzie przechowywać liczbę aktualnie zliczonych obrotów. Na początku będzie ich oczywiście 0.
  4. int indents – zmienna indents (od słowa ang. indents – wcięcie) będzie przechowywać liczbę zliczonych ząbków.  Na początku będzie ich oczywiście 0.

Przejdźmy więc do głównej funkcji programu – loop.

Na początku do zmiennej zn wczytujemy stan z czujnika – będzie to stan 1 lub 0 w zależności od tego czy w pozycji startu ząbek akurat jest między czujnikiem czy nie (nie ma to żadnego znaczenia). Używamy do tego funkcji digitalRead(7) gdzie '7′ jest oczywiście numerem naszego pinu.

Następnie pojawia się warunek if – jeżeli nasz wczytany stan zn będzie większy od stanu trzymanego w zmiennej pomocniczej temp – czyli będzie równy 1 – wtedy :

  1. indents ++   – zwiększ liczbę zliczonych ząbków o 1
  2. temp = zn   – zmienna temp przyjmuje wartość zn
  3. wypisz policzone obroty i wcięcia

w przeciwnym przypadku, jeżeli będzie mniejszy lub taki sam, wykonuje się tylko przypisanie wartości temp :

  1. temp = zn   – zmienna temp przyjmuje wartość zn

Co tu się właściwie stało? Tak jak pisałem wcześniej Arduino odczytuje stany czujnika w następujący sposób:

000000001111111111000000000000000111111111111110000001111111111111

Można tu wyróżnić sekwencje zer i jedynek. Sekwencja jedynek oznacza że przez tą krótką chwile czujnik odczytał ząbek między widełkami. Kiedy więc będzie można powiedzieć że ząbek przeskoczył przez czujnik? Wtedy i tylko wtedy gdy transoptor wczyta jedynkę po zerze. Zaczyna się wtedy sekwencja jedynek – ząbek jest chwile między widełkami, następnie znowu sekwencja zer – ząbka brak, i znowu sekwencja jedynek, czyli kolejny ząbek.

000000001111111111000000000000000111111111111110000001111111111111

Załóżmy że program zaczyna się od sekwencji zer – podawane stany będą ciągle zerami. Dopóki aktualny stan nie będzie większy od temp czyli nie będzie wynosił 1 (bo temp przyjmuje wartość '0′ na starcie programu), licznik ząbków nie powiększy się.

Kiedy program natrafi na pierwszą jedynkę – licznik ząbków powiększy się o 1, natomiast zmienna temp która do tej pory trzymała 0, przyjmie wartość 1. Gdy do zmiennej zn zostanie wczytana następna jedynka z sekwencji, licznik nie powiększy się ponieważ nie został spełniony warunek:   zn>temp   –   przecież jedynka nie jest większa od jedynki 😀

I tak w kółko dopóki znów nie zacznie się sekwencja zer – oczywiście warunek dalej nie zostanie spełniony bo 0 tym bardziej nie jest większe od 1, ale za to temp przyjmie wartość 0, tak żeby warunek spełnił się na początku kolejnej sekwencji jedynek i licznik ząbków znów powiększył się o 1.

Ostatnia i niezbędna rzecz w naszym programie – warunek   if (indents==16).

Musimy pamiętać że cały czas dodawaliśmy ząbki koła zębatego, a w sumie jest ich 16. Wnioskując logicznie Arduino musi odczytać te 16 ząbków, po czym:

  1. rotates++   – zwiększyć liczbę obrotów o 1
  2. indents=0   – wyzerować aktualnie zliczone ząbki, ponieważ już zatoczyło się pełne koło. Nasz program będzie je teraz dodawał od nowa.

Podsumowanie

Zakładam że połowa osób przysnęła czytając moje wypociny, dlatego zachęcam do samodzielnej zabawy. Na pewno umiejętność używania czujnika szczelinowego przyda się jeszcze nie raz.

Na przyszłych zajęciach będziemy dalej ulepszać nasz pojazd, szczególnie skupimy się na usprawnieniu sterowania 🙂 Zachęcam do bycia na bieżąco.

 

(c) Przemysław Baj 2018

Liczymy obroty (TCRT5000) – sukces!

Liczymy obroty silniczka D65:

Znalezione obrazy dla zapytania d65 zestaw napedowytutaj nasz program:

 

bool stan, poprz;
unsigned long int t1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  stan=false;
}

int odczyt;
int licz=0;
void loop() {
  poprz=stan;
  odczyt=analogRead(A0);
  if (odczyt<50)
    stan=true;
  else
    stan=false;
//  Serial.print(odczyt);
//  Serial.print("   ");
//  Serial.print(stan?"jasne":"ciemne");
//  Serial.print("   ");
  if (stan!=poprz){
    licz++;
    Serial.print(" KLIK ");
    Serial.print(licz);
    Serial.print(" ");
    if (licz%2==0){
      Serial.print(1000./(millis() - t1)*60);
      Serial.println(" rpm");
      t1= millis();
    }
  }
//  else
//    Serial.println();
}

I działa bardzo fajnie, nawet z tylko jednym znacznikiem! Wyniki są bardzo powtarzalne (przy zasilaniu około 7V – jeden obrót w 230-240ms, czyli 4 obroty w 1 sekundę, a to daje 4*60=240 obrotów na minutę – rpm).

Rozbudowa?

  1. więcej znaczników (już 2 polepszają sprawę, 4 to zdecydowanie OK).
  2. inny algorytm – zliczanie liczny obrotów i aktualizowanie wartości rpm co określony czas, np. 2 sek

Liczymy obroty (TCRT5000)

Liczymy obroty silniczka D65:

Znalezione obrazy dla zapytania d65 zestaw napedowy

który przy zasilaniu 6V powinien mieć 100 rpm (=obrotów na minutę). My wykorzystujemy poznaną czujkę odbiciową TCRT5000:

 

Znalezione obrazy dla zapytania tcrt5000

Pierwsze zgrubne wyniki dały 1 pełen obrót w czasie 250ms, czyli 240 rpm (trochę dużo, ale to dlatego, że zailalem silniczek 8V – „nielegalnie”). Zrzut ekranu:

oraz program (wyjaśnienia i dyskusja później, jak też i omówienie dokładności pomiaru):

int pomiar[3],i=0,maksior;
unsigned long t1,delta;

void setup() {
  Serial.begin(9600);
  t1=millis();    
}
void loop() {
//  Serial.print(millis());
//  Serial.print("   ");
  pomiar[0]=pomiar[1];
  pomiar[1]=pomiar[2];
  pomiar[2]=analogRead(A0);
  //Serial.println(pomiar[2]);  
  if ((pomiar[1]<950)&&(pomiar[1]>300)&&(pomiar[1]>pomiar[0])&&(pomiar[1]>pomiar[2])){
    delta=millis()-t1;
    if(delta>50){
      Serial.print("1 obrot w ");
      Serial.print(delta);
      t1=millis();    
      Serial.print("ms, czyli rpm=");  
      Serial.println(60*1000.0/delta); 
    }
  }  
  //delay(100);
}