Probleme mit 30°-Verschiebung bei BLDC-Ansteuerung

Gast #4102853
Lesenswert?

Hallo,

ich bin gerade drüber einen Motortreiber mit einem ATmega88 für einen 
BLDC zu realisieren.
EMK wird mittels Analog-Komparator (AC) ausgewertet.
Funktioniert alles soweit, nur hab ich Probleme die 30° 
Phasenverschiebung für das richtige Timing für max. Drehmoment mit 
Interrupt zu realisieren.

TIMER1 hab ich im CTC-Mode laufen.

Um Stillstand festzustellen nehm ich OCR1A vom TIMER1 (bei 
OCR1A-Interrupt wird einfach Neustart des Motors ausgeführt).

Für die Phasenverschiebung möchte ich OCR1B benutzen.
Meine Idee:
Bei einem AC-Interrupt wird OCR1B auf TCNT1>>1 (=30°) gesetzt und TCNT1 
anschließend auf Null gesetzt.
Im OCR1B-Interrupt wird dann einfach in den nächsten Kommutierzustand 
geschaltet.

Wenn ich die Phasenverschiebung nun mit Oszi nachmesse beträgt diese 
Null.

Mach ich das Ganze mit einem normalen Delay statt mit OCR1B, also im 
AC-Interrupt eine einfache Verzögerung mit delay_us (basierend auf 
_delay_us aus delay.h), übergeb dieser ((TCNT1>>1) * Timertaktdauer) und 
setz danach TCNT1 = 0 (danach wird Kommutiert), so funktioniert es 
tadellos (ist aber leider keine optimale Lösung, da delay im Interrupt).

Bevor ich mit Codeschnipsel komme,
kann das so überhaupt richtig funktionieren? Also mit TIMER1 im CTC-Mode 
und OCR1B? Oder gibts da irgendwelche Probleme, die ich im Datenblatt 
übersehn hab?

Schonmal Vielen Dank für eure Tipps!
Gast #4103337
Lesenswert?

Hab hier mal die paar relevanten Codeschnipsel:

Initialisierung des TIMER1 in meiner main-Funktion:
1
TCCR1A = 0;
2
  TCCR1B = (0<<WGM13)|(1<<WGM12)|(1<<CS12)|(0<<CS11)|(0<<CS10);
3
  
4
  OCR1A = 0x0080;          // entspricht: 8 * 16 * 32us = 4,096ms


Der Schluss-Teil meiner Motor-Anlauf-Routine, hier werden die Interrupts 
eingeschaltet:
1
// Einstellung des Timers für Kommutier-Timing
2
  TIFR1 |= (1<<OCF1B);  // Flag loeschen
3
  OCR1B = 25;
4
  TCNT1 = 0;
5
  
6
  //TIMSK1 |= (1<<OCIE1B);
7
  
8
  ACSR |= (1<<ACIE);  // aktiviert Interrupt
9
  
10
  
11
  delay_ms(100);
12
  
13

14
  // Einstellung des Time-Outs
15
  TIFR1 |= (1<<OCF1A);  // Flag loeschen
16
  //TCNT1 = 0;
17
  
18
  TIMSK1 |= (1<<OCIE1A);
19
  
20
  motor_start = 0;
21
}

Hier die ISRs:
1
// Bei Erreichen von OCR1B, kommutieren
2
ISR (TIMER1_COMPB_vect)
3
{
4
  TIMSK1 &= ~(1<<OCIE1B);
5
  next_commutate_state();
6
}
7

8

9
// bei Erreichen von OCR1A, Motor neustarten
10
ISR (TIMER1_COMPA_vect)
11
{
12
  motor_start = 1;
13
}
14

15

