PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : MultiIO & RP6M256 - GYRO-Demo



Dirk
27.07.2013, 18:49
Hallo MultiIO-Fans,

in der Demo für die Orientation-Lib haben wir den GYRO L3GD20 auf der minIMU-9 v2 etwas vernachlässigt, bzw. nur die Werte der 3 Achsen ausgegeben.

Hier noch eine kurze Demo, die die Winkelgeschwindigkeiten, mit denen der RP6 sich bewegt oder bewegt wird, auf allen 3 Achsen auf dem LCD darstellt.


Datei: RP6M256_MultiIO_05_GYRO_01.c:

/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
* ************************************************** **************************
* Example: RP6M256 MultiIO
* Author(s): Dirk
* ************************************************** **************************
* Description:
* In this example we show a fifth test for the MultiIO Project Board.
* It tests the "Orientation Sensors" (GPS module, 2D-Compass and/or 9D-IMU).
*
* The following sensors are used:
* - NL-552ETTL GPS module (ELV No. 94241) with the u-blox5 UBX-G5000-BT GPS
* chipset
* - HDMM01 compass module (Pollin No. 810164) with the MEMSIC MMC2120MG
* 2-axis magnetometer
* - MinIMU-9 v2 IMU module (Pololu No. 1268) with the L3GD20 3-axis gyro and
* the LSM303DLHC 3-axis accelerometer and 3-axis magnetometer
*
* ################################################## ##########################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* You should also connect to it via WIFI.
* ################################################## ##########################
* ************************************************** **************************
*/

/************************************************** ***************************/
// Includes:

#include "RP6M256Lib.h" // The RP6 M256 Library.
// Always needs to be included!
#include "RP6I2CmasterTWI.h" // Include the I2C-Bus Master Library
#include "RP6M256uart1.h" // The RP6 M256 UART1 Library
#include <math.h>

/************************************************** ***************************/
/************************************************** ***************************/
// Include our new "RP6M256 Orientation library":
// (This is the library for accessing certain sensors connected to the
// MultiIO Project Board!)

#include "RP6M256_OrientationLib.h"

/************************************************** ***************************/
// Defines:

//#define CALIBRATION

/************************************************** ***************************/
// Variables:

double xdpsg = 0.0;
double ydpsg = 0.0;
double zdpsg = 0.0;
double last_xg = 0.0;
double last_yg = 0.0;
double last_zg = 0.0;

/************************************************** ***************************/

#define CTRL_REG5_FIFO_EN 0b01000000 // FIFO on
#define FIFO_CTRL_REG_BYPASS 0b00000000 // Bypass mode (default)
#define FIFO_CTRL_REG_FIFO 0b00100000 // FIFO mode
#define FIFO_CTRL_REG_STREAM 0b01000000 // Stream mode
#define FIFO_CTRL_REG_STREAM2FIFO 0b01100000 // Stream-to-FIFO mode
#define FIFO_CTRL_REG_BYPASS2STREAM 0b10000000 // Bypass-to-Stream mode

/**
* Call this once in order to use the 3D-Gyro
* with the FIFO in Stream mode.
*
* Hint: Interrupts or FIFO watermark infos are
* NOT used here!
*
*/
void L3GD20_initStreamMode(void)
{
// Choose Stream mode:
I2CTWI_transmit2Bytes(I2C_MULTIIO_L3GD20_ADR, FIFO_CTRL_REG, FIFO_CTRL_REG_STREAM);
mSleep(10);
// Activate FIFO:
I2CTWI_transmit2Bytes(I2C_MULTIIO_L3GD20_ADR, CTRL_REG5, CTRL_REG5_FIFO_EN);
mSleep(10);
}

#define DPS_PER_DIGIT 0.00875 // @ +-250 dps (default)
//#define DPS_PER_DIGIT 0.0175 // @ +-500 dps
//#define DPS_PER_DIGIT 0.07 // @ +-2000 dps

