Zanim...
Zanim...



Polskie Forum FPV

Forum modelarzy i pilotów FPV
Dzisiaj jest środa 20 mar 2019, 00:43


Strefa czasowa UTC+1godz.




Nowy temat Odpowiedz w temacie  [ Posty: 8 ] 
Autor Wiadomość
Post: środa 02 sty 2019, 19:23 
Offline

Rejestracja: sobota 04 gru 2010, 21:19
Posty: 967
Lokalizacja: Toruń
Cześć, chciałem pomierzyć czasy PPM aparatury budując przełącznik 6 pozycyjny. Nie jestem specjalistą od Arduino, więc pytanie co poprawić i czy taki pomiar ma sens. Funkcja micros() dla Nano 16MHz ma dokładność 4uS. Robię 10 pomiarów i wyciągam średnią (w sumie to 11 i pierwszy odrzucany, bo pomiar mógł się zacząć w czasie trwania impulsu).
Wyniki już uśrednione z 10 pomiarów dla mojej aparatury dla kanału kraniec/center/kraniec są w następującym rozrzucie:
1061-1074 / 1487-1495 / 1910-1923

Pytanie czy te pomiary mają sens, czy można coś poprawić, przyspieszyć w kodzie, aby mieć tani miernik szerokości impulsu:

Poniżej program dla pastwienia się. ;)
Kod:
/*
Miernik PWM
Mierzy czas impulsu PWM kanału RC.
Program dokonuje 11 pomiarów (pierwszy odrzuca,
bo pomiar mógł się zacząć, gdy impuls już trwał)
i wyświetla pozostałe 10 na serial monitorze.
*/

// Ustaw pin do odczytu
const int PinOdczyt = 2; 

// deklaracja zmiennych:
int PPM[11]; //tabela na 11 pomiarów
int czas1, czas2, j=0;
int StanPinu = HIGH;

void setup() {
  Serial.begin(9600);
  // initializacja pinu odczytu jako input:
  pinMode(PinOdczyt, INPUT);     
}

void loop(){

  if (StanPinu == LOW && digitalRead(PinOdczyt) == HIGH) {
    //Czyli stan był niski a pojawił sie wysoki
    czas1 = micros();   //odczytaj czas
    // odczytaj stan pinu
    StanPinu = digitalRead(PinOdczyt);
  }
  else
    if (StanPinu == HIGH && digitalRead(PinOdczyt) == LOW) {
      // czyli impuls się skończył
      czas2 = micros();  //odczytaj czas
      // oblicz czas impulsu
      PPM[j] = czas2 - czas1;  //oblicz czas impulsu
      // odczytaj stan pinu
      StanPinu = digitalRead(PinOdczyt); 
      j++;
    }

 
  //wyświetlaj czasy
  if (j==11) {
  for (byte i=1; i<=10; i++){
    Serial.print(F("Pomiar "));Serial.print(i);Serial.print(F(" : "));Serial.println(PPM[i]);
    j=0;
  }
  //Wyświetl wartość średnią:
  Serial.print(F("Pomiar sredni : "));Serial.println((PPM[1]+PPM[2]+PPM[3]+PPM[4]+PPM[5]+PPM[6]+PPM[7]+PPM[8]+PPM[9]+PPM[10])/10);
  }

}


Edit: Zmiana tytułu + poprawa kodu.

_________________
Modelarstwo lotnicze Toruń


Ostatnio zmieniony środa 02 sty 2019, 20:32 przez labo, łącznie zmieniany 2 razy

Na górę
 Wyświetl profil  
 
Post: środa 02 sty 2019, 19:45 
Offline
Awatar użytkownika

Rejestracja: środa 19 mar 2014, 02:03
Posty: 6928
Lokalizacja: Polska
labo pisze:
Pytanie czy te pomiary mają sens

Nie, bo po pierwsze nie rozpoznajesz konca ramki, wiec tak naprawde nie wiesz wartosci jakich kanalow czytasz.

Po drugie wyswietlanie danych w tej samej petli w ktorej je czytasz wplywa na pomiar.

Po trzecie po co wymyslac kolo od nowa, skoro istnieja juz gotowe biblioteki i to oparte na przerwaniach?