16
// back EMF zero crossing detection
17
ISR (ANALOG_COMP_vect)
18
{
19
  switch (rotor_state)
20
  {
21
    case (0):
22
      if(SENSE_H)
23
      {
24
        //OCR1B = motor_start ? 25 : TCNT1 >> 1;
25
        OCR1B = 1;
26
        if(motor_start == 0) delay_us(32*(TCNT1>>2));
27
        TCNT1 = 0;
28
        TIMSK1 |= (1<<OCIE1B);
29
        
30
      }
31
      break;
32

33
    case (1):
34
      if(!SENSE_H)
35
      {
36
        //OCR1B = motor_start ? 25 : TCNT1 >> 1;
37
        OCR1B = 1;
38
        if(motor_start == 0) delay_us(32*(TCNT1>>2));
39
        TCNT1 = 0;
40
        TIMSK1 |= (1<<OCIE1B);
41
        
42
      }
43
      break;
44
  
45
    case (2):
46
      if(SENSE_H)
47
      {
48
        //OCR1B = motor_start ? 25 : TCNT1 >> 1;
49
        OCR1B = 1;
50
        if(motor_start == 0) delay_us(32*(TCNT1>>2));
51
        TCNT1 = 0;
52
        TIMSK1 |= (1<<OCIE1B);
53
        
54
      }
55
      break;
56

57
    case (3):
58
      if(!SENSE_H)
59
      {
60
        //OCR1B = motor_start ? 25 : TCNT1 >> 1;
61
        OCR1B = 1;
62
        if(motor_start == 0) delay_us(32*(TCNT1>>2));
63
        TCNT1 = 0;
64
        TIMSK1 |= (1<<OCIE1B);
65
        
66
      }
67
      break;
68

69
    case (4):
70
      if(SENSE_H)
71
      {
72
        //OCR1B = motor_start ? 25 : TCNT1 >> 1;
73
        OCR1B = 1;
74
        if(motor_start == 0) delay_us(32*(TCNT1>>2));
75
        TCNT1 = 0;
76
        TIMSK1 |= (1<<OCIE1B);
77
        
78
      }
79
      break;
80
      
81
    case (5):
82
      if(!SENSE_H)
83
      {
84
        //OCR1B = motor_start ? 25 : TCNT1 >> 1;
85
        OCR1B = 1;
86
        if(motor_start == 0) delay_us(32*(TCNT1>>2));
87
        TCNT1 = 0;
88
        TIMSK1 |= (1<<OCIE1B);
89
        
90
      }
91
      break;
92
  }
93
}

next_commutate_state schaltet nur den Kommutierschritt weiter.
So wies dasteht ist die delay_us zur Verzögerung aktiv, sonst hab ich 
immer "OCR1B = 1" und if(motor_start == 0) delay_us... auskommentiert.
#4103421
Lesenswert?

Fragender schrieb:
> Bei einem AC-Interrupt wird OCR1B auf TCNT1>>1 (=30°) gesetzt und TCNT1
> anschließend auf Null gesetzt.

Diesen Satz verstehe ich nicht ganz. Welches Register beschreibst du 
wann mit welchem Wert?

Ich mache das bei mir so:
Wenn ich kommutiere, dann setze ich das Timer1 Zähl-Register auf 0. Bei 
einem AC-Interrupt nehme ich den Zählerstand des Timer1 und kopiere ihn 
in OCR1x. Timer1 Zähl-Register wieder auf 0 und den Interrupt für den 
OCR1x einschalten. Wenn dieser Interrupt auslöst, sind die 30Grad um und 
ich kann kommutieren. Dann gehts wieder von vorn los. Eig ganz 
einfach...



Dennis

Edit: So wie ich deinen Code allein im AC-Interrupt verstehe, setzt du 
das Timer1 Zähl-Register auf 0 und den OCR1B auf 1. Also wird der OCR1B 
Interrupt direkt danach ausgeführt. Also der AC Interrupt wird noch 
fertig bearbeitet und direkt danach der OCR1B Interrupt. Damit ist es 
klar, dass die kommutierung direkt ausgeführt wird.
Gast #4103525
Lesenswert?

Erstmal danke für die Antworten.


Dennis H. schrieb:
> Fragender schrieb:
>> Bei einem AC-Interrupt wird OCR1B auf TCNT1>>1 (=30°) gesetzt und TCNT1
>> anschließend auf Null gesetzt.
>
> Diesen Satz verstehe ich nicht ganz. Welches Register beschreibst du
> wann mit welchem Wert?

Ich messe quasi die Zeit, die 60° dauern und teil die dann einfach durch 
2.
Ich versuchs nochmal zu beschreiben:

AC-Interrupt:
OCR1B = TCNT1 >> 1;      (entsprechen 30°)
TCNT1 = 0;

OCR1B-Interrupt:
next_commutate_state


