Brushless Motor per Arduino steuern

donvido

Erfahrener Benutzer
Du kannst ja einfach mal die Register auslesen und gucken, ob die einen Standardwert haben. 8Bit bekommst du auf jeden Fall immer mit analogWrite(), egal welcher Timer.
 

das_copter_198

Erfahrener Benutzer
Ich bin gerade ein bisschen verwirt. Also Multiwii nutz für einen Atmega328P, denn auch das Uno hat, die Timer 1(16Bit) und Timer 2(8Bit). Zum Initialisieren werden nur die Pins mit den Timern verbunden und sonst nichts. Außerdem werden an alle 4 Pins die selben Werte übergeben, egal ob 8 oder 16Bit Timer. Warum wird nicht der Mode und der Prescale bestimmt? Denn in dem Code vom Mega wird das gemacht. Und warum wird einen 16Bit Timer ein 8Bit Signal gegeben?
 

donvido

Erfahrener Benutzer
In der Tat sehr merkwürdig.
Wenn du mal das Datasheet checkst, wirst du feststellen, dass der Initialwert von TCCR2A und TCCR2B 0b00000000 ist.
Das bedeutet laut Datenblatt, dass der jeweilige Timer gestoppt ist. Es dürfte also nichtmal ein PWM-Signal auf den Pins geben.
Wenn ich aber auf meinem Mega einfach mal die Register ausgeben lasse.
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.print("TCCR3A: ");
Serial.println(TCCR3A,BIN);

Serial.print("TCCR3B: ");
Serial.println(TCCR3B,BIN);

}
, dann erhalte ich für
TCCR3A = 0b00000001
und
TCCR3B = 0b00000011,

Also PWM Mode 1, Phase Correct, 8-bit und Prescaler 8, und das obwohl laut Datenblatt die Register auch Null sind.

Könnte mir vorstellen, dass das für den 328p also einfach weggelassen wurde.
 

das_copter_198

Erfahrener Benutzer
Ich habe mich gerade näher mit den Timer Counter Registern befasst. Timer 1 hat 16 Modes, ich werden den 8Bit Phase Correct nehmen und für Timer 2 werde ich natürlich auch den Phase Correct Mode nehmen. Mit einem Prescale von 64 müssten beide Timer ca. 490 Hz haben. Ich hätte noch eine Frage. Wenn ich zB. TCCR2A |= _BV(WGM20); schreibe wird dann nur der Bit WGM20 auf HIGH gesetzt?
 

das_copter_198

Erfahrener Benutzer
Wenn ich Timer 1 auf 64 Prescale haben möchte und 8Bit Phase Correct könnte ich schreiben:
TCCR1A |= _bv(WGM10);
TCCR1B |= _bv(CS10);
TCCR1B |= _bv(CS11);

Das sollte so doch funktionieren oder?
 

donvido

Erfahrener Benutzer
Für den Fall, dass vorher eine andere Konfiguration aktiv war, würde ich immer vorher die Register Null setzen.

TCCR1A =0;
TCCR1A |= _bv(WGM10);
TCCR1B =0;
TCCR1B |= _bv(CS10) | _bv(CS11);
 

das_copter_198

Erfahrener Benutzer
TCCR1A = 0; //Clears the register
TCCR1B = 0; //Clears the register
TCCR2A = 0; //Clears the register
TCCR2B = 0; //Clears the register

TCCR1A |= _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
TCCR1B |= _BV(CS10) | _BV(CS11);

TCCR2A |= _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
TCCR2B |= _BV(CS22);
Habe das jetzt als Konfiguration, dass müsst stimmen, die Motoren drehen sich auch alle :D
 

das_copter_198

Erfahrener Benutzer
Hallo,

ich wollte gerade mal testen ob eine PID Reglung funktioniert mit dem Gyro. Dafür habe ich folgenden Code einfach in den void loop() gepackt.
float PC = 2;
float IC = 1;
float DC = 0.4;

static int16_t error_summe = 0;
static int16_t error_old = 0;

int16_t error = 0 - gyroy_rate;

int16_t P = (int16_t)(error * PC);

error_summe += (error * dt);

int16_t I = (int16_t)(error_summe * IC);

int16_t D = (int16_t)((error - error_old) / dt * DC);

int16_t PID = P + I + D;
Stimmt der Code so?
Denn irgendwie will er nicht so richtig stehen bleiben. Das kann natürlich auch an den Settings liegen aber leider habe ich es noch nicht geschafft diese korrekt einzustellen.

LG Vincent
 

donvido

Erfahrener Benutzer
error_old wird nirgends aktualisierts

Wenn du einen stabilen Schwebeflug erreichen willst, wirst du Winkel regeln müssen und nicht deren Winkelgeschwindigkeiten.
Also eher so: int16_t error = 0 - gyroy_angle;
 

das_copter_198

Erfahrener Benutzer
Ja stimmt error_old zu aktualisieren habe ich vergessen. Ich habe gestern den Code auch leicht geändert, damit er mit dem Winkel von dem Kalmanfilter regelt. Ich werde heute dann noch mal einige Werte durchprobieren, damit er gerade bleibt ;) Mir ist noch aufgefallen das die Motoren nicht "schön" laufen, weil es hört sich teilweise sehr schlimm an. Kann man was dagegen machen?
 

das_copter_198

Erfahrener Benutzer
Hallo,

ich habe heute nochmal versucht die PID Werte einzustellen, aber irgendwie will der Copter nicht stabil bleiben. Wie stell ich die PID Werte am Besten ein bzw. gibt es ein Verfahren mit dem man die PID Werte gut einstellen kann, denn bis jetzt habe ich es nur geschafft, dass er mit P & I regelt, wenn ich dann aber D dazuschalte, stabilisiert er sich überhaupt nicht mehr.
 

das_copter_198

Erfahrener Benutzer
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
#include "Kalman.h"

//MPU
MPU6050 MPU6050;
int16_t accx, accy, accz, gyrox, gyroy, gyroz;
int16_t gyrox_rate, gyroy_rate, gyroz_rate;
int16_t accy_euler, accx_angle, accy_angle;
bool MPU6050_state;

//Kalman
Kalman kalmanX;
Kalman kalmanY;
uint32_t timer;
float kalman_anglex, kalman_angley;

void setup()
{
pinMode(3, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);

TCCR1A = 0;
TCCR1B = 0;
TCCR2A = 0;
TCCR2B = 0;

TCCR1A |= _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
TCCR1B |= _BV(CS10) | _BV(CS11);

TCCR2A |= _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
TCCR2B |= _BV(CS22);

//OCR1A = PIN 9
//OCR1B = PIN 10
//OCR2A = PIN 11
//OCR2B = PIN 3

OCR1A = 900>>3;
OCR1B = 900>>3;
OCR2A = 900>>3;
OCR2B = 900>>3;

delay(1000);

Wire.begin();

Serial.begin(9600);

MPU6050.initialize();
MPU6050_state = MPU6050.testConnection();

while(MPU6050_state == 0)
{
Serial.println("Keine Verbindung zu MPU");
delay(10000);
MPU6050_state = MPU6050.testConnection();
}
if(MPU6050_state == 1)
{
Serial.println("Verbindung zu MPU");
}
accy_euler = atan2(accy, accz);

accx_angle = (atan2(-accx, (accy*sin(accy_euler)+accz*cos(accy_euler)))) * 180 / 3.14;
accy_angle = (atan2(accy, accz)) * 180 / 3.14;

kalmanX.setAngle(accx_angle);
kalmanY.setAngle(accy_angle);

timer = micros();
}

void loop()
{
float dt = (float)(micros() - timer) / 1000000;
timer = micros();

MPU6050.setFullScaleGyroRange(MPU6050_GYRO_FS_2000); //Muss in void loop() sein
MPU6050.getMotion6(&accx, &accy, &accz, &gyrox, &gyroy, &gyroz);

accy_euler = atan2(accy, accz);

accx_angle = (atan2(-accx, (accy*sin(accy_euler)+accz*cos(accy_euler)))) * 180 / 3.14;
accy_angle = (atan2(accy, accz)) * 180 / 3.14;

gyrox_rate = (gyrox + 12) / 16.4;
gyroy_rate = (gyroy - 29) / 16.4;
gyroz_rate = (gyroz + 17) / 16.4;

kalmanX.setAngle(accx_angle);
kalmanY.setAngle(accy_angle);

kalman_anglex = kalmanX.getAngle(accx_angle, gyrox_rate, dt);
kalman_angley = kalmanY.getAngle(accy_angle, gyroy_rate, dt);

//RC
static int16_t throttle = 1300;

//PID Setup
float PC = 0.00;
float IC = 0.00;
float DC = 0.00;

//PID
float error = 0.00 - kalman_angley;
static float error_summe = 0;
static float error_old = 0;

int16_t P = (int16_t)(error * PC);

error_summe += (error * dt);

int16_t I = (int16_t)(error_summe * IC);

int16_t D = (int16_t)((error - error_old) * DC);

error_old = error;

//Motor
OCR1A = (throttle + P + D + I)>>3;
OCR1B = (throttle - P - D - I)>>3;
OCR2A = (throttle - P - D - I)>>3;
OCR2B = (throttle + P + D + I)>>3;
}
Der Code ist bis jetzt sehr einfach gehalten. Sollte ich D noch nur die Looptime teile oder muss das nicht sein?
 
FPV1

Banggood

Oben Unten