Fredag, 04 maj 2018 10:52

Accessory dekoder til styring af servoer (prototype)

Formålet med dette projekt er at undersøge om det er muligt at lave sin egen styring af servomotorer, signaler og andet vha. Arduino og Raspberry Pi boards. Mit setup er en lille testbane med en ECoS 50200 centralstation og en computer med JMRI installeret.

Bemærk at løsningen ikke er i drift - men jeg har udviklet en fungerende prototype.

Illustrationen viser de forskellige komponenter, både software og hardware, der indgår i løsningen.


Farvekoder til kasserne på illustrationen:
Blå = hardware
Hvid = baggrundsprocesser
Gul = forgrundsprocesser med grafisk brugerinterface
Grå = tråde i en process

Hardware:
Arduino shield:
Et hjemmelavet shield med en optokobler og nogle dioder. Formålet er at isolere arduinoen fra skinnerne og konvertere DCC signalerne på skinnerne til et spændingsniveau, som ikke brænder arduinoen af.
Arduino:
Modtager DCC signalet fra skinnerne via ovennævnte shield og sender de relevante pakker videre til Raspberry Pi. Da dekodning af DCC signaler er meget tidskritisk, har jeg valgt at dedikere en arduino til dette, fremfor også at lade det køre på Rapberry Pi, da Linux er ikke et real time operativsystem.
Raspberry Pi:
Modtager DCC pakker fra arduinoen, fortolker dem og sender kommandoer til servo driver boardene via I2C bussen.
Servo driver board:
Et Adafruit (eller lign.) board baseret på PCA9685 chippen. Kan styre 16 servoer. Der kan sidde op til 62 af disse boards på I2C bussen - svarende til 992 servoer.

Software:
DCC Analyzer (Arduino):
Denne Arduino sketch dekoder DCC signalerne fra skinnerne. Basic Accessory Packets sendes videre til Raspberry PI via et USB kabel. Alle andre pakker smides væk.
For ikke at bruge tid på at genopfinde hjulet, har jeg modificeret en sketch oprindelig lavet af Robin McKay og Ruud Boer, så den passer til mit formål. Jeg har brugt Arduino udviklingsværktøjet - aner ikke, hvad programmeringssproget hedder, men det ligner C og C++ meget.

DCC Decoder (Raspberry Pi):
Ved opstart indlæses konfigurationsfilen, der indeholder information om alle servoer defineret i systemet.
For hver Basic Accessory Packet der modtages over USB findes de relevante parametre i konfigurationen og herefter startes en tråd (Servo command generator), som er ansvarlig for at udstede de nødvendige kommandoer til servomotoren
. Hvis servoen skal dreje langsomt, er man nødt til at flytte den i flere små trin med passende interval. Det er dette Servo command generator tråden håndterer - og så snart tråden er startet er DCC Decoder processen fri til at behandle den næste Basic Accesory Packet. Derved kan flere servoer drejes samtidigt.
Output fra Servo command generator trådene sendes til en named pipe, som sikrer at servo kommandoerne behandles i den rækkefølge, de ankommer.

Servo command processor (Raspberry Pi):
For at undgå at flere processer/tråde slås om adgangen til I2C bussen, har jeg valgt at lægge al I2C kommunikation i en enkelt proces.
Ved opstart læses konfigurationsfilen for at se, hvilke driverboards systemet har defineret, hvorefter de initialiseres.
Herefter læses servokommandoerne en af gangen
fra pipe'n og sendes til de relevante boards.

Configurator (Raspberry Pi):
Dette program er det eneste i systemet med en grafisk brugergrænseflade. Det betyder, at der skal installeres desktop software på Pi'en. Der er måske lidt overkill.
Programmets opgave er at vedligeholde konfigurationsfilen samt at afprøve de valgte parametre. Programmet indeholder simpel datavalidering, fx. at servo adresserne ikke forekommer flere gange.

