Raspberry Pi a regulátor Turnigy Multistar

Po přečtení inspirativního článku na rootu jsem se rozhodl postavit si vlastní quadrocoptéru. Pořád mi ale vrtalo hlavou, jestli je k řízení regulátorů opravdu nezbytný Arduino Nano, nebo to jde jen s pomocí Raspberry Pi (dále jen „malina“)…

K regulací výkonu motorů jsem si pořídil regulátory Turnigy Multistar 30A ESC, které by měly vykazovat lepší vlastnosti u multi-koptérových systémů (zejména vyšší frekvence posílaní dat – až 499Hz – a rychlejší reakce). V zásadě je ale jedno, jestli místo nich použijete Plush nebo Basic. Fungovat by měly všechny.

Jak už bylo v článku výše popsáno, regulátory fungují tak, že jim posíláte v určité frekvenci pulzy o délce od 1ms (0% výkonu) do 2ms (100% výkonu). Frekvence se může mírně lišit, například u regulátorů Multistar je doporučovaná frekvence 480 Hz a vyšší (až do 499Hz), což ale znamená, že pulzy posíláte každých cca 2,083ms. To je příliš krátká doba na to, abyste jednoduše napsali program na malině a v nějaké smyčce posílali impulzy na GPIO piny. Linux totiž není real-time OS a občas (čti často) se stane, že program nedostane přidělen dostatek času k tomu, aby dokázal produkovat kvalitní výstup. A tak se tu a tam stane, že se pulz nadměrně prodlouží, či naopak zkrátí a regulátory podle toho i jednají. Prostě zešílí.

Autor článku vyřešil problém tak, že přihodil k malině Arduino Nano, které dokáže pulzy generovat už velice přesně. Na obrázku výše vidíte průběh pulzů pro 50% výkon motoru (délka trvání jednoho pulzu je tedy 1,5ms). Jak takového výstupu dosáhnout jen s malinou? Klíč se nachází ve využití DMA kanálů.

Když jsem začal pátrat na internetu, nalezl jsem zajímavý projekt ServoBlaster od Richarda Hirsta, který slouží k ovládaní serv pomocí standardních GPIO pinů. Funguje to tak, že se vytvoří mapa pulzů v paměti a pak se řekne DMA řadiči, aby je v pravidelných intervalech kopíroval na určitou adresu v paměti. Tam „sídlí“ GPIO řadič, který posléze posílá signály na piny. Takto jsme schopni generovat pulzy s dostatečnou přesností 10µs v 20ms intervalech. Jenže my potřebujeme interval cca 2ms… Když jsem se ho pokoušel zkrátit přímo v kódu, malina se z toho dočista zbláznila a stala se neovladatelnou.

Své „bingo“ jsem nalezl až v knihovně RPIO a její v céčku napsané části pro PWM regulaci. Shodou okolností je to knihovna postavená na práci Richarda Hirsta, ale navíc umožňuje přidávat do zvoleného intervalu dílčí pulzy, jak můžete vidět zde. Řekl jsem si, že když nemohu posílat pulzy v cca 2ms intervalech, tak je „zabalím“ do balíčku 5 pulzů s intervalem dlouhým 10,4ms. A hle, funguje to naprosto přesně a spolehlivě s 0% zátěží CPU!

Následující program využívá soubory pwm.c (očesaný o funkci main) a pwm.h z knihovny RPIO. Výstupem jsou pulzy dlouhé 1200µs, tedy 20% výkonu, posílané každých 2080µs (odpovídá frekvenci cca 480,8 Hz).

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include "pwm.h"
 
#define PULS_US 2080 // delka pulzu v us
#define PULSES_IN_BLOCK 5 // pocet pulzu v bloku
#define INTERVAL_US PULSES_IN_BLOCK*PULS_US // delka intervalu
 
#define DMA_CHANNEL 0 // pouzity DMA kanal (0)
#define PIN 17  // Pouzity pin pro vystup
 
// nastavi pulzy na dany vykon (od 0 do 100)
int set_pulses(int perf)
{
  if (perf < 0) perf = 0; if (perf > 100) perf = 100;
  for (int i=0; i<PULSES_IN_BLOCK; i++)
    add_channel_pulse(DMA_CHANNEL, PIN, 
      (PULS_US/10)*i, // zacatek delime 10 (viz granularita)
      100+perf // Ve skutecnosti (100+perf)*10 (viz granularita)
    );
}
 
int main()
{ 
  /* Inicializace s 10us granularitou, 
     prodlevy zajistuje PWM na maline */
  setup(10, DELAY_VIA_PWM);
  // Inicializace DMA kanalu s danym intervalem
  init_channel(DMA_CHANNEL, INTERVAL_US);
  /* Nastavime 0% vykonu kvuli 
     synchronizaci regulatoru a maliny */
  set_pulses(0);
  usleep(50000);
  // Zrusime pulzy
  clear_channel_gpio(DMA_CHANNEL, PIN);
  // Nastavime pulzy s 20% vykonem
  set_pulses(20);
  while (getc(stdin) != EOF); 
  clear_channel_gpio(DMA_CHANNEL, PIN);
  shutdown();
  exit(0);
}

Nezapomeňte, že funkce add_channel_pulse na řádku č. 19, přijímá argumenty začátku pulzu a délky pulzu v granularitě. Tu máme nastavenou na 10µs, viz řádek č. 29. Dále mějte na paměti, že „zabalením“ více pulzů do jednoho balíku, snižujete efektivní frekvenci regulace na cca 100 Hz. Dle mého názoru to bohatě stačí, ale je třeba na to myslet. Každopádně, experimentům se meze nekladou, tak jen zkoušejte, regulujte a lítejte 🙂

GPIO Raspberry

 

Sdílet na sociálních sítích