addi241
30.07.2014, 22:39
Hallo Community!
Ich bin schon seit längerer Zeit hier im Forum Mitleser und habe bereits einige nützliche Informationen erhalten, auch für mein aktuelles Projekt (einen Quadrocopter zu bauen :) ). Doch nun stehe ich vor einem Problem, das mich seit Tagen verwirrt. :confused:
Ich habe einen zentralen Controller (Atmega644PA), der den Sensor ausliest (MPU6050), alle Berechnungen durchführt und die Daten für die Geschwindigkeit an die 4 Motorregler (Atmega88A) überträgt.
Die gesamte Kommunikation zwischen den Bauteilen läuft über I2C (mit der fleury-lib) , jedoch nur etwa 0-30sec, danach funktioniert der I2C-Part nicht mehr. Doch nun ein wenig genauer:
Was ich bisher getestet habe:
- Auslesen des Sensors + Berechnung (Winkel, PID (aktuell nur P)) und Ausgabe auf einem LCD Display (es werden die Werte genauso angezeigt wie sie zu einem Motorregler gesendet werden würden) Das funktioniert wunderbar, auch beliebig lange.
- Kommunikation mit den Reglern (Atmega88A als Slave) und Motorsteuerung. Die Regler (+Software) sind ein Nachbau der Regler von Ulrich Radig. Die Motoren fahren langsam hoch und starten wieder von vorne, das Ganze ebenfalls beliebig lange.
Hier die main für die Augabe aufm LCD:
while(1){
while(a!=1); // wait until timer1 overflow (sets a=1) -> constant sample rate (500Hz)
a=0;
get_gyro_data(gyro_data); //gyro_data -> uint16_t , reads raw data from MPU6050
get_acc_data(acc_data);
//complementary filter + angle calculation in degrees
angle_calculation(acc_data,gyro_data,gyro_data_off set,&pitch,&roll); //gyro_data_offset -> uint16_t, pitch/roll -> float
pid_calculation(0,&pitch,&pid_pitch); //pid_pitch -> int16_t
motora+=pid_pitch; //motora -> uint8_t
i2c_send_data_to_lcd(motora); //sends data to lcd display
}
Und hier für die Motoren:
while(1){
while(a!=1); // wait until timer1 overflow (sets a=1) -> 10Hz
a=0;
motora++;
motorb++;
i2c_start(MOTORA+I2C_WRITE); //MOTORA: adress of motor A
i2c_write(motora);
i2c_stop();
i2c_start(MOTORB+I2C_WRITE); //MOTORB: adress of motor B
i2c_write(motorb);
i2c_stop();
}
Da beides so sehr gut funktioniert kann ich eigentlich ein Hardware-Fehler ausschließen. Trotzdem hier noch kurz: Pull-ups für I2C sind 4,7k, der MPU6050 ist über einen Pegelwandler, bestehend aus 2 Transistoren (siehe AN10441), angeschlossen. Stromversorgung ist ein 3S Lipo (mit 78S05 für die 5V). Elkos müssten genug 1mF low-esr drauf sein). Wenn ein Schaltplan hilfreich ist, stell ich ihn auch noch rein.
Tja nur zusammen läuft es nicht wirklich. Wenn ich die berechneten Werte, statt an das Display, an die Regler schicke, dann läuft es maximal 30 Sekunden, dann bricht die Kommunikation zusammen. Innerhalb dieser 30 sec stabilisiert sich aber mein quad 1achsig auf einer Holzkonstruktion (und schwingt dabei, ist aktuell ja nur ein P-Regler). Immerhin etwas :D
Bei den Reglern kommt es zu einem i2c-timeout. d.h. es werden keine neuen Werte mehr vom Atmega644PA versendet und die Motoren gehen aus.
Der Atmega644PA hängt sich aber nicht vollkommen auf. In der ISR für den Timer1 habe ich einen Zähler eingebaut, der eine LED blinken lässt. Gehen die Motoren aus, blinkt diese weiter.
-> d.h. die while(1) schleife hängt irgendwo nach 30sec fest.
Dann habe ich eine Variable drin, die überprüft ob sie von der while(1) schleife zurückgesetzt wurde (d.h. die schleife noch aktiv ist), wenn sie in der ISR abgefragt wird.
Wenn sie nicht zurückgesetzt wurde dann resete ich das TWI und übertrage neue Daten an den Motor (langsames hochfahren), dann läuft er wieder!
Hier die ISR:
ISR(TIMER1_COMPA_vect){
if(b==1){ //d=1 if while(1) in main does nothing -> reset TWI + send new datas to motor
TWCR &= ~((1 << TWSTO) | (1 << TWEN));
TWCR |= (1 << TWEN);
for(int b=0;b<50;b++){ //shows that I2C works again
i2c_start(MOTORC+I2C_WRITE);
i2c_write(b);
i2c_stop();
_delay_ms(100);
}
}
a=1; //for while(1)
DDRB|=(1<<PB1);
if(c==250){
PORTB^=(1<<PB1); //toggle green led (=ISR works)
c=0;
}
c++;
}
Der Fehler, wo es nun hängt liegt offenbar in der Funktion i2c_start(), genauer hier:
Die LED bleibt an, der Controller hängt in dieser Schleife. Anscheinend kommt kein ACK/NACK mehr zurück. Überprüfen kann ich das leider nicht, meine Soundkarte als Oszi ist nicht schnell genug ;) btw die i2c-Frequenz zu senken bringt leider nichts, im Gegensatz selbst TWBR=5; (~760kHz) funktioniert.
unsigned char i2c_start(unsigned char address)
{
//....... other code
PORTB|=(1<<PB3); //red led = on
// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT)));
PORTB&=~(1<<PB3); //red led = off
//....... other code
}
Eine Lösung wäre in der ISR TWI zu resetten und dann an den Anfang der Schleife zu springen, aber das ist, soweit ich weiß, ein nogo... Ein Watchdog kommt eher nicht in Frage da ich am Anfang vom Programm ja den Gyro-Offset bestimmen muss und zudem noch andere Einstellungen vornehmen muss. Außerdem suche ich nach einem Weg das Hängenbleiben zu vermeiden. Ständige Resets in einem Quadrocopter sind nicht das wahre ;)
28775
28783 28781 28780 28779 28778 28776 28782 28777
Vielen Dank im Voraus! :D
mfg adrian
Ich bin schon seit längerer Zeit hier im Forum Mitleser und habe bereits einige nützliche Informationen erhalten, auch für mein aktuelles Projekt (einen Quadrocopter zu bauen :) ). Doch nun stehe ich vor einem Problem, das mich seit Tagen verwirrt. :confused:
Ich habe einen zentralen Controller (Atmega644PA), der den Sensor ausliest (MPU6050), alle Berechnungen durchführt und die Daten für die Geschwindigkeit an die 4 Motorregler (Atmega88A) überträgt.
Die gesamte Kommunikation zwischen den Bauteilen läuft über I2C (mit der fleury-lib) , jedoch nur etwa 0-30sec, danach funktioniert der I2C-Part nicht mehr. Doch nun ein wenig genauer:
Was ich bisher getestet habe:
- Auslesen des Sensors + Berechnung (Winkel, PID (aktuell nur P)) und Ausgabe auf einem LCD Display (es werden die Werte genauso angezeigt wie sie zu einem Motorregler gesendet werden würden) Das funktioniert wunderbar, auch beliebig lange.
- Kommunikation mit den Reglern (Atmega88A als Slave) und Motorsteuerung. Die Regler (+Software) sind ein Nachbau der Regler von Ulrich Radig. Die Motoren fahren langsam hoch und starten wieder von vorne, das Ganze ebenfalls beliebig lange.
Hier die main für die Augabe aufm LCD:
while(1){
while(a!=1); // wait until timer1 overflow (sets a=1) -> constant sample rate (500Hz)
a=0;
get_gyro_data(gyro_data); //gyro_data -> uint16_t , reads raw data from MPU6050
get_acc_data(acc_data);
//complementary filter + angle calculation in degrees
angle_calculation(acc_data,gyro_data,gyro_data_off set,&pitch,&roll); //gyro_data_offset -> uint16_t, pitch/roll -> float
pid_calculation(0,&pitch,&pid_pitch); //pid_pitch -> int16_t
motora+=pid_pitch; //motora -> uint8_t
i2c_send_data_to_lcd(motora); //sends data to lcd display
}
Und hier für die Motoren:
while(1){
while(a!=1); // wait until timer1 overflow (sets a=1) -> 10Hz
a=0;
motora++;
motorb++;
i2c_start(MOTORA+I2C_WRITE); //MOTORA: adress of motor A
i2c_write(motora);
i2c_stop();
i2c_start(MOTORB+I2C_WRITE); //MOTORB: adress of motor B
i2c_write(motorb);
i2c_stop();
}
Da beides so sehr gut funktioniert kann ich eigentlich ein Hardware-Fehler ausschließen. Trotzdem hier noch kurz: Pull-ups für I2C sind 4,7k, der MPU6050 ist über einen Pegelwandler, bestehend aus 2 Transistoren (siehe AN10441), angeschlossen. Stromversorgung ist ein 3S Lipo (mit 78S05 für die 5V). Elkos müssten genug 1mF low-esr drauf sein). Wenn ein Schaltplan hilfreich ist, stell ich ihn auch noch rein.
Tja nur zusammen läuft es nicht wirklich. Wenn ich die berechneten Werte, statt an das Display, an die Regler schicke, dann läuft es maximal 30 Sekunden, dann bricht die Kommunikation zusammen. Innerhalb dieser 30 sec stabilisiert sich aber mein quad 1achsig auf einer Holzkonstruktion (und schwingt dabei, ist aktuell ja nur ein P-Regler). Immerhin etwas :D
Bei den Reglern kommt es zu einem i2c-timeout. d.h. es werden keine neuen Werte mehr vom Atmega644PA versendet und die Motoren gehen aus.
Der Atmega644PA hängt sich aber nicht vollkommen auf. In der ISR für den Timer1 habe ich einen Zähler eingebaut, der eine LED blinken lässt. Gehen die Motoren aus, blinkt diese weiter.
-> d.h. die while(1) schleife hängt irgendwo nach 30sec fest.
Dann habe ich eine Variable drin, die überprüft ob sie von der while(1) schleife zurückgesetzt wurde (d.h. die schleife noch aktiv ist), wenn sie in der ISR abgefragt wird.
Wenn sie nicht zurückgesetzt wurde dann resete ich das TWI und übertrage neue Daten an den Motor (langsames hochfahren), dann läuft er wieder!
Hier die ISR:
ISR(TIMER1_COMPA_vect){
if(b==1){ //d=1 if while(1) in main does nothing -> reset TWI + send new datas to motor
TWCR &= ~((1 << TWSTO) | (1 << TWEN));
TWCR |= (1 << TWEN);
for(int b=0;b<50;b++){ //shows that I2C works again
i2c_start(MOTORC+I2C_WRITE);
i2c_write(b);
i2c_stop();
_delay_ms(100);
}
}
a=1; //for while(1)
DDRB|=(1<<PB1);
if(c==250){
PORTB^=(1<<PB1); //toggle green led (=ISR works)
c=0;
}
c++;
}
Der Fehler, wo es nun hängt liegt offenbar in der Funktion i2c_start(), genauer hier:
Die LED bleibt an, der Controller hängt in dieser Schleife. Anscheinend kommt kein ACK/NACK mehr zurück. Überprüfen kann ich das leider nicht, meine Soundkarte als Oszi ist nicht schnell genug ;) btw die i2c-Frequenz zu senken bringt leider nichts, im Gegensatz selbst TWBR=5; (~760kHz) funktioniert.
unsigned char i2c_start(unsigned char address)
{
//....... other code
PORTB|=(1<<PB3); //red led = on
// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT)));
PORTB&=~(1<<PB3); //red led = off
//....... other code
}
Eine Lösung wäre in der ISR TWI zu resetten und dann an den Anfang der Schleife zu springen, aber das ist, soweit ich weiß, ein nogo... Ein Watchdog kommt eher nicht in Frage da ich am Anfang vom Programm ja den Gyro-Offset bestimmen muss und zudem noch andere Einstellungen vornehmen muss. Außerdem suche ich nach einem Weg das Hängenbleiben zu vermeiden. Ständige Resets in einem Quadrocopter sind nicht das wahre ;)
28775
28783 28781 28780 28779 28778 28776 28782 28777
Vielen Dank im Voraus! :D
mfg adrian