/**
* This is the L3GD20 gyroscope task.
*
* The task stores the averaged dps values in
* the global double variables xdpsg, ydpsg,
* zdpsg.
*
* ATTENTION: Stopwatch 7 is used for the GYRO
* task! Please do not use this
* stopwatch elsewhere in your
* program!
*
* Hint: You must calibrate the gyro carefully
* before using this task!
*
*/
void task_GYRO(void)
{
uint8_t readBuf[6];

if(getStopwatch7() > 100) // 100ms
{
I2CTWI_transmitByte(I2C_MULTIIO_L3GD20_ADR, (OUT_X_L | 0x80));
I2CTWI_readBytes(I2C_MULTIIO_L3GD20_ADR, readBuf, 6); // Read X-/Y-/Z-axis
// xb = y:
x_axisg = (readBuf[OUT_Y_H - OUT_X_L] << 8) + readBuf[OUT_Y_L - OUT_X_L];
// yb = -x:
y_axisg = (readBuf[OUT_X_H - OUT_X_L] << 8) + readBuf[OUT_X_L - OUT_X_L];
y_axisg *= -1;
// zb = z:
z_axisg = (readBuf[OUT_Z_H - OUT_X_L] << 8) + readBuf[OUT_Z_L - OUT_X_L];
normalizeL3GD20();
xg *= DPS_PER_DIGIT;
yg *= DPS_PER_DIGIT;
zg *= DPS_PER_DIGIT;
xdpsg = (last_xg + xg) / 2;
ydpsg = (last_yg + yg) / 2;
zdpsg = (last_zg + zg) / 2;
last_xg = xg;
last_yg = yg;
last_zg = zg;
setStopwatch7(0);
}
}

/************************************************** ***************************/

/**
* Write a floating point number to the LCD.
*
* Example:
*
* // Write a floating point number to the LCD (no exponent):
* writeDoubleLCD(1234567.890, 11, 3);
*
* The value of prec (precision) defines the number of decimal places.
* For 32 bit floating point variables (float, double ...) 6 is
* the max. value for prec (7 relevant digits).
* The value of width defines the overall number of characters in the
* floating point number including the decimal point. The number of
* pre-decimal positions is: (width - prec - 1).
*/
void writeDoubleLCD(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
dtostrf(number, width, prec, &buffer[0]);
writeStringLCD(&buffer[0]);
}

/************************************************** ***************************/
// I2C Error handler

/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P_WIFI("\nI2C ERROR - TWI STATE: 0x");
writeInteger_WIFI(errorState, HEX);
writeChar_WIFI('\n');
}

/************************************************** ***************************/
// Main function - The program starts here:

int main(void)
{
initRP6M256(); // Always call this first! The Processor will not work
// correctly otherwise.

initLCD(); // Initialize the LC-Display (LCD)
// Always call this before using the LCD!

setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);

writeString_P_WIFI("\n\nRP6M256 Multi IO Selftest 5 GYRO!\n");

// IMPORTANT:
I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
// with 100kHz SCL Frequency


// Register the event handler:
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

setLEDs(0b1111);

// Write a text message to the LCD:
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("RP6v2-M256-WIFI ", "Example Program");
mSleep(2500);
showScreenLCD("RP6M256 Multi IO", "Selftest 5 GYRO");
mSleep(2500);
clearLCD();

setLEDs(0b0000);

// ---------------------------------------

clearLCD();
startStopwatch1();
startStopwatch7(); // Used for GYRO task!

// IMPORTANT:
orientation_init(); // Orientation init!

L3GD20_initStreamMode(); // Gyro Stream mode init!

while(true)
{
#ifndef CALIBRATION
task_I2CTWI();
task_GYRO();
#endif
task_I2CTWI();
if(getStopwatch1() > 500) // 500ms
{
#ifdef CALIBRATION
// GYRO calibration part:
readL3GD20(); // Get sensor values
//normalizeL3GD20();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisg, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeIntegerLCD(y_axisg, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeIntegerLCD(z_axisg, DEC);
writeStringLCD_P(" ");
#else
// Display part:
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeDoubleLCD(xdpsg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeDoubleLCD(ydpsg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeDoubleLCD(zdpsg, 6, 1);
writeStringLCD_P(" ");
#endif
setStopwatch1(0);
}

}

return 0;
}


Bedingungen:
- Orientierungs-Lib und RP6M256_MultiIO.h im Programmverzeichnis
- In der RP6M256_Orientation.h NUR IMU_9D aktivieren und GET_TEMP auskommentieren
- Den GYRO sorgfältig kalibrieren, d.h. die Definitionen OFFSET_X/Y/Z in der RP6M256_Orientation.h so anpassen, dass die Sensor-Ausgabewerte (xg, yg, zg) bei nicht bewegtem RP6 um den Nullpunkt schwanken

Viel Spaß!

fabqu
28.07.2013, 12:29
Nicht schlecht ;)

Dirk
28.07.2013, 15:09
Hi Fabian!
Danke! :)

Es geht noch weiter mit einer 2. GYRO Demo:
Die GYRO Demo 1 weiter oben in diesem Thread ist ja ganz schön. Man kann die Drehgeschwindigkeit messen.
Leider hilft das nicht dabei, eine Winkelabweichung zu korrigieren.