Na górę
 Wyświetl profil  
 
Post: środa 02 sty 2019, 19:59 
Offline

Rejestracja: sobota 04 gru 2010, 21:19
Posty: 967
Lokalizacja: Toruń
pawelsky pisze:
Nie, bo po pierwsze nie rozpoznajesz konca ramki, wiec tak naprawde nie wiesz wartosci jakich kanalow czytasz.

Wiem na którym kanale, bo czytam długość na konkretnym kanale odbiornika w miejscu wyjścia na serwo, tam jest już jeden sygnał. Nie robię na S.Bus czy innym sumowanym na całej ramce.

pawelsky pisze:
Po drugie wyswietlanie danych w tej samej petli w ktorej je czytasz wplywa na pomiar.

Nie wyświetlam w tej samej pętli w której czytam. Najpierw czytam, później wyświetlam, popatrz na program.

pawelsky pisze:
Po trzecie po co wymyslac kolo od nowa, skoro istnieja juz gotowe biblioteki i to oparte na przerwaniach?

Jakiś przykład? Nie znalazłem, dlatego zacząłem pisać.


EDIT:
Dałem 100 pomiarów i wyświetlanie tylko średniej. Rozrzut teraz ok. 3uS.
1067-1070 / 1491-1493 / 1914-1917

Poniżej kod dla ciekawskich:
Kod:
/*
Miernik PWM
Mierzy czas impulsu PWM kanału RC na wyjściu serwa odbiornika.
Program dokonuje 101 pomiarów (pierwszy odrzuca,
bo pomiar mógł się zacząć, gdy impuls już trwał)
i wyświetla średnią ze 100 na serial monitorze.
*/

// Ustaw pin do odczytu
const int PinOdczyt = 2;

// deklaracja zmiennych:
int PPM[101]; //tabela na 101 pomiarów
int czas1, czas2, j=0;
long srednia=0;
int StanPinu = HIGH;

void setup() {
  Serial.begin(9600);
  // initializacja pinu odczytu jako input:
  pinMode(PinOdczyt, INPUT);     
  Serial.println(F("Czekaj na pomiar ok. 4 sekundy"));
}

void loop(){
  if (StanPinu == LOW && digitalRead(PinOdczyt) == HIGH) {
    //Czyli stan był niski a pojawił sie wysoki
    czas1 = micros();   //odczytaj czas
    // odczytaj stan pinu
    StanPinu = digitalRead(PinOdczyt);
  }
  else
    if (StanPinu == HIGH && digitalRead(PinOdczyt) == LOW) {
      // czyli impuls się skończył
      czas2 = micros();  //odczytaj czas
      // oblicz czas impulsu
      PPM[j] = czas2 - czas1;  //oblicz czas impulsu
      // odczytaj stan pinu
      StanPinu = digitalRead(PinOdczyt);
      j++;
    }

 
  //wyświetlaj czasy
  if (j==101) {
  for (byte i=1; i<=100; i++){
//    Serial.print(F("Pomiar "));Serial.print(i);Serial.print(F(" : "));Serial.println(PPM[i]);
    srednia=srednia+PPM[i];
  }
  //Wyświetl wartość średnią:
  Serial.print(F("Pomiar sredni : "));Serial.println(srednia/100);
  j=0;
  srednia = 0;
  }

}

Edit: Poprawa kodu

_________________
Modelarstwo lotnicze Toruń


Ostatnio zmieniony środa 02 sty 2019, 20:32 przez labo, łącznie zmieniany 1 raz

Na górę
 Wyświetl profil  
 
Post: środa 02 sty 2019, 20:19 
Offline
Awatar użytkownika

Rejestracja: środa 19 mar 2014, 02:03
Posty: 6928
Lokalizacja: Polska
labo pisze:
Wiem na którym kanale

Nie wiesz, bo nie wiesz na ktory kanal w ramce PPM trafi Ci petla loop na poczatku. Moze na pierwszy, moze na drugi, a moze na inny. Czysty przypadek, bo nie wykrywasz poczatku/konca ramki PPM (ktora zawiera kilka kanalow w jednym).

