Brushless Motor per Arduino steuern

das_copter_198

Erfahrener Benutzer
#41
Ich glaub schon das er sich auch neigt, wen sich die Motoren neigen. Beim Heli funktioniert das ja auch, der fliegt nicht nur nach vorne sondern neigt sich auch noch nach vorne. Mal schauen wie das sein wird.
Wegen dem Gyro werde ich nachher mal ein paar Daten messen, die ich dann zum testen benutzen werden. Der Multiwii Sketch macht das folgendermaßen:

gyroData[axis] = (gyroADC[axis]*3+gyroADCprevious[axis]+16)/4/8;

Also er nimmt die "Rohdaten" 3 mal plus einmal den alten Wert zu dem er 16 dazuzählt(wozu auch immer) und dann Teilt er das durch 4(logisch) und dann noch mal durch 8, dabei steht als Erklärung: /8 is to reduce the sensibility of gyro. Das ist auch verständlich. Den Wert nimmt er dann direkt für die PID Regelung. Wen er dann zu stark regelt oder zu schwach regelt, dann kann ich einfach mal die Werte K* Werte erhöhen.
 

das_copter_198

Erfahrener Benutzer
#42
Hallo,

heute sind die Motoren gekommen. Und jetzt mal wieder eine Frage die was mit dem ursprünglichem Thema zutun hat. Und zwar, ich habe vorher die Esc und Motoren zusammen gelötete und dann mal an einem Empfänger ausprobiert. Das ging auch nach dem Einlernen. Dann wollte ich das ganze mit dem Arduino machen und mit der Servo Libary aber der sch*** Motor springt iwie nicht so richtig an, wie er sollte. Ich habe am Anfang writeMicroseconds(1000); damit initialisiert der Motor auch. Aber wen ich dann in loop() Teil writeMicroseconds(1500); schreibe passiert gar nichts :( Der Motor lief allerdings als ich die Motorgesch. mit einer for() Schleife von 1000 auf 2000 laufen ließ. Leider habe ich jetzt keine Ahnung woran das liegt(obwohl ich denke das die Regler anders sind als welche mit SimonK). Weiß jemand was ich noch ausprobieren kann oder vielleicht sogar woran es genau liegt?

Lg Vincent
 

donvido

Erfahrener Benutzer
#44
Durchforste mal das Internet nach Arduino 11bit PWM, kann dir grad keinen passenden Link dazu geben.
Damit kannst du ein HardwarePWM mit 11bit Auflösung generieren, also die exakte Pulslänge in µs vorgeben und sparst dabei noch Rechenpower.
Für einen Mege2560 sähe das so aus.
// init 16bit timer 3
TCCR3A &= ~(1<<WGM30); // phase correct mode 10
TCCR3A |= (1<<WGM31);
TCCR3B &= ~(1<<WGM32);
TCCR3B |= (1<<WGM33);

TCCR3B &= ~(1<<CS30); // prescaler 8
TCCR3B |= (1<<CS31);
TCCR3B &= ~(1<<CS32);

ICR3 |= 0x07FF; // TOP to 2048; Mode 10


// init 16bit timer 4
TCCR4A &= ~(1<<WGM40); // phase correct mode 10
TCCR4A |= (1<<WGM41);
TCCR4B &= ~(1<<WGM42);
TCCR4B |= (1<<WGM43);

TCCR4B &= ~(1<<CS40); // prescaler 8
TCCR4B |= (1<<CS41);
TCCR4B &= ~(1<<CS42);

ICR4 |= 0x07FF; // TOP to 2048; Mode 10


// init 16bit timer 5
TCCR5A &= ~(1<<WGM50); // phase correct mode 10
TCCR5A |= (1<<WGM51);
TCCR5B &= ~(1<<WGM52);
TCCR5B |= (1<<WGM53);

TCCR5B &= ~(1<<CS50); // prescaler 8
TCCR5B |= (1<<CS51);
TCCR5B &= ~(1<<CS52);

ICR5 |= 0x07FF; // TOP to 2048; Mode 10

TCCR3A |= (1<<COM3B1); // connect pin 2 to timer 3 channel B
TCCR3A |= (1<<COM3C1); // connect pin 3 to timer 3 channel C
TCCR3A |= (1<<COM3A1); // connect pin 5 to timer 3 channel A
TCCR4A |= (1<<COM4A1); // connect pin 6 to timer 4 channel A
TCCR4A |= (1<<COM4B1); // connect pin 7 to timer 4 channel B
TCCR4A |= (1<<COM4C1); // connect pin 8 to timer 4 channel C
TCCR5A |= (1<<COM5A1); // connect pin 44 to timer 4 channel A
TCCR5A |= (1<<COM5B1); // connect pin 45 to timer 4 channel B
TCCR5A |= (1<<COM5C1); // connect pin 46 to timer 4 channel C

pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(44,OUTPUT);
pinMode(45,OUTPUT);
pinMode(46,OUTPUT);

//Pulslänge in µs
OCR3B=1000; //Pin2
OCR3C=1100; //Pin3
OCR3A=1200; //Pin5
OCR4A=1300; //Pin6
OCR4B=1400; //Pin7
OCR4C=1500; //Pin8

OCR5C=1600; //Pin44
OCR5B=1700; //Pin45
OCR5A=1800; //Pin46
 

das_copter_198

Erfahrener Benutzer
#45
Hallo,

die Motoren habe ich inzwischen zum laufen gebracht :) Das mit dem 11bit PWM Signal sieht gut aus. Ich werde nachher mal suchen was ich dazu finde. Seh ich das richitg das Multiwii das inzwischen auch nuzt? Weil ich habe mir auch noch ältere Multiwii Codes angeschaut und da wird noch mit analogWrite() gearbeitet.