Was heißt das? Nehmen wir an, der RP6 soll um 90° nach rechts drehen und dann wieder um 90° nach links. Dabei sollte er NATÜRLICH in der Ausgangsstellung wieder ankommen.
Mit der Odometrie gelingt das nicht gut. Man könnte das aber z.B. auch mit dem Magnetfeldsensor hinbekommen,- aber nur da, wo keine fremden Magnetfelder stören.

Der GYRO kann das am besten. Allerdings braucht man dann nicht die Winkelgeschwindigkeit, die der GYRO mißt, sondern den Winkel pro Zeiteinheit, den man integriert (aufsummiert), solange eine (Dreh-)Bewegung anliegt.

Hier also die 2. GYRO Demo, die die kumulierten Drehwinkel auf dem LCD anzeigt.
In Ruhelage des RP6 sollten die Werte bei 0 bleiben oder nur ganz langsam über die Zeit "wegdriften". Dieses Driften ist einerseits eine (schlechte) Gyro-Eigenschaft, die hoch temperaturabhängig ist und sich nicht beeinflussen läßt.
Andererseits: Wenn die Werte schnell (innerhalb weniger Sekunden) wegdriften, dann ist die Kalibrierung nicht sorgfältig genug gemacht worden. Wenn man das nicht besser hinkriegt, kann man auch den Wert von OFFSET_ZERO (aktuell 75) weiter erhöhen. Besser ist aber IMMER die gute Kalibrierung, weil durch die Erhöhung von OFFSET_ZERO die "Empfindlichkeit" für sehr langsame Drehungen geringer wird.

Datei: RP6M256_MultiIO_05_GYRO_02.c:

/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
* ************************************************** **************************
* Example: RP6M256 MultiIO
* Author(s): Dirk
* ************************************************** **************************
* Description:
* In this example we show a fifth test for the MultiIO Project Board.
* It tests the "Orientation Sensors" (GPS module, 2D-Compass and/or 9D-IMU).
*
* The following sensors are used:
* - NL-552ETTL GPS module (ELV No. 94241) with the u-blox5 UBX-G5000-BT GPS
* chipset
* - HDMM01 compass module (Pollin No. 810164) with the MEMSIC MMC2120MG
* 2-axis magnetometer
* - MinIMU-9 v2 IMU module (Pololu No. 1268) with the L3GD20 3-axis gyro and
* the LSM303DLHC 3-axis accelerometer and 3-axis magnetometer
*
* ################################################## ##########################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* You should also connect to it via WIFI.
* ################################################## ##########################
* ************************************************** **************************
*/

/************************************************** ***************************/
// Includes:

#include "RP6M256Lib.h" // The RP6 M256 Library.
// Always needs to be included!
#include "RP6I2CmasterTWI.h" // Include the I2C-Bus Master Library
#include "RP6M256uart1.h" // The RP6 M256 UART1 Library
#include <math.h>

/************************************************** ***************************/
/************************************************** ***************************/
// Include our new "RP6M256 Orientation library":
// (This is the library for accessing certain sensors connected to the
// MultiIO Project Board!)

#include "RP6M256_OrientationLib.h"

/************************************************** ***************************/
// Defines:

//#define CALIBRATION

/************************************************** ***************************/
// Variables:

double xdg = 0.0;
double ydg = 0.0;
double zdg = 0.0;

/************************************************** ***************************/

#define CTRL_REG5_FIFO_EN 0b01000000 // FIFO on
#define FIFO_CTRL_REG_BYPASS 0b00000000 // Bypass mode (default)
#define FIFO_CTRL_REG_FIFO 0b00100000 // FIFO mode
#define FIFO_CTRL_REG_STREAM 0b01000000 // Stream mode
#define FIFO_CTRL_REG_STREAM2FIFO 0b01100000 // Stream-to-FIFO mode
#define FIFO_CTRL_REG_BYPASS2STREAM 0b10000000 // Bypass-to-Stream mode

/**
* Call this once in order to use the 3D-Gyro
* with the FIFO in Stream mode.
*
* Hint: Interrupts or FIFO watermark infos are
* NOT used here!
*
*/
void L3GD20_initStreamMode(void)
{
// Choose Stream mode:
I2CTWI_transmit2Bytes(I2C_MULTIIO_L3GD20_ADR, FIFO_CTRL_REG, FIFO_CTRL_REG_STREAM);
mSleep(10);
// Activate FIFO:
I2CTWI_transmit2Bytes(I2C_MULTIIO_L3GD20_ADR, CTRL_REG5, CTRL_REG5_FIFO_EN);
mSleep(10);
}

#define DPS_PER_DIGIT 0.00875 // @ +-250 dps (default)
//#define DPS_PER_DIGIT 0.0175 // @ +-500 dps
//#define DPS_PER_DIGIT 0.07 // @ +-2000 dps
#define OFFSET_ZERO 75 // Zero offset (of raw values)
#define D_CORR_FACTOR 1.065 // Corrigation factor
#define GYRO_INTERVAL 50 // Measuring interval [ms]