No chyba ze nie rozumiesz roznicy miedzy PPM a PWM...

labo pisze:
Nie wyświetlam w tej samej pętli w której czytam. Najpierw czytam, później wyświetlam, popatrz na program.

Wszystko robisz w jednej i tej samej petli loop, co 11 jej obrotow zabierasz iles milisekund czasu na wyswietlenie danych, w tym czasie prawdopodobnie przegapiajac pare impulsow.

labo pisze:
Jakiś przykład? Nie znalazłem,

Google Arduino PPM library


Na górę
 Wyświetl profil  
 
Post: środa 02 sty 2019, 20:30 
Offline

Rejestracja: sobota 04 gru 2010, 21:19
Posty: 967
Lokalizacja: Toruń
pawelsky pisze:
labo pisze:
Wiem na którym kanale

Nie wiesz, bo nie wiesz na ktory kanal w ramce PPM trafi Ci petla loop na poczatku. Moze na pierwszy, moze na drugi, a moze na inny. Czysty przypadek, bo nie wykrywasz poczatku/konca ramki PPM (ktora zawiera kilka kanalow w jednym).

No chyba ze nie rozumiesz roznicy miedzy PPM a PWM...

Ups, no tak, cały czas myślę o PWM, sorry, mea culpa.

pawelsky pisze:
labo pisze:
Nie wyświetlam w tej samej pętli w której czytam. Najpierw czytam, później wyświetlam, popatrz na program.

Wszystko robisz w jednej i tej samej petli loop, co 11 jej obrotow zabierasz iles milisekund czasu na wyswietlenie danych, w tym czasie prawdopodobnie przegapiajac pare impulsow.

W przypadku PWM nieistotnie i tak pierwszy po wznowieniu pomiaru jest odrzucany.

pawelsky pisze:
labo pisze:
Jakiś przykład? Nie znalazłem,

Google Arduino PPM library

Dziękuję poszukam.

Zmienię też temat wątku na poprawniejszy.

_________________
Modelarstwo lotnicze Toruń


Na górę
 Wyświetl profil  
 
Post: środa 02 sty 2019, 20:37 
Offline
Awatar użytkownika

Rejestracja: środa 19 mar 2014, 02:03
Posty: 6928
Lokalizacja: Polska
labo pisze:
W przypadku PWM nieistotnie i tak pierwszy po wznowieniu pomiaru jest odrzucany.

W przypadku PWM owszem, ale Ty chciales mierzyc PPM :)

labo pisze:
Dziękuję poszukam.

Tylko po co, skoro chcesz mierzyc PWM a nie PPM :) Pomijam juz ze do tego pomiaru wystarczy Ci metoda pulseIn

labo pisze:
Zmienię też temat wątku na poprawniejszy.

Po co? Zeby wprowadzic jeszcze wiecej zamieszania w dyskusji? :)


Na górę
 Wyświetl profil  
 
Post: środa 02 sty 2019, 21:09 
Offline

Rejestracja: sobota 04 gru 2010, 21:19
Posty: 967
Lokalizacja: Toruń
pawelsky pisze:
labo pisze:
W przypadku PWM nieistotnie i tak pierwszy po wznowieniu pomiaru jest odrzucany.

W przypadku PWM owszem, ale Ty chciales mierzyc PPM :)

Chcieć i mierzyć, to chciałem i mierzyłem PWM, tylko bez sensu pisałem PPM. :)

pawelsky pisze:
labo pisze:
Zmienię też temat wątku na poprawniejszy.

Po co? Zeby wprowadzic jeszcze wiecej zamieszania w dyskusji? :)

Oj tam, oj tam ;)

pawelsky pisze:
labo pisze:
Dziękuję poszukam.

Tylko po co, skoro chcesz mierzyc PWM a nie PPM :) Pomijam juz ze do tego pomiaru wystarczy Ci metoda pulseIn

Ooo, to jest dobre...

Teraz wyniki po 7-10 uS niższe niż wcześniejszą metodą... Są też bardziej powtarzalne, choć rozrzuty potrafią być w niektórych pomiarach 10uS.
Średnia ze 100 stoi w miejscu: 1061 / 1483 / 1904.
Ciekawe na ile różnica od idealnego 1000 / 1500 / 2000 wynika z metody pomiaru, a ile na prawdę daje aparatura.
Czy można zaufać temu programowi, czy bez analizatora stanów logicznych lub oscyloskopu ani rusz?