> Edit: So wie ich deinen Code allein im AC-Interrupt verstehe, setzt du
> das Timer1 Zähl-Register auf 0 und den OCR1B auf 1. Also wird der OCR1B
> Interrupt direkt danach ausgeführt. Also der AC Interrupt wird noch
> fertig bearbeitet und direkt danach der OCR1B Interrupt. Damit ist es
> klar, dass die kommutierung direkt ausgeführt wird.

So wie ichs hier gepostet hab, ist die Version mit dem delay_us.
Ich habs da so auf die schnelle gemacht, damit ich nicht viel ändern 
muss ;)
Mit Interrupts ist das normal auskommentiert, genauso wie dann die Zeile 
mit dem delay.

Wie machst du es eigentlich beim Motoranlauf?
Mit welcher Zeit belegst du OCR1x vor?


Fred Feuerstein schrieb:
> Fragender schrieb:
>> OCR1A = 0x0080;
>
> C ist mir fremd, aber geht das bei 8bit Registern?

OCR1A ist 16 Bit breit, müsste also so passen.
Gast #4103544
Lesenswert?

Habs jetzt mal so geändert, wie Dennis H. es gesagt hat:
1
// Bei Erreichen von OCR1B, kommutieren
2
ISR (TIMER1_COMPB_vect)
3
{
4
  TIMSK1 &= ~(1<<OCIE1B);
5
  next_commutate_state();
6
  TCNT1 = 0;
7
}
8

9

10
// back EMF zero crossing detection
11
ISR (ANALOG_COMP_vect)
12
{
13
  switch (rotor_state)
14
  {
15
    case (0):
16
      if(SENSE_H)
17
      {
18
        OCR1B = TCNT1;
19
        TCNT1 = 0;
20
        TIMSK1 |= (1<<OCIE1B);
21
        
22
      }
23
      break;
24

25
    case (1):
26
      if(!SENSE_H)
27
      {
28
        OCR1B = TCNT1;
29
        TCNT1 = 0;
30
        TIMSK1 |= (1<<OCIE1B);
31
        
32
      }
33
      break;
34
  
35
    case (2):
36
      if(SENSE_H)
37
      {
38
        OCR1B = TCNT1;
39
        TCNT1 = 0;
40
        TIMSK1 |= (1<<OCIE1B);
41
        
42
      }
43
      break;
44

45
    case (3):
46
      if(!SENSE_H)
47
      {
48
        OCR1B = TCNT1;
49
        TCNT1 = 0;
50
        TIMSK1 |= (1<<OCIE1B);
51
        
52
      }
53
      break;
54

55
    case (4):
56
      if(SENSE_H)
57
      {
58
        OCR1B = TCNT1;
59
        TCNT1 = 0;
60
        TIMSK1 |= (1<<OCIE1B);
61
        
62
      }
63
      break;
64
      
65
    case (5):
66
      if(!SENSE_H)
67
      {
68
        OCR1B = TCNT1;
69
        TCNT1 = 0;
70
        TIMSK1 |= (1<<OCIE1B);
71
        
72
      }
73
      break;
74
  }
75
}

Ergebnis: Motor stottert nur rum.... :(
#4103560
Lesenswert?

Fragender schrieb:
> So wie ichs hier gepostet hab, ist die Version mit dem delay_us.
> Ich habs da so auf die schnelle gemacht, damit ich nicht viel ändern
> muss ;)
> Mit Interrupts ist das normal auskommentiert, genauso wie dann die Zeile
> mit dem delay.

Ich glaube, das beste wäre, wenn du den Code postest, mit dem du 
Probleme hast. Das macht glaube ich am meisten sinn...

Fragender schrieb:
> Wie machst du es eigentlich beim Motoranlauf?
> Mit welcher Zeit belegst du OCR1x vor?

Motoranlauf ist so eine Wissenschaft. Selbst die Chinesen hatten lange 
damit Probleme. Die Frage ist, willst du den Anlauf für viele 
unterschiedliche Motoren nutzen oder wirst du deinen Regler nur für 
einen Motor nutzen? Ich nutze meine nur für einen Motor, deswegen habe 
ich einfach durch-probiert, bis es gepasst hat. Was bei mir ganz gut 
funktioniert, eine Phase an Masse und die anderen beiden mit sehr 
kleiner PWM an 12V(oder eben deine Spannung). Damit sich der Motor erst 
mal in eine feste Position zieht. Dann bleibt Masse an der Phase wie 
eben schon, und nur eine der anderen beiden Phasen bekommt die 12V. 
Damit sollte der Motor schon ein kleines bisschen losdrehen. Dann habe 
ich nur noch 5 - 10 feste kommutierungen, bei denen ich die Zeitabstände 
einfach ausprobiert habe und dann läuft der Motor von allein weiter. Das 
klappt aber eben nur, wenn du immer den selben Motor hast und beim Start 
die selbe Last. Wie das professioneller geht, weis ich nicht, musste ich 
mich nie damit beschäftigen..


