Arduino a RC vysílačka

Stáhnout jako PDF autor: Johny, arduino, dne 9.12.2014


Potřeboval jsem řídit krokový motor pomocí modelářské vysílačky. Motor řídit umím, nicméně se čtením PWM signálu z vysílačky jsem se trochu trápil. Celkově jsem vyzkoušel tři přístupy jak hodnotu z vysílačky číst. První nápad byl použít pulseIn(), dále manuální čtení stavu pinu a výpočet času změny. Nakonec nejlepším řešením bylo použití interuptu.

Co vlastně načítám?

PWM signál z vysílačky je v podstatě neustále se měnící 1 a 0 (HIGH/LOW) hodnota. Čím rychleji se mění, tím menší hodnota na vysílačce je. Čím pomaleji se mění, tím vyšší hodnota na vysílačce je.

Tento článek tedy rozebírá v podstatě pouze to, jak nejlépe a co možná nejpřesněji měřit délku pulzů, které nám jdou z přijímače.

Modelářský PWM signál

Pro názornost přikládám obrázek z mého osciloskopu, kde je vidět jak signál vypadá když je „plynová páčka“ na vysílačce v poloze MIN a MAX (stačí přejet přes obrázek myší). Jeden dílek na stupnici je 500us. Z toho je patrné, že minimální hodnota pro signál je cca 1000us a maximální cca 2000us. Na mojí vysílačce to je přesněji cca 990us až 1980us, jak rozebírám později.

Zapojení vysílačky

Než se pustím do vysvětlování výše popsaných řešení, bylo by dobré abych vysvětlil jak připojit modelářskou vysílačku k arduinu. Přijímače co znám jsou vždy na 5V, takže stačí zapojit 5V pin a GND pin, přijímač by se měl rozblikat, pokud je správně párovaný, měl by svítit. (Může se lišit u různých přijímačů). Signál PWM připojíme na nějaký pin arduina, já zvolil PIN 2, důvod vysvětlím na konci článku.

Řešení pomocí pulseIn()

Zde skoro není co popisovat, pomocí pulseIn se zkrátka měří doba, kdy se změní stav na pinu z LOW na HIGH. Toto řešení je úplně nejsnadnější, nicméně arduino při čekání na změnu stavu pinu čeká – je blokované. Takže pokud potřebujete dělat i něco jiného v čekací pauze, míte smůlu. Já se například snažil generovat pulzní signál pro řízení krokového motoru, nicméně generovat pulzy rychleji než je frekvence modelářkého PWM zkrátka nešlo. Takže řešení s pulseIn doporučuji jen tomu, kdo nepotřebuje kromě čtení řešit nic jiného.

void setup() {
  Serial.begin(115200);
  pinMode(2, INPUT);
}

void loop() {
  Serial.print ("Ch1:");
  Serial.println (pulseIn (2,HIGH));
}

Řízení pomocí odečítání času

Druhý nápad byl o tom, že budu zkrátk pořád dokola kontrolovat stav HIGH/LOW na pinu a když zistím, že aktuální hodnota je jiná než naposledy zaznamenaná hodnota, tak si odečtu čas od poslední změny. Tohle řešení mi přišlo rozumné a s ohledem na to, že arduino mi běží na 16MHZ a modelářský PWM signál je v rozsahu 0.00095 sec. až 0.00198 sec. by to nemusel být problém.

const int PWM_Pin=3;
unsigned long last;
unsigned long cas;
unsigned long naposledy_VYS;

void setup()
{
  pinMode(PWM_Pin, INPUT);
  Serial.begin(115200);
}


void loop() {

  if(digitalRead(PWM_Pin)==LOW){
    if(last == HIGH){
      cas = micros()-naposledy_VYS;
      naposledy_VYS = micros();
    }

    last = LOW;
  }else{
    if(last == LOW){
      cas = micros()-naposledy_VYS;
      naposledy_VYS = micros();
    }
   last = HIGH;
  }

    Serial.print("Hodnota: ");
    Serial.println(cas);
}

Nedokážu říct, proč toto zlobilo. Hodnoty hodně kolísali a i když jsem se na radu kamaráda pokusil použít vážený průměr (low pass filtr) tak to nepomohlo.

Řešení pomocí Interuptu

Nakonec se ukázalo, že nejlepším řešením je pouřít interuptu. Arduino umí za jistých okolností přerušit běh hlavní smyčky a vykonat jinou definovanou činnost. Přerušení hlavní smyčky se dá navázat na změnu stavu pinu. Bohužel, nižší verze arduina s čipem ATmega 3128P (Nano, Mini) umí použít interupt pouze na nožičce 2 a 3. Přehled které to arduino má kde jaký interupt je nejlépe popsané přímo na „stránce arduina“:http://arduino.cc/…achInterrupt

V hlavičce programu setup se musí zaregistrovat interupt a co se při dané akci stane.

void setup()
{
  //vysilacka na pinu cislo 2 (preruseni 0)
  attachInterrupt(0, VYSILACKA_count_pwm, CHANGE);
}

Díky tomuto řádku arduino ví, že kdykoliv dojde ke změně stavu na pinu 2 (interupt 0) tak zavolá funkci VYSILACKA_count_pwm.

Funkce VYSILACKA_count_pwm si pamatuje kdy byla volána a vždy jen odečte aktuální čas micros() od času, kdy naposledy byla volána. Tím získáme délku pulzu a defakto kýženou hodnotu.

Bohužel, nevím proč se mi to děje ale občas mi délka pulzu vyjde jako obří číslo kolem 16000 – možná něco přeteklo, nevím. Proto při čtení času mám podmínku, že výpočet proběhne pouze tehdy, pokud je pulz maximálně 3000. Běžná délka pulzu na mojí vysílačce pak je v rozsahu 990 až cca 1980.

Kompletní příklad řízení bipolárního motoru

Nakonec kompletní příklad, jak sem to nakonec naprogramoval. Pro pochopení je dobré napsat, že na PINech 12 a 13 mám připojený motor. Kdykoliv do pinu 13 přijde pulz, motor udělá krok. Pin 12 pak udává směr, když je HIGH, točíme se ve směru hodinových ručiček, když je LOW – jedeme obráceně.

Program funguje tak, že definuje tři intervaly, konkrétně rozsah „točíme se doleva“ pak rozsah „stojíme“ a nakonec rozsah „točíme se doprava“.

const int PIN_motor_rychlost = 13;
const int PIN_motor_smer = 12;

//rozsah doleva MIN-MAX, rozsah doprava MIN, MAX
const int rozsah_vysilacky[] = {994, 1494, 1501, 1980};

//mapujeme na rychlost kroků v rozsahu MIN, MAX
const int mapovany_rozsah[] = {100, 10000};

unsigned long vysilacka_pwm_kanal = 0;
unsigned long vysilacka_pwm_kanal_naposledy = 0;
unsigned long naposledy = 0;


unsigned long MOTOR_rychlost_cilova = 10000;
unsigned long MOTOR_rychlost = 10000;
unsigned long MOTOR_smer = 10000;
unsigned long MOTOR_pause=1;

int MOTOR_aktualni_krok = HIGH;

void setup()
{
  //vysilacka na pinu cislo 2 (preruseni 0)
  attachInterrupt(0, VYSILACKA_count_pwm, CHANGE);
}


void loop() {
  if(micros() > (MOTOR_rychlost + naposledy) && !MOTOR_pause){
      digitalWrite(PIN_motor_rychlost,MOTOR_aktualni_krok=MOTOR_aktualni_krok==HIGH?LOW:HIGH);
      digitalWrite(PIN_motor_smer, MOTOR_smer);
      naposledy = micros();
  }
}


void VYSILACKA_count_pwm()
{
  if(micros()-vysilacka_pwm_kanal_naposledy<3000){
    vysilacka_pwm_kanal = micros()-vysilacka_pwm_kanal_naposledy;

          if(vysilacka_pwm_kanal<rozsah_vysilacky[1]){
             MOTOR_pause = 0;
             MOTOR_smer = 1;
             MOTOR_rychlost_cilova = map(vysilacka_pwm_kanal, rozsah_vysilacky[0],rozsah_vysilacky[1],mapovany_rozsah[0],mapovany_rozsah[1]);

          }else if(vysilacka_pwm_kanal>rozsah_vysilacky[2]){
             MOTOR_pause = 0;
             MOTOR_smer = 0;
             MOTOR_rychlost_cilova = map(vysilacka_pwm_kanal, rozsah_vysilacky[2],rozsah_vysilacky[3],mapovany_rozsah[1],mapovany_rozsah[0]);

          }else if((vysilacka_pwm_kanal>rozsah_vysilacky[1] && vysilacka_pwm_kanal<rozsah_vysilacky[2])){
             MOTOR_pause = 1;

          }

          MOTOR_rychlost=MOTOR_rychlost_cilova;
  }

  vysilacka_pwm_kanal_naposledy = micros();
}

PPM Sum

Nakonec snad jen zmínka – některé přijímače umí spojit všechny kanály do jednoho časového multiplexu. Pak se na jednom pinu stále dokola přenáší definovaný počet kanálů. Zatím jsem nepřemýšlel jak toto použít, nicméně z obrázku je patrné, že kanály jsou po sobě a jednotlivé bloky n PPM signálu jsou oddělené delší prodlevou. Až budu mít čas a náladu, mohu zkusit vymyslet způsob, jak dané hodnoty načítat.

Obrázek z osciloskopu.

PPM Sum

Zde je vidět jak jsou stále dokola opakováno 9 kanálů v jednom časovém multiplexu. Bez dlouhého váhání mám tušení, jak to dát dohromady – základ je odlišit jednotlivé opakování od sebe – což je snadné, interval cca 5ms. Druhý postřeh je, že budu měřit pulzy dokola jako v případě PWM signálu, jen budu naměřenou hodnotu postupně ukládat do bufferu 0,1,2,3… atd pro jednotlivé kanály. Pak 5ms pauza a znovu ;-)

Připojená fotogalerie: 2014/2014_12_12_Vysilacka/
Podobné články:

Štítky tohoto článku:

 


Diskuze: Arduino a RC vysílačka

  1. petr ujezdsky (4.1.2016, 10:56)

    Mám arduino s „návodem“ a tam píšou, že není dobré v loop() volat analogRead / digitalRead bez delay. To podle mě způsobilo selhání tvého druhého pokusu.

    Jinak se teda divím, že na netu není už nějaká knihovna pro čtení PWM (pokud jsi teda vůbec hledal, já se nekoukal)

    Reagovat na tento příspěvek
  2. jirka.stepanek (2.6.2016, 00:32)

    pro převod signálů z 8 kanálů na PPM signál používám http://www.ebay.com/…400979188190?… 8 vstupů a 5V napájení se zapojí do servovýstupů přijímače. na výstupu je PPM signál s řadou 8 záporných pulzů délky 0,4 ms. Vzdálenost mezi sestupnými hranami = délka kanálových pulzů. Opakovací kmitočet je 50 Hz

    Reagovat na tento příspěvek
  3. R3wvdgf (   333qessrddrt   16.6.2017, 21:39)

    Rvtdddtzhukh

    Reagovat na tento příspěvek
  4. Judix (   http://www.LnAJ7K8QSpfMO2wQ8gO.com   7.8.2018, 10:14)

    6gDas7 http://www.LnAJ7K8QSpfMO2wQ8gO.com

    Reagovat na tento příspěvek
  5. kodqwo (   http://dsqdnfcksfxc.com/   15.11.2018, 20:53)

    6GQvJj vswxltwrglms, [url=http://sbj­kragqtohk.com/]sbjkrag­qtohk[/url], [link=http://fy­zucfrcxlad.com/]fy­zucfrcxlad[/lin­k], http://upinfoqqsjgg.com/

    Reagovat na tento příspěvek

  6.  
    Diskuze: Arduino a RC vysílačka
    Vaše jméno (povinné)
    Váš email (nebude zveřejněn, povinný)
    WEB (bude zveřejněn, pište s http://)
    Text vzkazu:
    Kolik je 3×2? (ochrana proti spamu)
 
[CNW:Counter]