/**
* This is the L3GD20 gyroscope task.
*
* The task stores the cumulated angle values in
* the global double variables xdg, ydg, zdg.
*
* ATTENTION: Stopwatch 7 is used for the GYRO
* task! Please do not use this
* stopwatch elsewhere in your
* program!
*
* Hint: You must calibrate the gyro carefully
* before using this task!
*
*/
void task_GYRO(void)
{
uint8_t readBuf[6];

if(getStopwatch7() > GYRO_INTERVAL) // GYRO_INTERVAL [ms]
{
I2CTWI_transmitByte(I2C_MULTIIO_L3GD20_ADR, (OUT_X_L | 0x80));
I2CTWI_readBytes(I2C_MULTIIO_L3GD20_ADR, readBuf, 6); // Read X-/Y-/Z-axis
// xb = y:
x_axisg = (readBuf[OUT_Y_H - OUT_X_L] << 8) + readBuf[OUT_Y_L - OUT_X_L];
// yb = -x:
y_axisg = (readBuf[OUT_X_H - OUT_X_L] << 8) + readBuf[OUT_X_L - OUT_X_L];
y_axisg *= -1;
// zb = z:
z_axisg = (readBuf[OUT_Z_H - OUT_X_L] << 8) + readBuf[OUT_Z_L - OUT_X_L];
normalizeL3GD20();
xg *= DPS_PER_DIGIT; // Calculate dps
yg *= DPS_PER_DIGIT;
zg *= DPS_PER_DIGIT;
xg /= ((double) 1000 / GYRO_INTERVAL); // Angle per interval
yg /= ((double) 1000 / GYRO_INTERVAL);
zg /= ((double) 1000 / GYRO_INTERVAL);
if (abs(x_axisg) > OFFSET_ZERO) // Don't cumulate 0 dps values
xdg += (xg * D_CORR_FACTOR); // Cumulated angle values [°]
if (abs(y_axisg) > OFFSET_ZERO)
ydg += (yg * D_CORR_FACTOR);
if (abs(z_axisg) > OFFSET_ZERO)
zdg += (zg * D_CORR_FACTOR);
setStopwatch7(0);
}
}

/**
* This function resets the cumulated angle
* values [°] stored in the global double
* variables xdg, ydg, zdg by the L3GD20
* gyroscope task.
*
*/
void resetGYRO(void)
{
xdg = 0.0;
ydg = 0.0;
zdg = 0.0;
}

/************************************************** ***************************/

/**
* Write a floating point number to the LCD.
*
* Example:
*
* // Write a floating point number to the LCD (no exponent):
* writeDoubleLCD(1234567.890, 11, 3);
*
* The value of prec (precision) defines the number of decimal places.
* For 32 bit floating point variables (float, double ...) 6 is
* the max. value for prec (7 relevant digits).
* The value of width defines the overall number of characters in the
* floating point number including the decimal point. The number of
* pre-decimal positions is: (width - prec - 1).
*/
void writeDoubleLCD(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
dtostrf(number, width, prec, &buffer[0]);
writeStringLCD(&buffer[0]);
}

/************************************************** ***************************/
// I2C Error handler

/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P_WIFI("\nI2C ERROR - TWI STATE: 0x");
writeInteger_WIFI(errorState, HEX);
writeChar_WIFI('\n');
}

/************************************************** ***************************/
// Main function - The program starts here:

int main(void)
{
initRP6M256(); // Always call this first! The Processor will not work
// correctly otherwise.

initLCD(); // Initialize the LC-Display (LCD)
// Always call this before using the LCD!

setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);

writeString_P_WIFI("\n\nRP6M256 Multi IO Selftest 5 GYRO!\n");

// IMPORTANT:
I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
// with 100kHz SCL Frequency


// Register the event handler:
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

setLEDs(0b1111);

// Write a text message to the LCD:
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("RP6v2-M256-WIFI ", "Example Program");
mSleep(2500);
showScreenLCD("RP6M256 Multi IO", "Selftest 5 GYRO");
mSleep(2500);
clearLCD();

setLEDs(0b0000);

// ---------------------------------------

clearLCD();
startStopwatch1();
startStopwatch7(); // Used for GYRO task!

// IMPORTANT:
orientation_init(); // Orientation init!

L3GD20_initStreamMode(); // Gyro Stream mode init!
resetGYRO(); // Reset GYRO!

while(true)
{
#ifndef CALIBRATION
task_I2CTWI();
task_GYRO();
#endif
task_I2CTWI();
if(getStopwatch1() > 500) // 500ms
{
#ifdef CALIBRATION
// GYRO calibration part:
readL3GD20(); // Get sensor values
//normalizeL3GD20();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisg, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeIntegerLCD(y_axisg, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeIntegerLCD(z_axisg, DEC);
writeStringLCD_P(" ");
#else
// Display part:
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeDoubleLCD(xdg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeDoubleLCD(ydg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeDoubleLCD(zdg, 6, 1);
writeStringLCD_P(" ");
#endif
setStopwatch1(0);
}

}

return 0;
}

Bedingungen:
- Orientierungs-Lib und RP6M256_MultiIO.h im Programmverzeichnis
- In der RP6M256_Orientation.h NUR IMU_9D aktivieren und GET_TEMP auskommentieren
- Den GYRO sorgfältig kalibrieren, d.h. die Definitionen OFFSET_X/Y/Z in der RP6M256_Orientation.h so anpassen, dass die Sensor-Ausgabewerte (xg, yg, zg) bei nicht bewegtem RP6 um den Nullpunkt schwanken

Viel Spaß!

inka
11.08.2013, 09:21
Hi Dirk,

im moment bin ich noch im urlaub, aber ab und zu mal auch online...

meinst Du ich könnte so in einer woche die m32 version testen? Ich weiss nicht, ob Du zum umprogrammieren umbauen musst, evtl. gehts auch so, dass ich teste?

Dirk
11.08.2013, 10:10
Hi inka,

die M32-Versionen sind schon fertig. Wenn du wieder zuhause bist, kann ich sie dir schicken.
Schönen Rest-Urlaub noch!

inka
11.08.2013, 10:24
Hi Dirk,

danke für die wünsche und die files - freue mich schon drauf...

ende nächster woche melde ich mich von zuhause aus...

inka
17.08.2013, 17:45
Hi Dirk,

danke für die M32-files,es liess mir doch keine ruhe noch ein paar tage zu warten:

bei der demo_1 werden im LCD x/y/z werte angezeigt, die sich im sekundenrhythmus verändern und um 0 im der größenordnung von 0,1 bis 0,2 schwanken. Daraus würde ich schliessen, dass die kalibrationswerte stimmen...

bei der demo_2 wird nur für x/y/z unverändert 0,0 angezeigt...

sonst passiert bei beiden demos nichts, auch wenn der RP6 gedreht wird...

hätte ich an den dateien noch etwas verändern sollen?

Dirk
17.08.2013, 18:19
Hi inka,

bei der 1. Demo sollte die Winkelgeschwindigkeit angezeigt werden. Wenn du den RP6 also in der Hand hältst und rechts herum drehst, müßte die Z-Anzeige einen positiven Wert [Grad/Sekunde] zeigen. Nach links gedreht wäre der Wert negativ. Die Höhe des Werts hängt ab von der Geschwindigkeit, in der du die Drehung machst: Drehst du also in einer Sekunde um 90°, müßte der Wert auch maximal 90 anzeigen. Natürlich geht der wieder auf 0 zurück, wenn der RP6 nicht mehr bewegt wird. Ein Wert <> 0 wird also nur WÄHREND der Drehung angezeigt.

Bei der 2. Demo wird der Winkel angezeigt, um den du drehst. Wenn du also den RP6 ruhig stehen läßt, müßten alle Werte bei 0 bleiben, wenn die Kalibrierung ok ist. Drehst du den RP6 dann z.B. um 90° nach rechts, müßte die Z-Achse wieder 90 anzeigen, wobei der Wert nicht genau zu erreichen ist, kann also auch 87 oder 95° zeigen. Der Wert bleibt auch erhalten, während der RP6 nicht mehr bewegt wird. Wenn du also den RP6 nicht mehr anfasst, bleibt die Z-Achse bei 90° stehen. Drehst du jetzt wieder auf die Ursprungsposition zurück (also 90° nach links), wird der Z-Achsen Wert ungefähr wieder bei 0° liegen.

Das funktioniert so bei beiden Demos auf allen Achsen, also bei der Neigung nach rechts/links (Roll) und Nase rauf/runter (Pitch).

An den Demos muss nichts verändert werden.

inka
18.08.2013, 10:56
hi Dirk,

nach dem kompilieren mit make (code:blocks hat wohl immer noch ne macke) habe ich bei demo 1 folgende werte:

x -31,7
y -3,2
z -9,3

diese verändern sich in der ersten stelle hinterm koma, reagieren aber nicht auf drehung (weder nach links, noch nach rechts)

bei demo 2 driften die werte sehr schnell weg, reagieren nicht auf eine drehung...

das hängt wohl mit der kalibrierung zusammen, ich werde dann in diesem thread (https://www.roboternetz.de/community/threads/62419-minIMU-9-v2-software-kalibrierung) weitermachen...

Dirk
18.08.2013, 12:56
Hi inka,

ja, da spricht alles dafür, dass die Kalibrierung noch nicht ok ist.

Übrigens:
Du kannst die Kalibrierung des Gyro auch gut mit diesen Demos machen:
Wenn du in der Demo die "//" vor #define CALIBRATION wegmachst, kannst du mit der Demo die Rohwerte ausgeben.
Also so (z.B. Demo GYRO_02,- die ist am besten geeignet!):
1. In RP6Control_Orientation.h:
a) #define IMU_9D aktivieren, die beiden anderen Definitionen (GPS, COMPASS_2D) auskommentieren
b) #define GET_TEMP auskommentieren: //#define GET_TEMP
c) OFFSET_X, OFFSET_Y, OFFSET_Z auf 0 setzen
d) Datei speichern

2. Demo neu kompilieren (.st und .o der Orientation-Lib und alle Hilfsdateien der Demo VORHER LÖSCHEN!)

3. In Ruhelage des RP6 die Werte beobachten: Schwanken sie z.B. bei X zwischen +20 und +140, also im Mittel um den Wert +80, dann in OFFSET_X -80 eintragen. Das so für alle 3 Achsen machen. Noch ein Beispiel: Schwanken die Werte bei Y zwischen -50 und +30, also im Mittel um -10, dann in OFFSET_Y +10 eintragen. Am Ende RP6Control_Orientation.h speichern.

4. In der Demo die "//" vor normalizeL3GD20(); wegmachen

5. Demo neu kompilieren (.st und .o der Orientation-Lib und alle Hilfsdateien der Demo VORHER LÖSCHEN!)

6. Ausgabewerte ansehen: Sie müßten jetzt um den Nullpunkt schwanken,- jedenfalls viel besser um 0 gemittelt sein. Gibt es da noch konstante Abweichungen, dann mit Punkt 3. weitermachen, dabei die neuen Offsets nur zu den vorhandenen addieren, also nicht bei 0 wieder anfangen. (Dabei bleibt die Zeile normalizeL3GD20(); immer mit drin!) Das so lange machen, bis du zufrieden bist, dann Kalibrierung ENDE!!!

7. Jetzt KANN es noch mit der Demo GYRO_02 ans "Feintuning" gehen:
a) In der Demo die "//" vor #define CALIBRATION wieder hinmachen (Messbetrieb, keine Kalibrierung mehr!).
b) Demo neu kompilieren (.st und .o der Orientation-Lib und alle Hilfsdateien der Demo VORHER LÖSCHEN!)
c) Idealerweise bleiben in Ruhelage des RP6 jetzt alle Achsen dauerhaft bei 0.0, dann Feintuning ENDE!!!
d) Ist das nicht der Fall und wandert eine Anzeige langsam immer weiter in den negativen oder positiven Bereich, kann man in der RP6Control_Orientation.h die OFFSET_X, _Y, _Z Werte vorsichtig korrigieren: Ich würde um max. +- 5 korrigieren, die Datei speichern und bei 7.b) weiter machen.

Noch ein Hinweis für ganz Exakte: Man kann jetzt noch den Wert OFFSET_ZERO der Demo kleiner machen (z.B. auf 60 oder 50 reduzieren). Dann driften die schön kalibrierten Werte evtl. wieder weg und man kann bei 7.b) weiter machen. Ende des Feintuning, wenn man das mehr als 2 Jahre gemacht hat oder wegen Vernachlässigung seiner sonstigen Aufgaben in der Psychiatrie liegt :-)

inka
03.09.2013, 13:18
@Dirk,

tolle anleitung...

irgendwie funktioniert sie aber hier bei mir nicht. Hier die daten aus der RP6control_orientation.h

ursprüngliche werte:


// L3GD20 gyroscope:
#define I2C_MULTIIO_L3GD20_ADR 0xd6 // Default (SDO -> VCC)
//#define I2C_MULTIIO_L3GD20_ADR 0xd4 // SDO -> GND

// L3GD20 gyroscope calibration data:
#define MAX_X 20000 // Max. X-axis value
#define MIN_X -20000 // Min. X-axis value
#define OFFSET_X 0 // Offset X-axis
#define MAX_Y 20000 // Max. Y-axis value
#define MIN_Y -20000 // Min. Y-axis value
#define OFFSET_Y 0 // Offset Y-axis
#define MAX_Z 20000 // Max. Z-axis value
#define MIN_Z -20000 // Min. Z-axis value
#define OFFSET_Z 0 // Offset Z-axis

// L3GD20 temperature sensor definitions:
//#define GET_TEMP // Use temperature sensor
//#define OFFSET_TEMP



werte nach der kalibrierung mittels der demo_05_02:


// L3GD20 gyroscope:
#define I2C_MULTIIO_L3GD20_ADR 0xd6 // Default (SDO -> VCC)
//#define I2C_MULTIIO_L3GD20_ADR 0xd4 // SDO -> GND

// L3GD20 gyroscope calibration data:
#define MAX_X 20000 // Max. X-axis value
#define MIN_X -20000 // Min. X-axis value
#define OFFSET_X 3625 // Offset X-axis
#define MAX_Y 20000 // Max. Y-axis value
#define MIN_Y -20000 // Min. Y-axis value
#define OFFSET_Y 364 // Offset Y-axis
#define MAX_Z 20000 // Max. Z-axis value
#define MIN_Z -20000 // Min. Z-axis value
#define OFFSET_Z 1073 // Offset Z-axis

// L3GD20 temperature sensor definitions:
//#define GET_TEMP // Use temperature sensor
//#define OFFSET_TEMP

nach der kompilierung der demo_05_02 mit den originalwerten driften alle drei achsen recht schnell weg, nach der kompilierung mit den werten nach der kalibration stehen die werte dauerhaft bei

(normalize L3GD20() ist in der demo_05_02 auskomentiert, also mit"//" versehen)

x -31,7
y -3,2
z -9,3

wenn ich die "//" bei normalize L3GD20() in der demo_05_02 entferne, stehen alle drei werte bei 0.0


/#define CALIBRATION ist in beiden fällen auskomentiert


was läuft da schief?

Dirk
04.09.2013, 20:03
Hi inka,


nach der kompilierung der demo_05_02 mit den originalwerten driften alle drei achsen recht schnell weg,
Soweit ok.


nach der kompilierung mit den werten nach der kalibration stehen die werte dauerhaft bei
(normalize L3GD20() ist in der demo_05_02 auskomentiert, also mit"//" versehen)
x -31,7
y -3,2
z -9,3
Nach dem ERSTEN Eintragen der OFFSET-Werte (Punkte 1 bis 3) wird die Neukompilierung MIT der Funktion normalizeL3GD20() in der Demo gemacht, um die 1. Kalibrierung zu prüfen (Punkte 4 bis 6, auch beim Wiederholen der Kalibrierung ab Punkt 3).


wenn ich die "//" bei normalize L3GD20() in der demo_05_02 entferne, stehen alle drei werte bei 0.0
Das ist gut und sollte nach erfolgreicher Kalibrierung bei ruhig stehendem RP6 auch so sein.


/#define CALIBRATION ist in beiden fällen auskomentiert
Nein, CALIBRATION sollte zur Kalibrierung NICHT auskommentiert, also definiert sein.


was läuft da schief?
Anleitung evtl. nicht 1:1 nachvollzogen?

inka
04.09.2013, 20:45
Nach dem ERSTEN Eintragen der OFFSET-Werte (Punkte 1 bis 3) wird die Neukompilierung MIT der Funktion normalizeL3GD20() in der Demo gemacht, um die 1. Kalibrierung zu prüfen (Punkte 4 bis 6, auch beim Wiederholen der Kalibrierung ab Punkt 3).
habe den rp6 jetzt nicht zu hand, werde es morgen aber überprüfen



Das ist gut und sollte nach erfolgreicher Kalibrierung bei ruhig stehendem RP6 auch so sein. Aber die anzeige verändert sich auch beim drehen des rp6 nicht!



Nein, CALIBRATION sollte zur Kalibrierung NICHT auskommentiert, also definiert sein.hier war es so gemeint, dass die kalibration abgeschlosseh ist, daher wieder auskomentiert



Anleitung evtl. nicht 1:1 nachvollzogen? s.o.

seit wann geht das "doppelquoten"(man sieht auch das was der vor/vor autor geschrieben ha) im forum nicht? Zu verständlichkeit trägt es nicht gerade bei...

inka
06.09.2013, 13:07
@Dirk,

also die nochmalige kalibrierung des gyros mit der demo_05_02 ergab fast identische werte.

- wenn ich bei der demo 05_01 und der demo 05_02 nicht kalibrieren will, sondern die vom gyro gemessenen werte nur anzeigen will, muss ich in beiden fällen die zeile "#define CALIBRATION" auskommentieren. Stimmt?

- dann wird in der while(true) schleife der abschnitt zwischen "#ifdef CALIBRATION" und "else" übersprungen und nur das "display part" ausgeführt:


// Display part:
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeDoubleLCD(xdpsg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeDoubleLCD(ydpsg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeDoubleLCD(zdpsg, 6, 1);
writeStringLCD_P(" ");

das stimmt doch auch, oder?

- müsste in diesem fall in diesem displaypart nicht noch am anfang die zeile "readL3GD20();" hinzu? Und wie ist es mit dem "gyrotask"? Muss diese nicht auch aufgerufen werden? Oder zumindets "resetgyro"?

ich habe jetzt auf jeden fall in der demo_05_01 die zeile "readL3GD20();" hinzugefügt, die demo zeigt dann veränderungen in allen drei achsen an, je nachdem wie ich der robby drehe. Die im ruhezustand angezeigten werte der drei achsen (bei demo_05_01) sind natürlich nicht bei 0.0, weil ja der rest nicht kalibriert ist, aber der sensor reagiert immerhin...

dass sich die anzeige bei auskommentierterm define fürs kalibrieren überhaupt nicht rührte, hat mich schon sehr iritiert...

die demo_05_02 ist gut geeignet für die kalibrierung des gyros. Hast Du evtl. noch etwas womit man vergleichbar "einfach" den accelerator und magnetometer kalibrieren könnte? Ich weiss nicht ob man der minIMU irgendwie vorgaugeln kann dass sie gedreht wird und sie dann die min/max werte für die kalibrierung auf dem display ausgibt?

Dirk
06.09.2013, 21:20
Hi inka,

Ich weiss nicht ob man der minIMU irgendwie vorgaugeln kann dass sie gedreht wird und sie dann die min/max werte für die kalibrierung auf dem display ausgibt?
Nein, die IMU muss schon real bewegt werden!
Es gibt aber Kalibrierungs-Programme, die die Min/Max-Werte beim Drehen selbst "einsammeln" und ausgeben.
Ein Beispiel gab es glaube ich für die orangutan-Plattform. Geh mal suchen.

inka
07.09.2013, 06:51
Hi Dirk,
treffen den meine annahmen/fragen:


müsste in diesem fall in diesem displaypart nicht noch am anfang die zeile "readL3GD20();" hinzu? Und wie ist es mit dem "gyrotask"? Muss diese nicht auch aufgerufen werden? Oder zumindets "resetgyro"? Und an welcher stelle? In der while(true) schleife oder schon davor?

zu? Oder habe ich damit nur einen an einer anderen stelle von mir gemachten fehler korrigiert?

Dirk
07.09.2013, 10:43
Hi inka,

im "calibration part" ist ja readL3GD20() zum Einlesen der Gyro-Daten und (optional, zuerst auskommentiert) normalizeL3GD20() zum Normalisieren drin.
Im "Display part" ist die task_GYRO() drin, diese Funktion enthält einen eigenen Programm-Teil zum Einlesen der Daten (anstelle von readL3GD20() ) und normalizeL3GD20() zum Normalisieren.

Somit gibt es in beiden Versionen einen Teil zum Einlesen der Daten und zum Normalisieren.
Beim "Display part" findet das Einlesen, Normalisieren und die Auswertung der Daten (mit der task_GYRO() ) nicht hinter der Kommentarzeile "// Display part:" statt, sondern DAVOR in diesem Bereich:

#ifndef CALIBRATION
task_I2CTWI();
task_GYRO();
#endif

inka
07.09.2013, 13:20
Hi Dirk,

damit wir vom gleichen reden, hier die while schleife der demo_05_02 (im originalzustand in dem ich das runtergeladen habe):


while(true)
{
#ifndef CALIBRATION
task_I2CTWI();
task_GYRO();
#endif
task_I2CTWI();
if(getStopwatch1() > 500) // 500ms
{
#ifdef CALIBRATION
// GYRO calibration part:
readL3GD20(); // Get sensor values
//normalizeL3GD20();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisg, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeIntegerLCD(y_axisg, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeIntegerLCD(z_axisg, DEC);
writeStringLCD_P(" ");
#else
// Display part:
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeDoubleLCD(xdg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(0, 8); // line 1 pos 9
writeStringLCD_P("Y");
writeDoubleLCD(ydg, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("Z");
writeDoubleLCD(zdg, 6, 1);
writeStringLCD_P(" ");
#endif
setStopwatch1(0);
}

}

ich finde im displaypart kein "task_gyro", nur fürs kalibrieren...

hier


#endif
task_I2CTWI();
if(getStopwatch1() > 500) // 500ms müsste die zeile doch dabei sein, oder?

das davor gehört doch zu kalibration?

Dirk
07.09.2013, 15:22
Hi inka,

das davor gehört doch zu kalibration?
Das davor, also das hier:

#ifndef CALIBRATION
task_I2CTWI();
task_GYRO();
#endif

... gehört NICHT (#ifndef) zur Kalibrierung, sondern zur Anzeige.