Skocz do zawartości

ESP32 - licznik do rowerka treningowego


roz

Pomocna odpowiedź

Hej, mam rowerek treningowy (stacjonarny) z uszkodzonym komputerem.

Chcę zrobić własny.

Mam problem z obliczeniem prędkości/dystansu. Pedałując jednostajnie prędkość bardzo skacze. Nie potrafię znaleźć przyczyny/rozwiązania problemu.

Może ktoś poratuje pomocnym rozwiązaniem?

Poniżej kod:

 

#include <Arduino.h>

#define reed_pin 35
volatile int oldcnt, counter = 0;

//
unsigned long timeold = 0;         // Czas ostatniego pomiaru
float wheelDiameter = 0.7;         // Średnica koła w metrach
float pi = 3.14159265358979323846; // Wartość liczby pi
float distance = 0;                // Przebyty dystans
float speed = 0;                   // Prędkość

//

void IRAM_ATTR counterUp()
{
    counter++;
}

void setup()
{
    Serial.begin(115200);
    pinMode(reed_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(reed_pin), counterUp, FALLING);
}

void loop()
{
    unsigned long timenow = millis();
    if (timenow - timeold >= 1000)
    {
        detachInterrupt(digitalPinToInterrupt(reed_pin));
        distance = counter * wheelDiameter * pi;
        speed = distance / 1000 * 3600;
        Serial.print("Prędkość: ");
        Serial.print(speed);
        Serial.println(" km/h");
        counter = 0;
        timeold = timenow;
        attachInterrupt(digitalPinToInterrupt(reed_pin), counterUp, FALLING);
    }
}

 

Poniżej to, co na serialu wychodzi z obliczeń:

 

17:37:10:302 -> Prędkość: 0.00 km/h
17:37:11:302 -> Prędkość: 0.00 km/h
17:37:12:302 -> Prędkość: 23.75 km/h
17:37:13:302 -> Prędkość: 23.75 km/h
17:37:14:302 -> Prędkość: 0.00 km/h
17:37:15:302 -> Prędkość: 23.75 km/h
17:37:16:302 -> Prędkość: 23.75 km/h
17:37:17:302 -> Prędkość: 23.75 km/h
17:37:18:302 -> Prędkość: 23.75 km/h
17:37:19:302 -> Prędkość: 23.75 km/h
17:37:20:302 -> Prędkość: 47.50 km/h
17:37:21:302 -> Prędkość: 23.75 km/h
17:37:22:302 -> Prędkość: 47.50 km/h
17:37:23:302 -> Prędkość: 39.58 km/h
17:37:24:302 -> Prędkość: 31.67 km/h
17:37:25:302 -> Prędkość: 47.50 km/h
17:37:26:302 -> Prędkość: 23.75 km/h
17:37:27:302 -> Prędkość: 0.00 km/h
17:37:28:302 -> Prędkość: 0.00 km/h

 

Edytowano przez roz
Link do komentarza
Share on other sites

(edytowany)

Niepotrzebnie poczas każdego pomiaru odczepiasz i podłączasz przerwania.

Jeśli chodzi o ewentualne zachowanie "atomiczności", to stosujemy noInterrupts() oraz  interrupts().

Edytowano przez jand
Link do komentarza
Share on other sites

@jand ok, dziękuję, usunąłem wyłączanie i załączanie przerwań.

Jednak dalej "świruje" 😞 Ogromne skoki się pojawiają..

18:27:18:104 -> Prędkość: 23.75 km/h
18:27:19:104 -> Prędkość: 23.75 km/h
18:27:20:104 -> Prędkość: 23.75 km/h
18:27:21:104 -> Prędkość: 23.75 km/h
18:27:22:104 -> Prędkość: 23.75 km/h
18:27:23:104 -> Prędkość: 23.75 km/h
18:27:24:104 -> Prędkość: 47.50 km/h
18:27:25:104 -> Prędkość: 23.75 km/h
18:27:26:104 -> Prędkość: 39.58 km/h
18:27:27:104 -> Prędkość: 31.67 km/h
18:27:28:104 -> Prędkość: 23.75 km/h
18:27:29:104 -> Prędkość: 47.50 km/h
18:27:30:104 -> Prędkość: 23.75 km/h
18:27:31:104 -> Prędkość: 47.50 km/h
18:27:32:104 -> Prędkość: 23.75 km/h
18:27:33:104 -> Prędkość: 23.75 km/h
18:27:34:104 -> Prędkość: 47.50 km/h
18:27:35:104 -> Prędkość: 23.75 km/h
18:27:36:104 -> Prędkość: 47.50 km/h
18:27:37:104 -> Prędkość: 23.75 km/h
18:27:38:104 -> Prędkość: 47.50 km/h
18:27:39:104 -> Prędkość: 23.75 km/h
18:27:40:104 -> Prędkość: 23.75 km/h
18:27:41:104 -> Prędkość: 23.75 km/h
18:27:42:104 -> Prędkość: 23.75 km/h
18:27:43:103 -> Prędkość: 23.75 km/h

 