Dennis
Gast #4103595
Lesenswert?

Vielen Dank für deine Hilfe!

Dennis H. schrieb:
> Fragender schrieb:
>> So wie ichs hier gepostet hab, ist die Version mit dem delay_us.
>> Ich habs da so auf die schnelle gemacht, damit ich nicht viel ändern
>> muss ;)
>> Mit Interrupts ist das normal auskommentiert, genauso wie dann die Zeile
>> mit dem delay.
>
> Ich glaube, das beste wäre, wenn du den Code postest, mit dem du
> Probleme hast. Das macht glaube ich am meisten sinn...

Ok, hier der Code:
Ausschnitt aus Motorstartup:
1
// Einstellung des Timers für Kommutier-Timing
2
  TIFR1 |= (1<<OCF1B);      // Flag loeschen
3
  OCR1B = 10;
4
  TCNT1 = 0;
5
  
6
  //TIMSK1 |= (1<<OCIE1B);
7
  
8
  ACSR |= (1<<ACIE);        // aktiviert Interrupt
9
  
10
  
11
  delay_ms(1000);
12

13
  motor_start = 0;
14
}

Restlicher Teil:
1
// Bei Erreichen von OCR1B, kommutieren
2
ISR (TIMER1_COMPB_vect)
3
{
4
  TIMSK1 &= ~(1<<OCIE1B);
5
  next_commutate_state();
6
}
7

8

9
// back EMF zero crossing detection
10
ISR (ANALOG_COMP_vect)
11
{
12
  switch (rotor_state)
13
  {
14
    case (0):
15
      if(SENSE_H)
16
      {
17
        if(motor_start == 0) OCR1B = TCNT1 >> 1;
18
        TCNT1 = 0;
19
        TIMSK1 |= (1<<OCIE1B);
20
        
21
      }
22
      break;
23

24
    case (1):
25
      if(!SENSE_H)
26
      {
27
        if(motor_start == 0) OCR1B = TCNT1 >> 1;
28
        TCNT1 = 0;
29
        TIMSK1 |= (1<<OCIE1B);
30
        
31
      }
32
      break;
33
  
34
    case (2):
35
      if(SENSE_H)
36
      {
37
        if(motor_start == 0) OCR1B = TCNT1 >> 1;
38
        TCNT1 = 0;
39
        TIMSK1 |= (1<<OCIE1B);
40
        
41
      }
42
      break;
43

44
    case (3):
45
      if(!SENSE_H)
46
      {
47
        if(motor_start == 0) OCR1B = TCNT1 >> 1;
48
        TCNT1 = 0;
49
        TIMSK1 |= (1<<OCIE1B);
50
        
51
      }
52
      break;
53

54
    case (4):
55
      if(SENSE_H)
56
      {
57
        if(motor_start == 0) OCR1B = TCNT1 >> 1;
58
        TCNT1 = 0;
59
        TIMSK1 |= (1<<OCIE1B);
60
        
61
      }
62
      break;
63
      
64
    case (5):
65
      if(!SENSE_H)
66
      {
67
        if(motor_start == 0) OCR1B = TCNT1 >> 1;
68
        TCNT1 = 0;
69
        TIMSK1 |= (1<<OCIE1B);
70
        
71
      }
72
      break;
73
  }
74
}



