Inhaltsverzeichnis
Rutscherle 2 - Ein selbstbanancierender Elektroroller
Beim Rutscherle 2 handelt es sich um einen selbstbalancierenden Elektroroller mit großer Ähnlichkeit zum bekannten Segway. Es war und ist beabsichtigt, besser zu sein als das Original. Auch wenn das bisher noch nicht ganz gelungen ist. Dies ist kein kommerzielles Projekt und soll es auch nicht werden. Noch eine Warnung: Das ist kein ungefährliches Projekt. Schon kleine Programmierfehler können sehr schmerzhafte folgen haben.
Und so fährts: Rutscherle2 auf Youtube
Technische Daten
Antrieb
2 BLDC Felgenmotoren mit je 1000W/36V. Vom Hersteller in China direkt importiert. Mittlerweile gibt es auch in Europa vergleichbare Motoren zu kaufen. Die stammen zwar auch aus China, müssen jedoch nicht selbst importiert werden. Die Motoren sind im Lieferzustand nicht direkt verwendbar. Die Sensorik muss um 3 weitere Hallsensoren erweitert werden. Die bisherige Höchstgeschwindigkeit beträgt 27km/h.
Akkus
4 Bleiakkus mit 12V/18AH von denen 3 in Reihe geschaltet sind für die Motoren, einer allein für die Steuerung und eine zukünftige Beleuchtung. Geladen werden die Akkus an einem handelsüblichen Kfz-Ladegerät. Die Reichweite beträgt auf jeden Fall mehr als 20km. Die Entscheidung für Bleiakkus wurde bewusst getroffen. Eine kWh verteuert sich um ca. 50 cent wenn sie durch den Bleiakku geht bei Litium-Polymer-Akkus sind das ca. 5 Euro. Auch sind Bleiakkus beim Laden wesentlich unempfindlicher.
Elektronik
2 Motorregler mit Atmega 168/10Mhz sowie eine Hauptsteuerung mit einem Atmega 644/20Mhz. Zusätzlich noch ein Display von Display3000 als Tacho und Datenlogger. Beschleunigungssensor: ADXL335, Gyros: LISY300AL (ArduIMU Sensor Board - Six Degrees of Freedom) Die ganze Elektronik wurde sehr einfach gehalten. (Zu mehr hats nicht gereicht) Das hat aber den Vorteil, daß keine besonderen Spezialkentnisse erforderlich sind. Wer schonmal eine Platine mit dem Bügeleisen hergestellt hat bekommt auch das hin.
Software
Die Software ist in Bascom geschrieben. Zeitkritische Teile in Assembler.
Mechanik
Der Mechanische Aufbau besteht nahezu komplett aus Aluminium. Dabei wurde darauf geachtet, dass alles mit einfachen Werkzeugen herstellbar ist. (Eine Ständerbohrmaschine sollte man schon haben.) Die Konstruktion ist so ausgelegt, dass so wenige Teile wie möglich hinter den Rädern hervorstehen. Dies verhindert Kratzer bei den ersten Fahrversuchen.
Sicherheitshinweis
Achtung! Bauen Sie sowas nur wenn Sie genau wissen was Sie machen. Es können an der Elektonik sehr hohe Ströme auftreten. Auch an den Motoren können, vor allem im Fehlerfall, sehr hohe Drehmomente entstehen. Beschweren Sie sich also nicht wenn Sie im Krankenhaus aufwachen. Sie haben es so gewollt.
Funktion
Die Funktion ist im groben recht banal. Im Prinzip macht das Teil das gleiche wie jeder Mensch beim gehen. Kommt ein Mensch nach vorn aus dem Gleichgewicht macht er einen Schritt nach vorn. Entsprechend nach hinten. Hier wird das gleiche elektronisch nachbildet. Bewegt sich die Platform nach vorn wird nach vorn beschleunigt. Die genaue technische Umsetzung wird dann doch etwas aufwändiger. Die Regelung selbst erledigt ein PID-Regler. Danach kommen jedoch noch einige zusätzliche Faktoren die z.B. die Motorkennlinie ausgleichen sowie ungewollte Richtungsänderungen bei unebenen Oberflächen reduzieren. Ähnlich aufwendig wird es bei den Motorreglern. Eine reine Blockkommutierung wie bei solchen Motoren üblich ist nur auf glatten Untergründen brauchbar. Darum müssen die Motoren um zusätzliche Hallsensoren erweitert und mit Drehstrom oder genauer Drehspannung angesteuert werden.
Elektronik
Motorregler
Der Motorregler regelt natürlich den Motor. Zusätzlich misst und übermittelt der Motorregler auch Spannung, Strom und Fahrstrecke. Die Temperatur des Kühlkörpers wird ebenfalls gemessen und wenn nötig ein Lüfter zugeschaltet. Die Ansteuerung des Motors ist keine Blockkomutierung. Diese hat sich als untauglich gezeigt. Tatsächlich wird auf den 3 Leitungen eine vereinfachte Sinusspannung ausgegeben. Das reduziert die Drehmomentwelligkeit und das Rückspeisen der Energie beim Bremsen ist deutlich besser. Ob und wieweit sich dadurch der Motorwirkungsgrad ändert wurde bisher nicht gemessen. Die ganze Einheit wird vom PC aus über die Serielle Schnittstelle (5V) parametriert und kalibriert.
Der Motorregler ist auf zwei Platinen aufgebaut. Der Grund dafür ist die einfachere Herstellung der Platinen mit der Bügeleisenmethode sowie die räumliche Trennung der hohen Ströme vom Kontroller. Ob dies wegen der Störsicherheit wirklich notwendig ist wurde aus Kostengründen nie getestet. An der Stelle ist aber eine unnötige Sicherheit besser als eine vergessene. Die Verbindung zwischen den beiden Platinen bildet ein 16-Adriges Flachkabel. Programmierstecker und der Serielle Bus werden seitlich am Kontrollerboard gesteckt. Die Verbindung zu den Hallsensoren wird über ein 6-Adriges Flachkabel hergestellt. Zusätzlich zu den beiden Platinen gehört zum Motorregler auch die im Motor verbaute Sensorplatine. Auf dieser werden die Signale der drei zusätzlichen Hallsensoren zu einem Signal zusammengefasst. Nach einem Ausfall wurde auch noch eine Zusatzplatine mit den Snubbern und den Supressordioden nachgerüstet. Ohne diese ist eine Halbbrücke nach ca. 125km Fahrt ausgefallen.
Motorregler Software
'Version 19
$prog &HFF , &HFF , &HD4 , &HF9 'Fusebits
$regfile = "m168def.dat"
$crystal = 10000000
$baud = 57600
$hwstack = 32
$swstack = 10
$framesize = 40
Declare Sub Setspeed
Declare Sub Pwm_start
Declare Sub Pwm_stop
Config Portc.0 = Input 'UBAT
Config Portc.1 = Input 'USHUNT
Config Portc.2 = Input 'TEMP
Config Portc.3 = Output 'LED1
Config Portc.4 = Output 'Lüfter
Config Portc.5 = Input 'Jumper1
Config Portd.2 = Input 'Hall_C
Config Portd.3 = Output 'A+
Config Portd.4 = Input 'Hall_B
Config Portd.5 = Output 'C+
Config Portd.6 = Output 'C-
Config Portd.7 = Input 'Hall_A
Config Portb.0 = Input 'Hall_D
Config Portb.1 = Output 'B-
Config Portb.2 = Output 'B+
Config Portb.3 = Output 'A-
Config Portb.4 = Output 'LED2
Config Portb.5 = Input 'Unbelegt (SCK)
Hall_a Alias Pind.7 'gelb
Hall_b Alias Pind.4 'blau
Hall_c Alias Pind.2 'Grün
Hall_d Alias Pinb.0
Led1 Alias Portc.3
Led2 Alias Portb.4
Fan Alias Portc.4
Jumper1 Alias Pinc.5
Dim Uzu As Integer At $100
Dim Izu As Integer At $102
Dim Ausgabeticks As Integer At $104 'Anzahl Kommutieren zwischen Seriellen Telegrammen
Dim Temperatur As Integer At $106 '
Dim Drehzahl As Integer At $108 'Drehzahl
Dim M1 As Byte At $100 Overlay
Dim M2 As Byte At $101 Overlay
Dim M3 As Byte At $102 Overlay
Dim M4 As Byte At $103 Overlay
Dim M5 As Byte At $104 Overlay
Dim M6 As Byte At $105 Overlay
Dim M7 As Byte At $106 Overlay
Dim M8 As Byte At $107 Overlay
Dim M9 As Byte At $108 Overlay
Dim M10 As Byte At $109 Overlay
Dim Kalibrierwert As Integer At $10a
Dim Kal(2) As Byte At $10a Overlay
Dim A(15) As Byte At $10c
Dim S(12) As Byte At $11b
Dim Sinus(12) As Byte At $127
Dim Richtung(255) As Byte At $133
Dim Motorposition As Byte At $232
Dim Istrichtung As Integer At $233
Dim Altrichtung As Integer At $235
Dim Aposition As Byte At $237
Dim Zposition As Byte At $238
Dim Zwangskommutieren As Byte At $239
Dim Temp As Word At $23a
Dim Fancount As Word At $23c
Dim Motoradresse As Byte At $23e
Dim Vwinkel As Byte At $23f
Dim Rwinkel As Byte At $240
Dim Ticks As Integer At $241
Dim N As Byte At $243
Dim Notaus As Byte At $244
Dim Loopcount As Word At $245
Dim Sollrichtung As Byte At $247
Dim Altsollrichtung As Byte At $248
Dim Sollspeed As Byte At $249
Dim Altsollspeed As Byte At $24a
Dim Bdummy As Byte At $24b
Dim Intbdummy As Byte At $24c
Dim Intidummy As Integer At $24d
Dim Sdummy As Single At $24f
Dim Idummy1 As Integer At $253
Dim Idummy2 As Integer At $255
Dim Uw As Word At $257
Dim Iw As Word At $259
Dim Uwsum As Long At $25b
Dim Iwsum As Long At $25f
Dim Wcount As Long At $263
Dim Uoffset As Single At $267
Dim Ufaktor As Single At $26b
Dim Ioffset As Single At $26f
Dim Ifaktor As Single At $273
Dim Ep0 As Byte At $277
Dim Ep1 As Byte At $278
Dim Ep2 As Byte At $279
Dim Ep3 As Byte At $27a
Dim Ep4 As Byte At $27b
Dim Ep5 As Byte At $27c
Dim Ta As Byte At $27d
Dim Tb As Byte At $27e
Dim Tc As Byte At $27f
Dim Fehler As Byte At $280
Sollspeed = 0
Pwm_stop 'Erstmal alles auschalten
'Variablen für die Richtungserkennung vorbelegen
'Diese Variante frisst zwar viel Arbeitsspeicher, ist aber sehr schnell
For N = 1 To 15
A(n) = 0
Next
For N = 1 To 255
Richtung(n) = 2
Next
If Jumper1 = 0 Then 'R
Motoradresse = 82
A(12) = 12
A(4) = 11
A(6) = 10
A(14) = 9
A(10) = 8
A(2) = 7
A(3) = 6
A(11) = 5
A(9) = 4
A(1) = 3
A(5) = 2
A(13) = 1
Richtung(21) = 3
Richtung(93) = 3
Richtung(220) = 3
Richtung(196) = 3
Richtung(70) = 3
Richtung(110) = 3
Richtung(234) = 3
Richtung(162) = 3
Richtung(35) = 3
Richtung(59) = 3
Richtung(185) = 3
Richtung(145) = 3
Richtung(81) = 1
Richtung(25) = 1
Richtung(155) = 1
Richtung(179) = 1
Richtung(50) = 1
Richtung(42) = 1
Richtung(174) = 1
Richtung(230) = 1
Richtung(100) = 1
Richtung(76) = 1
Richtung(205) = 1
Richtung(213) = 1
Else
Motoradresse = 76 'L
A(11) = 1
A(3) = 2
A(1) = 3
A(9) = 4
A(13) = 5
A(5) = 6
A(4) = 7
A(12) = 8
A(14) = 9
A(6) = 10
A(2) = 11
A(10) = 12
Richtung(236) = 3
Richtung(196) = 3
Richtung(69) = 3
Richtung(93) = 3
Richtung(217) = 3
Richtung(145) = 3
Richtung(19) = 3
Richtung(59) = 3
Richtung(186) = 3
Richtung(162) = 3
Richtung(38) = 3
Richtung(110) = 3
Richtung(42) = 1
Richtung(171) = 1
Richtung(179) = 1
Richtung(49) = 1
Richtung(25) = 1
Richtung(157) = 1
Richtung(213) = 1
Richtung(84) = 1
Richtung(76) = 1
Richtung(206) = 1
Richtung(230) = 1
Richtung(98) = 1
End If
'AD-Wandler einstellen
Config Adc = Single , Prescaler = Auto , Reference = Off
Start Adc
'<Test Hallsensoren>
Fehler = 1
Fan = 1
While Fehler = 1
Fehler = 0
Motorposition = 0
Motorposition.0 = Hall_a
Motorposition.1 = Hall_b
Motorposition.2 = Hall_c
Motorposition.3 = Hall_d
If Motorposition = 0 Then Fehler = 1 'Stecker nicht gesteckt
If Motorposition > 0 Then
If A(motorposition) = 0 Then Fehler = 1 'Das währe eine Motorposition die es nicht gibt!
End If
If Fehler = 1 Then
Toggle Led1
Toggle Led2
Waitms 500
End If
Wend
'</Test Hallsensoren>
On Timer2 Update_pwm Nosave
'Pin-Change Interrupt einstellen:
Pcmsk2 = &B10010100
Pcmsk1 = &B00000000
Pcmsk0 = &B00000001
Pcicr = &B00000101
On Pcint2 Kommutieren Nosave
On Pcint0 Kommutieren Nosave
Readeeprom Uoffset , 1
Readeeprom Ufaktor , 5
Readeeprom Ioffset , 9
Readeeprom Ifaktor , 13
'Angepasste Sinuskurve aus dem EEprom laden
For N = 1 To 12
Bdummy = N + 16
Readeeprom Sinus(n) , Bdummy
Next
'Voreilwinkel:
Readeeprom Vwinkel , 29
Readeeprom Rwinkel , 30
If Ufaktor = 0 Then Ufaktor = 1
If Ifaktor = 0 Then Ifaktor = 1
On Urxc Datenempfang Nosave
Enable Urxc
Enable Interrupts
Fancount = 15000 'Lüfter erstmal einschalten
Do
Led1 = 0
'<Messen>
Uw = Getadc(0)
Uwsum = Uwsum + Uw
Iw = Getadc(1)
Iwsum = Iwsum + Iw
Incr Wcount
Temp = Getadc(2)
'</Messen>
'<Serielle Telegramme abarbeiten>
If Ep0 = 13 Then
If Ep5 = 13 Then
If Ep1 = Motoradresse Then '"R", "L"
Disable Urxc
$asm
lds R24,{EP1}
LDs R25,{EP2}
add R24,R25
LDs R25,{EP3}
add R24,R25
STS {Bdummy},R24
$end Asm
If Bdummy = Ep4 Then 'Die Prüfsumme stimmt
Led1 = 1
Pcicr = &B00000000 'Kommutieren kurz deaktivieren, weil sonst die Ticks während dem Zugriff geändert werden könnten
Ausgabeticks = Ticks
Ticks = 0
Pcicr = &B00000101
$asm
lds R24,{M1}
LDs R25,{M2}
add R24,R25
LDs R25,{M3}
add R24,R25
LDs R25,{M4}
add R24,R25
LDs R25,{M5}
add R24,R25
LDs R25,{M6}
add R24,R25
STS {Bdummy},R24
'Antwort ausgeben
'Print Chr(m1) ; Chr(m2) ; Chr(m3) ; Chr(m4) ; Chr(m5) ; Chr(m6) ; Chr(bdummy) ; Chr(13) ;
LdS R24,{M1}
STS udr,R24
Warten1:
LDS R24,UCSR0A
BST R24,5
Brtc warten1
LDS R24,{M2}
STS udr,R24
Warten2:
LDS R24,UCSR0A
BST R24,5
Brtc warten2
lds R24,{M3}
STS udr,R24
Warten3:
LDS R24,UCSR0A
BST R24,5
Brtc warten3
LDS R24,{M4}
STS udr,R24
Warten4:
LDS R24,UCSR0A
BST R24,5
Brtc warten4
LDS R24,{M5}
STS udr,R24
Warten5:
LDS R24,UCSR0A
BST R24,5
Brtc warten5
LDS R24,{M6}
STS udr,R24
Warten6:
LDS R24,UCSR0A
BST R24,5
Brtc warten6
LDS R24,{bdummy}
STS udr,R24
Warten7:
LDS R24,UCSR0A
BST R24,5
Brtc warten7
LDi R24,13
STS udr,R24
Warten8:
LDS R24,UCSR0A
BST R24,5
Brtc warten8
$end Asm
If Ep2 < 3 Then
Notaus = 0
Loopcount = 0
Sollrichtung = Ep2
Sollspeed = Ep3
If Sollrichtung = 2 Then
Sollrichtung = 1
Notaus = 1
Loopcount = 250
Sollspeed = 0
End If
Setspeed
'<Messwerte berechnen>
'Messwerte werden hier berechnet, weil genau jetzt 1/100s Zeit ist.
'Spannung berechnen
Sdummy = Uwsum / Wcount
Sdummy = Sdummy - Uoffset
Sdummy = Sdummy * Ufaktor
Uzu = Int(sdummy)
Uwsum = 0
'Strom berechnen
Sdummy = Iwsum / Wcount
Sdummy = Sdummy - Ioffset
Sdummy = Sdummy * Ifaktor
Izu = Int(sdummy)
Iwsum = 0
Wcount = 0
'</Messwerte berechnen>
Else
Select Case Ep2
Case 3 'Sinus(1) empfangen
Sinus(1) = Ep3
Writeeeprom Sinus(1) , 17
Case 4 'Sinus(2) empfangen
Sinus(2) = Ep3
Writeeeprom Sinus(2) , 18
Case 5 'Sinus(3) empfangen
Sinus(3) = Ep3
Writeeeprom Sinus(3) , 19
Case 6 'Sinus(4) empfangen
Sinus(4) = Ep3
Writeeeprom Sinus(4) , 20
Case 7 'Sinus(5) empfangen
Sinus(5) = Ep3
Writeeeprom Sinus(5) , 21
Case 8 'Sinus(6) empfangen
Sinus(6) = Ep3
Writeeeprom Sinus(6) , 22
Case 9 'Sinus(7) empfangen
Sinus(7) = Ep3
Writeeeprom Sinus(7) , 23
Case 10 'Sinus(8) empfangen
Sinus(8) = Ep3
Writeeeprom Sinus(8) , 24
Case 11 'Sinus(9) empfangen
Sinus(9) = Ep3
Writeeeprom Sinus(9) , 25
Case 12 'Sinus(10) empfangen
Sinus(10) = Ep3
Writeeeprom Sinus(10) , 26
Case 13 'Sinus(11) empfangen
Sinus(11) = Ep3
Writeeeprom Sinus(11) , 27
Case 14 'Sinus(12) empfangen
Sinus(12) = Ep3
Writeeeprom Sinus(12) , 28
Case 15 'Spannung Kalibrieren (Byte 1)
Kal(1) = Ep3
Case 16 'Spannung Kalibrieren (Byte 2)
Kal(2) = Ep3
Sdummy = Uwsum / Wcount
Ufaktor = Kalibrierwert / Sdummy
Writeeeprom Ufaktor , 5
Uoffset = 0 'Schaltungsbedingt
Writeeeprom Uoffset , 1
Case 17 'Strom Kalibrieren (Byte 1)
Kal(1) = Ep3
Case 18 'Strom Kalibrieren Byte (2)
Kal(2) = Ep3
Sdummy = Iwsum / Wcount
If Kalibrierwert = 0 Then 'Das ist der Offset
Ioffset = Sdummy + 1
Writeeeprom Ioffset , 9
Else 'Jetzt den Faktor berechnen
Sdummy = Sdummy - Ioffset
Ifaktor = Kalibrierwert / Sdummy
Writeeeprom Ifaktor , 13
End If
Case 19
Vwinkel = Ep3
Writeeeprom Vwinkel , 29
Case 20
Rwinkel = Ep3
Writeeeprom Rwinkel , 30
End Select
End If
$asm 'Empfangspuffer löschen
LDI R24,0
sTS {EP1},R24
sTS {EP2},R24
sTS {EP3},R24
sTS {EP4},R24
$end Asm
End If
Enable Urxc
End If
End If
End If
'</Serielle Telegramme abarbeiten>
'<Lüfter schalten>
If Temp > 740 Then Fancount = 15000 'Schaltet den Lüfter ein
If Fancount > 0 Then
Fan = 1
Else
Fan = 0
End If
If Fancount > 0 Then Decr Fancount
'</Lüfter schalten>
'Notaus mit Freilauf wenn keine Nachricht von Seriell
If Loopcount < 50 Then 'Das sind schätzungsweise 0.1s
Led2 = 1
Notaus = 0
Incr Loopcount
Else
Led2 = 0
Notaus = 1
Sollspeed = 0
Setspeed
End If
Loop
'********************************************************************************************
Kommutieren:
$asm
PUSH R10
PUSH R11
PUSH R16
PUSH R17
PUSH R20
PUSH R21
PUSH R24
PUSH R26
PUSH R27
IN R24,sreg
PUSH R24
clr R16
lds R17, $0023
BST R17,0
BLD R16,3
LDS R17, $0029
BST R17,2
bld R16,2
BST R17,4
bld R16,1
BST R17,7
bld R16,0
lds R17,{aposition}
!swap R17
andi R17,&B11110000
add R17,R16
STS {Aposition},R17
CLR R17
LDI R26,$0B
LDI R27,$01
ADD R26,R16
ADC R27,R17
LD R24,X
LDS R16,{Sollrichtung}
CPI R16,0
BREQ Sollrichtungnull
Jmp Sollrichtungnichtnull
Sollrichtungnull:
LDS R20,{Vwinkel}
Add R24,R20
JMP Richtunggesetzt
Sollrichtungnichtnull:
LDS R20,{Rwinkel}
Add R24,R20
Richtunggesetzt:
CPI R24,$0D
BRCC Istgroesser13_1
JMP Istkleiner13_1
Istgroesser13_1:
SUBI R24,$0C
Istkleiner13_1:
CLR R20
Ldi R26,$1a
LDI R27,$01
ADD R26,R24
ADC R27,R20
LD R16,X
STS {Ta},R16
subi R24,$fc
CPI R24,$0D
BRCC Istgroesser13_2
JMP Istkleiner13_2
Istgroesser13_2:
SUBI R24,$0C
Istkleiner13_2:
CLR R20
Ldi R26,$1a
LDI R27,$01
ADD R26,R24
ADC R27,R20
LD R16,X
STS {Tc},R16
subi R24,$fc
CPI R24,$0D
BRCC Istgroesser13_3
JMP Istkleiner13_3
Istgroesser13_3:
SUBI R24,$0C
Istkleiner13_3:
CLR R20
Ldi R26,$1a
LDI R27,$01
ADD R26,R24
ADC R27,R20
LD R16,X
STS {Tb},R16
lds R10,{Aposition}
CLR R11
LDI R26,$32
LDI R27,$01
ADD R26,R10
ADC R27,R11
LD R16,X+
CLR R17
LDI R20,$02
LDI R21,$00
!Sub R16 , R20
SBC R17,R21
LDI R26,$33
LDI R27,$02
ST X+,R16
ST X,R17
LDI R26,$41
LDI R27,$02
LD R16,X+
LD R17,X
LDI R26,$33
LDI R27,$02
LD R20,X+
LD R21,X
ADD R16,R20
ADC R17,R21
LDI R26,$41
LDI R27,$02
ST X+,R16
ST X,R17
LDS R24,timsk2
ORI R24,$01
STS timsk2,R24
POP R24
!Out sreg , R24
POP R27
POP R26
POP R24
POP R21
POP R20
POP R17
POP R16
POP R11
POP R10
$end Asm
Return
'********************************************************************************************
'********************************************************************************************
Update_pwm:
$asm
PUSH R24
IN R24,sreg
PUSH R24
lds R24,{Ta}
STS ocr2a,R24
STS ocr2b,R24
LDS R24,{Tb}
STS ocr1al,R24
STS ocr1bl,R24
lds R24,{Tc}
!OUT ocr0a,R24
!OUT ocr0b,R24
LDS R24,timsk2
ANDI R24,$FE
STS timsk2,R24
POP R24
!OUT sreg,R24
POP R24
$end Asm
Return
'********************************************************************************************
'********************************************************************************************
Datenempfang:
$asm
PUSH R24;
IN R24, SREG;
PUSH R24;
LDS R24,{EP1}
STS {EP0},R24
LDS R24,{EP2}
STS {EP1},R24
LDS R24,{EP3}
STS {EP2},R24
LDS R24,{EP4}
STS {EP3},R24
LDS R24,{EP5}
STS {EP4},R24
IN R24,UDR
STs {EP5},R24
POP R24;
Out Sreg , R24;
POP R24;
$end Asm
Return
'********************************************************************************************
'********************************************************************************************
Sub Setspeed
If Notaus = 1 Then
Pwm_stop
Sollspeed = 0
For N = 1 To 12
S(n) = 0
Next
Else
For N = 1 To 12
Idummy1 = Sollspeed * Sinus(n)
Idummy1 = Idummy1 / 100
S(n) = Idummy1
Next
If Tccr0a = 0 Then 'Wenn die PWM aus ist
Pwm_start
End If
'<Zwangskommutieren>
Zwangskommutieren = 0
If Sollrichtung <> Altsollrichtung Then Zwangskommutieren = 1
If Sollspeed <> Altsollspeed Then Zwangskommutieren = 1
If Zwangskommutieren = 1 Then
Pcicr = &B00000000 'Den Eigentlichen Kommutierinterrupt abschalten
$asm
clr R16
lds R17, $0023
BST R17,0
BLD R16,3
LDS R17, $0029
BST R17,2
bld R16,2
BST R17,4
bld R16,1
BST R17,7
bld R16,0
lds R17,{aposition}
!swap R17
andi R17,&B11110000
add R17,R16
STS {Aposition},R17
CLR R17
LDI R26,$0B
LDI R27,$01
ADD R26,R16
ADC R27,R17
LD R24,X
LDS R16,{Sollrichtung}
CPI R16,0
BREQ Sollrichtungnullz
Jmp Sollrichtungnichtnullz
Sollrichtungnullz:
LDS R20,{Vwinkel}
Add R24,R20
JMP Richtunggesetztz
Sollrichtungnichtnullz:
LDS R20,{Rwinkel}
Add R24,R20
Richtunggesetztz:
CPI R24,$0D
BRCC Istgroesser13_1z
JMP Istkleiner13_1z
Istgroesser13_1z:
SUBI R24,$0C
Istkleiner13_1z:
CLR R20
Ldi R26,$1a
LDI R27,$01
ADD R26,R24
ADC R27,R20
LD R16,X
STS {Ta},R16
subi R24,$fc
CPI R24,$0D
BRCC Istgroesser13_2z
JMP Istkleiner13_2z
Istgroesser13_2z:
SUBI R24,$0C
Istkleiner13_2z:
CLR R20
Ldi R26,$1a
LDI R27,$01
ADD R26,R24
ADC R27,R20
LD R16,X
STS {Tc},R16
subi R24,$fc
CPI R24,$0D
BRCC Istgroesser13_3z
JMP Istkleiner13_3z
Istgroesser13_3z:
SUBI R24,$0C
Istkleiner13_3z:
CLR R20
Ldi R26,$1a
LDI R27,$01
ADD R26,R24
ADC R27,R20
LD R16,X
STS {Tb},R16
$end Asm
Pcicr = &B00000101 'Den Eigentlichen Kommutierinterrupt einschalten
'Nur Overflow Interrupt (Seite 105)
Timsk2.toie2 = 1
Toggle Led2
End If
'</Zwangskommutieren>
End If
Altsollrichtung = Sollrichtung
Altsollspeed = Sollspeed
End Sub
'********************************************************************************************
'********************************************************************************************
Sub Pwm_start
Disable Interrupts 'Damit die Timer auch wirklich synchron laufen
Tccr0a = 161
Tccr0b = 1
Ocr0a = 0
Ocr0b = 0
Tccr1a = 161
Tccr1b = 1
Ocr1ah = 0
Ocr1al = 0
Ocr1bh = 0
Ocr1bl = 0
Tccr2a = 161
Tccr2b = 1
Ocr2a = 0
Ocr2b = 0
Tcnt0 = 0 'Timer Startwert, wegen Synchron
Tcnt1 = 6 'Timer Startwert, wegen Synchron
Tcnt2 = 9 'Timer Startwert, wegen Synchron
Enable Interrupts
End Sub
'********************************************************************************************
'********************************************************************************************
Sub Pwm_stop
Tccr0a = 0
Tccr0b = 0
Ocr0a = 0
Ocr0b = 0
Tccr1a = 0
Tccr1b = 0
Ocr1ah = 0
Ocr1al = 0
Ocr1bh = 0
Ocr1bl = 0
Tccr2a = 0
Tccr2b = 0
Ocr2a = 0
Ocr2b = 0
'alles aus
Portd.3 = 0 'A+
Portb.3 = 1 'A-
Portb.2 = 0 'B+
Portb.1 = 1 'B-
Portd.5 = 0 'C+
Portd.6 = 1 'C-
End Sub
'********************************************************************************************
Hauptsteuerung
Die Hauptsteuerung erledigt die gesamte Lageregelung. Sie steuert die Motoren und gibt die entsprechenden Meldungen an den Tacho/Datenlogger aus. Sie stellt auch die 5V für den Tacho bereit. Darum die Möglichkeit einen größeren Spannungsregler zu bestücken. Die Lageregelung speichert auch die gefahrenen Km, einigen Min-Max Werte und Diverse Werte bei einem Notaus. Diese Werte werden im EEprom als Text abgelegt, also direkt lesbar.
Sensoradapter
Zur Hauptsteuerung gehört auch der Sensoradapter. (Schaltbild siehe Hauptsteuerung) Dieser stellt die 3,3V für die Sensoren bereit. Im Unterschied zu ähnlichen Projekten besitzt das Rutscherle2 kein Potentiometer für die Lenkung. Zum Lenken werden die gesamten Sensoren gekippt. Darum auch dieser Sensoradapter. Die Sensoren werden mit dem Adapter direkt mit der Achse der Lenkung verbunden. Die ideale Position ist dabei natürlich genau im Schnittpunkt von Lenk- und Motorachse.
Tacho
Akkuladestecker
Software
Mechanik
Motorumbau