Configuration file:
Denne fil indeholder konfigurationsparametre til servoerne. Disse består af:
Servoens DCC adresse
Hvilket driverboard og kanal servoen er monteret på
Hvilker værdier servoen skal køre til i de to yderpositioner
Hvor store trin servoen skal flyttes med, når den bevæges mellem de to yderpositioner
Servoens nuværende position
(Står altid til "ukendt" i konfigurationsfilen. Når DCC decoder processen har indlæst konfigurationen i memory, bliver positionen opdateret der, så det undgås at røre servoen, hvis den allerede står rigtigt)

Filen indeholder xml data, så den kan i princippet vedligeholdes manuelt eller med en xml editor, men så mistes muligheden for at teste servoparametrene, mens man redigerer dem.


Alle programmer på Raspberry Pi er skrevet i Java med Eclipse som udviklingsplatform.
 

Skalerbarhed:
Som nævnt kan systemet håndtere op til 992 servoer og det burde der ikke være noget problem i. Det spørgsmål, man skal stille sig, er dog ikke hvor mange servoer, der kan styres, med derimod hvor mange der skal dreje samtidigt.

Under normale omstændigheder er der nok ikke behov for at dreje mange servoer samtidigt. Jeg kan dog forestille mig to situationer, hvor det er tilfældet: Når man starter sit system, er det et must at køre alle servoer til en kendt position (jeg har ingen aktive tilbagemeldinger). Det vil belaste systemet voldsomt - men JMRI har i denne situation en option til at holde en pause mellem hver kommando, den udsteder. Hvis man sætter denne pause svarende til den gennemsnitlige tid servoerne bruger på at dreje, burde det løse problemet.
Den anden situation, hvor man kan risikere at mange servoer er i brug, er ved indstilling af togveje. Jeg har lige nu kun en testbane, så jeg har ingen ide om, hvor stort problemet er. Måske har JMRI også her mulighed for at pause mellem hvert skift - det har jeg ikke undersøgt endnu.

Jeg har timet Servo command processoren til at bruge ca. 2ms pr. kommando, den håndterer. Pt. udsteder Servo command generatoren kommandoer med 20ms interval. Dvs. at man kan køre 6-8 servoer samtidigt uden side effekter. Hvis man prøver med flere, vil det virke, men de kører ikke glidende.

En anden begrænsning er, at for hver servo, der drejer, findes en kørende Servo command generator. Jeg ved pt. ikke om Java har en grænse for hvor mange tråde en process kan have kørende, men under alle omstændigheder sætter memory forbruget en øvre grænse. Jeg har endnu ikke målt, hvor meget memory, der forbruges pr. tråd.

Kabellængder kan også være et problem, hvis man har et stort anlæg. Både længden af I2C bussen og afstanden mellem et driverboard og de servoer, det skal styre. Jeg ved pt. ikke hvor grænsen går. Den maksimale længde af I2C bussen kan sikkert øges ved at sænke clockfrekvensen, men det ser ikke ud til at være en triviel operation på en Pi.

Den simpleste måde af afhjælpe alle de ovennævnte problemer at at duplikere systemet et passende antal gange og placere printene strategisk på anlægget. Men det øger jo udgifterne.
Man kan også nøjes med én Arduino koblet sammen med en Pi. Sidstnævnte distribuerer så DCC pakkerne til de andre Pi'er over Wifi.
Man kunne også lade JMRI sende kommandoerne over Wifi direkte til den relevante Pi og gå helt udenom DCC. Det kan dog vise sig at være en stor opgave. Desuden skal rettelserne i JMRI koden genindsættes, hver gang der kommer en ny version.

Videreudvikling:
For at undgå at installere en grafisk destop på Raspberry Pi, kan man med fordel omskrive configuratoren til at benytte ncurses eller Lanterna (som er native java).Så får man et pseudografisk program i et terminalvindue.

Som det er nu, indlæser DCC decoderen og Servo command processoren konfigurationsfilen ved opstart. Det ville være en fordel, at kunne tvinge dem til at genindlæse den, når Configurator processen har opdateret konfigurationen eller man har lavet manuelle rettelser. For nuværende skal processerne genstartes.

Baggrundsprocesserne skriver status og fejl til skærmen, fordi de i udviklingsfasen kører i forgrunden. Der skal implementeres et logsystem, så disse informationer i stedet skrives i en fil.


 


 

 

Senest ændret Mandag, 20 august 2018 01:52