> Fragender schrieb:
>> Wie machst du es eigentlich beim Motoranlauf?
>> Mit welcher Zeit belegst du OCR1x vor?
>
> Motoranlauf ist so eine Wissenschaft. Selbst die Chinesen hatten lange
> damit Probleme. Die Frage ist, willst du den Anlauf für viele
> unterschiedliche Motoren nutzen oder wirst du deinen Regler nur für
> einen Motor nutzen? Ich nutze meine nur für einen Motor, deswegen habe
> ich einfach durch-probiert, bis es gepasst hat. Was bei mir ganz gut
> funktioniert, eine Phase an Masse und die anderen beiden mit sehr
> kleiner PWM an 12V(oder eben deine Spannung). Damit sich der Motor erst
> mal in eine feste Position zieht. Dann bleibt Masse an der Phase wie
> eben schon, und nur eine der anderen beiden Phasen bekommt die 12V.
> Damit sollte der Motor schon ein kleines bisschen losdrehen. Dann habe
> ich nur noch 5 - 10 feste kommutierungen, bei denen ich die Zeitabstände
> einfach ausprobiert habe und dann läuft der Motor von allein weiter. Das
> klappt aber eben nur, wenn du immer den selben Motor hast und beim Start
> die selbe Last. Wie das professioneller geht, weis ich nicht, musste ich
> mich nie damit beschäftigen..

Genauso machs ich auch.
Ich nehm da nur den einen Motor.
Anlauf klappt mit 0° Verzögerung tadellos.


Wenn ich im Code immer das "if(motor_start == 0) " weglass, also nur 
OCR1B mit dem Timer-Wert lade, wenn ich nicht im Anlauf bin, startet er 
nicht, sondern stottert von anfang an nur rum...
Gast #4103720
Lesenswert?

Hab mal den Strom nachgemessen.
Stromverbrauch ist mit 30° Verzögerung (mit delay.h, dass geht ja, wie 
weiter oben beschrieben, nur unschöne Lösung) gleich dem mit 0° 
Verzögerung.
Rentiert sich das mit der Phasenverschiebung nun wirklich??
Hat da jemand ähnliche Erfahrungen gemacht?
Ich mein von der Theorie her sollte ja die Version mit 30° Verzögerung 
stromsparender sein.
#4104091
Lesenswert?

Also die 30 Grad Verzögerung benötigst du für einen sauberen Lauf. Bei 
hohen Drehzahlen kann man diese Verzögerung noch veringern. Die neuen 
BL-Regler vom Mikrokopter machen das z.B. über Einstellung. Es geht bei 
der Verzögerung nicht um den Stromverbrauch. Unter Last und/oder 
niedrigen Drehzahlen könnte ich mir vorstellen, läuft er schlecht bis 
gar nicht.

Mehreres könntest du jetzt probieren. Zum einen könntest du probieren, 
am Ende des AC-Interrupts das OCR-Flag nochmal zu löschen. Vielleicht 
reicht das schon. Wenn nicht, brauchst du noch irgend einen Interrupt, 
der dir den OCR-Interrupt verzögert einschaltet. Weiterhin könntest du 
dir mal auf Uart oder so die Werte von OCR1B ausgeben lassen. Einfach 
damit du weist, ob die richtigen Zahlenwerte überhaupt ankommen. Evtl. 
ist dein Vorteiler auch etwas hoch gewählt. Irgendwo in dieser Gegend 
vermute ich den Fehler. Kannst ja Erfolg oder Misserfolg hier 
schreiben...



Dennis
Gast #4104250
Lesenswert?

Hab den Fehler gefunden...
Im AC-Interrupt schalte ich nicht auf den nächsten ADC Kanal um, sondern 
nur in meiner next_commutate_state, die erst im Timer-Interrupt 
ausgeführt wird.
Habs geändert und jetzt gehts...
Also nochmal Danke für die Hilfe!

Hab auch gelesen, dass die das bei Mikrokopter seit der V3 implementiert 
haben.
Dass die das nicht schon eher mit eingebaut haben... ist ja eigentlich 
kein großer Aufwand (wenn mans richtig programmiert ;) ).
Gast #4104297
Lesenswert?

Hallo,

wie ist denn bei euch die BEMF-Schaltung aufgebaut? Wenn die so 
aufgebaut ist wie bei Mikrokopier mit R und C also einem Tiefpass gibt 
es doch eine Phasenverschiebung? Wie rechnet ihr die bei den 30° mit 
rein?

MfG
#4104317
Lesenswert?