Link do komentarza
Share on other sites

(edytowany)

Na pewno warto też kod ustawić tak aby jak najkrócej blokować zmienną counter. Nawiasem mówiąc, nie ma kompletnie nic o tym skąd się biorą impulsy. Może tam są jakieś zakłócenia i to trzeba filtrować? 

void loop()
{
    unsigned long timenow = millis();
    if (timenow - timeold >= 1000)
    {
      	// zróbmy jak najszybciej to co dotyczy zmiennej counter 
        detachInterrupt(digitalPinToInterrupt(reed_pin)); // to pewnie jest zbędne
        distance = counter * wheelDiameter * pi;
        counter = 0;
        attachInterrupt(digitalPinToInterrupt(reed_pin), counterUp, FALLING);// to pewnie jest zbędne
        // to też jak najszybiej, dzięki temu odcinki czasu będą najrówniejsze
        timeold = timenow;
      	// a teraz już nie przeszkadzamy w zliczaniu impulsów więc na spokojnie
        speed = distance / 1000 * 3600;
        // zwłaszcza jeśli chodzi o bardzo wolne Serial.print...
        Serial.print("Prędkość: ");
        Serial.print(speed);
        Serial.println(" km/h");
    }
}
Edytowano przez etet100
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

@etet100 Impulsy biorą się z kontaktronu (oryginalnie zamontowany na ramie) natomiast magnes oryginalnie zamontowany jest na kole z korbami i pedałami. W tej chwili nie ma nic oprócz kontaktronu i ESP podłączonego do komputera.

Zmienna counter podczas gdy magnes przechodzi przez kontaktron wzrasta o 2, 3 czasami o 1 a czasami o 4. Jakby drgania styków kontaktronu. Próbowałem dać kondensator 100nF, ale bez efektu - działo się to samo dalej.

Docelowo będzie (już działa) opaska do pomiaru uderzeń serca Polar H7 oraz oryginalny moduł do naciągu hamulca (silnik z przekładnią i potencjometrem) oraz wyświetlacz okrągły LCD.

Link do komentarza
Share on other sites

(edytowany)

Tu jest o tyle komfortowa sytuacja, że tych impulsów jest relatywnie malutko. Można zrobić prosty programowy 'debounce' w stylu
 

volatile unsigned long next_pulse;

void IRAM_ATTR counterUp()
{
    unsigned long now = millis();
    if (now < next_pulse)
    {
        return;
    }

    counter++;
    next_pulse = now + 10; // następny impuls za nie mniej niż 10ms
}

 

Edytowano przez etet100
  • Lubię! 1
Link do komentarza
Share on other sites

@etet100 Zrobiłem debounce jak zaproponowałeś. Efekt poniżej, dodatkowo wyrzuciłem na seriala zmienną counter. Sytuacja się poprawiła gdy ustawiłem podstawę czasu na 2 sekundy (było na jedną sekundę). Ale jeszcze go coś boli..

19:04:40:798 -> Counter: 0
19:04:42:798 -> Prędkość: 15.83 km/h
19:04:42:798 -> Counter: 4
19:04:44:798 -> Prędkość: 15.83 km/h
19:04:44:798 -> Counter: 4
19:04:46:798 -> Prędkość: 15.83 km/h
19:04:46:798 -> Counter: 4
19:04:48:798 -> Prędkość: 15.83 km/h
19:04:48:798 -> Counter: 4
19:04:50:798 -> Prędkość: 23.75 km/h
19:04:50:798 -> Counter: 6
19:04:52:798 -> Prędkość: 15.83 km/h
19:04:52:798 -> Counter: 4
19:04:54:798 -> Prędkość: 23.75 km/h
19:04:54:798 -> Counter: 6
19:04:56:798 -> Prędkość: 23.75 km/h
19:04:56:798 -> Counter: 6
19:04:58:798 -> Prędkość: 23.75 km/h
19:04:58:798 -> Counter: 6
19:05:00:798 -> Prędkość: 23.75 km/h
19:05:00:798 -> Counter: 6
19:05:02:798 -> Prędkość: 23.75 km/h
19:05:02:798 -> Counter: 6
19:05:04:798 -> Prędkość: 31.67 km/h
19:05:04:798 -> Counter: 8
19:05:06:798 -> Prędkość: 23.75 km/h
19:05:06:798 -> Counter: 6
19:05:08:798 -> Prędkość: 23.75 km/h
19:05:08:798 -> Counter: 6
19:05:10:798 -> Prędkość: 31.67 km/h
19:05:10:798 -> Counter: 8
19:05:12:798 -> Prędkość: 15.83 km/h
19:05:12:798 -> Counter: 4
19:05:14:798 -> Prędkość: 0.00 km/h
19:05:14:798 -> Counter: 0
19:05:16:798 -> Prędkość: 3.96 km/h

 