Lg Vincent
 

donvido

Erfahrener Benutzer
#46
Also ich habe hier die Version 2.3 auf der Platte, konnte sie aber noch nicht vollständig entziffern.
Ein schneller Blick in die Output.cpp führt zu der Erkenntnis, dass das da auch so gemacht wird, jedoch auf 14-bit PWM gesetzt wird.
Output.cpp Zeile 444-454
#if defined(MEGA)
#if (NUMBER_MOTOR > 0)
// init 16bit timer 3
TCCR3A |= (1<<WGM31); // phase correct mode
TCCR3A &= ~(1<<WGM30);
TCCR3B |= (1<<WGM33);
TCCR3B &= ~(1<<CS31); // no prescaler
ICR3 |= 0x3FFF; // TOP to 16383;

TCCR3A |= _BV(COM3C1); // connect pin 3 to timer 3 channel C
#endif
Das ist dann auch auf jeden Fall schneller als analogWrite(), da du direkt in die Register schreibst.
 

das_copter_198

Erfahrener Benutzer
#48
Hallo,

ich hätte noch mal eine Frage. In der Output.cpp steht: OCR3C = motor[0]<<3; // pin 3

OCR3C steht für den PIN 3, so viel weiß ich. Aber das bedeutet das <<3? Das kommt immer wieder im Multiwii Code vor aber ich weiß einfach nicht was das bedeutet.

Lg Vincent

P.s: <<3 soll < < 3 ohne Leerzeichen bedeuten. Leider wurde ein Herz daraus ;)
 

das_copter_198

Erfahrener Benutzer
#53
Hallo,

ich hätte noch ein paar Fragen zu dem PWM Signal bzw. ob das richtig ist was ich denke ;) Also ein Arduino hat meistens mehrere Timer. Die Timer werden so benannt TCCRXY. X ist dann die "Auflösung", also ob es ein 8-Bit Timer ist oder ein 11-Bit. Die Y steht dann für die Register, bzw. so wie das genannt wird, also z.B. A oder B oder auch C. Und jeder Timer kann mit 2 Pins verbunden werden. Stimmt das soweit schon mal?

Lg Vincent
 

donvido

Erfahrener Benutzer
#54
Nicht ganz. TCCRnX ist das Timer/Counter Control Register und das gibts für jeden Timer n als A und B Register (X) und legt zum Beispiel den PWM-Modus fest und ob ein Pin mit dem Timer verknüpft ist. Welche Auflösung welcher Timer hat, erfährst du im Datenblatt. Beim Mega sind 1,3,4,5 16-Bit Timer und 0 und 2 sind 8-Bit Timer. Die 8-Bit Timer sind nur mit 2 Pins verknüft und die 16-Bit Timer bist auf Timer 1 mit 3 Pins. Die Auflösung und Frequenz des PWM-Signals wird am Ende durch den PWM-Modus und den Prescaler bestimmt.
Und ein
TCCR5A=0;
TCCR5A |= (1 << 3);
Ist das gleiche wie
TCCR5A=0b00000000;
TCCR5A=TCCR5A|0b00001000;
Das ergibt am Ende also
0b00000000|0b00001000=0b00001000
udn wird einfach verwendet um die Bits in den Registern zu setzen.
 

das_copter_198

Erfahrener Benutzer
#55
Hallo,

das ist schon mal seht hilfreich.

#if defined(MEGA)
#if (NUMBER_MOTOR > 0)
// init 16bit timer 3
TCCR3A |= (1<<WGM31); // phase correct mode
TCCR3A &= ~(1<<WGM30);
TCCR3B |= (1<<WGM33);
TCCR3B &= ~(1<<CS31); // no prescaler
ICR3 |= 0x3FFF; // TOP to 16383;

TCCR3A |= _BV(COM3C1); // connect pin 3 to timer 3 channel C
#endif
#if (NUMBER_MOTOR > 1)
TCCR3A |= _BV(COM3A1); // connect pin 5 to timer 3 channel A
#endif
#if (NUMBER_MOTOR > 2)
// init 16bit timer 4
TCCR4A |= (1<<WGM41); // phase correct mode
TCCR4A &= ~(1<<WGM40);
TCCR4B |= (1<<WGM43);
TCCR4B &= ~(1<<CS41); // no prescaler
ICR4 |= 0x3FFF; // TOP to 16383;

TCCR4A |= _BV(COM4A1); // connect pin 6 to timer 4 channel A
#endif
#if (NUMBER_MOTOR > 3)
TCCR3A |= _BV(COM3B1); // connect pin 2 to timer 3 channel B
#endif
#endif
In dem Code vom Mega, wird doch zuerst der Timer 3, 16bit Timer, initialisiert. Danach wird Pin 3 & Pin 5 mit diesem Timer verbunden. Dann wird auch noch der der Timer 4 initialisiert. Und an Timer 4 werden dann sowohl Pin 6 als auch Pin 2 angeschlossen. So weit verstehe ich das. Wo ich noch Probleme habe:

TCCR3A |= (1<<WGM31); // phase correct mode
TCCR3A &= ~(1<<WGM30);
TCCR3B |= (1<<WGM33);
TCCR3B &= ~(1<<CS31); // no prescaler
ICR3 |= 0x3FFF; // TOP to 16383;
Es werden da TCCR3A und TCCR3B behandelt. Für was stehen WGM31, WGM30, WGM33 und CS31? Und das passiert in den ersten 4 Zeilen? Wird in der 5 zeile dann die Frequenz oder sowas ähnliches festgelegt(stand in Internet ;) )?

Lg Vincent
 

donvido

Erfahrener Benutzer
#56
WGMn0 bis WGMn3 (n entspricht Timer) sind die Waveform Generation Mode Bits, die den PWM-Modus festlegen. Die 16-Bit Timer haben 16 verschiedene Modi, die 8-Bit Timer nur 8.

CSn0 bis CSn2 sind die Clock Select Bits, welche für den Prescaler zuständig sind. Man kann wählen zwischen 1, 8, 64, 256, 1024, "external clock on falling edge" und "external clock on rising edge"

Die 5. Zeile legt den TOP Wert fest und damit die Auflösung.
Die Dauer einer PWM-Periode beträgt im "phase correct mode" (2*Prescaler*Auflösung)/Taktfrequenz

Das macht 2*1*16383/16.000.000=2,05ms. Das entspricht 488,3 Hz.

Anderes Beispiel:
Prescaler 8
Phase Correct Mode
Auflösung 11-bit

16.000.000/(2*8*2047)=488,5Hz
 

das_copter_198

Erfahrener Benutzer
#57
Also sind diese 5 Zeilen dafür das der Timer 3 richtig festgelegt wird. Und dann auch genutzt werden kann. Für das Mega werden in der initOutput() die Timer richtig festgelegt und mit dem Pin verbunden. Der genutzte Timer 3 ist ein 16Bit Timer. Bleibt das dann ein 16Bit Signal oder wird daraus dann noch ein 11Bit oder 14Bit Signal bzw. wo genau wird das umgewandelt?
 

donvido

Erfahrener Benutzer
#58
Der 16-Bit Timer zählt bis 65535 bis er wieder auf Null gesetzt wird. Das heißt er zählt bei 16MHz Taktrate 244 mal pro Sekunde bis 65535. Man könnte also auch ein 16-Bit Signal ausgeben, jedoch nur mit einer maximalen Frequenz von 244Hz. Für die ESCs werden aber um die 500Hz benötigt.
Also bräuchte man mindestens 15-bit Fast-PWM um auf 488Hz zu kommen.
Fast-PWM zählt immer von 0-Top, Phase Correct dagegen von 0 bis Top und anschließend von Top bis 0 (deshalb die 2 in der Frequenzberechnung)
Im Multiwii Code wird der TOP-Wert auf 14-Bit (16383) gesetzt. Das heißt, es wird nur noch bis 16383 gezählt. Eine Zählperiode ist damit schneller vorbei als bei 16-Bit.
In meinem Beispiel ist TOP=2047, da aber ein Prescaler (8) gesetzt ist, dauert es genausolange (2048*8=16384) wie im Multiwii-Beispiel.
Die Auflösung des Signals entspricht also dem gesetzten Top-Wert.
 

das_copter_198

Erfahrener Benutzer
#59
Danke, für die Erklärung :) Ich will ein Arduino Uno benutzen, mit einem Atmega328. Laut Datenblatt hat der nur einen 16Bit was zu wenig ist und 2 8Bit Timer. Das würde heißen, dass ich die 8Bit Timer nutzen werde. Das wäre das selbe wie ein ProMini im Multiwii Sketch. Und dort steht in der Init: TCCR1A |= _BV(COM1A1);
Bedeutet das, dass ich mir für einen 8Bit Timer den Rest sparren kann und einfach nur diese Zeile in der Init schreiben muss oder?
 

donvido

Erfahrener Benutzer
#60
Der Uno bietet auf den Pins 9 und 10 auch 16-Bit PWM. Ich bin mir nicht sicher, aber ich vermute wenn das so wie bei MultiWii gemacht wird, dann sind Standard Prescaler = 64 und Standard PWM Mode = PhaseCorrect.
Das ergibt 16.000.000/(2*64*255)=490Hz.
Macht bei einem Quadro Copter bloß nicht viel Sinn 2 Motoren mit 8-Bit Signal anzusteuern und die anderen 2 mit 14-Bit.
 
FPV1

Banggood

Oben Unten