Forum: Mikrocontroller und Digitale Elektronik MPU 92.65 Winkel berechnen


von Marco (Gast)


Lesenswert?

Einen wunderschönen guten Abend wünsche ich euch. Probiere gerade einen 
Gyrosensor auszulesen und einen Winkel zu bestimmen. Mit dem 
Beschleunigungssensor vom Board geht es soweit auch wunderbar, aber 
leider schaffe ich das mit dem Gyrosensor nicht.
Als Sensor habe ich den MPU92.65.

Das mit dem Offset klappt denke ich so weit auch ganz gut. Jedoch hängt 
es gerade mit dem drauf Rechnen der Winkelbeschleunigungswerte. Hat von 
euch eventuell jmd einen Tipp oder Anregung.

1
#include "mbed.h"
2
#include "stdio.h"
3
4
Serial pc(SERIAL_TX, SERIAL_RX);
5
SPI spi(PE_6,PE_5,PE_2);  //mosi,miso,sclk
6
DigitalOut ncs(PE_4);    //ssel
7
8
int main()
9
{
10
    spi.format(8,0);
11
    spi.frequency(1000000); 
12
    
13
    int16_t z_high, z_low;
14
    int16_t z_summe_off;
15
    int16_t x_off, y_off;
16
    float gz, zz_summe_off, z_off;
17
    int16_t i;
18
    
19
    pc.printf("\n\r");
20
    
21
    /****************//******/
22
    /*Initialisieren*//*Gyro*/
23
    /****************//******/
24
    
25
    ncs=0;
26
    spi.write(0x1B);     //Gyro_CONFIG  write  
27
    spi.write(0x18);     //Skalierung    00=+250dps;08=+500dps;10=+1000dps;18=+2000dps
28
    ncs = 1;                
29
    wait_ms(1); 
30
    
31
    ncs = 0;
32
    spi.write(0x6B);     //Standby aus
33
    spi.write(0x00);     
34
    ncs = 1;               
35
    wait_ms(1000); 
36
    
37
    z_summe_off = 0;
38
39
    /********//******/
40
    /*Offset*//*Gyro*/
41
    /********//******/ 
42
    
43
    for(i = 1;i <= 4000; i++)
44
    {
45
        ncs = 0;
46
        spi.write(0xc7);            //Z_OUT_H
47
        z_high = spi.write(0x0);
48
        ncs = 1;
49
        wait_ms(1); 
50
           
51
        ncs = 0;
52
        spi.write(0xc8);            //Z_OUT_L
53
        z_low = spi.write(0x0);
54
        ncs = 1;
55
        wait_ms(1); 
56
            
57
        z_summe_off = z_low + z_high << 8;
58
        zz_summe_off += z_summe_off;
59
    }
60
    pc.printf("\nOffset1:\n\rZ = %2.2f\n\r", zz_summe_off/4000.00);
61
    z_off = zz_summe_off/4000.00;
62
    pc.printf("\nOffset2:\n\rZ = %2.2f\n\r", z_off);
63
    /********//******/
64
    /*Messen*//*Gyro*/
65
    /********//******/     
66
    while(1)
67
    {  
68
        ncs = 0;
69
        spi.write(0xc7);            //Z_OUT_H
70
        z_high = spi.write(0x0);
71
        ncs = 1;
72
        wait_ms(1); 
73
           
74
        ncs = 0;
75
        spi.write(0xc8);            //Z_OUT_L
76
        z_low = spi.write(0x0);
77
        ncs = 1;
78
        wait_ms(1); 
79
                     
80
        z_summe_off = z_low + z_high << 8;  //Werte addieren
81
        pc.printf("Z_summe_off = %#6ld\t", z_summe_off);
82
        gz += (z_summe_off + z_off);
83
   
84
        pc.printf("Z = %2.2f\t\r", gz/22.2);
85
    }
86
}

von jemand (Gast)


Lesenswert?

Ein Gyro misst die Winkelgeschwindigkeit. Um auf einen Winkel zu kommen, 
muss über die Zeit integriert (aka aufsummiert) werden, aber eine 
Multiplikation mit einer Zeitdifferenz sehe ich in deinem Code nirgens.

von Yalu X. (yalu) (Moderator)


Lesenswert?

zz_summe_off wird anfangs nicht auf 0 gesetzt. Dadurch ist der
ermittelte Offset möglicherweise falsch. Auch gz sollte initialisiert
werden, um nachvollziehbare Ergebnisse zu erhalten. Vielleicht haben
beide Variablen anfangs zufälligerweise den Wert 0, aber garantiert ist
das in C nicht.