Link do komentarza
Share on other sites

(edytowany)

Ciężko stwierdzić poprawność bądź niepoprawność tych wyników. Dlaczego wszędzie jest parzyście?? To mnie troszkę zastanawia.

Pewnego "skakania" bym się tam spodziewał. Jeden impuls na obrót to za mało żeby nie było efektu skakania wyniku w obrębie kilku kolejnych wartości. Takie fabryczne urządzenia na pewno stosują jakieś "wygładzanie/uśrednianie". Przynajmniej w moim urządzeniu tam jest. 

Może wstaw też aktualny kod.

Edytowano przez etet100
Link do komentarza
Share on other sites

@etet100

#include <Arduino.h>

#define reed_pin 35


volatile int oldcnt, counter = 0;
volatile unsigned long next_pulse = 0;
//
unsigned long timeold = 0;         // Czas ostatniego pomiaru
float wheelDiameter = 0.7;         // Średnica koła w metrach
float pi = 3.14159265358979323846; // Wartość liczby pi
float distance = 0;                // Przebyty dystans
float speed = 0;                   // Prędkość

//

void IRAM_ATTR counterUp()
{
    unsigned long now = millis();
    if (now < next_pulse)
    {
        return;
    }

    counter++;
    next_pulse = now + 10; // następny impuls za nie mniej niż 10ms
}

void setup()
{
    Serial.begin(115200);
    pinMode(reed_pin, INPUT);
    attachInterrupt(digitalPinToInterrupt(reed_pin), counterUp, FALLING);
}

void loop()
{
    unsigned long timenow = millis();
    if (timenow - timeold >= 2000)
    {
        distance = counter * wheelDiameter * pi;
        int cntold = counter;
        counter = 0;
        speed = distance / 2000 * 3600;        
        timeold = timenow;
        Serial.print("Prędkość: ");
        Serial.print(speed);
        Serial.println(" km/h");
        Serial.print("Counter: ");
        Serial.println(cntold);
    }
}

 

Link do komentarza
Share on other sites

Nie widzę za bardzo błędu. Ja bym to sprawdził od strony mechanicznej/elektrycznej. Czy teraz jeden impuls z kontaktronu powoduje zliczenie 1? Nie wiem jak wygląda obwód tego kontaktronu, jest tam jakiś rezystor podciągający? Noże warto dać `pinMode(reed_pin, INPUT_PULLUP);` ? 



 

Link do komentarza
Share on other sites

Te linijki:

        distance = counter * wheelDiameter * pi;
        int cntold = counter;
        counter = 0;

zamień na:

noInterrupts();     
int cntold = counter;
counter = 0;  
interrupts();
distance = cntold * wheelDiameter * pi;

 

Link do komentarza
Share on other sites

Przy tak niskich częstotliwościach impulsów (rzędu 5Hz) brak blokowania przerwań nie powinien mieć jakiegokolwiek wpływu na działanie. Będę bardzo zdziwiony jeśli to coś zmieni.

Link do komentarza
Share on other sites

Zmień na 10s to się poprawi jeszcze lepiej, może zauważysz w tym jakąś prawidłowość.

Taką wybrałeś koncepcję programu, że to musi skakać. Jak jest 1-3 impulsy w ciągu 1s, w której je zliczasz i jeden przeliczysz na 100,  to wyniki będą skakały 100-300  z krokiem 100. Jak jest coś pomiędzy to w 1s zliczysz 2 impulsy, w kolejnej 3. Jak chcesz mieć płynnie to zamiast zliczać impulsy/s mierz czas między impulsami.

Gdyby tych impulsów było >1000+/- 10% /s to można by zliczać impulsy.

 

  • Lubię! 2
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.