Program z PulseIn():
Kod:
/*
Miernik PWM
Mierzy czas impulsu PWM kanału RC.
Program dokonuje 101 pomiarów (pierwszy odrzuca,
bo pomiar mógł się zacząć, gdy impuls już trwał)
i wyświetla średnią ze 100 na serial monitorze.
*/

// Ustaw pin do odczytu
const int PinOdczyt = 2;

// deklaracja zmiennych:
int PWM[100]; //tabela na 100 pomiarów
long srednia=0;

void setup() {
  Serial.begin(9600);
  // initializacja pinu odczytu jako input:
  pinMode(PinOdczyt, INPUT);     
  Serial.println(F("Czekaj na pomiar ok. 4 sekundy"));
}

void loop(){
  for (byte k=0; k<100; k++) {
    PWM[k] = pulseIn(PinOdczyt, HIGH);
  }

  //wyświetlaj czasy
  for (byte i=0; i<100; i++){
 //   Serial.print(F("Pomiar "));Serial.print(i);Serial.print(F(" : "));Serial.println(PWM[i]);
    srednia=srednia+PWM[i];
  }
  //Wyświetl wartość średnią:
  Serial.print(F("Pomiar sredni : "));Serial.println(srednia/100);
  srednia = 0;
}

_________________
Modelarstwo lotnicze Toruń


Na górę
 Wyświetl profil  
 
Post: sobota 05 sty 2019, 00:05 
Offline
Awatar użytkownika

Rejestracja: środa 12 sie 2015, 19:46
Posty: 95
Lokalizacja: Ruda Śląska
Witaj,

Czytając temat postanowiłem pomóc, jakiś czas temu poskładałem mały migacz LED do drona/samolotu, na własne potrzeby.
Pomiaru impulsu PWM z kanału odbiornika dokonuje w przerwaniu. Pomiar bardzo dokładny. Instrukcje w pętli głównej nie wpływają na odczytane wartości.
Różnice pomiaru długości miałem rzędu 1-3 taktów zegara. Co w zupełności było wystarczające do moich potrzeb.

W twoim programie marnujesz dużo czasu na dokonanie pomiarów. Dokładając dodatkowe funkcje/instrukcje w pętli głównej prawdopodobnie pominiesz zmianę wartości kanału długości impulsu PWM.

Poniżej wstawka moich skromnych poczynań - nie jestem zawodowym programistą, więc może lepiej można by to napisać.
Ustawienia rejestrów EICRA itp. są dla płytki Arduino Nano v3 z procesorem ATMega328

Program był pisany w środowisku: WinAvr, później Atmel Studio 7.0 - w obu działało tak jak powinno

Wzorując się na poniższym kodzie dasz radę "przetłumaczyć" to na Arduino

Życzę powodzenia :-)

Kod:
// nadanie nazw prostych do funkcji np zatrzymanie timera, zmiana zbocza niskie/wysokie

// Definicja zbocz dla przerwania INT0
#define INT0_zbocze_narastajace EICRA = 0x03   //(1 << ISC00 |1 << ISC01)
#define INT0_zbocze_opadajace   EICRA = 0x02   //(1 << ISC01)
#define INT0_stan_niski         EICRA = 0x00

#define INT0_enable            EIMSK = 1
#define INT0_disable           EIMSK = 0

#define TIMER1_start         TCCR1B = 3 //fcpu  1/1; 2/8; 3/64; 4/256; 5/1024
#define TIMER1_stop            TCCR1B = 0


volatile uint8_t zbocze_INT = 0, wartosc_PWM = 0;
volatile uint8_t flaga_przerwania = 0; //0 - zbocze narastajace, 1 - zbocze opadajace, 2 - wylaczenie
volatile uint16_t dlugosc_impulsu = 0;

volatile uint8_t offset_do_tabeli = 0, pwm_petla = 0, pwm_timer = 0, max_pwm_timer = 0;