Der Tiefpass ist eher dafür da, die PWM auf den Mess-Leitungen 
unkenntlich zu machen. Ein bisschen rechnen sollte man da schon auch, 
eine zu tiefe Grenzfrequenz wird sich dann sicher auswirken. Ich hatte 
es mal kurz berechnet, weis aber das ergebnis nicht mehr. Beim 
Mikrokopter war die grenzfrequenz bei mehreren khz, da kannst du das 
vernachlässigen. Schließlich zählt der Timer auch erst mal weiter, wenn 
der AC-Interrupt ausgelöst wird.


Dennis
Gast #4104872
Lesenswert?

Mal noch eine andere Frage...
Wenn ich nun den Rotor festhalte, sollte er ja nach Möglichkeit 
abschalten und nen Neustart ausführen (habs mit Timerüberlauf des TIMER1 
realisiert).
Wenn ich ihn halte, pfeift er aber nur.
Wie kann ich das abfangen??
Gast #4104940
Lesenswert?

Wenn der Motor außer tritt kommt oder du ihn festhältst kannst du doch 
einfach in der zugehörigen ISR die Phasen abschalten und die 
Startroutine neu aufrufen. Wenn mehrere Fehlstarts erfolgt sind könntest 
du komplett abschalten. Zusätzlich könntest du in deiner Main noch 
abfragen ob die Phase != Phasealt dann gab es eine Kommutierung.

Mit dem Timing meinte ich das ja für die verschiedensten Motorarten 
einen Timing empfohlen wird z.B. 10°. Wie verrechne ich das dann mit den 
30°?

MfG
Gast #4104962
Lesenswert?

BLDC schrieb:
> Wenn der Motor außer tritt kommt oder du ihn festhältst kannst du
> doch
> einfach in der zugehörigen ISR die Phasen abschalten und die
> Startroutine neu aufrufen. Wenn mehrere Fehlstarts erfolgt sind könntest
> du komplett abschalten. Zusätzlich könntest du in deiner Main noch
> abfragen ob die Phase != Phasealt dann gab es eine Kommutierung.

Ja, das mach ich indem ich TIMER1 laufen lasse, welcher mir auch die 30° 
Phasenverschiebung erzeugt und wenn dieser überläuft den Neustart 
auslöst.
Funktioniert auch bei niedrigen Drehzahlen, bei höheren hängt es vom 
Winkel ab, in dem ich festhalt, ob er den Timeout bemerkt oder einfach 
nur rasend schnell weiterkommutiert (=> pfeifen, habs auch mitm Oszi 
nachgemessen).


> Mit dem Timing meinte ich das ja für die verschiedensten Motorarten
> einen Timing empfohlen wird z.B. 10°. Wie verrechne ich das dann mit den
> 30°?

Also wenn im Datenblatt 10° empfohlen wird, würde ich nur 10° statt 30° 
verzögern. So würds ich machen.

MaWin schrieb:
> Fragender schrieb:
>> Wenn ich ihn halte, pfeift er aber nur.
>
> Du musst ihn wieder loslassen, damit er anlaufen kann.

Der Anlauf läuft bei mir so ab, dass er zuerst für 2 sec. bei kleiner 
PWM einen Kommutierzustand beibehält, dass ich einen definierten 
Ausgangspunkt hab.
Also wenn ich ihn permanent festhalt und er den Timeout registriert 
müsste er zu pfeifen aufhörn.
Gast #4104984
Lesenswert?

Normal sollte der Comparator eigentlich gar nicht mehr auslösen wenn du 
den Motor festhält. Vielleicht liegt der Fehler bei der Berechnung vom 
30° Timing, sodass diese den Motor weiter Kommutieren will?

MfG
Gast #4105010
Lesenswert?

Habs gerade ausprobiert, bei 0° Verzögerung ist das selbe Problem.
Ich vermute mal, dass durch das schnelle Weiterschalten, trotz absolutem 
Stillstand, Spannungen in den Wicklungen induziert werden, die der 
Analog-Komparator verwertet und so das Weiterschalten erzeugt...
Das Ganze ist nur in speziellen Winkeln des Rotors, in anderen schaltet 
der Timeout zuverlässig ab.
Hat jemand eine Idee wie ich das irgendwie abfangen könnte??
Gast #4146729
Lesenswert?

Hallo,

habs erst jetzt gesehen, dass du geschrieben hast...

Die Idee zum Programm kam von Ulrich Radig ;)