Das eigentliche Problem liegt aber hier:

1
        gz += (z_summe_off + z_off);

Du musst den Offset nicht addieren, sondern subtrahieren:

1
        gz += (z_summe_off - z_off);

Des Weiteren vermisse ich hier (wie auch "jemand") einen Zeitfaktor. Um
von der Winkelgeschwindigkeit auf einen Winkeländerung zu kommen, musst
du erstere mit der Zeitdauer zwischen jeweils zwei Sensorabfragen
multiplizieren, also:

1
        gz += (z_summe_off - z_off) * delta_t;

Bei konstanter Abfragerate kannst du delta_t auf einen festen Wert
setzen, andernfalls musst du delta_t für jede Abfrage mittels Timer
bestimmen.

Abgesehen davon sind deine Variablennamen teilweise sehr verwirrend.
Warum heißt bspw. die Winkelgeschwindigkeit in der while-Schleife
z_summe_off?

von Marco (Gast)


Lesenswert?

Wieder einmal wünsche ich euch einen wunderschönen Guten Abend und 
bedanke mich bei yalau und dem netten Gast für die Tipps.

@yalu Kannst du mir mal einen kleinen Denkanstoß geben, wie ich die 
Zeitkonstante Variabel über einen Timer lösen kann. Habe mich schon die 
ganze Zeit gefragt, wie das mit der Zeitkonstante gehen soll. Hier in 
meinem Code ist ja der Ablauf periodisch, aber wenn dem nicht so wäre, 
hätte man ja nie einen genauen Messwert.

Dadurch das ich den Offset jetzt Subtrahiere und eine Zeitkonstante mit 
eingebaut habe, bleibt der Winkel relativ Konstant bei 0°. Wenn ich mir 
auch ganz viel Zeit nehme und den Sensor sehr sehr langsam um 90° Drehe, 
lande ich auch bei 90° und nach dem zurück drehen wieder bei 0°.

Wenn ich den Sensor aber schnell um 90° Drehe, werden die Werte 
verschluckt und der Winkel ändert sich vielleicht um 2-3°. Dachte es 
liegt daran, das ich jeden Wert am Rechner ausgebe, aber daran liegt es 
leider nicht.

Habe den Code auch mal aufgeräumt und ein wenig "lesbarer" gemacht :)

Was mich auch sehr wundert, meine Zeitkonstante ist 0,5625µs. Wenn ich 
mir aber ein Messdurchlauf anschaue, messe ich 2,2µs.

Vielleicht hat von euch jmd noch einen Tipp für mich. Drehe mich 
irgendwie im Kreis.

1
#include "mbed.h"
2
#include "stdio.h"
3
4
Serial pc(SERIAL_TX, SERIAL_RX);
5
SPI spi(PE_6,PE_5,PE_2);  //mosi,miso,sclk
6
DigitalOut ncs(PE_4);    //ssel
7
8
int main()
9
{
10
    spi.format(8,0);
11
    spi.frequency(1000000); 
12
    
13
    int16_t z_high, z_low, z_high_low;
14
    float z_winkel, z_off, z_high_low_summe;
15
    int16_t i;
16
    
17
    pc.printf("\n\r");
18
    
19
    /****************//******/
20
    /*Initialisieren*//*Gyro*/
21
    /****************//******/
22
    ncs = 0;
23
    spi.write(0x6B);     // Register 107
24
    spi.write(0x80);     //Reset // Standby off
25
    ncs = 1;               
26
    wait_ms(1000); 
27
    
28
        
29
    ncs=0;
30
    spi.write(0x1A);     //CONFIG  write // DLPF_CFG // Register 26
31
    spi.write(0x00);     //Bandwidth: 250Hz// Delay: 0.97ms// Fs: 8kHz
32
    ncs = 1;                
33
    wait_ms(1);
34
    
35
    ncs=0;
36
    spi.write(0x1A);     //CONFIG  write//DLPF_CFG // Register 27
37
    spi.write(0x00);     //Bandwidth: 250Hz// Delay: 0.97ms// Fs: 8kHz
38
    ncs = 1;                
39
    wait_ms(1);
40
    
41
    ncs=0;
42
    spi.write(0x1B);     //Gyro_CONFIG  write  
43
    spi.write(0x18);     //Max. Skalenwert//00=+250dps;08=+500dps;10=+1000dps;18=+2000dps
44
    ncs = 1;                
45
    wait_ms(1); 
46
    
47
48
    z_high = 0; 
49
    z_low = 0;
50
    z_high_low = 0;
51
    z_high_low_summe = 0;
52
    z_winkel = 0;
53
    z_off = 0;
54
    i = 0;
55
56
    /********//******/
57
    /*Offset*//*Gyro*/
58
    /********//******/ 
59
     
60
    for(i = 1;i <= 4000; i++)
61
    {
62
        ncs = 0;
63
        spi.write(0xc7);            //Z_OUT_H
64
        z_high = spi.write(0x0);
65
        ncs = 1;
66
        wait_ms(1); 
67
           
68
        ncs = 0;
69
        spi.write(0xc8);            //Z_OUT_L
70
        z_low = spi.write(0x0);
71
        ncs = 1;
72
        wait_ms(1); 
73
            
74
        z_high_low = z_low + z_high << 8;   
75
        z_high_low_summe += z_high_low;
76
    }
77
    pc.printf("\nOffset:\n\rZ = %2.2f\n\r", z_high_low_summe/4000.00);
78
    z_off = z_high_low_summe/4000.00;
79
    
80
81
    /********//******/
82
    /*Messen*//*Gyro*/
83
    /********//******/   
84
    z_high_low_summe = 0; 
85
    i = 0; 
86
    while(1)
87
    {  
88
        i++;    //Zähler fpr den Printf
89
        
90
        ncs = 0;
91
        spi.write(0xc7);            //Z_OUT_H
92
        z_high = spi.write(0x0);
93
        ncs = 1;
94
        wait_ms(1);
95
           
96
        ncs = 0;
97
        spi.write(0xc8);            //Z_OUT_L
98
        z_low = spi.write(0x0);
99
        ncs = 1;
100
        wait_ms(1);
101
                     
102
        z_high_low = z_low + z_high << 8;                   //Low und High Byte zusammenfügen
103
        z_high_low_summe = z_high_low - z_off;              //Offset vom Messwert subtrahieren
104
        z_winkel = z_winkel + (z_high_low_summe * 0.0000005625);   //Messwert multipliziert mit der Zeitdifferenz
105
        if (i == 1000)
106
        {
107
            pc.printf("z_Winkel: = %3.5f\t\r", z_winkel); 
108
            i = 0;
109
        }
110
    }
111
}

von Marco (Gast)


Lesenswert?

Einen schönen Sonntag wünsche ich euch alle.

Habe jetzt meinen Code nocheinmal geändert und einen timer integriert.

So weit geht die Messung, jedoch nur bei langsamen Änderungen und was 
ich auch nicht verstehe, trotz des Timers muss ich noch mit einen festen 
Wert multiplizieren, um die Änderungen in Winkel zu haben.

Meine Einstellungen:
Full Scale Range: +-2000 °/s
Sensitivity Scale Factor: 16.4LSB/(º/s)

Bin auch so langsam mit meinem Latein am Ende und weiß nicht was ich 
noch machen kann -.- Ein Schleifendurchlauf dauert 119µs und die 
Abtastrate vom Sensor ist 8000Hz, also alle 125µs einmal Abtasten
1
    /********//******/
2
    /*Messen*//*Gyro*/
3
    /********//******/   
4
    z_high_low_summe = 0; 
5
    i = 0; 
6
    while(1)
7
    {  
8
        i++;    //Zähler fpr den Printf
9
        timer.start();
10
        
11
        ncs = 0;
12
        spi.write(0xc7);            //Z_OUT_H
13
        z_high = spi.write(0x0);
14
        ncs = 1;
15
        wait_us(1);
16
           
17
        ncs = 0;
18
        spi.write(0xc8);            //Z_OUT_L
19
        z_low = spi.write(0x0);
20
        ncs = 1;
21
        wait_us(70);
22
        zeit = timer.read_us();
23
        timer.reset();
24
        timer.start();
25
                     
26
        z_high_low = z_low + z_high << 8;                   //Low und High Byte zusammenfügen
27
        z_high_low_summe = z_high_low - z_off;              //Offset vom Messwert subtrahieren
28
        z_winkel = z_winkel + (z_high_low_summe * zeit * 0.0000000003);   //Messwert multipliziert mit der Zeitdifferenz
29
        if (i == 30000)
30
        {
31
            pc.printf("z_Winkel: = %3.5f\t%10luµs\r", z_winkel, zeit); 
32
            i = 0;
33
        }
34
    }
35
}

von Marco (Gast)


Lesenswert?

Habe jetzt das Geheimnis gelüftet, es lag daran, das ich das high byte 
mit dem low byte addirt habe und nicht verodert

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.