#define komp_3_6_pozycje 0 // 0 - kompilacja dla 3 pozycji, 1 kompilacja dla 6 pozycji

// W pętli głównej porównuje długość impulsu z kanału PWM z tym co jest poniżej i wykonywałem jakąś akcje
#if komp_3_6_pozycje == 0 // tutaj sa zmierzone granice dla przelacznika 3 pozycyjnego

//  247   375  503

   #define pos_1 247
   #define pos_2 375
   #define pos_3 503

   #define dead_band 30
#endif


#if komp_3_6_pozycje == 1 // tutaj dla 6-cio pozycyjnego
   #define pos_1 248
   #define pos_2 298
   #define pos_3 348
   #define pos_4 400
   #define pos_5 452
   #define pos_6 503
   #define dead_band 8
#endif



/*
0 - 248
1 - 298
2 - 348
3 - 400
4 - 452
5 - 503

*/

// Timer 0 - 8bit, generuje sygnal pwm na zadanych pinach
// Timer 1 - 16bit, zlicza dlugosc impulsu
// Timer 2 - 8bit, szybkosc zmiany odczytu z tabelek

// INT0 - reaguje na narastajace zbocze, wlacza timer 1, zmiana na opadajace zbocze, wylacza timer 1, zmiana na wysokie zbocze


// Obsluga przerwania na ktorym wisi kanal RC
// najpierw pojawienie stanu narastajacego zwieksza flaga przerwania na 1
// jesli flaga = 1 -> startuje timer do pomiaru dlugosci impulsu
// zmiana reakcji na opadajace zbocze
// kolejne wejscie zwieksza flage
// jesli flaga = 2, wtedy zatrzymujemy timer, przepisujemy wartosc licznika - dl. impulsu
// zerujemy licznik timera
// zmieniam czulosc na zbocze narastaace
ISR(INT0_vect)
{
   flaga_przerwania++;

   if(flaga_przerwania == 1)
   { TIMER1_start; INT0_zbocze_opadajace;}// start TIMER1 aby zliczał takty zegarowe, zmiana na jakie zbocze ma reagowac przerwanie
   
   
   if(flaga_przerwania == 2)
   {    TIMER1_stop;      // zatrzymanie zliczania dlugosci impulsu
      flaga_przerwania = 0;   // wyzerowanie zmiennej pomocniczej
      dlugosc_impulsu = TCNT1; // przepisanie ilosci zliczonych taktow zegara do zmiennej
      TCNT1 = 0;       // wyzerowanie licznika impulsow
      INT0_zbocze_narastajace; // zmiana reakcji przerwania na zbocze narastajace
//      uart_dec(dlugosc_impulsu,1);   // tutaj wysylalem do portu szerogowego to co sie zliczylo
   }
}


// konfiguracja timera i przerwania zewnętrznego
// Ustawienie przerwania INT0
   // wywolanie przerwania steruje praca timera 1ktory odczytuje dl impulsu
      EIMSK |= 1 << INT0; // Włączenie przerwania na pinie INT0
      INT0_zbocze_narastajace;   // reakcja na zbocze narastajace
      //PORTD |= 1 << 2;


// Ustawienie timera1 - 16bit
   // uzywany do odczytu dlugosci impulsu z kanalu rc
      TCCR1A = 0; // Wyjscia OCx jako normalne porty a nie wyjscia PWM
      TCCR1B = 0; // Chwilowo wyłączony timer1




_________________
Aparatura: Taranis 9XD + pulpit
Modele: Nieśmiertelny Easy Star II; MPX Easy Glider 4; Skywalker X6


Na górę
 Wyświetl profil  
 
Wyświetl posty nie starsze niż:  Sortuj wg  
Nowy temat Odpowiedz w temacie  [ Posty: 8 ] 

Strefa czasowa UTC+1godz.


Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 4 gości


Nie możesz tworzyć nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Przejdź do:  
cron
Technologię dostarcza phpBB® Forum Software © phpBB Group

Strona korzysta z plików cookie w celu realizacji usług zgodnie z . Polityką prywatności
Możesz określić warunki przechowywania lub dostępu do cookie w Twojej przeglądarce lub konfiguracji usługi.