Ich habs mir wie folgt erklärt:
Die Abfragen hat man für 0° Verzögerung benötigt, da hierdurch pro 
Kommutierschritt wirklich nur einmal geschalten wird.
Durch das Rauschen von der BEMF würde der Interrupt sonst mehrfach in 
der nähe der Nullstelle kurz hintereinander wild auslösen (ein Test hat 
es bestätigt).

Bei der neuen Implementierung mit Verzögerung entfällt das, da im 
AC-Interrupt nur die Zeit gesetzt wird, wielange bis zum schalten 
gewartet werden soll. Wichtig ist, dass hier nicht der Timer rückgesetzt 
wird, so wird also die Zeit bis zum letzten ausgelösten Interrupt 
gewartet.


Nochmal zum starten des BLDC...
Ich hab letztens ein Video mit einem kleinen Quadrokopter gesehn, der im 
ausgeschalteten Zustand in die Luft geworfen wurde und unverzüglich die 
Antriebe gestartet haben.
Mit meinem Start-Up wär der da schon längst am Boden ;)
Hat jemand eine Lösung für zügiges (blindes) Starten?
Induktivitätsmessung fällt leider raus, da Strom nur "geschätzt" wird 
(für Überstromerkennung reichts aus).

Gruß
Gast #4146973
Lesenswert?

Hallo,

wie das mit dem Start am besten funktioniert würde mich auch 
interessieren. Allein wenn ich schon zwei verschiedene Motoren benutzte 
funktioniert der Start nicht mehr sauber. Der eine hat z.B. ein höheres 
Rastmoment als der andere.
Ich handhabe es so das ich den Motor erst mal mit einem großen Duty 
Cycle in eine Position zwänge. Dann habe ich ein Array mit verschiedenen 
Delays was in einer for-Schleife abgearbeitet wird. In dieser wird die 
Zeit gewartet und dann weiter kommutiert. Ist das Array abgearbeitet 
hoffe ich das der Motor dem Drehfeld folgt und ich auf den geregelten 
Betrieb umschalten kann. Wie detektierst du ob der Motor angelaufen ist 
oder nicht?

Nochmal zum Timing:
Was sind denn jetzt genau die 30°? Ich kenne es bei Regler Herstellern 
so das sie z.B. 6°, 12°, 18° Timing angeben. Wären dann die 30° = 0° und 
ich müsste dann z.B. die 6° noch drauf rechnen also 36°? Da wird der 
Motor bei mir ziemlich schnell warm und zieht im Leerlauf schon ziemlich 
viel Strom.
1
// back EMF zero crossing detection
2
ISR (ANALOG_COMP_vect)
3
{
4
  
5
  OCR1A = TCNT1 >> 1;    // entspricht 30°
6
  
7
  TIFR1 = TIFR1;          // Flag löschen
8
  TCNT1 = 0;
9
  TIMSK1 |= (1<<OCIE1A);
10
  
11
  ACSR &= ~(1<<ACIE);
12
}
13

14

15
// Bei Erreichen von OCR1A, kommutieren
16
ISR (TIMER1_COMPA_vect)
17
{
18
  next_commutate_state();
19
  
20
  TIMSK1 &= ~(1<<OCIE1A);
21
  ACSR |= (1<<ACI);        // Flag löschen
22
  ACSR |= (1<<ACIE);
23
}

Danke. MfG
Gast #4147088
Lesenswert?

Die Detektion vom Stillstand oder Anlauf in falsche Richtung etc. mach 
ich mit dem Timer. Wenn einfach nach einer bestimmten Zeit kein 
AC-Interrupt kommt, soll der neustarten.

Mit dem in Position zwingen mach ich auch so, bis das nur mit Propeller 
alles ruhig ist, dauert es maximal 2s. Dann beschleunige ich mit 6 
Kommutierschritten (Delay wird linear verringert). Hab festgestellt, 
dass hier wenige Kommutierschritte am Besten sind, bei mehreren startet 
er nicht mehr zuverlässig.

Die Verzögerung ist immer vom AC-Interrupt bis zum Kommutierzeitpunkt 
gemeint.
Also 0° Verzögerung ist, wenn du direkt beim AC-Interrupt kommutierst.
Und 30° ist theoretisch der Optimalzustand (siehe angehängte Grafik).
Hab mal irgendwo gelesen, dass andere Verzögerungen der Optimalzustand 
in Abhängigkeit vom jeweiligen Motor sein können.
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren