mathias l. kjeldgaard elektronik & it aalborg universitet ... · realiseringen af et...
TRANSCRIPT
Styring af hobby 3D printer med DC motorer
Mathias L. Kjeldgaard
Elektronik & IT
Aalborg Universitet
Dato 19. Juli 2019
Fjerde Studieår, syvende semester v/ Det
Teknisk-Naturvidenskabelige Fakultet
Elektronik og IT
Frederiks Bajers Vej 7B
9220 Aalborg
http://www.tek-nat.aau.dk
Titel:
Styring af hobby 3D printer med DC
motorer
Projektperiode:
Marts 2019 - Juli 2019
Deltagere:
Mathias L. Kjeldgaard
Vejleder:
Kirsten Mølgaard Nielsen
Sidetal: 40
Appendiks: 2
Afsluttet 19. Juli 2019
Synopsis:
Denne rapport omhandler designet og
realiseringen af et styringssystem til en 3D
printer til hobby brug. Dette indebærer
bevægelse af 2 akser med DC-motorer
samt at modtage G-kode kommandoer fra
en PC.
Systemet har 2 overordnede opgaver, nem-
lig at modtage og fortolke G-kode kom-
mandoer fra en PC via en UART forbin-
delse, samt at bevæge 2 akser med 2 DC-
motorer.
Til håndtering af kommunikationen an-
vendes PSoC'ens kongurerbare hardware,
herunder DMA, til at automatisere mod-
tagelsen af hver enkel byte data. Dette
ytter en opgave der kunne tage proces-
sortid over i hardware, således det kører
automatisk.
For at styre de to akser designes først
en P-kontroller som ndes utilstrækkelig,
hvorefter en PD-kontroller designes og
testes. Denne PD-kontroller håndtunes til
en passende respons er opnået, hvilket
giver en usikkerhed i bevægelserne på 0.3
mm.
Konklusionen på systemet er, et delvist
vellykket produkt som kan danne base for
videre udvikling.
Forord
Størrelser og enheder gives i henhold til standarden ISO 80000.
Kildehenvisninger er angivet med kildenummer i rkantede parenteser[0]. Kilderne kan ndes i
bibliograen på side 41.
iii
Indholdsfortegnelse
Kapitel 1 Introduktion 1
1.1 Hvad er en 3D printer? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Initierende problemformulering . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Kapitel 2 Teori 2
2.1 Overblik over arbejdsgangen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2 STL lformatet og Sliceren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.3 G-kode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Kapitel 3 Problemformulering 6
3.1 Projektafgrænsning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Problemformulering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Kapitel 4 Kravspecikation 7
4.1 Funktionelle krav . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Kapitel 5 Design af kontrol til mekanisk system 8
5.1 Beskrivelse og modellering af mekanisk system . . . . . . . . . . . . . . . . . . . . 8
5.2 Design af controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2.1 Design af proportional kontroller vha. bodeplot . . . . . . . . . . . . . . . 12
5.2.2 Design af proportional kontroller . . . . . . . . . . . . . . . . . . . . . . . 15
5.2.3 Test af proportional kontroller . . . . . . . . . . . . . . . . . . . . . . . . 17
5.2.4 Implementering og test af proportional kontroller med oset . . . . . . . . 20
5.2.5 Design af PD-kontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.2.6 Implementering af PD-kontroller . . . . . . . . . . . . . . . . . . . . . . . 23
5.2.7 Test af PD-kontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Kapitel 6 Design af G-kode interface 26
6.1 Opsætning af DMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
6.2 Fortolkning af modtaget kommando . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.2.1 Fortolkning med strtok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.2.2 Tjek af modtagen data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.2.3 Fortolkning af kommando . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.3 Eksekvering af G-kode kommando . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.4 Sammensætning af software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Kapitel 7 Diskussion 38
Kapitel 8 Konklusion 40
Bibliogra 41
Appendiks A Udmåling af DC motor 42
Appendiks B Udmåling af XY gliders konstanter 47
iv
B.1 Friktion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
B.2 Inerti momentet af XY gliderens akser . . . . . . . . . . . . . . . . . . . . . . . . 48
v
Introduktion 11.1 Hvad er en 3D printer?
En 3D printer er et stykke værktøj der er i stand til at producere emner ved additiv fremstilling.
Dette er en modsætning til at fræse et emne, da en fræser fjerner materiale hvor en 3D printer
tilføjer det. Der er derfor ikke behov for at tilføre en 3D printer mere materiale end emnet skal
bruge, hvorimod en fræser kræver materialet er større end emnet. Der ndes ere typer 3D
printere, hvor fremstillingsmetoden, hastigheden og materialet de kan arbejde med, er forskellen.
Af de mest kendte [5] ndes:
Stereolithography (SLA)
Selective Laser Sintering (SLS)
Fused Deposit Modeling (FDM)
En SLA printer bruger en væske som hærdes med lys. Denne væske opbevares i et kar over en
lyskilde, hvor lyskilden hærder væsken der hvor der skal være materiale. Et eksempel på denne
type printer er Formlabs Form2 printer [4]. Denne printer anvender en laser der peger mod
bevægelige spejle som bestemmer hvor laseren skal hærde væsken. Selvom laseren rammer ret
præcist vil væsken omkring punktet der hærdes også blive påvirket. Dette gør at man ikke kan
genanvende den resterende væske mere end et par gange, og da denne væske er dyr sammenlignet
med en FDM printers materiale anvendes denne type printer sjældent til hobby brug.
En SLS printer virker lidt i stil med en SLA printer, men i stedet for væske anvendes en type
pulver. Pulveret kan være lavet af mange forskellige materialer som f.eks. plastik eller metal.
Denne type printer har samme problemstilling med spildmateriale som SLA printeren, da varmen
omkring smeltepunktet også påvirker pulveret omkring sig. Denne type printer bruges næsten
udelukkende af virksomheder, da den er dyr i drift men meget pålidelig.
En FDM printer skubber en plastiktråd gennem et varmelegeme og deponerer det smeltede
plastik der hvor der skal bruges materiale. Når der lægges et nyt lag plastik ovenpå en tidligere
lag smeltes de to sammen og der skabes et bånd mellem de to lag, i stil med en svejsning. Et
eksempel på en printer af denne type er Prusa's i3 mk3 [9]. Denne printer realiserer X- Y- og Z-
aksen ved at bevæge varmelegemet i X og Z retningen, og byggepladen i Y retningen. Da denne
type printer er den mest udbredte tages der udgangspunkt i denne type.
1.2 Initierende problemformulering
Hvordan er arbejdsgangen når og hvilke elementer indgår i en FDM 3D printer?
1
Teori 2I dette kapitel undersøges arbejdsgangen fra 3D CAD model til færdigt emne samt hvilke
elementer der indgår i en FDM 3D printer.
2.1 Overblik over arbejdsgangen
For at bruge en 3D printer, skal man have en CAD model i STL format. Denne model skal
igennem et program som kaldes en "slicer". Sliceren har til opgave at tage modellen, dele den
op i lag og danne de kommandoer der får printeren til at printe emnet. Kommandoerne dannes
i et format kaldet "Gcode"og er standarden. Gcoden skal så leveres til printeren, hvilket enten
foregår med et SD kort eller via en kablet forbindelse mellem PC'en og printeren hvorefter
printeren fremstiller emnet. Denne arbejdsgang kan tegnes som
STLModel Slicer Gcode 3D printer
Figur 2.1: Overblik over arbejdsgangen forbundet med en 3D printer, hvor man starter med enCAD model, exporterer til STL format, slicer den l og får G-kode ud som sendes til printeren
Da der nu er dannet et overblik over arbejdsgangen kan de enkelte dele undersøges nærmere for
at skabe en forståelse for brugen af en 3D printer.
2.2 STL lformatet og Sliceren
STL er en lformat opfundet af 3D Systems i 1987 og navnet STL er en aedning af ordet
Stereolithography. Dette lformat blev opfundet til 3D Systems første stereolithography printer
og understøttes nu af langt de este CAD programmer [11] [2]. En STL l indeholder en
beskrivelse af overaden af en 3D CAD model, men beskrevet med trekanter i det katesiske
rum.
2
Figur 2.2: Skitseret forskel på CAD model og STL repræsentation. Kilde: [11]
På gur 2.2 ses en skitse af hvordan en STL l ser ud sammenlignet med den originale CADmodel.
Denne skitse er en overdrevet illustration af hvordan en cirkel vil se ud når den er konverteret til
STL. Det kan ses der er en forskel på STL modellen sammenlignet med CAD modellen, hvilket
skyldes der ikke kan laves kurvede linjer i STL. Denne forskel kan mindskes ved at øge antallet
af trekanter. Da STL udelukkende har rette linjer, er det derfor ikke nødvendigt at printeren kan
udføre runde bevægelser. Dette skyldes G-koden vil være en samling af rette linjer.
Denne STL l skal igennem en slicer, som har til opgave at genere G-koden. Det er i sliceren
at brugeren kan styre indstillingerne for hvordan printet skal printes. Det er eksempelvis her
brugeren denerer hvor mange vægge, eller hvor meget inll printet skal have. Der er også
indstillinger for hvordan printeren skal bevæge sig under printet, hvor de relevante er:
Laghøjde [mm]
Hastighed [mm/s]
Acceleration [mm/s2]
Disse 3 parametre har stor betydning for printets udseende samt dets styrke. Derudover er det
også i sliceren brugeren bestemmer hvilken temperatur der skal printes med. Det er derfor vigtigt
at brugeren har kontrol over disse.
3
2.3 G-kode
G-kode er et Numerical Control programmeringssprog (NC), som bruges til at styre en lang
række af forskellige maskiners bevægelse. Sproget blev opfundet i 1960-erne og k det ocielle
navn RS-274D. Grunden til sproget kaldes G-kode er at de mest gængse kommandoer starter
med bogstavet G [3]. Der ndes forskellige rmware til 3D printere, som understøtter forskellige
G-koder, hvor Marlin er en af de mest udbredte. Marlin udvikles af Ultimaker og er open-source,
så derfor tages der udgangspunkt i denne rmware.
De kommandoer der bruges mest er:
G-kode Kort beskrivelse
G28 Udfør homing routine
G1 Linear Move
G90 Absolut positionering
G91 Relativ positionering
G92 Set nuværende position
M104 Set hotend temperatur
M109 Set hotend temperatur og vent
M140 Set heatbed temperatur
M190 Set heatbed temperatur og vent
M106 Set emnekøler hastighed
Tabel 2.1: Tabel over de 10 mest anvendte G-koder. Kilde: [1]
Den mest gængse kommando er "Move" kommandoen, hvor man får maskinen til at bevæge sig
til et punkt. Denne kommando ser således ud:
G1 X10.0 Y20.0 Z30.0 E5.1 F1500
Denne kommando, G1, er et "raid move", men bruges af de mest gængse printere som et
extrusion-move. Det vil altså sige at ved dette move skal der lægges plastik ud. G1 er efterfulgt
at X, Y, Z og E koordinater angivet i [mm]. Printeren vil altså ytte printhovedet til punktet
10.0, 20.0, 30.0. Hvis extruderen står i 0, vil den ligeledes lægge 5.1 mm plastik ud fordelt på
hele turen til punktet [7]. Den sidste parameter, F, angivet i kommandoen er feedraten. Denne
angiver den ønskede maksimale hastighed i [mm/min] og gælder for alle moves efter dette move,
hvis ikke en ny feedrate er angivet.
En anden move-kommando er G0, som anvendes til ikke-print-moves. Dette vil sige at printeren
ytter printhovedet til en position uden at lægge plastik ud og det er derfor ikke kritisk
hvordan printeren kommer til punktet. Derfor gælder ofte en højere acceleration og hastighed
sammenlignet med G1.
For at printeren ved hvor den er, ndes en kommando til at få printeren til at gå til 0, 0, 0.
Denne kommando kaldes Auto Home [8], G28, og bruges således:
G28 X Z
Når denne kommando bruges således, får den printeren til at home X og Z aksen, men ikke Y
aksen da der ikke er en Y parameter i kommandoen. Det er god skik at home printeren i starten
af ethvert print.
En komplet liste af understøttede G-koder i Marlin kan ndes ved [6].
4
Når kommandoerne sendes til printeren, gemmer printeren kommandoen i en buer før den rå
kommando bliver fortolket. I Marlin er denne buer indstillet til 96 bytes pr. kommando og i alt
4 kommandoer kan gemmes før bueren fyldes [10].
5
Problemformulering 33.1 Projektafgrænsning
Styringen af en 3D printer kan implementeres på mange forskellige måder, hvor den mest gængse
gør brug af et feed-forward system med step-motorer. Da dette projekt er et bachelorprojekt
vælges at anvende DC motorer i stedet for step-motorer, da disse tillader at gå mere i dybden
med regulering.
Den fysiske del af 3D printeren anses ikke for vigtig i relation til styringen, så derfor kommer
fokus til at lægge på at styre 2 motorer, nemlig X og Y. Der arbejdes ud fra at få det bedste ud
af det mekaniske system som er udleveret.
3.2 Problemformulering
På baggrund af analysen i kapitel 2 er det nu mulige at opstille en problemformulering til dette
projekt.
Hvordan implementeres styringen af en hobby 3D printer, med DC motorer på X-
og Y-aksen hvor de resterende funktionaliteter bibeholdes?
6
Kravspecifikation 44.1 Funktionelle krav
1. Systemet skal være så præcist som det er muligt med de anvendte motorer
2. X- og Y- aksen skal kunne følges ad
3. Systemet skal understøtte de 10 mest anvendte G-koder fra tabel 2.1
4. RX bueren skal kunne modtage 96 bytes pr kommando
5. RX bueren skal kunne gemme 4 kommandoer
7
Design af kontrol tilmekanisk system 5
5.1 Beskrivelse og modellering af mekanisk system
Det mekaniske system der er stillet til rådighed er en XY-glider hvor X- og Y-aksen kan bevæges
uafhængigt at hinanden. Systemet ser således ud
Figur 5.1: Oversigt over det mekaniske system, hvor X aksen er markeret med lilla og Y aksener markeret med grøn
På gur 5.1 ses systemet hvor X aksen er markeret med lilla og Y aksen er markeret med grøn.
De to akser er realiseret på samme måde hvor den roterende bevægelse fra motoren bliver oversat
til en lineær bevægelse gennem en tandrem og et tandhjul. Der er forskel på de to aksers masse,
da X-aksens motor er monteret på Y aksen så der vil være forskel på hver akses konstanter. Hver
akse kan skitseres således:
8
Tandhjul
0
X-Akse
Tandrem
DC MotorTandhjul
Ia(t)
Tandhjul
Tandrem
Motor akse
Set fra toppen Set fra siden
Masse M1
X1
Masse M1
Figur 5.2: Skitseret mekanisk system hvor det koblingen mellem motor og masse sker gennem entandrem.
For at kunne kunne opstille ligninger for systemet tegnes der først et free body diagram, hvilke
er ens for de to akser. Her antages at tandremmen er meget stiv, så fjedereekten er ubetydelig.
Motoren, dens gearing og tandhjulet antages at være samme del, som det vil fremgå af modellen.
ωp
Kt*Ia
Jp
r1
Bmωp
fm
Masse M1
B1X'1
X1
fm
Tandhjul & motor
Figur 5.3: Free body diagram for motoren samt massen hvor de virkende kræfter er indtegnet.
Fra free body diagrammet er det nu muligt at opstille ligninger for hhv. motoren og massen:
Jpωp = KtIa(t)− r1fm(t)−Bmωp(t) (5.1.1)
Ua(t) = RaIa(t) + LadIa(t)
dt+Keωp(t) (5.1.2)
M1x1(t) = fm −B1x1(t) (5.1.3)
Herefter Laplace transformeres (med begyndelsesværdi 0) de tre ligninger og løses til en ligning
Jpsωp(s) = KtIa(s)− r1fm(s)−Bmωp(s) (5.1.4)
Ua(s) = RaIa(s) + LasIa(s) +Keωp(s) (5.1.5)
9
M1s2x1(s) = fm(s)−B1sx1(s) (5.1.6)
Ved at isolere fm i (5.1.6) fåes
fm(s) = M1s2x1(s) +B1sx1(s) (5.1.7)
Herefter indsættes (5.1.7) i (5.1.4)
Jpsωp(s) = KtIa(s)− r1 ·(M1s
2x1(s) +B1sx1(s))−Bmωp(s) (5.1.8)
Fra udmålingen af motorens konstanter ses at La er meget lille, derfor sættes La = 0. Ved at
isolere Ia i (5.1.5) fåes
Ua(s) = RaIa(s) +Keωp(s)⇒ Ia(s) =Ua(s)−Keωp(s)
Ra(5.1.9)
Herefter indsættes (5.1.9) i (5.1.8)
Jpsωp(s) = Kt ·Ua(s)−Keωp(s)
Ra− r1 ·
(M1s
2x1(s) +B1sx1(s))−Bmωp(s) (5.1.10)
Jpsωp(s) =Ua(s) ·Kt
Ra− KtKeωp(s)
Ra− r1M1s
2x1(s)− r1B1sx1(s)−Bmωp(s) (5.1.11)
Det gælder at
x1(s) = θp · r1 ⇒ θp =x1(s)
r1⇒ ωp(s) = s · x1(s)
r1(5.1.12)
Med (5.1.12) substitueres ωp i (5.1.11)
Jps2x1(s)
r1=Ua(s)Kt
Ra−KtKes
x1(s)r1
Ra− r1M1s
2x1(s)− r1B1sx1(s)−Bms ·x1(s)
r1(5.1.13)
Jps2x1(s)
r1=Ua(s)Kt
Ra− sx1(s)
r1·(KtKe
Ra+Bm
)− r1sx1(s) ·
(M1s+B1
)(5.1.14)
Nu isoleres Ua(s)Kt
Raog ligningen reduceres yderligere
Ua(s)Kt
Ra= Jps
2x1(s)
r1+ s
x1(s)
r1·(KtKe
Ra+Bm
)+ r1sx1(s) ·
(M1s+B1
)(5.1.15)
Ua(s)Kt
Ra= s
x1(s)
r1·(Jps+
KtKe
Ra+Bm
)+ r1sx1(s) ·
(M1s+B1
)(5.1.16)
10
Nu kan x1(s) trækkes udenfor en parentes
Ua(s)Kt
Ra= x1(s) ·
(Jps2
r1+KtKes
Ra · r1+Bms
r1
)+ x1(s) ·
(M1s
2r1 +B1r1s)
(5.1.17)
Herefter rykkes RaKt
over på højre side, og x1(s) over på venstre:
Ua(s)
x1(s)=RaKt·(Jps2
r1+KtKes
Ra · r1+Bms
r1+M1s
2r1 +B1r1s)
(5.1.18)
x1(s)
Ua(s)=Kt
Ra· 1(Jp
s2
r1+ KtKes
Ra·r1 + Bmsr1
+M1s2r1 +B1r1s) (5.1.19)
Nu reduceres yderligere
x1(s)
Ua(s)=Kt
Ra· 1
s2 ·(Jpr1
+M1r1
)+ s ·
(KtKeRa·r1 + Bm
r1+B1r1
) (5.1.20)
Hvilket også kan skrives som
x1(s)
Ua(s)=Kt
Ra· 1
s ·(Jpr1
+M1r1
)+(KtKeRa·r1 + Bm
r1+B1r1
) · 1
s(5.1.21)
Fra ligning (5.1.21) kan ses at overføringsfunktionen har et første ordens lavpas lter og et
integrations led.
Når værdierne indsættes fåes overføringsfunktionen
G(s) =5.1369
s(s+ 21.88)(5.1.22)
5.2 Design af controller
Med overføringsfunktionen af systemet fra tidligere er det muligt at designe en passende
kontroller. Først designes en proportional kontroller, hvorefter det undersøges om den er
tilstrækkelig.
KontrollerD(s)
SystemG(s)
TilbagekoblingH(s)
SetpointR(s)
ErrorE(s)
Output U(s)
PositionX(s)
Figur 5.4: Illustration af proportional kontrolleren
På gur 5.4 ses modellen af kontrolsystemet. Målet er at nde en kontroller, D(s), for både X-
11
aksen og Y-aksen. Designet af hver kontroller er identisk, men med forskellige værdier. Derfor
designes X-aksens kontroller i dette afsnit, mens Y-aksens kontroller udelades.
5.2.1 Design af proportional kontroller vha. bodeplot
Kontrolleren skal designes således den ikke har oversving, da det vil resultere i der lægges plastik
ud hvor der ikke skal. I kurset Modeling And Control blev givet følgende graf
Figur 5.5: Illustration af sammenhængen mellem fase margin og oversving. Kilde: Modeling andControl
Fra gur 5.5 ses at for at opnå 0% oversving skal kontrolleren have en fase margin på minimum
90°. Dette bliver derfor designkravet, at opnå en fase margin på 90°. For at bestemme proportional
kontrollerens gain tegnes et bodeplot for systemet
12
-200
-150
-100
-50
0
50
Magnitude (
dB
)
10-3
10-2
10-1
100
101
102
-180
-135
-90
Phase (
deg)
G(s)
Frequency (rad/s)
System: G
Frequency (rad/s): 0.0438
Phase (deg): -90.1
System: G
Frequency (rad/s): 0.0438
Magnitude (dB): 14.6
Figur 5.6: Bode plot af systemets overføringsfunktion for X aksen.
Fra bodeplottet på gur 5.6 ses 2 aæsninger ved samme frekvens. Det ses at systemet har en
gain på 14.6 dB ved ≈90°. Kontrollerens gain skal vælges således at det samlede systems gain er
lig 0 dB ved samme frekvens som fasen er ≈90°. Kontrolleren skal derfor have et gain på -14.6
dB, svarende til Kp = 10(−14.6/20) = 0.18621. Denne værdi indsættes som D(s) og der tegnes et
nyt bode plot for D(s) ·G(s).
13
-150
-100
-50
0
50
Ma
gn
itu
de
(d
B)
10-2
10-1
100
101
102
103
104
-180
-135
-90
Ph
ase
(d
eg
)
D*G*H
Frequency (rad/s)
Figur 5.7: Bode plot af D(s) ·G(s) ·H(s), hvor H(s) = 1.
Fra gur 5.7 aæses fase margin til ≈90°, gain margin til ≈160 dB og crossover frekvensen aæses
til ≈ 0.05 rad/s.
Med den Kp der nu er bestemt, er det muligt at se step-responsen for systemet. Denne tegnes
med Matlab's step funktion, som også kan give risetime, settletime og overshoot.
14
Figur 5.8: Steprespons for systemet
Fra Matlab fås risetime er 50.1447 sekunder, hvilket er uacceptabelt langsomt, men oversving er
0 hvilket var målet. Det langsomme system kan skyldes metoden der er brugt, som kræver der
aæses værdier fra grafer, hvilket kan være svært at gøre præcist. Risetime kan reduceres ved at
øge Kp, hvilket vil resultere i at oversvinget øges. For at nde den maksimale Kp før systemet
får oversving tages en anden metode i brug.
5.2.2 Design af proportional kontroller
En anden måde at bestemme proportional kontrolleren er ved en generel approksimation af et
andet ordens system. Systemet der skal kontrolleres genopfriskes med modellen
KontrollerD(s)
TilbagekoblingH(s)
SetpointR(s)
ErrorE(s)
Output U(s)
PositionX(s)System
G(s) 1/s
Figur 5.9: Kontrolsystem
For et anden ordens system gælder approksimationen:
T (s) =X(s)
R(s)=
K
s2 + 2ζωns+ ωn2(5.2.1)
15
hvor K er systemets gain, ζ er systemets dæmpningsfaktor og ωn er systemets naturlige
udæmpede frekvens. For en sådant system gælder 3 design regler:
Risetime : tr ≈1.8
ωn(5.2.2)
Settletime : ts(x) =− ln(x)
ζωn(5.2.3)
Overshoot : Mp = e−π·ζ/√
1−ζ2 (5.2.4)
Så længe systemet er tilstrækkelig hurtig er den nøjagtige risetime og settletime ligegyldig, det
vigtige er der ikke er oversving. Fra den sidste design regel ses at jo tættere dæmpningsfaktoren
er på 1, jo mindre oversving vil der være.
For at kunne bruge approksimationen, skal lukkesløjfe overføringsfunktionen for systemet
udregnes. I dette tilfælde er tilbagekoblingen H(s) = 1.
T (s) =X(s)
R(s)=
D(s) ·G(s) · 1s1 +D(s) ·G(s) · 1s ·H(s)
⇒ (5.2.5)
Kp · 0.2349(0.457s+1)s
1 +Kp · 0.2349(0.457s+1)s
=Kp · 0.2349
(0.0457s+ 1)s+Kp · 0.2349=
Kp · 0.2349
0.0457s2 + s+Kp · 0.2349(5.2.6)
For at ligning (5.2.6) kan sammenlignes med (5.2.1), skal den skaleres således at konstanten der
ganges med s2 er lig 1, svarende til 10.0457 = 21.8818. Dette resulterer i overføringsfunktionen:
K
s2 + 2ζωns+ ωn2=
Kp · 5.14
s2 + 21.8818s+Kp · 5.14(5.2.7)
Fra ligning (5.2.7) ses at 2ζωn = 21.8818 og
ωn2 = 5.14Kp ⇒ ωn =
√5.14Kp (5.2.8)
For at undgå oversving sættes ζ = 1, hvilket giver at
2ζωn = 21.8818⇒ ωn =21.8818
2ζ⇒ ωn =
21.8818
2= 10.94 (5.2.9)
Med ligning (5.2.8) er det muligt at bestemme Kp:
ωn = 10.94 =√
5.14Kp ⇒ Kp = 23.28 (5.2.10)
Med denne Kp er det muligt at se stepresponsen:
16
Figur 5.10: Steprespons for systemet
Som det kan ses på gur 5.10 vil denne kontroller ikke have oversving og med en risetime på
≈0.4 sekunder er den også tilstrækkelig hurtig så den testes.
5.2.3 Test af proportional kontroller
Når kontrolleren skal implementeres er der nogle fysiske begrænsninger som ikke er indregnet i
stepresponsen fra gur 5.10. Figur 5.9 genopfriskes:
KontrollerD(s)
TilbagekoblingH(s)
SetpointR(s)
ErrorE(s)
Output U(s)
PositionX(s)System
G(s) 1/s
Figur 5.11: Genopfriskning af kontrolsystemet
Da driver-printet forsynes med +12VDC, kan motoren altså ikke få højere spænding. Det vil sige
outputtet af kontrolleren ikke kan overskride ± 12VDC, svarende til signalet U(s) på gur 5.11.
Ligeledes har motoren også en maksimal hastighed den kan opnå, målt i appendiks A til 172.2
rad/s.
Den komplette simulering ser således ud:
17
X(s)[m]
U(s)[V]
E(s)[m]
R(s)[m]
Hastighed[m/s]
P(s)
P ControllerInput
G_UdenInt
OverføringsFunktionUden integration
1s
MaksSpænding
Max Speed
Figur 5.12: Skærmbillede af modellen i Simulink
Dette giver en mere virkelighedsnær simulation. Forskellen på de to modeller kan ses i
stepresponsen:
Figur 5.13: Steprespons for den simple og den avancerede model
Som det kan ses på gur 5.14 vil systemet være lidt langsommere end først antaget, hvilket kan
accepteres da tidsforskellen er så lille. Denne avancerede model bruges til at sammenligne den
virkelige opførsel med den simulerede. Kontrolleren implementeres og en test foretages. Resultatet
kan ses på guren herunder.
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
Sekunder
0
0.02
0.04
0.06
0.08
0.1
0.12
0.14
0.16
0.18
Po
sitio
n [
m]
Step i position
Simuleret position
Målt position
Setpunkt
Figur 5.14: Målt respons sammenlignet med forventet respons.
Som det kan ses på gur 5.14 rammer systemet ikke setpunktet og det ligner der er en lille smule
oversving før den står stille. Dette kunne tyde på der er en fejl i implementeringen af kontrolleren,
hvilken vil kunne ses i outputtet af kontrolleren, så derfor plottes spændingsoutputtet fra
kontrolleren og sammenlignes med den simulerede. Kontrolleren implementeres og testes, og
resultatet kan ses på guren herunder.
18
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5
Sekunder
-4
-3.5
-3
-2.5
-2
-1.5
-1
-0.5
0
Sp
æn
din
g [
V]
Spænding over tid
Simuleret spænding
Målt spænding
Figur 5.15: Målt og simuleret spænding fra samme test som gur 5.14
Fra spændingsplottet på gur 5.16 ses kontrollerens output på ≈-2.5V. Det vil altså sige at
kontrolleren ønsker at ytte nærmere setpunktet, men ikke kan overkomme friktionen.
Fra gur 5.14 kan ses at systemet accelererer langsommere end forventet. Dette ses ved kurvens
hældning umiddelbart efter steppet i setpunktet ikke er lige så stejl som forventet. Denne
hældning svarer til hastigheden af systemet i m/s. At hastigheden er lavere end forventet kan
skyldes en forkert friktionskonstant, da friktionen er proportional med hastigheden. Det kan
også ses at lige efter steppet accelererer systemet langsommere end forventet, hvilket kan være
forårsaget af det beregnede inertimoment er mindre end det reelle inertimoment.
Når friktion beregnes er der tale om to forskellige typer, nemlig dynamisk og statisk friktion.
Den dynamiske friktion er den som er medregnet i modellen er konstant og proportional med
hastigheden, svarende til jo hurtigere systemet bevæger sig, jo højere friktion. Den statiske
friktion er en konstant som gælder når systemet ikke bevæger sig. Disse kan skitseres som
- 0
Hastighed
0
Dynamisk
Statisk
Friktion
Friktion som funktion af hastighed
Figur 5.16: Skitseret friktionskonstant som funktion af hastigheden. Det ses den statiske friktioner større end den dynamiske, men kun gælder ved ω ≈ 0
I modellen er det antaget at kontrollerens output altid er høj nok til at overkomme den statiske
friktion og dermed få systemet i bevægelse. Fra gur 5.14 kan konkluderes at kontrollerens
output er højt nok til at overkomme den statiske friktion, men ikke er højt nok til at overkomme
den dynamiske friktion. Dette kan ses ved at systemet faktisk ytter sig, men stopper efter
kontrollerens output kommer under en værdi.
19
5.2.4 Implementering og test af proportional kontroller med oset
For at undgå kontrollerens output kommer under den spænding der skal til for at holde systemet
i bevægelse, forsøges at lægge en konstant til outputtet af kontrolleren, svarende til den spænding
der skal til for at overkomme den statiske friktion. Denne spænding er fundet til 3.79 V. På denne
måde burde systemet ikke gå i stå på vej mod setpunktet.
0 0.5 1 1.5 2 2.5 3 3.5 4
Sekunder
0
0.02
0.04
0.06
0.08
0.1
0.12
0.14
0.16
0.18
Positio
n [m
]
Step i position
Simuleret position
Målt position
Setpunkt
Figur 5.17: Målt position med en konstant lagt til outputtet af kontrolleren sammenlignet medden simulerede respons uden konstanten.
Som det kan ses på gur 5.17 gør denne konstant at systemet reagerer hurtigere end simuleret,
men med det resultat at der er oversving samt ripple omkring setpunktet. For at se kontrollerens
output laves et plot af spændingen.
0 0.5 1 1.5 2 2.5 3 3.5 4
Sekunder
-4
-3.5
-3
-2.5
-2
-1.5
-1
-0.5
0
0.5
Sp
æn
din
g [
V]
Spænding over tid
Simuleret spænding
Målt spænding
Figur 5.18: Målt og simuleret spænding fra samme test som gur 5.17
På gur 5.18 ses outputtet af kontrolleren før konstanten lægges til (blå) sammenlignet med den
simulerede (rød). Denne respons ligner en normal P-kontrol med et højt gain. Som det ses er der
ripple omkring setpunktet, hvilket helst ikke skulle være der, men udover det er kontrollerens
output som forventet.
Da de forgående sammenligninger har været med den simulerede respons uden tilsvarende
konstant i udgangen af kontrolleren, er det svært at bestemme om den nye respons er den samme
som kunne forventes. At den grund sættes en ny simulering op i Simulink, med denne konstant
lagt til udgangen.
20
R(s)[m]
E(s)[m]
U(s)[V]
X(s)[m]
Hastighed[m/s]
P(s)
P ControllerInput MaksSpænding
1s
G_UdenInt
OverføringsFunktionUden integration
Voltoffset
Sign
Figur 5.19: Simulering i Simulink, med et spændingsoset lagt til kontrollerens output.
På gur 5.19 ses opsætningen i Simuling. Her ses den ekstra summation efter kontrolleren P(s).
Her lægges en konstant til, som ganges med fortegnet af outputtet af kontrolleren. Dette resulterer
i følgende simulering:
0 0.5 1 1.5 2 2.5
Sekunder
0
0.02
0.04
0.06
0.08
0.1
0.12
0.14
0.16
0.18
0.2
Positio
n [m
]
Step i position
Simuleret position
Målt position
Setpunkt
Figur 5.20: Simuleret og målt position med oset efter kontrolleren.
Som det kan ses fra gur 5.20 er den nye simulering næsten identisk med den målte respons.
Den største forskel ligger i oversvinget, hvor simuleringen resulterer i større oversving, hvilket
giver god mening da det fra gur 5.14 blev konkluderet den faktiske friktion er større end den
beregnede.
Fra overføringsfunktionen for modellen, ligning (5.1.21), kan ses der er en integration i modellen,
derfor burde steady-state fejlen være lig 0. Dette vil sige outputtet af kontrolleren burde være
lig 0, hvilket kan ses på gur 5.16 ikke er tilfældet. Da det er blevet konkluderet at friktionen
i systemet er højere end målt, skal der en højere spænding til for at systemet bevæger sig.
Det er forsøgt at tilføje et oset i outputtet fra kontrolleren for at kompensere for friktionen,
hvilket resulterede i oversving og en ripple omkring setpunktet. Osettet svarer til et højere
proportionalt gain, hvilket er kendt for at have en indydelse på oversving. En anden måde at få
et større proportionalt gain på, er ved at implementere en Proportional-Dierential-kontroller.
Denne type kontroller tillader et større proportional gain, da dierential-delen vil begrænse
hastigheden af systemet.
5.2.5 Design af PD-kontroller
En PD-kontroller er en variation af den velkendte PID kontroller, hvor det kun er proportional-
og dierential-delen der tages i brug. PID-kontrollens 3 dele kan illustreres som
21
Figur 5.21: De 3 dele af en PID kontrol skitseret. Det ses at P-delen er størrelsen af fejlen ogD-delen er hældningen af fejlen. Kilde: Modeling and Control kurset.
Fra gur 5.21 ses at dierential-delen kigger på hældningen af error-signalet, hvilket vil sige
at hvis systemet nærmer sig setpunktet hurtigt, vil dierential-delen begrænse outputtet fra
kontrolleren. Dette kontrolsystem regulerer positionen af et mekanisk system, hvilket vil sige at
dierential-delen af kontrolleren regulerer hastigheden af det mekaniske systems bevægelse. Det
er dermed muligt at få kontrolleren til selv at bremse det mekaniske system hvis dierential-gainet
er tilpas højt. Dette tillader et meget højere proportional gain, hvilket resulterer i kontrollerens
output kan øges væsentligt ved lave hastigheder, uden at give oversving.
En PD-kontroller har overføringsfunktionen
U(s)
E(s)= Kp +Kds (5.2.11)
hvilket også kan skrives som
U(s)
E(s)= Kp(1 +
Kd
Kps) = Kp(1 + Td · s) (5.2.12)
hvor Td = KdKp
.
Fra ligning (5.2.11) kan ses at kontrolleren har et nulpunkt i − 1Td. Denne kan placeres oveni
en af systemets poler således de to udligner hinanden og det samlede system vil få en større
båndbredde. Det huskes at overføringsfunktionen for systemet er
G(s) =5.1369
s(s+ 21.88)(5.2.13)
Fra ligning (5.2.13) kan ses at der er en pol i 0 og en pol i -21.88. Det vil derfor være muligt at
udligne polen i -21.88 med nulpunktet fra PD-kontrolleren ved at sætte
− 1
Td= −21.88⇒ Td =
1
21.88= 0.0457 (5.2.14)
Med Td er det muligt at bestemme Kd fra ligning (5.2.12). Kp sættes til samme værdi som fra
22
ligning (5.2.10)
Td =Kd
Kp⇒ Kd = Td ·Kp = 0.0457 · 23.28 = 1.063896 (5.2.15)
Med Td fra ligning fra (5.2.14) er det muligt at lave et bodeplot med Matlab.
-100
-50
0
50
100
Magnitude (
dB
)
10-2 100 102 104
-90
Phase (
deg)
Bodeplot af D*G*H
Frequency (rad/s)
Figur 5.22: Bodeplot for PD-kontrollen. Her ses nulpunktet ligger perfekt ovenpå polen, såledesamplituden ændres med -20 dB/dekade og skærer 0 dB ved ≈ 5 rad/s.
Som det kan ses på gur 5.22 er fasen 90° ved alle frekvenser. Dette er kun muligt i teorien, da
det kræver at kontrollerens nulpunkt ligger nøjagtig oveni en af systemets poler. I den virkelige
verden er det meget svært at ligge det nulpunkt præcist det rigtige sted, hvilket vil resultere i
en "pukkel" i fasen, hvor fasen enten vil være over eller under -90°.
5.2.6 Implementering af PD-kontroller
Da PD-kontrollerens konstanter nu er bestemt, er det muligt at implementere den i systemet.
For at få samme tid mellem hver eksekvering af kontrolleren vælges at implementere den i en
interrupt (ISR), på denne måde afhænger den ikke af resten af systemets processeringstid. Når
en ISR implementeres skal den udløses af noget, så det vælges at lave en ny clock og koble på
den. Når kontrollerens ISR udløses eksekveres en funktion som navngives HandleControl.
Kodeeksempel 5.1: ISR til PD-kontrolleren, handleControl
1 void handleControl()
2 const float Kp = 23.28; // Kontrollerens
3 const float Kd = 1.063896; // konstanter
4
5 setpointM = setpoint * 1E-3; // Omregner setpunktet fra [mm] til [m]
6
7 int32 encoderData = XEncoder_GetCounter(); // Aflaeser encoderen paa motoren
8 float absoluteM = encoderData * 189.39E-6; // Omregner antal encoder-pulser til bevaegelse i [m]
23
9
10 float errorM = setpointM - absoluteM; // Udregner fejlen
11 double voltageOutput = (errorM * Kp) + (Kd *(errorM - lastError)); // Selve PD-kontrol.
12
13 // Her begraenses spaendingen
14 if(voltageOutput > 12.0)
15 voltageOutput = 12.0;
16 else if(voltageOutput < -12.0)
17 voltageOutput = -12.0;
18
19 setMotorVoltage(voltageOutput); // Saetter motor-spaending
20 lastError = errorM; // Omdaterer sidste fejl
21
I kodeeksempel 5.1 ses implementeringen af PD-kontrolleren i en ISR. Det bemærkes at
dierentiationen til D-kontrollen approksimeres som "Ny fejl" - "Gammel fejl". Det bemærkes
ligeledes at de to variable "setpoint" og "lastError" er to globale variabler.
5.2.7 Test af PD-kontroller
I afsnit 5.2.3 blev fundet at modellen for systemet ikke stemmer helt overens med det virkelige
system, hvilket resulterer i nulpunktets placering ikke er helt præcist. Derfor anvendes de
udregnede konstanter som et startpunkt, hvorfra systemet 'hånd-tunes'. Resultatet af denne
håndtuning ses på guren herunder.
0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
Sekunder
0
0.02
0.04
0.06
0.08
0.1
0.12
0.14
0.16
0.18
Positio
n [m
]
Step i position
Setpunkt
Målt position
Figur 5.23: Målt steprespons med PD-kontrol.
Som det kan ses på gur 5.23 passer denne kontroller væsentligt bedre til systemet. Umiddelbart
ligner det systemet ikke har oversving og har en steady-state error på 0, derfor laves et nyt plot
hvor der er zoomet ind på Y-aksen omkring setpunktet.
0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
Sekunder
0.164
0.166
0.168
0.17
0.172
0.174
0.176
Positio
n [m
]
Step i position
Setpunkt
Målt position
X 1.05
Y 0.1697
Figur 5.24: Målt steprespons med PD-kontrol zoomet ind omkring setpunktet.
På gur 5.24 kan det ses at der er en uvæsentlig smule oversving og systemet går i stå igen,
24
hvilket resulterer i en steady-state error. Positionen den går i stå ved, er aæst til 0.1697 m,
svarende til en fejl på 0.0003 m, eller 0.3 mm. Denne kontroller vurderes tilstrækkelig.
Kontrollerens konstanter efter håndtuningen blev fundet til Kp = 23.28 ·6 = 139.68 og Kd = 100
hvilket resulterer i en Td = KdKp
= 0.716. Med den nye Td værdi kan det med ligning (5.2.14)
beregnes at nulpunktet er yttet ind i -1.4.
-20
0
20
40
60
80
Magnitude (
dB
)
10-2 10-1 100 101 102 103-90
0
Phase (
deg)
Bodeplot af D*G*H
Frequency (rad/s)
Figur 5.25: Bodeplot af den håndtunede kontroller
På gur 5.25 ses bodeplottet med den håndtunede kontroller. Det ses at da nulpunktet er yttet
giver det en "pukkel" i fasen samt et lille stykke omkring 5 rad/s hvor amplituden udligner sig.
Det kan også ses at det større proportional gain har givet kontrollerenen større båndbredde, da
amplitude-plottet først skærer 0 dB ved ≈540 rad/s.
25
Design af G-kode interface 6Målet med dette kapitel er at muliggøre kommunikation mellem printer og computer-programmet
der styrer printeren. Dette opnås ved først at planlægge hvordan kommunikationssystemet skal
virke og derefter implementere det.
Printeren får kommandoerne fra en PC via UART, hvilket er en seriel interface. Denne forbindelse
muliggør kommunikation svarende til det fysiske lag (lag 1) i OSI-modellen. Når en kommando
sendes fra PCen til PSoC'en, modtages den byte for byte i PSoC'ens RX-buer. Denne buer
er 4 bytes, hvilket er væsentligt mindre end de 96 bytes der skal kunne ligge i bueren. Det er
derfor nødvendigt at ytte hver modtaget byte ud af RX-bueren og over i en anden buer for
at kunne efterkomme krav 4.
Modtag data Buffer med kommandoerPC
UART
Fortolk data
PSoC
Figur 6.1: Simpel model af kommunikationen mellem system og PC
På gur 6.1 ses en simpel gur der illustrerer kommunikationen mellem system og PC. Da det
ikke er muligt udelukkende at bruge PSoC'ens RX-buer, skal der implementeres et system der
kan ytte modtagen data væk fra RX-bueren og over i en større buer. Der skal ligeledes
implementeres et system der kan fortolke hver modtagen kommando. Først bestemmes indholdet
af boksen "modtag data".
For at ytte hver modtagen byte ud af RX-bueren, kan en Interrupt Service Routine (ISR)
tages i brug. Med denne ISR er det muligt at få processoren til at pause hvad end den laver
og eksekvere noget kode når en Interrupt triggeres. Opgaven at ytte 1 byte fra ét sted til et
andet, er en ret triviel opgave så det vil være at foretrække hvis det ikke er nødvendigt at bruge
processoren.
En anden måde at ytte hver byte er med Direct Memory Access (DMA). Dette er et stykke
hardware som kan implementeres i PSoC'en og kan ytte data fra et sted til et andet helt uden
at gøre brug af processoren. Det vælges derfor at tage DMA i brug.
Da hver kommando afsluttes med et Line Feed skal der for hver byte tjekkes om det er et
Line Feed. Dette er ligeledes en triviel opgave og kan implementeres i hardware. Med PSoCen
er det muligt at implementere et kontrol-register som kan forbindes til en digital compare, hvor
indholdet af kontrol-registret kan sammenlignes med en konstant. Hver modtagen byte skal derfor
yttes fra RX-bueren over i kontrol-registret og derefter fra kontrol-registret til en buer.
26
DMA_1UART indbyggetbuffer (RX-buffer) Kontrolregister DMA_2 Ufortolket kommando
Modtag Data
Figur 6.2: Indholdet af boksen "Modtag Data" fra gur 6.1.
På gur 6.2 ses et skitseret indhold af boksen "Modtag data" fra gur 6.1. Her er illustreret at
DMA_1 ytter hver byte fra RX-buer til et kontrol register. Hvis den modtagne byte ikke er
et Line Feed, yttes den af DMA_2 til en buer for ufortolkede kommandoer.
Fra krav 4 er det nødvendigt at kunne gemme 96 bytes pr. kommando, og fra krav 5 er
det nødvendigt at gemme 4 kommandoer i bueren. Det vælges derfor at lave ét array med
datatypen char på 96 bytes, hvor der gemmes én kommando. Det bliver her en DMA ytter
den indkommende byte hen og den kaldes "rxBuerForDMA". Formålet med denne buer er, at
samle en hel kommando så den kan fortolkes.
6.1 Opsætning af DMA
Der er nu styr på hvordan hver byte skal yttes fra RX-bueren og over i arrayet
"rxBuerForDMA", så det er derfor oplagt at implementere de 2 DMA der skal udføre opgaven.
En DMA består af en kanal og en "Transaction Descripitor" (forkortet TD). Kanalen er
den hardware rute som dataene skal yttes gennem og Transaction Descripitoren er den som
indeholder al styringen af DMA'en.
Den første DMA som skal implementeres er den som ytter data fra RX-bueren og over i kontrol
registret, svarende til DMA_1 fra gur 6.2. Denne navngives "DMA_RX_TO_CTRL_REGISTER"og
processen kan skitseres som:
Control_Reg_11 byteRX Buffer 1 byteDMA_RX_TO_CTRL_REGISTER
Figur 6.3: Processen hvor en DMA (boksen i midten) ytter 1 byte fra RX bueren til kontrolregistret. Figuren svarer til RX-buer, DMA_1 og Kontrolregister fra gur 6.2.
Selve opsætningen af en DMA kan ikke implementeres i hardware så der skal derfor eksekveres
noget kode før DMA'en kører. Først skal kanalen sættes op, hvilket gøres således:
Kodeeksempel 6.1: Opsætning af kanal til DMA
1 uint8 rxToCtrlChannel = DMA_RX_TO_CTRL_REGISTER_DmaInitialize(DMA_RX_TO_CTRL_REGISTER_BYTES_PER_BURST,
DMA_RX_TO_CTRL_REGISTER_REQUEST_PER_BURST,
HI16(DMA_RX_TO_CTRL_REGISTER_SRC_BASE),
HI16(DMA_RX_TO_CTRL_REGISTER_DST_BASE));
Som det ses i kodeeksempel 6.1 initialiseres DMA kanalen med et funktionskald som indeholder 4
parametre. Den første, DMA_RX_TO_CTRL_REGISTER_BYTES_PER_BURST, bestem-
mer hvor mange bytes der skal yttes når DMA'en kører. Den anden,
27
DMA_RX_TO_CTRL_REGISTER_REQUEST_PER_BURST, bestemmer hvor mange
hardware requests der skal til for at få DMA'en til at køre. Da formålet med denne DMA er at
ytte én byte hver gang der modtages en byte, skal både første og anden parameter være 1.
De sidste to parametre er de højeste 16 bit af adressetypen på hhv. hvor byten yttes fra og hvor
byten yttes til. Disse er konstanter som er slået op i databladet på de enkelte moduler.
Det næste der skal sættes op er Transaction Descripitoren, hvilket gøres med:
Kodeeksempel 6.2: Opsætning af Transation Descripitoren til DMA
1 uint8 rxToCtrlTD = CyDmaTdAllocate();
2
3 CyDmaTdSetConfiguration(rxToCtrlTD, 1u, rxToCtrlTD , (DMA_RX_TO_CTRL_REGISTER__TD_TERMOUT_EN));
4
5 CyDmaTdSetAddress(rxToCtrlTD, LO16((uint32)UART_RXDATA_PTR), LO16((uint32)Control_Reg_1_Control_PTR));
6
7 CyDmaChSetInitialTd(rxToCtrlChannel, rxToCtrlTD);
8
9 CyDmaChEnable(rxToCtrlChannel, STORE_TD_CFG_ONCMPLT);
I kodeeksempel 6.2 ses opsætningen af TD'en. Først allokeres pladsen og på linje 3 sættes
kongurationen. Som det ses kræves 4 parametre til kongurationen, disse er:
Den TD der skal kongureres
Hvor mange transfers der skal udføres
Hvilken TD der skal bruges når transfer er færdig
Ekstra konguration
Da formålet med denne DMA er at ytte 1 byte fra én adresse til en anden, gentagende gange
sættes antallet af transfers til 1 og den næste TD der skal bruges til den samme som den første.
Dette får DMA'en til at genstarte efter hver byte er yttet hvilket er nøjagtig det der ønskes.
Den sidste parameter sættes til DMA_RX_TO_CTRL_REGISTER__TD_TERMOUT_EN
hvilket betyder at DMA'en trigger et interrupt hver gang en transfer er færdig. På denne måde er
det muligt at holde styr på hvornår den er færdig, samt tælle antallet at bytes der er modtaget.
På linje 5 sættes adressen, hvor TD'en skal bruge de laveste 16 bit af adressen. I PSoC-miljøet
er deneret nogle pointere til hvert register, så disse bruges.
På linje 7 linkes den TD der lige er blevet kongureret og kanalen fra tidligere sammen hvilket
konkluderer opsætningen af denne DMA.
På linje 9 sættes DMA'en i gang, hvor den første parameter beskriver hvilken kanal der skal
startes og den anden parameter bestemmer at TD'en skal gemmes når en transfer er færdig.
Da den første DMA nu er designet, kan den anden designes. Dette er DMA_2 fra gur 6.2. Denne
DMA har til opgave at ytte dataene fra kontrol registret over i et array. Den skal derfor ikke
være nøjagtig ligesom den første da destinationen er et array. Hver ny byte skal derfor sættes
ind efter den forgående byte så destinations-adressen skal derfor øges hver gang 1 byte er blevet
overført. Denne process kan skitseres som:
28
1 byteControl_Reg_11 byte
DMA_CTRL_TO_BUFFERrxBufferForDMA
1 2 3 ... 96
Figur 6.4: Processen hvor en DMA (boksen i midten) ytter 1 byte fra RX bueren i en plads iet array.
Opsætningen af denne DMA kan ses i kodeeksemplet herunder.
Kodeeksempel 6.3: Opsætning af Transation Descripitoren til DMA_CTRL_TO_BUFFER
1 uint8 CtrlToBufferTD = CyDmaTdAllocate();
2
3 CyDmaTdSetConfiguration(CtrlToBufferTD, BUFFER_SIZE, CtrlToBufferTD , (TD_INC_DST_ADR |
DMA_CTRL_TO_BUFFER__TD_TERMOUT_EN));
4
5 CyDmaTdSetAddress(CtrlToBufferTD, LO16((uint32)Control_Reg_1_Control_PTR), LO16((uint32)rxBufferForDMA));
6
7 CyDmaChSetInitialTd(CtrlToBufferChannel, CtrlToBufferTD);
8
9 CyDmaChEnable(CtrlToBufferChannel, 0u);
Som det ses i kodeeksempel 6.3 ligner denne opsætning den fra kodeeksempel 6.2, hvor forskellene
er på linje 3 og 9.
På linje 3 sættes antallet af transfers der skal udføres til BUFFER_SIZE, hvilket er de 96
bytes fra krav 4. Ligeledes sættes den sidste parameter til TD_INC_DST_ADR, hvilket sætter
den bit der øger destinationsadressen med 1 hver gang 1 byte er overført. Derudover sættes
DMA_CTRL_TO_BUFFER__TD_TERMOUT_EN hvilket aktiverer en hardware interrupt
når overførslen af 96 bytes er færdig. Aktiveres denne interrupt er der altså modtaget ere bytes
end der er plads i bueren.
På linje 9 sættes DMA'en i gang, men den indstilles til ikke at gemme den TD den starter med.
Dette skyldes at adressen ikke skal øges for evigt, men genstartes når en kommando er modtaget.
Begge DMA's er nu implementeret og det samlede kredsløb kan tegnes. Se gur 6.5.
29
Figur 6.5: Schematic for den samledede process hvor en byte modtages og yttes over i buerenved brug af 2 DMA, som det er sat på i PSoC Creator.
På gur 6.5 ses det samlede schematic for hele processen. Når en byte er modtaget via
UART går rx_interrupt høj, hvilket får DMA_RX_TO_CTRL_REGISTER til at ytte
den byte fra RX bueren over i Control_Reg_1. Her sker en digital compare med et
ASCII line feed. Når DMA_RX_TO_CTRL_REGISTER gør dens "nrq"ben høj, hvilket får
DMA_CTRL_TO_BUFFER til at ytte byten fra kontrol registret over i en buer.
Det ses ligeledes at der gøres brug af en counter, BuerCounter, til at holde styr på hvor mange
bytes der ligger i bueren. Counteren er opsat således at den ayrer et interrupt hvis den tæller
over 96 bytes hvilket tvinger DMA_CTRL_TO_BUFFER til at genstarte. Dette er gjort for at
sikre der ikke modtages en kommando længere end buerens længde.
Nu er begge DMA's implementeret og dermed samles en hel kommando ét sted. Da kommandoen
ligger som en string, skal den fortolkes.
30
6.2 Fortolkning af modtaget kommando
Når en kommando er modtaget er den gemt som en string. I dette afsnit implementeres en række
funktioner der har til opgave at fortolke den string og producere en kommando der kan forstås
af systemet. En modtagen kommando kan se således ud:
N1 G1 X50.0 y24.5 ∗ 46 (6.2.1)
Denne kommando består af et linjenummer (N1), en kommando (G1) samt 2 koordinater (X50.0
og y24.5) samt en checksum (*46). Linjenummer og checksum er en header som tilføjes af det
computer-program der håndterer kommunikationen mellem printer og PC. For at kunne behandle
kommandoen yderligere, skal den fortolkes.
6.2.1 Fortolkning med strtok
En måde at fortolke kommandoen på er ved at dele kommandoen op i mindre bider. Eksemplet
6.2.1 kan denne opdeles ved mellemrum, newline og carriage return. Til dette kan bruges en
funktion i C kaldet "strtok" fra C biblioteket "string.h".
Strtok funktion tager to pointere til to strings som parametre, hvor den første er den string der
skal søges i, og den anden er hvad der søges efter. Funktionen returnerer en pointer til den første
forekomst, så når den bruges på eksemplet vil den første gang returnerer en pointer til "N1".
Kan funktionen ikke nde endnu en forekomst returnerer den en Null-pointer. Hvis strtok skal
bruges på samme string ere gange, behøver man ikke give den samme string ere gange, men
NULL i stedet. På denne måde kan processen automatiseres med et while-loop:
Kodeeksempel 6.4: Opdeling af string med strtok
1 char * pointerToToken;
2 char tokenArray[10][20];
3 int where = 0;
4 pointerToToken = strtok(localArray, " \n\r");
5 strcpy(tokenArray[where], pointerToToken);
6
7 // Fylder token-arrayet. Dette deler string'en op i smaa bidder
8 while(pointerToToken != NULL)
9 pointerToToken = strtok(NULL, " \n\r"); // Finder naeste bid
10 if(pointerToToken != NULL) // Hvis en bid blev fundet
11 where++; // Laegges en til indexet
12 strcpy(tokenArray[where], pointerToToken); //... og bidden kopieres over i arrayet
13
14
Når kodeeksempel 6.4 er eksekveret på kommandoen fra 6.2.1 indeholder tokenArray:
Kodeeksempel 6.5: Print af indholdet af tokenArray
1 tokenArray[0]: N1
2 tokenArray[1]: G1
3 tokenArray[2]: X50.0
4 tokenArray[3]: y24.5
5 tokenArray[4]: *46
Fra kodeeksempel 6.5 ses at den første plads i tokenArray indeholder linjenummeret og den sidste
indeholder checksummen. Det er derfor muligt at tjekke om den modtagne data er korrekt.
31
6.2.2 Tjek af modtagen data
Linjenummeret angivet efter "N" øges med 1 for hver ny kommando der sendes. Checksummen
angives efter "*" og udregnes ved at XOR hver karakter i den modtagne string fra start til
*-symbolet. Denne process producerer et 1-byte tal som er specik for den kommando.
Checksummen udregnes således:
Kodeeksempel 6.6: Udregning af checksum
1 int checksum = 0;
2 for(i = 0; cmd[i] != '*' && cmd[i] != NULL; i++) // Cmd er modtagen string
3 checksum = checksum ^ cmd[i];
Når checksummen udregnes og sammenlignes med den modtagne checksum er det muligt at
tjekke integriteten af den modtagne data. Denne funktionalitet svarer til Data Link laget fra
OSI modellen. Hvor Data Link laget også har til opgave at håndtere adressering i et netværk, er
der i denne implementering kun tale om 2 enheder, så adresseringen bliver overødig. Stemmer
den udregnede checksum ikke overens med den modtagne skal linjen sendes igen.
Kodeeksempel 6.7: Fortolkning af linjenummer
1 const char tokensToCheckFor[] = "nNgGmMxXyYzZeEfFsSaA*";
2 uint8 whereToStartParsing = 0;
3
4 if(tokenArray[0][0] == 'N' || tokenArray[0][0] == 'n')
5 currentLineNumber = atoi(strtok(tokenArray[0], tokensToCheckFor));
6
7 if(currentLineNumer == lastLineNumber + 1)
8 // Kommandoen er OK
9 else
10 // Linjenummeret er ikke OK
11 resendLastLine();
12
13
14 whereToStartParsing = 1; // Opdater hvor vi skal parse fra
15
16 if(tokenArray[where + 1][0] == '*')
17 // Modtaget checksum
18 int cs_modtaget = atof(strtok(tokenArray[where+1], tokensToCheckFor));
19
20 // Udregner den modtagne checksum
21 int cs = 0;
22 for(int i = 0; rxBufferWithCommands[rxRingBuffer.head][i] != '*'; i++)
23 cs = cs ^ rxBufferWithCommands[rxRingBuffer.head][i];
24
25 cs &= 0xff; // For en sikkerheds skyld begraenses stoerrelsen
26
27 if(cs == cs_modtaget)
28 //printf("CS er ens\n");
29 else
30 //printf("CS er IKKE ens\n");
31
32
33
I kodeeksempel 6.7 fortolkes linjenummeret og checksummen beregnes. På linje 4 foretages et
tjek for om der er modtaget et linjenummer. Hvis ikke der er modtaget et linjenummer er der
heller ikke modtaget en checksum og i så fald er dette stykke kode overødigt.
32
I eksempel 6.2.1 er der sendt et linjenummer og checksum med, så den skal igennem denne
funktion. På linje 5 fortolkes linjenummeret fra en string ("N1") med strtok, hvilket returnerer
en pointer til en string indeholdende ("1"), hvilken fortolkes til en integer med atoi(). Herefter
kan tjekkes om linjenummeret er som forventet, hvorefter der forsættes til udregningen af
checksummen som i eksempel 6.6.
6.2.3 Fortolkning af kommando
I de forgående afsnit er integriteten af hver modtagen kommando blevet tjekket, så den er nu
klar til at blive fortolket. Figur 6.1 genopfriskes:
Modtag data Buffer med kommandoerPC
UART
Fortolk data
PSoC
Figur 6.6: Gentagelse af gur 6.1. Simpel model af kommunikationen mellem system og PC
Fra gur 6.6 huskes at boksen "Modtag data" er udfyldt, så tilbage er "Fortolk data" og "Buer
med kommandoer", hvilket er målet for dette afsnit. Disse designes bagfra, så først bestemmes
hvordan "Buer med kommandoer" skal være og efterfølgende designes en fortolkningsalgoritme
som passer.
Buer med kommandoer skal, fra krav 5, kunne indeholde 4 kommandoer. Hver kommando kan
bestå af en masse forskellige bogstaver og tal, så en struct kan med fordel bruges til at samle
dem. På denne måde kan der laves et array med 4 structs og en ring-buer til at styre hvilken
plads i arrayet der skal gemmes til.
Kommandoerne kan have varierende struktur, så både
N1 G1 X50.0 y24.5 ∗ 46 (6.2.2)
og
N2 G28 X y1 Z0 ∗ 52 (6.2.3)
er gyldige kommandoer. Kom det kan ses fra eksempel 6.2.3 har X ikke noget tal med, men den
er stadig tilstede. I dette eksempel er det en Home akser kommando, hvor
X: Home X til default
y1: Home Y til MAX position
Z0: Home Z til MIN position
Det er derfor nødvendigt at vide 3 ting om hvert bogstav, nemlig om det var med i kommandoen,
havde det en koordinat og hvad var den koordinat. Det er nu muligt at opstille strukturen for
den struct der skal opbevare de fortolkede kommandoer.
33
Kodeeksempel 6.8: Struct til opbevaring af fortolket kommando
1 struct parsedCommand
2
3 //Kommando
4 char type; // Hvilken type. Gemmer G og M.
5 uint16 commandNumber; // Gemmer kommando-nummeret saa G28 vil vaere
6 // type = G, commandNumber = 28.
7
8 // Koordinater
9 double xCord;
10 _Bool xPresent;
11 _Bool xHadCord;
12
I kodeeksempel 6.8 ses en forkortet udgave af den struct der bruges til at opbevare den fortolkede
kommando. Det er kun kommandoen samt X-aksens variable der er med. De undladte er Y, Z,
E, F, A og S, men de er identiske med X. For at initialisere structen kaldes:
Kodeeksempel 6.9: Initialisering af ring-bueren samt structen til opbevaring af fortolket
kommando.
1 struct newRingBuffer parsedCommandsRingBuffer;
2 struct parsedCommand parsedCommandBuffer[PARSED_COMMANDS_IN_BUFFER];
Nu er det bestemt hvorledes "Buer med kommandoer" skal være, så det er muligt at designe en
fortolkningsalgoritme. Kommandoen er allerede delt op i bidder, fra eksempel 6.5. Det er derfor
muligt at tjekke værdien af første plads i hver string og matche den med et bogstav.
Kodeeksempel 6.10: Fortolkning af kommando: Eksempel med G og X
1 for(int i = whereToStartParsing; i <= (where); i++)
2 switch(tokenArray[i][0])
3 case 'G':
4 parsedCommandBuffer[parsedCommandsRingBuffer.tail].type = 'G'; // Set type to G
5 parsedCommandBuffer[parsedCommandsRingBuffer.tail].commandNumber =
atoi(strtok(tokenArray[i], tokensToCheckFor));
6 break;
7
8 case 'X':
9 parsedCommandBuffer[parsedCommandsRingBuffer.tail].xPresent = 1u; // X fundet
10 uint sizeOfToken = strlen(tokenArray[i]);
11 double cord = atof(strtok(tokenArray[i], tokensToCheckFor));
12 // atof returnerer 0 hvis den fejler, saa tjek om cord = 0 er en korrekt vaerdi
13 if(sizeOfToken <= 1)
14 parsedCommandBuffer[parsedCommandsRingBuffer.tail].xHadCord = 0u;
15 else if(cord == 0 && sizeOfToken > 2)
16 // Vi forventede en vaerdi over 1 byte, saa cord = 0 er forkert
17 printf("Error in X Cord\n");
18 else
19 parsedCommandBuffer[parsedCommandsRingBuffer.tail].xHadCord = 1u;
20 parsedCommandBuffer[parsedCommandsRingBuffer.tail].xCord = cord;
21
22 break;
23
24 // Nu er alt fortolket, saa laeg en til tail i bufferen
25 addOneToTail(&parsedCommandsRingBuffer);
I eksempel 6.10 kan ses at fortolkningen af G foregår på samme måde, med atoi(), som
linjenummeret fra eksempel 6.7.
34
Fortolkningen af X er væsentligt mere omfattende, da der bruges atof() til at omdanne talværdien
fra en string til en double. Denne funktion returnerer 0 hvis den fejler, men 0 kan også være en
korrekt værdi. Det er derfor svært at skældne mellem en forkert og en korrekt værdi. En string
indeholdende tallet 0 fylder 1 byte, så det er muligt at tjekke om længden af den modtagne string
stemmer overens med en talværdi på 0. Dette gøres ved at bestemme længden af stringen (linje
10) samt hvad talværdien er (linje 11).
Hvis længden af stringen er 1, var der intet tal med så den indeholder altså kun "X". Er den til
gengæld større end 2 bytes og talværdien er 0 bestemmes at der er fejl i koordinaten. Dette kan
give et falsk positiv hvis den modtagne string er: "X00", da atof() vil give 0 og strlen() giver 3.
Risikoen for falsk positiv anses for ubetydelig, da G-koden er genereret af en computer og det
antages at overførslen er optimeret således der ikke sendes mere data end nødvendigt.
Fortolkningen fra eksempel 6.10 gentages for de resterende bogstaver, altså Y, Z, E, F, A og S.
Kommandoerne kan nu fortolkes og gemmes i en buer, så næste skridt er at kunne eksekvere
en passende rutine for hver kommando.
6.3 Eksekvering af G-kode kommando
For at kunne eksekvere en passende rutine for hver kommando, laves funktionen ExecuteNe-
xtCommand(). Denne får til opgave at tage én kommando fra bueren, eksekvere en funktion
svarende til kommandoen og opdatere bueren.
Kodeeksempel 6.11: Funktionen ExecuteNextCommand
1 void executeNextCommand(struct parsedCommand *command, struct newRingBuffer *buffer)
2 if(!isBufferEmpty(buffer))
3 switch(command[buffer->head].type)
4 case 'G':
5 switch(command[buffer->head].commandNumber)
6 case 1:
7 executeG1(command, buffer);
8 break;
9
10 case 'M':
11 switch(command[buffer->head].commandNumber)
12 case 105:
13 executeM105();
14 break;
15
16 popRingBuffer(command, buffer);
17
18
Som det kan ses i kodeeksempel 6.11 gøres der brug af i alt 3 switch-case til at eksekvere de
korrekte kommandoer. Den første switch (linje 5) bruger "type" fra den fortolkede kommando
(kodeeksempel 6.8) og skifter mellem "G" og "M". Herefter switches på kommando nummeret
(linje 8 & 15) hvor der opstilles en case for hver kommando nummer hvorfra den tilhørende
funktion kaldes. Når funktionen G1 kaldes (linje 10) får den to argumenter med som call-by-
reference, det er altså adressen til hvor den fortolkede kommando ligger. På denne måde er det
muligt at skrive funktioner som fungerer uanset hvilken plads i bueren der kaldes fra. Dette gør
koden robust og nem at skalere hvis en større buer ønskes. Strukturen med switch-case gør det
nemt og overskueligt at tilføje ere funktioner.
35
Når den korrekte funktion er eksekveret afslutter ExecuteNextCommand med at poppe bueren,
hvilket ændrer hvilken plads i bueren der læses fra næste gang.
Alle dele af systemets software er nu designet så det kan nu samles.
6.4 Sammensætning af software
Gennem dette kapitel er der designet en række del-elementer som tilsammen udgør hele softwaren.
Disse elementer skal samles og eksekveres på en fornuftig måde, hvilket er målet med dette afsnit.
For at gøre dette følges en kommando fra en PC til den er eksekveret af dette system, hvilket
illustreres med en genopfriskning af gur 6.1 fra tidligere
Modtag data Buffer med kommandoerPC
UART
Fortolk data
PSoC
Figur 6.7: Gentagelse af gur 6.1. Simpel model af kommunikationen mellem system og PC
I afsnit 6.1 blev designet et delsystem som har til opgave at modtage dataen fra PC'en og gemme
dem ufortolket i en buer. Dette delsystem svarer til "Modtag data" fra gur 6.7. Delsystemet
er designet således at det hovedsageligt ligger i hardware og den smule overhead der er er
implementeret som interrupt, hvilket gør at så længe der er tilstrækkelig processorkraft kører
dette delsystem af sig selv.
PD-kontrollen er også implementeret som en interrupt, men udløses periodisk af en clock. Denne
ISR sættes som højest prioritet, således bevægelsen ikke forstyrres.
I afsnit 6.2 er designet delsystemet kaldet "Fortolk data" fra gur 6.7. Dette system er designet
som en software løsning og skal derfor eksekveres af PSoC'ens processor. Alt efter længden af
den modtagne kommando vil fortolkningen variere i eksekveringstid, hvilket er underordnet så
længe bueren med fortolkede kommandoer ikke løber tør.
Af de beskrevne delsystemer er det kun fortolkningen af kommandoerne samt eksekveringen af
kommandoerne er ikke har en interrupt. Det er derfor muligt at forkorte main-løkken til
Kodeeksempel 6.12: Løkken i main.c
1 for(;;)
2 // Checker om der er en ufortolket kommando
3 if(!isBufferEmpty(&rxRingBuffer))
4 // Der er en kommando tilgaengelig!
5 parseCommand();
6 else
7 // Der er ingen nye kommandoer...
8
9
10 // Checker om der er en fortolket kommando
11 if(!isBufferEmpty(&parsedCommandsRingBuffer))
12 // Der er en kommando i bufferen
13 executeNextCommand(parsedCommandBuffer, &parsedCommandsRingBuffer);
36
14 sendOK();
15 else
16 // Bufferen er tom...
17
18
I kodeeksempel 6.12 ses den uendelige løkke som kører så længe systemet er tændt hvor der først
tjekkes om der er en ufortolket kommando eller om der er en fortolket kommando. Er en af de
to til stede skal der enten fortolkes eller eksekveres.
37
Diskussion 7På baggrund af de opstillede krav og de enkelte tests kan det ses, at systemet fungerer men ikke
opfylder krav 2, at begge akser skal kunne følges ad. Systemet kan modtage kommandoer fra
en PC, fortolke dem og lagre dem i en buer til senere eksekvering. Der hvor det er muligt, er
det samlede systems delsystemer implementeret i kongurerbar hardware og der er gjort brug af
interrupts hvilket vurderes til at være et godt valg.
Der er dog plads til forbedringer og udvidelser af de implementerede funktionaliteter. Diverse
overvejelser i denne forbindelse vil blive diskuteret i dette kapitel.
Lagring af data før fortolkning
Den valgte hardware platform har en række muligheder for at implementere systemer i
kongurerbar hardware, herunder et antal DMA. Disse er taget i brug for at håndtere owet
af data til PSoC'en på en sådan måde at der ikke spildes processortid. På denne måde kan
processoren arbejde på en hel kommando, i stedet for først at skulle samle en kommando.
Selvom en DMA på papiret virker oplagt at bruge til opgaven, har denne en smule overhead hver
gang den skal startes og stoppes. I dette systems skal den ene DMA resettes for hver kommando,
hvilket involverer den omtalte overhead. Hver gang DMA'en resettes gøres dette med en interrupt,
men er ude af drift i den periode den resettes. Dette kan udgøre en potentiel risiko for at der
sendes data fra PC'en før DMA'en er klar til at modtage den. Risikoen for det sker vurderes
ubetydelig, da det ville kræve at der kommunikeres mere mellem systemerne. Skulle der ske en
fejl vil denne blive fanget i det tjek af kommandoens intigritet som foretages lige før kommandoen
fortolkes.
Et alternativ til DMA'en er at bruge en simpel interrupt som udløses hver gang der er modtaget
en byte og bare ytter den nye byte over i en buer. Denne metode er simpel, men kræver
processortid ved hver eksekvering. I dette projekt vil processortiden brugt ved denne metode
sandsynligvis være ubetydelig, men det er ikke umuligt at forestille sig et scenarie hvor al
processortid er værdifuld hvis ere funktionaliteter skulle tilføjes.
Eksekvering af G-Kode
Når en kommando er fortolket af G-koden skal der udføres en handling. Strukturen der er
valgt i ExecuteNextCommand() er ikke valgt på baggrund af eksekveringstid, men for dens
overskuelighed. Da der eksisterer ca 100 G-kommandoer og ca 900 M-kommandoer[6] der hver
skal have en funktion, er overskuelighed at foretrække. ExecuteNextCommand() kaldes på en
sådan måde, at den ikke er tidskritisk så det er acceptabelt at ofre en smule eksekveringstid til
fordel for overskueligheden.
38
Valg af regulator
For ikke at vælge en unødvendigt kompliceret kontroller blev der først opstillet et free-body-
diagram og derefter designet en proportional kontroller, ud fra bodeplot. Det viste sig, at denne
metode gav en risetime på lige over 50 sekunder, hvilket var uacceptabelt. Herefter blev brugt en
anden metode til at bestemme det proportionale gain, Kp, hvilket gav en væsentligt bedre risetime
i simuleringen. For at teste kontrolleren yderligere, blev en mere avanceret model op i Simulink,
hvor der tages højde for maksimal spænding til motoren, hvilket ændrede stepresponsen en smule
med den var stadig acceptabel. Grundet usikkerheder i udmålingen af friktion i det mekaniske
system, var den designede P-kontrol utilstrækkelig.
Som løsning blev designet en PD-kontrol, således friktionen kunne overkommes. Efter håndtuning
af de to gains gav PD-regulatoren et fornuftigt resultat med en steady-state error på 0.3 mm.
Det mekaniske system er ikke særlig stift, hvilket ikke er medtaget i free-body diagrammet så
kontrolleren har ingen måde at tage højde for det. Derfor anses nøjagtigheden på 0.3 mm som
grænsen for dette system. Dysestørrelsen på en almindelig 3D printer er 0.4 mm, så usikkerheden
i bevægelserne svarer til hver linje kan ligge helt forkert. En usikkerhed på 0.05 mm kunne
accepteres, men ikke 0.3 mm.
Kontrolleren er designet efter først at kunne regulere hver akse for dernæst at få akserne til
at køre synkront og grundets projektets omfang, er dette ikke implementeret. En metode til at
synkronisere de to akser er ved at anvende en state-space model som kan tage 2 inputs og give
2 outputs. Denne type regulering er dog uden for studiets omfang.
39
Konklusion 8Igennem projektet blev arbejdet ud fra følgende problemformulering:
Hvordan implementeres styringen af en hobby 3D printer, med DC motorer på X-
og Y-aksen hvor de resterende funktionaliteter bibeholdes?
Projektets formål var at udvikle en alternativ styring af en 3D printer hvor der gøres brug af
normale DC-motorer med encodere i stedet for stepper-motorer som almindeligvis bruges på 3D
printere til hobby brug. Fra universitets side blev udleveret et mekanisk system, en XY-glider,
som er brugt gennem udviklingen. Dette har sat nogle grænser for præcisionen af systemets
bevægelser. Det vurderes at resultatet af den håndtunede kontroller er så godt som det kan gøres
på dette mekaniske system, men det er stadig utilstrækkeligt til en reel printer. Krav 1 er derfor
delvist opfyldt.
Krav 2 er at X- og Y- aksen skal kunne følges ad, hvilket de ikke er designet til. Derfor er krav
2 ikke opfyldt.
Softwaren er udviklet til, at der nemt kan understøttes ere G-koder. Da nogle af
funktionaliteterne af G-koderne fra tabel 2.1 er ubetydelige for udviklingen af systemet er disse
ikke implementeret, herunder G90 - Absolut positionering og G91 - Relativ positionering. Krav
3 anses derfor som delvist opfyldt.
Buerene er designet således, en ufortolket kommando på maksimalt 96 byte og 4 fortolkede
kommandoer i bueren. De 4 fortolkede kommandoer ligger i en ring-buer hvis størrelse nemt
kan ændres hvis en større eller mindre buer ønskes. Krav 4 og 5 er derfor opfyldt.
De 5 krav opsummeres
Nummer Krav Opfyldt
1 Systemet skal være så præcist som det er muligt med de anvendte motorer Devis
2 X- og Y- aksen skal kunne følges ad 7
3 Systemet skal understøtte de 10 mest anvendte G-koder fra tabel 2.1 Delvis
4 RX bueren skal kunne modtage 96 bytes pr kommando 3
5 RX bueren skal kunne gemme 4 kommandoer 3
Tabel 8.1: Tabel over kravene og deres status.
På baggrund af overstående vurderes projektets resultat til at være en vellykket demonstration
af, hvordan styringen til en 3D printer kan realiseres med DC-motorer.
I forhold til kommercielle styringer er det færdige produkt ikke i stand til at konkurrere, men
de basale funktioner er på plads. Dette projekt kan eventuelt bruges som grundlaget til en mere
"komplet" styring.
40
Bibliografi
[1] Simplify 3D. The 10 Most Common G-Code Commands for 3D Printing.
[2] Dibya Chakravorty. STL File Format (3D Printing) Simply Explained.
[3] Marti Deans. G-Code: The CNC Programming Language.
[4] Formlabs. Form 2.
[5] 3D Insider. The 9 Dierent Types of 3D Printers.
[6] Marlin. G-Code.
[7] Marlin. G0, G1 - Linear Move.
[8] Marlin. G28 - Auto Home.
[9] Prusa Research. Original Prusa i3 MK3S kit.
[10] Serial Command Buer.
[11] STL (File format).
41
Udmåling af DC motor AI dette appendiks gennemgås målerapporten for DC motorene til X og Y aksen, hvor de enkelte
konstanter måles.
Der tages udgangspunkt i den model for en DC motor der blev givet i kurset "Modeling and
Control".
Figur A.1: Modellen for en DC motor
Udstyret der anvendes til målingerne er følgende:
Udstyr AAU Nummer
Oscilloscop 105617
Strømforsyning 60773
Amperemeter 78551
Multimeter 60763
Torquemeter 105645
Tachometer 08246
Tabel A.1: Tabel over anvendt udstyr
42
Motorens indre modstand, Ra
Ra kan måles ved at fastholde motorens akse og påtrykke en spænding (Ua) mens strømmen (Ia)
måles. Da både spolen La og generatoren Ke vil virke som en kortslutning, er det udelukkende
modstanden Ra der bestemmer strømmen. Herefter anvendes Ohms lov;
U = R ∗ I ⇔ R =U
I(A.0.1)
Ua [V] Ia [A] Udregnet Ra [Ω]
-3.01 -1.26 2.388888889-2.52 -1.11 2.27027027-2.04 -0.935 2.181818182-1.5 -0.714 2.100840336-1.32 -0.625 2.112-1.11 -0.535 2.074766355-0.908 -0.448 2.026785714-0.7 -0.346 2.023121387-0.51 -0.256 1.9921875-0.32 -0.166 1.9277108430.32 0.118 2.7118644070.53 0.209 2.5358851670.71 0.293 2.4232081910.91 0.385 2.3636363641.1 0.46 2.3913043481.31 0.68 1.9264705881.5 0.813 1.845018452.03 1.07 1.8971962622.5 1.306 1.914241963.03 1.54 1.967532468
Middelværdi: 2.153737384
Tabel A.2: Målinger af Ua og Ia til udregning af Ra
Værdien af Ra er bestemt til 2.15 Ω.
43
Motorens induktans, La
Induktansen kan ndes ved at påtrykke et step i spændingen over motoren da der gælder
La = Ra · τ (A.0.2)
Så ved at kende Ra kan La ndes ved at måle tiden fra steppet påtrykkes til strømmen når 63%
af den maksimale strøm.
-0.003 -0.002 -0.001 0 0.001 0.002 0.003 0.004 0.005 0.006 0.007
Tid [s]
-0.5
0
0.5
1
1.5
2
Am
pe
re [
A]
Figur A.2: Måling af induktansen, La
På gur A.2 ses målingen af strømmen, hvor den maksimale strøm er fundet til 1.837 [A] så
I63% = 1.837 · 0.63 = 1.18 [A] (A.0.3)
Denne strøm ndes ved tidspunket 700 µs så
La = Ra · τ = 2.15 · 0.0007 = 0.0015 [H] (A.0.4)
44
Generatorkonstanten Ke
Da generatorkonstanten er proportional med vinkelhastigheden ω og der gælder at
Ke =Ua −RaIa
ω(A.0.5)
kan Ke ndes ved at påtrykke en spænding over motoren Ua og måle strømmen Ia samt
omdrejningshastigheden ω. Da det anvendte tachometer måler i omdrejninger/minut og ω er
i rad/s, skal der laves en konvertering.
Ua [V] Ia [A] RPM Udregnet rad/s
2.65 0.235 435 0.2775073513.02 0.287 497 0.316253663.26 0.315 531 0.3413864023.55 0.35 602 0.3717551314.03 0.252 736 0.4220206134.54 0.212 830 0.4754276885.04 0.246 924 0.5277875666.15 0.335 1103 0.64402649412.03 0.33 2302 1.259778654
Tabel A.3: Målinger til bestemmelse af Ke
Gennemsnittet af målingerne giver 0.046[V·srad
].
Motorkonstanten Kt
Motorkonstanten er et udtryk for hvor meget kraft der kan forventes af motoren ved en given
strømstyrke. Der gælder altså at
τm = Kt · Ia (A.0.6)
Kt =τmIa
(A.0.7)
Kraften måles ved at spænde motoren til et torquemeter og fastholde den anden ende af
torquemetret. Herefter sendes en strøm gennem motoren og kraften måles. Torquemetret giver
en spænding ud svarende til 0.2 Nm/V og et oset på 0.038 V er målt.
Kt =(0.583− 0.038) · 0.2
2.16= 0.050
[Nm
A
](A.0.8)
Motorens friktion, B
Når en strøm løber gennem motoren ydes en kraft proportional med strømmen, nemlig Kt. Denne
kraft ville få motoren til at accelerere uendeligt hvis ikke motoren har en friktion, hvilket gør
45
motoren vil have en given hastighed ved en given strømstyrke. Når motoren når steady-state i
hastigheden gælder derfor:
Kt · Ia = B · ω ⇒ B =Kt · Iaω
[Nm
rad/s
](A.0.9)
Det er derfor muligt at bestemme motorens friktion eksperimentelt ved at måle strømmen gennem
motoren samt motorens vinkelhastighed i steady-state. Målingerne fra Ke i tabel A.3 anvendes
til udregningen af B, hvilket giver en middelværdi på 191.17
[µNmrad/s
].
Tidskonstanten τ og gain K
Motorens gain er den hastighed motoren når en given spænding påtrykkes. Denne er målt til
172.2 [rad/s] hvilket giver
K =172.2 [rad/s]
12 [V]= 14.35
[rad
s ·V
](A.0.10)
Tidskonstanten er den tid det tager at nå 63% af den maksimale hastighed, altså 108.48 [rad/s].
Dette giver τ = 32.4 [ms]
0.15 0.2 0.25 0.3 0.35 0.4 0.45
Sekunder
0
50
100
150
200
250
Rad
ian
er
0
50
100
150
200
250
Ra
dia
ne
r/se
c
Tidskonstant og gain
Vinkel
Hastighed
Figur A.3: Måling af tidskonstant og gain, ved et step i spænding over motoren ved tiden 0.12.
46
Udmåling af XY gliderskonstanter B
B.1 Friktion
For at bestemme friktionen for hver akse af XY glideren, er fremgangsmådes ens med målingen
af motorens friktion i appendiks A. Det huskes at friktionen er givet ved:
Btotal =Kt · Iaω
[Nm
rad/s
](B.1.1)
Da motorens friktion blev målt, var motoren ikke mekanisk koblet til noget, så derfor var Btotal
= Bmotor. Når motoren kobles på XY glideren vil den totale friktion være summen af gliderens
friktion og motorens friktion, det gælder derfor at
Btotal = Bakse +Bmotor ⇒ Bakse =Kt · Iaω
−Bmotor
[Nm
rad/s
](B.1.2)
Da Kt og Bmotor allerede er bestemt er det muligt at bestemme Bakse ved at måle motorens strøm
og hastighed i steady state.
XY glideren ikke er uendeligt stor, så motoren kan ikke køres i maksimal hastighed da XY
glideren vil nå den fysiske begrænsning før steady state opnås.
0 0.1 0.2 0.3 0.4 0.5 0.6
Sekunder
0
5
10
15
20
25
30
Ra
dia
ne
r
0
10
20
30
40
50
60
70
80
90
Ra
dia
ne
r/se
cFriktion X akse
Vinkel
Hastighed
Figur B.1: Måling af vinkelhastighed for X aksen.
På gur B.1 ses testen udført på XY gliderens X-akse. Den vandrette sorte streg angiver systemets
steady state hastighed, målt til 57.4 rad/s. Strømmen er målt til 0.369 A. Dette giver
Bx =Kt · Iaω
−Bmotor =0.05 · 0.369
57.4· 106 − 191.17 = 130.26
[µNm
rad/s
](B.1.3)
Samme fremgangsmåde tages i brug for Y-aksen, hvor målingen kan ses på guren herunder.
47
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8
Sekunder
0
5
10
15
20
25
30
Ra
dia
ne
r
0
10
20
30
40
50
60
70
Ra
dia
ne
r/se
c
Friktion Y akse
Vinkel
Hastighed
Figur B.2: Måling af vinkelhastighed for Y aksen. Bemærk gurens x akse har en anden skalasammenlignet med B.1
XY gliderens Y-akse er tungere end X-aksen, hvilket kan ses da Y-aksens hastighed først når
steady state ved 0.3 sekunder, hvorimod X-aksen nåede steady state ved ca 0.1 sekunder. Denne
vægtforskel kan have betydning for lejernes friktion og dermed aksens friktion. Hastigheden er
målt til 43.05 rad/s og strømmen til 0.663 A. Dette giver
By =Kt · Iaω
−Bmotor =0.05 · 0.663
43.05· 106 − 191.17 = 578.86
[µNm
rad/s
](B.1.4)
B.2 Inerti momentet af XY gliderens akser
Aksernes inerti moment kan ndes eksperimentelt ved at køre motoren i en fast hastighed og ved
T=0 slukke strømmen til motoren og måle udløbet. For hastigheder ω(t) > 0 gælder:
ω(t) =−τcB
+ (ω0 +τcB
)e−t·BJ (B.2.1)
hvor inerti momentet J kan isoleres
ln(Bω(t) + τc)− ln(Bω0 + τc) = −t · BJ⇒ (B.2.2)
J =−t ·B
ln(Bω(t) + τc)− ln(Bω0 + τc)(B.2.3)
Med ligning (B.2.3) kan nu tages målinger. Først udføres forsøget på X aksen.
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
Sekunder
-50
0
50
100
150
200
Ra
dia
ne
r/se
c
Udløb X akse
Vinkel
Hastighed
Motor Strøm * 100
Figur B.3: Måling af udløb på X aksen. Her ses steady-state opnåes ca ved T=0.1 og strømmenslukkes ved T=0.2
48
På gur B.3 ses målingerne fra eksperimentet. Da det kun er udløbet der har interesse vælges at
bruge området fra T=0.2 til T=0.32. Da målingerne svinger meget vælges at anvende Matlab's
polyt for at få en blød kurve for udløbet.
0 0.02 0.04 0.06 0.08 0.1 0.12
Sekunder
0
50
100
150
Ra
dia
ne
r/se
c
Data
Polyfit
Figur B.4: Målingerne af udløbet i blå og den ttede kurve i rød.
Fra den ttede kurve vælges 4 hastigheder hvor inerti momentet udregnes fra, dette giver et
gennemsnit på
Jx = 26.03 [µg ·m2] (B.2.4)
Tilsvarende eksperiment udføres på Y aksen. Dette giver følgende målinger:
0 0.2 0.4 0.6 0.8 1 1.2 1.4
Sekunder
-40
-20
0
20
40
60
80
100
120
Ra
dia
ne
r/se
c
Udløb Y akse
Vinkel
Hastighed
Motor Strøm
Figur B.5: Måling af udløb på X aksen. Her ses steady-state opnåes ca ved T=0.5 og strømmenslukkes ved T=0.62
Som for X aksen bruges kun målinger fra udløbet, ca fra T=0.6 til T=0.8.
0 0.05 0.1 0.15 0.2 0.25
Sekunder
-40
-20
0
20
40
60
80
100
Ra
dia
ne
r/se
c
Data
Polyfit
Figur B.6: Målingerne af udløbet i blå og den ttede kurve i rød.
Her vælges også 4 tidspunkter hvorfra inerti momentet udregnes, hvilket giver et gennemsnit på
Jy = 47.77 [µg ·m2] (B.2.5)
49