PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : minIMU-9 v2, software, kalibrierung...



inka
03.07.2013, 14:15
@Dirk:

habe jetzt wieder ein neues thema aufgemacht, finde ich übersichtlicher...

hier (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Library_f.C3.BCr_die_Orientierung_im_Rau m) wird z.b. die kalibreierung der minIMU beschrieben:

Gyrosensor:

Wenn der RP6 ruhig auf einer ebenen Fläche steht und nicht bewegt wird, sollten die Werte der X-, Y- und Z-Achse um den Nullpunkt schwanken.
Tatsächlich wird es Abweichungen zum Nullwert geben. Zur Kompensierung der Null-Abweichung kann man die Definitionen OFFSET_X,
OFFSET_Y und OFFSET_Z verwenden, um die Achsen zu "nullen". Zeigt die X-Achse in Ruhe z.B. 756 an, trägt man für OFFSET_X -756 ein.



die werte die ich in der ersten anzeige am LCD (demo_5) messe sind a) wesentlich kleiner als z.b. -759 und b) sie streuen sehr:

X: -66/ -68/ -58/ -83/ -66
Y: -8/ 1/ -23/ -8/ -20
Z: -56/ -26/ -76/ -57/ -64

die 5 werte sind jeweils beim neustart der demo_5 entstanden, der RP6 wurde nicht bewegt und störeinflüsse kann man ausschileßen (weit weg vom pc und sonstigen störquellen)

fragen:

1) ist die streuung so ok?
2) welchen wert soll ich in die OFFSET's eintragen? durchschnitt?
3) die erste LCD anzeige ist noch recht gut interpretierbar. Gibt es irgendwo eine erklärung was in den beiden folgenden LCD anzeigen für werte ausgegeben werden?

Dirk
03.07.2013, 18:47
Hi inka,

Zu 1:
Das dürften die kalibrierten Werte sein. Siehe 2!


Zu 2:
Wichtig ist, dass du dir die ROHWERTE, die der Sensor direkt ausgibt, ansiehst. Für den Gyro wären das also die Werte, die die Funktion readL3GD20() ausgibt. Wenn die Werte erst durch die Normalisierungsfunktion normalizeL3GD20() gejagt sind, kannst du sie für die Kalibrierung nicht mehr verwenden, weil die Normalisierungsfunktion ja genau die von dir angegebenen Kalibrierungswerte nutzt, um die Rohwerte anzupassen.
Siehe auch den Hinweis im RN-Wissen-Artikel:

HINWEISE ZUR KALIBRIERUNG:
* Das Demo-Programm ist nicht sehr gut geeignet, um die Kalibrierungen durchzuführen.
* Man sollte mit einem eigenen kurzen Programm die Rohwerte der jeweiligen X-, Y- und Z-Achse z.B. zweimal pro Sekunde ausgeben.
* Es müssen die Rohwerte angezeigt werden, BEVOR sie durch die Funktionen normalizeHDMM01(), normalizeL3GD20(), normalizeLSM303DLHC_A() oder normalizeLSM303DLHC_M() verändert werden,- also direkt nach dem Lesen der Rohwerte aus dem Sensor.
Das heißt:
Die Demo ist ungeeignet, um die Kalibrierung durchzuführen, sondern sie dient dazu, nach der Kalibrierung die "fertigen", d.h. kalibrierten Werte anzuzeigen.
Du müßtest dir also als erstes ein "Kalibrierungsprogramm" schreiben, das die Rohwerte anzeigt. Du kannst die Demo dazu so abwandeln, dass die normalizeL3GD20() Funktion auskommentiert wird.
Die X-/Y-/Z-Achsen Rohwerte läßt du dann wie beschrieben ausgeben. Liegen die z.B. in Nullstellung des RP6 zwischen -120 und -40, dann müßtest du als Offset 80 eintragen (-(-40 - -120)). Wenn du dann als Kontrolle wieder die unveränderte Demo 05 laufen läßt, müßten die Werte dann zwischen -40 und +40 schwanken, also genau um den Nullpunkt.


Zu 3:
Die MinIMU hat ja 3 Sensoren. In der Control M32 Demo gibt es also drei LCD-Anzeigen für jeden der 3 Sensoren:

1. Gyro:
Zeile 1 -> X-Achse Y-Achse
Zeile 2 -> Z-Achse Temperatur*

Zu *) Falls GET_TEMP definiert ist, sonst leer!


2. Beschleunigungssensor:
Zeile 1 -> X-Achse Y-Achse Z-Achse
Zeile 2 -> Pitch Roll


3. Kompasssensor:
Zeile 1 -> X-Achse Y-Achse Z-Achse*
Zeile 2 -> Heading TC-Heading**

Zu *) ODER Temperatur, wenn GET_TEMP_M definiert ist!
Zu **) Tilt kompensiertes Heading!

inka
04.07.2013, 16:58
@Dirk:

ich muss noch einmal zu diesem thema zurück:



Dirk: Geschafft:
Alle drei Libs (RP6ControlServoLib, RP6Control_LFSBumperLib und RP6Control_MultiIOLib) nacheinander mit eingebunden, allerdings ohne eine Funktion daraus aktiv zu nutzen.
Ergebnis: Demo 05 läuft.
Also:
Keine Ahnung, was da gelaufen ist.

inka:

bei mir läuft die demo_05 nur wenn ich die "RP6Control_MultiIOLib.c" NICHT in den projektsettings verwende. Die anderen beiden (RP6ControlServoLib, RP6Control_LFSBumperLib) sind eingebunden, es werden aber keine funktionen daraus verwendet...

ich versuche jetzt die demo_5 so anzupassen, dass ich die rohwerte bekomme. damit ich flexibel bin, wollte ich die möglichkeit der 4 taster auf der I/O nutzen, das sieht so aus:


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_OrientationLib.h"
#include "RP6ControlServoLib.h"

#define I2C_RP6_BASE_ADR 10

/************************variables***************** ************************/

uint8_t ch;
char item[12];
char dir[3];


/*********************I2C-fehlermeldungen******************/

void I2C_transmissionError(uint8_t errorState) //gibt I2C fehlermeldungen über LCD aus
{
clearLCD();
writeStringLCD_P("I2C ERROR -->");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("TWI STATE: 0x");
writeIntegerLCD(errorState, HEX);
}
/*********************calculateDir***************** ****************************/

/**
* Returns a 2 character string for the eighth
* parts of the direction calculated from the
* heading value.
*
* Input: heading -> Heading value [0..359]
*
*/
void calculateDir(char *dir, uint16_t heading)
{
dir[1] = ' ';
dir[2] = '\0';
if ((heading <= 22) || (heading >=338)) dir[0] = 'N';
if ((heading >= 23) && (heading <= 67)) {dir[0] = 'N'; dir[1] = 'E';}
if ((heading >= 68) && (heading <= 112)) dir[0] = 'E';
if ((heading >= 113) && (heading <= 157)) {dir[0] = 'S'; dir[1] = 'E';}
if ((heading >= 158) && (heading <= 202)) dir[0] = 'S';
if ((heading >= 203) && (heading <= 247)) {dir[0] = 'S'; dir[1] = 'W';}
if ((heading >= 248) && (heading <= 292)) dir[0] = 'W';
if ((heading >= 293) && (heading <= 337)) {dir[0] = 'N'; dir[1] = 'W';}
}

/************************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]);
}



/*************** hauptprogramm ***********/

int main(void)
{


initRP6Control();
multiio_init();
initLCD();
//orientation_init();


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

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen

showScreenLCD(" RP6Control M32", " min_IMU");
mSleep(2500);
clearLCD();



while(true)
{

/*****************anzeige gedrückter buttons****************/
clearLCD();
pressedMultiIOButtonNumber = getMultiIOPressedButtonNumber();
setCursorPosLCD(0, 0);
writeStringLCD("Button: ");
writeIntegerLCD(pressedMultiIOButtonNumber, DEC);
mSleep(500);

uint8_t key = getMultiIOPressedButtonNumber();


/********************funktion der buttons*********************/
if(key)
{
switch(key)
{
case 1://
setLEDs(0b0001);

startStopwatch1();

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

while(true)
{
if(getStopwatch1() > 1000) // 15s
{
#ifdef IMU_9D
// 9D-IMU test:
// L3GD20 gyroscope:
task_I2CTWI();
readL3GD20(); // Get sensor values
// normalizeL3GD20();
task_I2CTWI();
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(" ");
#ifdef GET_TEMP
temperatureg = calcTempL3GD20(temperatureg) + 5;
temperatureg += OFFSET_TEMP;
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("T");
writeIntegerLCD(temperatureg, DEC);
writeStringLCD_P(" ");
#endif
task_I2CTWI();
mSleep(10000);
// LSM303DLHC accelerometer:
task_I2CTWI();
readLSM303DLHC_A(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
writeStringLCD_P("Z");
writeIntegerLCD(z_axisa, DEC);
writeStringLCD_P(" ");
normalizeLSM303DLHC_A(); // Normalize data
positionLSM303DLHC_A(); // Calculate position
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("P");
writeDoubleLCD(pitch, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("R");
writeDoubleLCD(roll, 6, 1);
writeStringLCD_P(" ");
task_I2CTWI();
mSleep(10000);
// LSM303DLHC magnetometer:
task_I2CTWI();
readLSM303DLHC_M(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
#ifndef GET_TEMP_M
writeStringLCD_P("Z");
writeIntegerLCD(z_axism, DEC);
writeStringLCD_P(" ");
#else
temperature_imu = (double) temperaturem / 8.0 + OFFSET_TEMP_M;
writeStringLCD_P("T");
writeDoubleLCD(temperature_imu, 5, 1);
#endif
normalizeLSM303DLHC_M(); // Normalize data
headingm = headingLSM303DLHC_M(); // Calculate heading
calculateDir(dir, headingm);
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("H");
writeIntegerLengthLCD(headingm, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
headingtc = headingLSM303DLHC_TC(); // Calculate TILT COMPENSATED
calculateDir(dir, headingtc); // heading
writeStringLCD_P(" C");
writeIntegerLengthLCD(headingtc, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
writeStringLCD_P(" ");
task_I2CTWI();
#endif
setStopwatch1(0);
}

task_I2CTWI();
}

break;

case 2://
setLEDs(0b0010);

break;
case 3://
setLEDs(0b0100);

break;
case 4://
setLEDs(0b1000);

break;

}
}


}


return 0;
}


weil ich jetzt die abfrage der taster nutze, muss ich die "RP6Control_MultiIOLib.c" in code:blocks einbinden, das bedeutet das programm stürzt wieder nach der (diesmal der zweiten) anzeige der werte ab. Es wird also noch roll und pitch angezeigt und dann ist schluss...

Dirk
05.07.2013, 20:06
Ich habe dein Programm mal als Projekt in WinAVR/PN aufgesetzt,- mit allen Libs, die du auch eingebunden hast.
Wie erwartet kompiliert das ohne Fehler.
Da ich nicht ständig die M256 gegen die M32 tauschen will, teste ich das Ganze wohl erst irgendwann an diesem Wochenende.
Mal sehen ...

inka
05.07.2013, 22:35
Du könntest mir aber die hexdatei schicken? vielleicht liegt es ja wirklich an der konfiguration von code:blocks und nicht an deiner lib?

inka
07.07.2013, 14:07
hi Dirk,

also die hexdatei, die du mir geschickt hast, die hat funktioniert, Die selbst kompilierte immer noch nicht...

Den "schalter" bei code:blocks zum löschen aller hilfsdateien fürs kompilieren habe ich nur indirekt gefunden: "erstellen" und "neu erstellen", wobei das neu erstellen die objekt- datein löscht. Auch das manuelle löschen dieser dateien brachte keine abhilfe - die darstellung der LCD-seiten bricht nach der zweiten seite ab...

schade, aber ich weiss echt nicht weiter...

Dirk
07.07.2013, 14:29
Ich auch nicht.
Frage: Werden durch "neu erstellen" auch die Hilfsdateien für ALLE Libs gelöscht?
Immerhin bindest du ja 7 Libs ein. Du müßtest also im Programmverzeichnis (3 Libs), aber auch in den Ordnern RP6common (2 Libs) und RP6control (2 Libs) die zu den Libs gehörigen .st und .o Dateien vor dem Neukompilieren löschen. Im Programmverzeichnis würde ich auch noch den Hilfsordner .dep löschen oder die .d Dateien da drin.

inka
07.07.2013, 16:12
also bei mir werden in diesem fall 7 *.o dateien erstellt (in einem verzeichnis), keine *.st, ordner .dep gibt es bei code:blocks - zumindest in der einsehbaren, für die programmierung verwendeten - stuktur nicht...

ich werde also die imu mal auf die seite legen und mich wieder mit den servos und normaler programmierung beschäftigen...

danke noch einmal Dirk...

inka
11.07.2013, 17:40
@Dirk:

eigentlich mehr oder weniger zufällig folgendes entdeckt:

- der code stürzt bei NICHT auskommentierter zeile 196 (// normalizeLSM303DLHC_M(); // Normalize data) - im codebereich magnetometer - reproduzierbar nach der zweiten LCD-anzeige ab

- ist die zeile auskommentiert, laufen alle drei LCD-anzeigen nacheinander durch

- die drei dateien, um die es hier zum schluss ging (RP6ControlServoLib, RP6Control_LFSBumperLib und RP6Control_MultiIOLib) sind included


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_OrientationLib.h"
#include "RP6ControlServoLib.h"
#include "RP6Control_LFSBumperLib.h"
#define I2C_RP6_BASE_ADR 10

/************************variables***************** ************************/

uint8_t ch;
char item[12];
char dir[3];


/*********************I2C-fehlermeldungen******************/

void I2C_transmissionError(uint8_t errorState) //gibt I2C fehlermeldungen über LCD aus
{
clearLCD();
writeStringLCD_P("I2C ERROR -->");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("TWI STATE: 0x");
writeIntegerLCD(errorState, HEX);
}
/*********************calculateDir***************** ****************************/

/**
* Returns a 2 character string for the eighth
* parts of the direction calculated from the
* heading value.
*
* Input: heading -> Heading value [0..359]
*
*/
void calculateDir(char *dir, uint16_t heading)
{
dir[1] = ' ';
dir[2] = '\0';
if ((heading <= 22) || (heading >=338)) dir[0] = 'N';
if ((heading >= 23) && (heading <= 67)) {dir[0] = 'N'; dir[1] = 'E';}
if ((heading >= 68) && (heading <= 112)) dir[0] = 'E';
if ((heading >= 113) && (heading <= 157)) {dir[0] = 'S'; dir[1] = 'E';}
if ((heading >= 158) && (heading <= 202)) dir[0] = 'S';
if ((heading >= 203) && (heading <= 247)) {dir[0] = 'S'; dir[1] = 'W';}
if ((heading >= 248) && (heading <= 292)) dir[0] = 'W';
if ((heading >= 293) && (heading <= 337)) {dir[0] = 'N'; dir[1] = 'W';}
}

/************************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]);
}



/*************** hauptprogramm ***********/

int main(void)
{


initRP6Control();
//multiio_init();
initLCD();
//orientation_init();


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

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen

showScreenLCD(" RP6Control M32", " min_IMU");
mSleep(2500);
clearLCD();



while(true)
{
setLEDs(0b0001);

startStopwatch1();

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

while(true)
{
if(getStopwatch1() > 1000) // 1,5s
{
#ifdef IMU_9D
// 9D-IMU test:

// L3GD20 gyroscope:
task_I2CTWI();
readL3GD20(); // Get sensor values
normalizeL3GD20();
task_I2CTWI();
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(" ");
#ifdef GET_TEMP
temperatureg = calcTempL3GD20(temperatureg) + 5;
temperatureg += OFFSET_TEMP;
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("T");
writeIntegerLCD(temperatureg, DEC);
writeStringLCD_P(" ");
#endif
task_I2CTWI();
mSleep(3000);//4,5 sec
clearLCD();

// LSM303DLHC accelerometer:
clearLCD();
task_I2CTWI();
readLSM303DLHC_A(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
writeStringLCD_P("Z");
writeIntegerLCD(z_axisa, DEC);
writeStringLCD_P(" ");
normalizeLSM303DLHC_A(); // Normalize data
positionLSM303DLHC_A(); // Calculate position
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("P");
writeDoubleLCD(pitch, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("R");
writeDoubleLCD(roll, 6, 1);
writeStringLCD_P(" ");
task_I2CTWI();
mSleep(3000);

// LSM303DLHC magnetometer:
clearLCD();
task_I2CTWI();
readLSM303DLHC_M(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
#ifndef GET_TEMP_M
writeStringLCD_P("Z");
writeIntegerLCD(z_axism, DEC);
writeStringLCD_P(" ");
#else
temperature_imu = (double) temperaturem / 8.0 + OFFSET_TEMP_M;
writeStringLCD_P("T");
writeDoubleLCD(temperature_imu, 5, 1);
#endif
// normalizeLSM303DLHC_M(); // Normalize data
headingm = headingLSM303DLHC_M(); // Calculate heading
calculateDir(dir, headingm);
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("H");
writeIntegerLengthLCD(headingm, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
headingtc = headingLSM303DLHC_TC(); // Calculate TILT COMPENSATED
calculateDir(dir, headingtc); // heading
writeStringLCD_P(" C");
writeIntegerLengthLCD(headingtc, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
writeStringLCD_P(" ");
mSleep(3000);//4,5 sec
clearLCD();
task_I2CTWI();
#endif
setStopwatch1(0);
}

task_I2CTWI();
}



}


return 0;
}

ich weiss jetzt natürlich nicht was die werte, die da angezeigt werden, nun bedeuten, ob sie richtig sind...

Dirk
11.07.2013, 19:21
Ok, am Wochenende baue ich wieder um ... :x

inka
12.07.2013, 08:41
Du musst aber nicht - Du kannst mir auch die hex schicken und ich teste...

Dirk
12.07.2013, 21:22
Hi inka,

HEX ist auf dem Weg zu dir!

inka
13.07.2013, 06:38
hi Dirk,

sie funktioniert, es ist nun die frage ob die, die ich selbst kompiliere es auch tut?

Dirk
13.07.2013, 07:00
Hi inka,

ja, das probier mal mit den Kalibrierungs-Werten, die ich geschickt hatte.
Wenn das nicht klappt:
Stell eine zip zusammen mit allen Dateien, die du fehlerfrei kompiliert hast und die dann aber NICHT läuft. :MistPC
Ich kompiliere sie dann bei mir und schicke sie dir, wenn sie funktioniert, als HEX zum Testen.

inka
13.07.2013, 12:15
hi Dirk,

in einer mail die zip datei an Dich:

- libs (c + h) die in der "min_IMU_RP6Control_MultiIO_05.c" included sind
- mein komplettes libverzeichnis, sollte ich was vergessen haben
- c + hex datei - funktioniert
- c + hex datei - funktioniert nicht

funktioniert, bzw. funktioniert nicht - unterscheiden sich NUR in der auskommentierter zeile 196 in der "min_IMU_RP6Control_MultiIO_05.c"

kompilieren lassen sich beide versionen fehlerfrei...

Deine daten in der RP6Control_orientation.h habe ich vor dem kompilieren eingefügt...

inka
14.07.2013, 08:35
Hi Dirk,

ich habe den code ähnlich der struktur des base-selftest umstrukturiert:


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_OrientationLib.h"
//#include "RP6ControlServoLib.h"

#define I2C_RP6_BASE_ADR 10

/************************variables***************** ************************/

uint8_t ch;
char item[12];
char dir[3];



/*********************I2C-fehlermeldungen******************/

void I2C_transmissionError(uint8_t errorState) //gibt I2C fehlermeldungen über LCD aus
{
clearLCD();
writeStringLCD_P("I2C ERROR -->");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("TWI STATE: 0x");
writeIntegerLCD(errorState, HEX);
}

/**
* Returns a 2 character string for the eighth
* parts of the direction calculated from the
* heading value.
*
* Input: heading -> Heading value [0..359]
*
*/
void calculateDir(char *dir, uint16_t heading)
{
dir[1] = ' ';
dir[2] = '\0';
if ((heading <= 22) || (heading >=338)) dir[0] = 'N';
if ((heading >= 23) && (heading <= 67)) {dir[0] = 'N'; dir[1] = 'E';}
if ((heading >= 68) && (heading <= 112)) dir[0] = 'E';
if ((heading >= 113) && (heading <= 157)) {dir[0] = 'S'; dir[1] = 'E';}
if ((heading >= 158) && (heading <= 202)) dir[0] = 'S';
if ((heading >= 203) && (heading <= 247)) {dir[0] = 'S'; dir[1] = 'W';}
if ((heading >= 248) && (heading <= 292)) dir[0] = 'W';
if ((heading >= 293) && (heading <= 337)) {dir[0] = 'N'; dir[1] = 'W';}
}

/************************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]);
}


void writeDouble(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
dtostrf(number, width, prec, &buffer[0]);
writeString(&buffer[0]);
}

/*****************gyroscope***************/
void gyroscope(void) // L3GD20 gyroscope
{
orientation_init();
task_I2CTWI();
readL3GD20(); // Get sensor values
// normalizeL3GD20();
task_I2CTWI();
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(" ");
#ifdef GET_TEMP
temperatureg = calcTempL3GD20(temperatureg) + 5;
temperatureg += OFFSET_TEMP;
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("T");
writeIntegerLCD(temperatureg, DEC);
writeStringLCD_P(" ");
#endif
task_I2CTWI();
mSleep(3000);//4,5 sec
clearLCD();
}

/************accelerometer****************/
void accelerometer(void) // LSM303DLHC accelerometer
{
orientation_init();
clearLCD();
task_I2CTWI();
readLSM303DLHC_A(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
writeStringLCD_P("Z");
writeIntegerLCD(z_axisa, DEC);
writeStringLCD_P(" ");
normalizeLSM303DLHC_A(); // Normalize data
positionLSM303DLHC_A(); // Calculate position
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("P");
writeDoubleLCD(pitch, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("R");
writeDoubleLCD(roll, 6, 1);
writeStringLCD_P(" ");
task_I2CTWI();
mSleep(3000);
}

/*****************magnetometer************/
void magnetometer(void) // LSM303DLHC magnetometer
{
orientation_init();
clearLCD();
task_I2CTWI();
readLSM303DLHC_M(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
#ifndef GET_TEMP_M
writeStringLCD_P("Z");
writeIntegerLCD(z_axism, DEC);
writeStringLCD_P(" ");
#else
temperature_imu = (double) temperaturem / 8.0 + OFFSET_TEMP_M;
writeStringLCD_P("T");
writeDoubleLCD(temperature_imu, 5, 1);
#endif
// normalizeLSM303DLHC_M(); // Normalize data
headingm = headingLSM303DLHC_M(); // Calculate heading
calculateDir(dir, headingm);
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("H");
writeIntegerLengthLCD(headingm, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
headingtc = headingLSM303DLHC_TC(); // Calculate TILT COMPENSATED
calculateDir(dir, headingtc); // heading
writeStringLCD_P(" C");
writeIntegerLengthLCD(headingtc, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
writeStringLCD_P(" ");
mSleep(3000);//4,5 sec
clearLCD();
task_I2CTWI();
}



/*************** hauptprogramm ***********/

int main(void)
{


initRP6Control();
multiio_init();
initLCD();
//orientation_init();

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

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen

// Voltage & current sensor test:
LTC2990_measure();
setCursorPosLCD(0, 0);
//writeStringLCD("BAT Current: ");
//writeDoubleLCD(cbat, 6, 1);
writeStringLCD(" accu: ");
writeDoubleLCD(vbat, 4, 1);
writeStringLCD( " V");
mSleep(1500);


showScreenLCD(" RP6Control M32", " gyro_test_3");
mSleep(2500);
clearLCD();



while(true)
{

/*****************anzeige gedrückter buttons****************/
clearLCD();
pressedMultiIOButtonNumber = getMultiIOPressedButtonNumber();
setCursorPosLCD(0, 0);
writeStringLCD("Button: ");
writeIntegerLCD(pressedMultiIOButtonNumber, DEC);
mSleep(500);

uint8_t key = getMultiIOPressedButtonNumber();


/********************funktion der buttons*********************/
if(key)
{
switch(key)
{
case 1://
setLEDs(0b0001);
gyroscope();
break;

case 2://
setLEDs(0b0010);
accelerometer();
break;

case 3://
setLEDs(0b0100);
magnetometer();
break;

case 4://
setLEDs(0b1000);
gyroscope();
accelerometer();
magnetometer();
break;
}
}
}
return 0;
}

folgendes fiel mir auf wofür ich noch nach einer erklärung suche:

1) die anweisung "orientation_init();" stand ursprünglich am anfang der main(), als ich feststellte, dass beim case2 der pitch und rool mit jeweils einer null angezeigt wurden, versetzte ich diese in die jeweiligen unterprogramme (gyroscope, accelerometer und magnetometer) - jetzt werden die werte richtig angezeigt. War das die richtige massnahme?

2) wenn ich den RP6 neu einschalte (nicht start mit dem startbutton, sondern S1) werden beim ersten druck des button 1 die gyrowerte 4stellig, also nicht normalisiert angezeigt. Beim zweiten druck auf button 1, kommen sie nur noch 2stellig. Womit wird das verursacht?

Dirk
14.07.2013, 12:36
Hi inka,

Demo und HEX sind auf dem Weg zu dir!

inka
14.07.2013, 16:03
hi Dirk,

danke für die files, beide von dir kompilierten hex funktionieren bei mir...

das mit der anzeige der accuspannung habe ich auch geschafft...

meine kompilierung der 05_05 funktioniert nach wie vor nicht, absturz an der bekannten stelle - normalize im magnetometerabschnitt...


wenn ich den RP6 (http://www.rn-wissen.de/index.php/RP6) neu einschalte (nicht start mit dem startbutton, sondern S1) werden beim ersten druck des button 1 die gyrowerte 4stellig, also nicht normalisiert angezeigt. Beim zweiten druck auf button 1, kommen sie nur noch 2stellig. Womit wird das verursacht?

was hälst du denn davon? das passiert auch bei deiner, von dir kompilierten, 05_04, bei der 05_05 nicht...

frage: lassen sich die funktionierenden werte (also ohne den magnetometer) nicht - wie bei der HDMM - auch in gradzahlen und heading umrechnen?

Dirk
14.07.2013, 17:48
Hi inka,

1.:
Die 05_04 ist nicht ok, weil multiio_init() [und orientation_init()] VOR dem Befehl I2CTWI_initMaster(100) stehen.
Das geht nicht, weil die init-Funktionen den I2C-Bus brauchen,- also muss der I2C-Bus VOR den inits gestartet werden.
Daher kannst du die 05_04 vergessen.

2.:
Dass du die 05_05 immer noch nicht selbst funktionsfähig kompilieren kannst (obwohl sie ja von mir kompiliert funktioniert!), verstehe ich weiterhin nicht. Was damit die Funktion normalizeLSM303DLHC_M() zu tun hat, weiß ich auch nicht.
Du könntest aber versuchen, es herauszufinden:
Im 1. Schritt kommentiere mal in der Funktion die Zeilen:
x_axism += OFFSET_X_M;
y_axism += OFFSET_Y_M;
z_axism += OFFSET_Z_M;
... aus.
Funktioniert die Demo bei dir neu kompiliert (und Hilfsdateien gelöscht!) damit?
Im 2. Schritt ersetz mal die Zeilen:
xm = (x_axism - MIN_X_M) / (MAX_X_M - MIN_X_M) * 2 - 1;
ym = (y_axism - MIN_Y_M) / (MAX_Y_M - MIN_Y_M) * 2 - 1;
zm = (z_axism - MIN_Z_M) / (MAX_Z_M - MIN_Z_M) * 2 - 1;
... durch:
xm = (double) x_axism;
ym = (double) y_axism;
zm = (double) z_axism;
Funktioniert die Demo bei dir neu kompiliert (und Hilfsdateien gelöscht!) damit?


frage: lassen sich die funktionierenden werte (also ohne den magnetometer) nicht - wie bei der HDMM - auch in gradzahlen und heading umrechnen?
Der HDMM01 ist ja auch ein Magnetometer!?? Für die Himmelsrichtung braucht man das ja auch,- bei der minIMU ist das dann der Magnetometer im LSM303DLHC. Man kommt also nicht ohne den aus, wenn man die Himmelsrichtung braucht. Oder was meinst du?

inka
14.07.2013, 19:12
Dass du die 05_05 immer noch nicht selbst funktionsfähig kompilieren kannst (obwohl sie ja von mir kompiliert funktioniert!), verstehe ich weiterhin nicht. Was damit die Funktion normalizeLSM303DLHC_M() zu tun hat, weiß ich auch nicht.
Du könntest aber versuchen, es herauszufinden:
Im 1. Schritt kommentiere mal in der Funktion die Zeilen:
x_axism += OFFSET_X_M;
y_axism += OFFSET_Y_M;
z_axism += OFFSET_Z_M;
... aus.
Funktioniert die Demo bei dir neu kompiliert (und Hilfsdateien gelöscht!) damit?

nein, absturz in case3...


Im 2. Schritt ersetz mal die Zeilen:
xm = (x_axism - MIN_X_M) / (MAX_X_M - MIN_X_M) * 2 - 1;
ym = (y_axism - MIN_Y_M) / (MAX_Y_M - MIN_Y_M) * 2 - 1;
zm = (z_axism - MIN_Z_M) / (MAX_Z_M - MIN_Z_M) * 2 - 1;
... durch:
xm = (double) x_axism;
ym = (double) y_axism;
zm = (double) z_axism;
Funktioniert die Demo bei dir neu kompiliert (und Hilfsdateien gelöscht!) damit?

die im schritt 1 auskommentierten zeile blieben im schritt 2 auskommentiert, zusätzlich ersatz der anderen 3 zeilen, demo stürzt in case3 ab...Anschliessen habe ich die funktion in den originalzustand versetzt...


Der HDMM01 ist ja auch ein Magnetometer!?? Für die Himmelsrichtung braucht man das ja auch,- bei der minIMU ist das dann der Magnetometer im LSM303DLHC. Man kommt also nicht ohne den aus, wenn man die Himmelsrichtung braucht. Oder was meinst du?

ich meine, wir versuchen hier den magnetometer zum laufen zu bekommen. Ich hatte früher ein wenig mit kreiseln zu tun. Mechanisch, mit ein paar spulen, schnell drehenden bürstenllosen motoren mit schwungmasse und etwas auswertungselektronik (transistoren!). Damals war noch kein rede von strap down, schon garnicht von elektronischen gyros auf 5mm² fläche...
Was ich nicht begreife ist, weiso ich einen magnetometer brauche, wenn ich einen gyro und beschlenigungsmesser habe? Aber die erklärung würde hier vermutlich zu weit führen. testen wir also weiter...

Ich kann verstehen, dass dir das langsam auf den keks geht, aber du bist etztendlich der einziger hier der mir da weiterhelfen kann...

Dirk
14.07.2013, 19:35
Fragen:

absturz in case3...
Nur zur Sicherheit:
1. Ist das genau die Art "Absturz", die auch vorher so schon passiert ist?
2. Woher weißt du, WO der Absturz erfolgt?

Immerhin wissen wir jetzt, dass es wohl nicht an der normalizeLSM303DLHC_M() Funktion liegt, weil der Inhalt nach der Änderung völlig "harmlos" ist.

Letztlich kommen wir so auch nicht weiter.

Ich müßte wohl Code:Blocks installieren und alles in deiner Entwicklungsumgebung nachvollziehen ... Uff ...
Wenn du Lust hast, schick mir doch den ganzen Kram einschließlich deiner Demos, Libs und Code:Blocks. Am besten auch eine kurze Hilfe, wie ich das alles installieren sollte (damit es genau so ist, wie bei dir...).


Was ich nicht begreife ist, weiso ich einen magnetometer brauche, wenn ich einen gyro und beschlenigungsmesser habe? Aber die erklärung würde hier vermutlich zu weit führen.
Natürlich kann man mit Gyro und Beschleunigungssensor in gewissen Grenzen eine Richtung halten, hat aber letztlich keine Hinweise darauf, welche (Himmels-) Richtung das ist.

inka
14.07.2013, 21:02
Fragen:

Nur zur Sicherheit:
1. Ist das genau die Art "Absturz", die auch vorher so schon passiert ist?
2. Woher weißt du, WO der Absturz erfolgt?

1- genauso wie vorher, programm wird beendet, nach dem zweiten druck auf den startbutton startet es neu
2. absturz erfolgt unmittelbar nach dem druck auf button 3 = case 3 in der 05_05...


Immerhin wissen wir jetzt, dass es wohl nicht an der normalizeLSM303DLHC_M() Funktion liegt, weil der Inhalt nach der Änderung völlig "harmlos" ist.
seltsam, dass die auskommentierung der funktion den absturz verhindert...


Letztlich kommen wir so auch nicht weiter.

können wir überhaupt sicher sagen, dass es an der software bzw. entwicklungsumgebung liegt? Schliesst Du hardwareproblem völlig aus?


Ich müßte wohl Code:Blocks installieren und alles in deiner Entwicklungsumgebung nachvollziehen ... Uff ...
Wenn du Lust hast, schick mir doch den ganzen Kram einschließlich deiner Demos, Libs und Code:Blocks. Am besten auch eine kurze Hilfe, wie ich das alles installieren sollte (damit es genau so ist, wie bei dir...).

nette idee, aber ich arbeite mit linux (ubuntu), weiss inzwischen welche verzeichnisse die daten und welche die konfiguration beinhalten - aber wie ist es bei Dir? Windows?



Natürlich kann man mit Gyro und Beschleunigungssensor in gewissen Grenzen eine Richtung halten, hat aber letztlich keine Hinweise darauf, welche (Himmels-) Richtung das ist.
bedeutet ich hätte z.b. eine anzeige von 270° aber nicht die dazugehörige himmelsrichtung, also "W" (wenn so die zuordnung stimmt)?

Dirk
14.07.2013, 21:31
Ja, ich arbeite mit W7. Theoretisch könnte ich Code:Blocks unter Windows installieren, entweder mit dem Mingw oder GNU GCC, so wie du das unter Linux gemacht hast.


seltsam, dass die auskommentierung der funktion den absturz verhindert...
Richtig. Das bleibt ein Mysterium.


...bedeutet ich hätte z.b. eine anzeige von 270° aber nicht die dazugehörige himmelsrichtung, also "W" (wenn so die zuordnung stimmt)?

Mit dem Gyro könnte man ja Lageänderungen feststellen und kompensieren, d.h. gegen die Lageänderung steuern. Eine konkrete Richtungsinformation hat man dadurch leider nicht.


Schliesst Du hardwareproblem völlig aus?
Ja. Grund: Jede HEX, die bei mir lief, lief auch bei dir und die minIMU ist offenbar ansprechbar, genauso auch die Taster.

- - - Aktualisiert - - -

Mir fallen noch 3 Sachen ein:
1. Zu wieviel % sind deine Data gefüllt? Normalerweise wird dieser Wert am Ende der Kompilierung irgendwo angezeigt. Grund der Frage: Überlauf des RAMs?
2. Zu wieviel % ist der Programmspeicher voll?
3. Wenn es wirklich an der Funktion normalizeLSM303DLHC_M() liegen sollte (???), dann probier doch noch Folgendes:
a) Kopier die Zeilen:
xm = (double) x_axism;
ym = (double) y_axism;
zm = (double) z_axism;
... ans Ende der Funktion readLSM303DLHC_M(). Damit entfällt dann die Funktion normalizeLSM303DLHC_M() komplett.

inka
14.07.2013, 21:33
bin jetzt nicht an meinem pc, sondern am tablet und da ist vieles ganz anders. auch das schreiben...

kann ich irgendwelche jumper falsch gesetzt haben?

können irgendwelche bauteile an der IO dadurch, dass sie evtl. nicht richtig kontakt haben diesesproblem verursachen?

welche werte müsste eine mit deinen, an deine minimu angepassten korrekturwerten liefern? Müssten z.b. die himmelsrichtungen ungefähr stimmen? Mein rp stand z.b. in richtung nord, angezeigt wurde ost...

Dirk
14.07.2013, 21:45
Hi,

kann ich irgendwelche jumper falsch gesetzt haben?
Ich denke nicht.
Prüfung: Klick (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Multi_IO_Projekt_Library) und Klick (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Multi_IO_Projekt_Library_3).


können irgendwelche bauteile an der IO dadurch, dass sie evtl. nicht richtig kontakt haben diesesproblem verursachen?
Ich denke nicht. Der Fehler passiert ja sehr konstant an einer bestimmten Stelle einer bestimmten Kompilierung, während er bei einer anderen Kompilierung nie passiert. Das ist kein Hardwareproblem.


welche werte müsste eine mit deinen, an deine minimu angepassten korrekturwerten liefern? Müssten z.b. die himmelsrichtungen ungefähr stimmen? Mein rp stand z.b. in richtung nord, angezeigt wurde ost...
Die Richtungsangaben könnten bei dir deutlich abweichen, weil das ja nicht deine Kalibrierungswerte sind.

inka
15.07.2013, 07:21
hi Dirk,

ich habe jetzt noch einen versuch bezüglich code:blocks gestartet. Und zwar von null an einen neues projekt angelegt. Im ersten anlauf gelang es eine hexdatei zu kompilieren, wo auch der magnetometer MIT normalize lief. Dann habe ich noch an den einstellungen etwas geändert mit dem ergebnis, dass dann eine hex entstand, die sich genauso verhält, wie die vorherigen, stürzt ab.
Ich hoffe die installation von code:blocks bleibt dir erspart, bin dem ziel - die minIMU zu kalibrieren und zu nutzen - einen großen schritt näher gekommen...

melde mich wieder, danke...

inka
15.07.2013, 13:39
hi Dirk,

es ist mir nicht gelungen das noch einmal zu wiederholen. Ich habe jetzt die normalize funktion "leergemacht", es ist alles auskommentiert bis auf {}. Nun läuft die compilierung fehlerfrei durch und auch das programm läuft durch - natürlich mit nicht normalisierten werten...


Ich hatte bei einer anderen gelegenheit probleme/fehlermeldungen wegen einer fehlenden *.h datei. Weiss jetzt nicht genau um welche es ging, ist jetzt auch egal. Könnte es hier nicht ähnlich sein, dass eine für die funktion erforderliche avr-grundfunktion bei mir nicht verfügbar ist und dass es der compiler nicht merkt, sondern es erst beim programmablauf schief läuft?

frage: welche datei/en könnten es sein? welche werden im hintergrund der "normalizeLSM303DLHC_M()" verwendet?

Dirk
15.07.2013, 19:26
Hi inka,

Ich habe jetzt die normalize funktion "leergemacht", es ist alles auskommentiert bis auf {}. Nun läuft die compilierung fehlerfrei durch und auch das programm läuft durch - natürlich mit nicht normalisierten werten...
Das ist gut.
Du könntest jetzt noch probieren, ob du den Inhalt der normalizeLSM303DLHC_M()-Funktion ans Ende der Funktion readLSM303DLHC_M() stellen kannst.
Die sähe dann so aus:

void readLSM303DLHC_M(void)
{
uint8_t readBuf[6];

I2CTWI_transmitByte(I2C_MULTIIO_LSM303DLHC_M_ADR, OUT_X_H_M);
I2CTWI_readBytes(I2C_MULTIIO_LSM303DLHC_M_ADR, readBuf, 6); // Read X-/Y-/Z-axis
// xb = y:
x_axism = (readBuf[OUT_Y_H_M - OUT_X_H_M] << 8) + readBuf[OUT_Y_L_M - OUT_X_H_M];
// yb = -x:
y_axism = (readBuf[OUT_X_H_M - OUT_X_H_M] << 8) + readBuf[OUT_X_L_M - OUT_X_H_M];
y_axism *= -1;
// zb = z:
z_axism = (readBuf[OUT_Z_H_M - OUT_X_H_M] << 8) + readBuf[OUT_Z_L_M - OUT_X_H_M];
mSleep(10);
#ifdef GET_TEMP_M
// Read temperature raw value:
I2CTWI_transmitByte(I2C_MULTIIO_LSM303DLHC_M_ADR, TEMP_OUT_H_M);
readBuf[0] = I2CTWI_readByte(I2C_MULTIIO_LSM303DLHC_M_ADR);
I2CTWI_transmitByte(I2C_MULTIIO_LSM303DLHC_M_ADR, TEMP_OUT_L_M);
readBuf[1] = I2CTWI_readByte(I2C_MULTIIO_LSM303DLHC_M_ADR);
temperaturem = ((readBuf[0] << 8) + readBuf[1]) / 16;
mSleep(10);
#endif
// Add hard iron offsets:
x_axism += OFFSET_X_M;
y_axism += OFFSET_Y_M;
z_axism += OFFSET_Z_M;
// Scale raw values:
xm = (x_axism - MIN_X_M) / (MAX_X_M - MIN_X_M) * 2 - 1;
ym = (y_axism - MIN_Y_M) / (MAX_Y_M - MIN_Y_M) * 2 - 1;
zm = (z_axism - MIN_Z_M) / (MAX_Z_M - MIN_Z_M) * 2 - 1;
}
Wenn das so läuft, hättest du Glück: Du könntest dann auch kalibrieren.


Könnte es hier nicht ähnlich sein, dass eine für die funktion erforderliche avr-grundfunktion bei mir nicht verfügbar ist
Das weiß ich nicht. Die besten Chancen hättest du sicher, wenn du die GNU GCC Tool-Chain verwenden würdest, falls das unter Linux geht. Unter Windows ist das mit Code:Blocks möglich. Dann wäre das ja der gleiche Kompiler, den ich auch verwende.

inka
17.07.2013, 08:07
Du könntest jetzt noch probieren, ob du den Inhalt der normalizeLSM303DLHC_M()-Funktion ans Ende der Funktion readLSM303DLHC_M() stellen kannst.
die version funktioniert auch nicht, leider...


Das weiß ich nicht. Die besten Chancen hättest du sicher, wenn du die GNU GCC Tool-Chain verwenden würdest, falls das unter Linux geht. Unter Windows ist das mit Code:Blocks möglich. Dann wäre das ja der gleiche Kompiler, den ich auch verwende.
ich habe seit gestern viel zeit investiert in die installation von eclipse mit avr, bekomme aber das avr-plugin nicht zum laufen...

jetzt noch ein versuch, ohne den ganzen "wasserkopf": ich habe Dir per mail die letzte version der testdatei geschickt. Würdest Du sie bitte noch einmal kompilieren und mir per zip die komplette "kompilierumgebung", heisst die notwendigen libs und das makefile schicken? Auch wenn ich überhaupt keine ahnung habe wie das geht, es ist der einziger weg um festzustellen, ob es an meiner IDE oder am unterbau liegt...

Dirk
17.07.2013, 16:56
Hi inka,

Würdest Du sie bitte noch einmal kompilieren und mir per zip die komplette "kompilierumgebung", heisst die notwendigen libs und das makefile schicken?
Ist unterwegs ...

inka
17.07.2013, 17:05
hi Dirk,
mir fält die frage ein . wie starte ich unter linux eine make_clean.bat?

inka
18.07.2013, 08:43
hi,

die zu kompilierende datei befindet sich im verzeichnis: /home/georg/workspace/gyro_test_3
die RP6lib in: /home/georg/workspace/RP6Lib

der erste teil des makefiles:


################################################## #############################
# Target file name (without extension).
# This is the name of your main C source file! Do NOT append the ".c"!
# Example: Let's assume your main source file is "RP6Base_MyProgram.c", then
# you would write: TARGET = RP6Base_MyProgram

TARGET = gyro_test_3

################################################## #############################



################################################## #############################
# Specify relative path to RP6 library files here.
# This is "../../RP6lib" or "../RP6lib" usually.

RP6_LIB_PATH=../RP6lib
RP6_LIB_PATH_OTHERS= $(RP6_LIB_PATH)/RP6control $(RP6_LIB_PATH)/RP6common

################################################## #############################


die rückmeldung des "make":



georg@netzserver:~/workspace/gyro_test_3$ make

-------- begin --------
avr-gcc (GCC) 4.5.3
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

make: *** Keine Regel vorhanden, um das Target »gyro_test_3.elf«,
benötigt von »elf«, zu erstellen. Schluss.
georg@netzserver:~/workspace/gyro_test_3$


ich glaub ich gibs auf: was habe ich noch vergessen?

Dirk
18.07.2013, 08:45
Keine Ahnung von Linux. Das ist eine simple Batchdatei, die hier eigentlich nur eine weitere Funktion aufruft.
Wenn du das ersetzen willst, müßtest du in Linux eine eigene Makrofunktion schreiben (gibt's das da?), die alle Compiler-Hilfsdateien löscht, genau so, wie du es manuell machen würdest.
Dient also letztlich nur als Arbeitserleichterung...

inka
18.07.2013, 11:03
nein, hier geht es nicht mehr um die "make_all.bat", da steht ja ohnehin nur:

set LANG=C
make all

drinn, man kann es auch als linux script ausführen, hier geht es um die in meinem zweiten post geschilderte antwort auf ein "make" in einem terminalfenster:

------------------------------------------
make: *** Keine Regel vorhanden, um das Target »gyro_test_3.elf«, benötigt von »elf«, zu erstellen. Schluss.
---------------------------------------------

btw: das ".dep" verzeichnis wird immerhin erstellt, und es wird hier von einer "elf" extention gesprochen, die extention ist mir auch schon von code:blocks bekannt...


auf das eingeben von "make_all" erscheint die fehlermeldung "befehl nicht gefunden"...

wo finde ich den inhalt des "make" scriptes? Das ist ja wohl nicht das makefile, oder?

Dirk
18.07.2013, 12:10
Oh, da hatten wir wohl gleichzeitig getippt (9:43 und 9:45), so dass ich deinen Post von 9:43 nicht gelesen hatte, sondern auf deinen Post von gestern geantwortet habe.

Diese Meldung "Keine Regel vorhanden ..." gibt es immer, wenn die .c Datei (Source) nicht gefunden wird. In der makefile Datei muss stehen:
TARGET = gyro_test_3

Wenn make_all nicht gefunden wird:
Mit einem Texteditor eine Datei make_all.bat anlegen mit dem Inhalt (2 Zeilen):
set LANG=C
make all

Die Datei kommt ins selbe Verzeichnis wie die Source-Datei.

Frage:
Was machst du gerade? Welche Umgebung richtest du ein?

Wenn du gar nicht klar kommst, geh doch nach der Anleitung zum RP6 zur Einrichtung der Software unter Linux!

inka
18.07.2013, 13:34
Frage:
Was machst du gerade? Welche Umgebung richtest du ein?

ich versuche das deb paket von der arexx webseite zu installieren...

avr-gcc, binutils, avr-libc und Patches

Hier finden Sie Pakete für Debian/Ubuntu Linux.
Diese stammen von: http://www.wrightflyer.co.uk/avr-gcc/
Nach der Installation müssen Sie noch
"export PATH=$PATH:/usr/local/avr/bin"
ausführen um die Tools verwenden zu können.


Wenn du gar nicht klar kommst, geh doch nach der Anleitung zum RP6 zur Einrichtung der Software unter Linux!


webseite arexx:
Die Beschreibung ist auch nicht mehr auf dem aktuellen Stand und muss teilweise etwas angepasst werden. Also besser falls möglich die fertigen .deb Pakete verwenden (in brauchbarer Form gab es sowas zu dem Zeitpunkt an dem die Anleitung entstanden ist noch nicht). Bei Fragen wenden Sie sich bitte an den Support.

und da auch dort nicht alles reibungslos funktioniert, habe ich mich an den support gewendet...

Dirk
18.07.2013, 14:16
Hi inka,

wenn du beim Service keine passenden Antworten bekommst, mach am besten einen eigenen Thread zu dem Thema auf und frag SlyD (https://www.roboternetz.de/community/members/120-SlyD). Der hilft immer.

inka
18.07.2013, 14:48
hi Dirk,

seine mailadresse stand unter support...

SlyD
18.07.2013, 18:12
Hallo,

s. https://www.roboternetz.de/community/threads/46846-probleme-mit-linuxumgebung/page3?p=582973&viewfull=1#post582973

Aber:


georg@netzserver:~/workspace/gyro_test_3$ make

-------- begin --------
avr-gcc (GCC) 4.5.3
Copyright (C) 2010 Free Software Foundation, Inc.


Offenbar hast Du den avr-gcc schon installiert.
Also etwas aufpassen was Du da wie installierst... schau erstmal nach wo die Version da her kommt und obs damit funktioniert.



Die Batch Dateien sind übrigens nur für Windows gedacht - unter Linux braucht man sowas nicht, einfach konsole auf und
make
oder
make all
tippen, fertig (das all kann man weglassen wird als standard angenommen).
Geht unter Windows zwar auch, aber da kann man gar nicht erwarten, dass die Anwender wissen wie man eine
Kommandozeile bedient ;-)


MfG,
SlyD

inka
18.07.2013, 20:15
hi SlyD,


-------- begin --------
avr (http://www.rn-wissen.de/index.php/AVR-Einstieg_leicht_gemacht)-gcc (http://www.rn-wissen.de/index.php/Gcc) (GCC (http://www.rn-wissen.de/index.php/Gcc)) 4.5.3
Copyright (C) 2010 Free Software Foundation, Inc.
Offenbar hast Du den avr-gcc schon installiert.

Also etwas aufpassen was Du da wie installierst... schau erstmal nach wo die Version da her kommt und obs damit funktioniert.

naja über das ubuntu-softwarezenter, dachte nicht, dass der schaden könnte. Alternative?

SlyD
18.07.2013, 20:19
Ich meinte damit nur dass Du nicht BEIDE Versionen gleichzeitig installieren sollst.

Was genau ist denn aktuell noch das Problem?
Lassen sich die orginalen unveränderten Beispielprogramme übersetzen?
(falls ja, liegt das Problem nicht bei der avr-gcc Installation ;) )

MfG,
SlyD

EDIT:
Ach hattest die Ordnerstruktur ja weiter oben was gepostet.
Aber: Welche Dateien sind genau im Verzeichnis drin und heissen die genau so wie im makefile angegeben?

inka
19.07.2013, 07:38
hallo SlyD,

hier das ganze zusammengefasst:


Ich meinte damit nur dass Du nicht BEIDE Versionen gleichzeitig installieren sollst.


da ich nicht weiss, wo das problem liegt, dachte ich eher daran, die deb version als ersatz zu verwenden, da dort „alles aus einer hand“ und von avr ist. Nachdem ich über eclipse zu code:blocks kam und mit letzterem eigentlich zufrieden war tauchten diese probleme auf (siehe weiter unten). Jetzt möchte ich wissen, ob ich (so wie Dirk) mit make und makefile weiterkomme...

der letzter stand, die reaktion auf ein make im terminal, da suche ich die antwort drauf...


georg@netzserver:~/workspace/gyro_test_3$ make
-------- begin -------- avr-gcc (GCC) 4.5.3 Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
make: *** Keine Regel vorhanden, um das Target »gyro_test_3.elf«, benötigt von »elf«, zu erstellen. Schluss.
georg@netzserver:~/workspace/gyro_test_3$





Was genau ist denn aktuell noch das Problem?
Lassen sich die orginalen unveränderten Beispielprogramme übersetzen?
(falls ja, liegt das Problem nicht bei der avr-gcc Installation :wink: )
eigentlich weiss weder Dirk, noch ich woran es liegt. Ich versuche mal das problem zu beschreiben:


dieser code:

#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_OrientationLib.h"
//#include "RP6ControlServoLib.h"

#define I2C_RP6_BASE_ADR 10

/************************variables***************** ************************/

uint8_t ch;
char item[12];
char dir[3];



/*********************I2C-fehlermeldungen******************/

void I2C_transmissionError(uint8_t errorState) //gibt I2C fehlermeldungen über LCD aus
{
clearLCD();
writeStringLCD_P("I2C ERROR -->");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("TWI STATE: 0x");
writeIntegerLCD(errorState, HEX);
}

/**
* Returns a 2 character string for the eighth
* parts of the direction calculated from the
* heading value.
*
* Input: heading -> Heading value [0..359]
*
*/
void calculateDir(char *dir, uint16_t heading)
{
dir[1] = ' ';
dir[2] = '\0';
if ((heading <= 22) || (heading >=338)) dir[0] = 'N';
if ((heading >= 23) && (heading <= 67)) {dir[0] = 'N'; dir[1] = 'E';}
if ((heading >= 68) && (heading <= 112)) dir[0] = 'E';
if ((heading >= 113) && (heading <= 157)) {dir[0] = 'S'; dir[1] = 'E';}
if ((heading >= 158) && (heading <= 202)) dir[0] = 'S';
if ((heading >= 203) && (heading <= 247)) {dir[0] = 'S'; dir[1] = 'W';}
if ((heading >= 248) && (heading <= 292)) dir[0] = 'W';
if ((heading >= 293) && (heading <= 337)) {dir[0] = 'N'; dir[1] = 'W';}
}

/************************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]);
}


void writeDouble(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
dtostrf(number, width, prec, &buffer[0]);
writeString(&buffer[0]);
}

/*****************gyroscope***************/
void gyroscope(void) // L3GD20 gyroscope


{

// orientation_init();
task_I2CTWI();
readL3GD20(); // Get sensor values
normalizeL3GD20();
task_I2CTWI();
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(" ");
#ifdef GET_TEMP
temperatureg = calcTempL3GD20(temperatureg) + 5;
temperatureg += OFFSET_TEMP;
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("T");
writeIntegerLCD(temperatureg, DEC);
writeStringLCD_P(" ");
#endif
task_I2CTWI();
mSleep(3000);//4,5 sec
clearLCD();
}

/************accelerometer****************/
void accelerometer(void) // LSM303DLHC accelerometer
{
// orientation_init();
clearLCD();
task_I2CTWI();
readLSM303DLHC_A(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
writeStringLCD_P("Z");
writeIntegerLCD(z_axisa, DEC);
writeStringLCD_P(" ");
normalizeLSM303DLHC_A(); // Normalize data
positionLSM303DLHC_A(); // Calculate position
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("P");
writeDoubleLCD(pitch, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("R");
writeDoubleLCD(roll, 6, 1);
writeStringLCD_P(" ");
task_I2CTWI();
mSleep(3000);
}

/*****************magnetometer************/
void magnetometer(void) // LSM303DLHC magnetometer
{
// orientation_init();
clearLCD();
task_I2CTWI();
readLSM303DLHC_M(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
#ifndef GET_TEMP_M
writeStringLCD_P("Z");
writeIntegerLCD(z_axism, DEC);
writeStringLCD_P(" ");
#else
temperature_imu = (double) temperaturem / 8.0 + OFFSET_TEMP_M;
writeStringLCD_P("T");
writeDoubleLCD(temperature_imu, 5, 1);
#endif
normalizeLSM303DLHC_M(); // Normalize data
headingm = headingLSM303DLHC_M(); // Calculate heading
calculateDir(dir, headingm);
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("H");
writeIntegerLengthLCD(headingm, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
headingtc = headingLSM303DLHC_TC(); // Calculate TILT COMPENSATED
calculateDir(dir, headingtc); // heading
writeStringLCD_P(" C");
writeIntegerLengthLCD(headingtc, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
writeStringLCD_P(" ");
mSleep(3000);//4,5 sec
clearLCD();
task_I2CTWI();
}



/*************** hauptprogramm ***********/

int main(void)
{


initRP6Control();
initLCD();

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

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen

multiio_init();
orientation_init();

// Voltage & current sensor test:
LTC2990_measure();
setCursorPosLCD(0, 0);
//writeStringLCD("BAT Current: ");
//writeDoubleLCD(cbat, 6, 1);
writeStringLCD(" accu: ");
writeDoubleLCD(vbat, 4, 1);
writeStringLCD( " V");
mSleep(1500);


showScreenLCD(" RP6Control M32", " gyro_test_3");
mSleep(2500);
clearLCD();



while(true)
{

/*****************anzeige gedrückter buttons****************/
clearLCD();
pressedMultiIOButtonNumber = getMultiIOPressedButtonNumber();
setCursorPosLCD(0, 0);
writeStringLCD("Button: ");
writeIntegerLCD(pressedMultiIOButtonNumber, DEC);
mSleep(500);

uint8_t key = getMultiIOPressedButtonNumber();


/********************funktion der buttons*********************/
if(key)
{
switch(key)
{
case 1://
setLEDs(0b0001);
gyroscope();
break;

case 2://
setLEDs(0b0010);
accelerometer();
break;

case 3://
setLEDs(0b0100);
magnetometer();
break;

case 4://
setLEDs(0b1000);
gyroscope();
accelerometer();
magnetometer();
break;
}
}
}
return 0;
}
lässt sich:


bei Dirk wie auch bei mir fehlerfrei kompilieren
bei Dirk kompilierte version läuft bei uns beiden problemlos
die bei mir kompilierte version läuft bei mir NICHT (ob sie bei Dirk läuft weiss ich jetzt nicht mehr, vermutlich nicht)





Dirk kompiliert mit make und makefile
ich arbeite mit code:blocks, welche art der compilierung da im hintergrund läuft weiss ich nicht
das problem trat zuerst mit den dateien auf, in denen Dirks libs für das multi-IO board und die minIMU verwendet wurden (RP6Control_OrientationLib.c, RP6Control_Orientation.h, RP6Control_OrientationLib.h)






Ach hattest die Ordnerstruktur ja weiter oben was gepostet.
Aber: Welche Dateien sind genau im Verzeichnis drin und heissen die genau so wie im makefile angegeben?


files aus der gyro_test_3:


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_OrientationLib.h"

angaben im makefile:


# you would write: TARGET = RP6Base_MyProgram

TARGET = gyro_test_3

################################################## #############################



################################################## #############################
# Specify relative path to RP6 library files here.
# This is "../../RP6lib" or "../RP6lib" usually.

RP6_LIB_PATH=../RP6lib
RP6_LIB_PATH_OTHERS= $(RP6_LIB_PATH)/RP6control $(RP6_LIB_PATH)/RP6common

################################################## #############################


SRC += $(RP6_LIB_PATH)/RP6control/RP6ControlLib.c
SRC += $(RP6_LIB_PATH)/RP6common/RP6uart.c
#SRC += $(RP6_LIB_PATH)/RP6common/RP6I2CslaveTWI.c
SRC += $(RP6_LIB_PATH)/RP6common/RP6I2CmasterTWI.c

SRC += RP6Control_I2CMasterLib.c
SRC += RP6Control_MultiIOLib.c
SRC += RP6Control_OrientationLib.c
SRC += RP6Control_LFSBumperLib.c
SRC += $(RP6_LIB_PATH)/RP6control/RP6ControlServoLib.c


dateien im verzeichnis:


gyro_test_3.c
makefile
RP6Control_I2CMasterLib.c
RP6Control_I2CMasterLib.h
RP6Control_LFSBumperLib.c
RP6Control_LFSBumperLib.h
RP6Control_MultiIO.h
RP6Control_MultiIOLib.c
RP6Control_MultiIOLib.h
RP6Control_Orientation.h
RP6Control_OrientationLib.c
RP6Control_OrientationLib.h

SlyD
19.07.2013, 09:10
Hallo Inka,

> ich arbeite mit code:blocks, welche art der compilierung da im hintergrund läuft weiss ich nicht

Naja wird wohl den avr-gcc verwenden den Du schon installiert hast.
IDEs erzeugen oft auch nur ein makefile und rufen dann make auf und analysieren die Ausgaben.
Code::blocks verwendet aber glaube ich was eigenes.


Einen offensichtlichen Fehler kann ich da im makefile nicht erkennen.
Pack den ganzen Ordner inklusive RP6Lib mal (zip oder tar.gz) und schick ihn mir per Mail.
Ich schau mir dass dann mal an.

Und nochmal die Frage:
Lassen sich die orginalen unveränderten Beispielprogramme (ohne Code::blocks, direkt mit make!)
fehlerfrei übersetzen und laufen die dann auch auf dem RP6?
Das ist der erste Test den Du machen solltest um zu prüfen ob mit dem avr-gcc alles OK ist.



MfG,
SlyD

inka
19.07.2013, 09:56
hi SlyD,


Einen offensichtlichen Fehler kann ich da im makefile nicht erkennen.
Pack den ganzen Ordner inklusive RP6Lib mal (zip oder tar.gz) und schick ihn mir per Mail.
Ich schau mir dass dann mal an.

ist unterwegs...


Und nochmal die Frage:
Lassen sich die orginalen unveränderten Beispielprogramme (ohne Code::blocks, direkt mit make!)
fehlerfrei übersetzen und laufen die dann auch auf dem RP6?
Das ist der erste Test den Du machen solltest um zu prüfen ob mit dem avr-gcc alles OK ist.

die antwort auf ein make im terminal ist die gleiche - ich wüsste zu gerne welche "regel" er da sucht...


-------- begin --------
avr-gcc (GCC) 4.5.3
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

make: *** Keine Regel vorhanden, um das Target »RP6Base_SELFTEST.elf«,
benötigt von »elf«, zu erstellen. Schluss.
georg@netzserver:~/workspace/RP6_selftest$


den ordner für diesen test schicke ich auch...

SlyD
19.07.2013, 11:26
Naja das kann so natürlich nicht funktionieren (wenn das exakt die Ordnerstruktur ist die Du verwendest).

Den Ordner 2012_lib_komplett hast Du gar nicht ins makefile eingetragen.
(make ist absichtlich dumm gehalten, Du musst dem Tool ALLES explizit mitteilen damit eindeutig klar ist welche Dateien genommen werden sollen)
Und die Unterordner der RP6Lib sind ja komplett entfernt und alles in einen Ordner gepackt worden (warum?).
Aber dann muss man auch die Pfade im makefile entsprechend anpassen.

Das mit dem Selftest kann aus demselben Grund nicht funktionieren - Du hast nicht mehr die Ordnerstruktur aus den Beispielprogrammen - dann kann das makefile was dabei ist nicht funktionieren.
Mit "mit den orginalen Beispielen probieren" meinte ich: Archiv entpacken und alles genau so lassen nicht einzelne Ordner da rauskopieren ;)

Die Lösung ist einfach: Pfade anpassen!



RP6_LIB_PATH=../2012_lib_komplett
RP6_LIB_PATH_OTHERS= $(RP6_LIB_PATH)/RP6control $(RP6_LIB_PATH)/RP6common

SRC += $(RP6_LIB_PATH)/RP6ControlLib.c
SRC += $(RP6_LIB_PATH)/RP6uart.c
#SRC += $(RP6_LIB_PATH)/RP6common/RP6I2CslaveTWI.c
SRC += $(RP6_LIB_PATH)/RP6I2CmasterTWI.c

SRC += RP6Control_I2CMasterLib.c
SRC += RP6Control_MultiIOLib.c
SRC += RP6Control_OrientationLib.c
SRC += RP6Control_LFSBumperLib.c
SRC += $(RP6_LIB_PATH)/RP6ControlServoLib.c


Dann läufts problemlos durch.

MfG,
SlyD

- - - Aktualisiert - - -

PS:
Im makefile vom Selbsttest ist ein (eigentlich bereits bekannter) winzig kleiner bug drin: RP6Lib versus RP6lib funktioniert unter Linux nicht (Windows unterscheidet nicht zwischen Klein- und Großbuchstaben). Aber das war bei Dir nicht das Problem sondern das oben genannte.

Hast Dir da aber das einzige Programm aus allen Beispielen rausgepickt wo das der Fall ist bei allen anderen passts ;)
Den Bug wollte ich schonmal letztes Jahr korrigieren, aber hab wohl nicht mehr dran gedacht.

inka
19.07.2013, 12:05
Hi SlyD,



Naja das kann so natürlich nicht funktionieren (wenn das exakt die Ordnerstruktur ist die Du verwendest).
auf der gleichen "höhe" der struktur ist auch ein ordner "RP6Lib", der auch die entsprechenden unterordner hat. Das habe ich, nach dem es mit meinem ordner "2012_lib_komplett" nicht funtioniert hat versucht. Habe ich bei dem vielen schreiben vergessen zu erwähnen...



Den Ordner 2012_lib_komplett hast Du gar nicht ins makefile eingetragen.

den pfad im makefile habe ich angepasst gehabt:
- RP6_LIB_PATH=/2012_lib_komplett
- RP6_LIB_PATH=../2012_lib_komplett
- RP6_LIB_PATH=../../2012_lib_komplett

keine der drei varianten funktionierte...


(make ist absichtlich dumm gehalten, Du musst dem Tool ALLES explizit mitteilen damit eindeutig klar ist welche Dateien genommen werden sollen)
Und die Unterordner der RP6Lib sind ja komplett entfernt und alles in einen Ordner gepackt worden (warum?).

weil es für code:blocks einfacher war...ansonsten s.o.


Die Lösung ist einfach: Pfade anpassen!

was bedeutet eigentlich nun die fehlermeldung über die fehlende regel? Die kommt doch immer, egal wie ich die pfade gesetzt habe - und irgendeine version der pfade und der verzeichnisse hätte doch funktionieren müssen!?!

SlyD
19.07.2013, 13:23
auf der gleichen "höhe" der struktur ist auch ein ordner "RP6Lib", der auch die entsprechenden unterordner hat. Das habe ich, nach dem es mit meinem ordner "2012_lib_komplett" nicht funtioniert hat versucht. Habe ich bei dem vielen schreiben vergessen zu erwähnen...


Sind in dem RP6Lib Ordner denn auch die ganzen anderen Datei drin die da normalerweise nicht dabei sind (inka.c und der ganze MultiIO kram)?
Du musst ALLE Ordner und wichtigen lib Dateien im makefile drin haben.
Wenn Du es auf ZWEI Ordner aufgeteilt hast, muss das entsprechend angepasst werden.




den pfad im makefile habe ich angepasst gehabt:
- RP6_LIB_PATH=/2012_lib_komplett
- RP6_LIB_PATH=../2012_lib_komplett
- RP6_LIB_PATH=../../2012_lib_komplett

keine der drei varianten funktionierte...


../ heisst ein Verzeichnis höher und ist hier richtig.
Zwei Verzeichnisse höher passt natürlich nicht.
/ ist das Wurzelverzeichnis (quasi das "C:" von Linux)




was bedeutet eigentlich nun die fehlermeldung über die fehlende regel? Die kommt doch immer, egal wie ich die pfade gesetzt habe - und irgendeine version der pfade und der verzeichnisse hätte doch funktionieren müssen!?!

Jede Datei muss über die Angaben im makefile gefunden werden können.
Wird auch nur eine einzige nicht gefunden, kommt die Fehlermeldung (ist ziemlich nichtssagend, ich weiss, k.a. warum da nicht mal jemand etwas bessere Fehlermeldungen eingebaut hat ;) ).
Du hast da scheinbar einiges auf zwei Ordner aufgeteilt (dein 2012_komplett Ordner und RP6Lib). Hast das aber nicht im makefile drin stehen.

Das ist auch das einzige Problem hier: Du hast nicht alle Pfade korrekt angegeben.
Wie gesagt - wenn ich das hier so wie oben schon gepostet ändere funktioniert es sofort.
Entpacke doch mal das Archiv das Du mir geschickt hast 1:1 irgendwo hin und passe nur das makefile genau so an wie ich oben geschrieben habe.
Dann sollte es eigentlich klappen.

MfG,
SlyD

inka
20.07.2013, 13:17
hi SlyD,

Das ist auch das einzige Problem hier: Du hast nicht alle Pfade korrekt angegeben.
Wie gesagt - wenn ich das hier so wie oben schon gepostet ändere funktioniert es sofort.
Entpacke doch mal das Archiv das Du mir geschickt hast 1:1 irgendwo hin und passe nur das makefile genau so an wie ich oben geschrieben habe.
Dann sollte es eigentlich klappen.

es waren die pfade :-(

nach der anpasssung der pfade auf:

################################################## #############################
# Specify relative path to RP6 library files here.
# für ein gemeinsames verzeichnis "../2012_lib_komplett"

RP6_LIB_PATH_OTHERS=../2012_lib_komplett
RP6_LIB_PATH=../2012_lib_komplett

################################################## #############################

und änderungen bei der einbindung der sourcedateien lief es dann. Muss zugeben, bin richtig erschrocken, als make zum erstenmal fehlerfrei durchlief...

die probleme bei code:blocks sind auch behoben, dort war es eine andere ursache. Nachdem ich das programm deinstalliert habe und eine neuere version installiert habe, meldete sich code:blocks beim ersten kompilieren mit "<bits/predef.h> missing", nach längerem googeln musste ich libc6-dev-i386 nachinstallieren und ein pfad beim compiler von code:blocks ändern...

so habe ich nun auch die möglichkeit die ergebnisse von code:blocks mit make zu überprüfen...

vielen dank noch einmal an beide: SlyS und Dirk für euere mühe und geduld...

@Dirk: ich habe Dir eine *.c und die dazugehörige hex geschickt: welche werte liefert bei Dir button1?

SlyD
20.07.2013, 14:35
Ah sehr gut!



Muss zugeben, bin richtig erschrocken, als make zum erstenmal fehlerfrei durchlief...

;)

MfG,
SlyD

Dirk
20.07.2013, 16:07
@inka:

ich habe Dir eine *.c und die dazugehörige hex geschickt: welche werte liefert bei Dir button1?
Du hast eine Mail.

inka
20.07.2013, 16:16
@Dirk:

nachdem meine kompilier-umgebung nun wieder läuft bin ich die kalibriervorschrift mal durchgegangen. :-(

Wäre es nicht besser sich einen winkelstück (oder kugelgelenk mit klemmschraube) zu bauen mit dem man die verschiedenen lagen der minIMU simulieren kann ohne sich auf den boden legen zu müssen um auf dem RP6 der auf dem kopf steht die LCD abzulesen? Abgesehen davon dass man sehr aufpassen muss um den auch waagerecht zu halten!

Dirk
20.07.2013, 16:59
@inka:
Prima, dass bei dir jetzt alles wieder läuft.

Ja, eine Testumgebung braucht man.
In der Appnote AN3192 von ST, S. 15, wird eine hölzerne (!!!) Plattform (ohne Nägel/Schrauben/Metallteile!) empfohlen, auf der ein nivellierter Teller gedreht werden kann. Zusätzlich gibt es noch einen Kippmechanismus für den Sensor auf dem Teller und eine zuverlässige Nordmarkierung.
Mir war das zu umständlich, so dass ich mitten in einem Raum (weit weg von Kabeln, Metallteilen, ...) einen ca. 1m hohen "Turm" aus Holzkisten, Plastikkisten o.ä. aufgebaut habe. Oben drauf der RP6, auf einer glatten Fläche (Folie o.ä.) manuell drehbar. Eine Kippvorrichtung habe ich nicht vorgesehen, weil die Kalibrierung ja nicht variable Winkel braucht (außer 90° Winkel, die man auch so hinkriegt).
Also: Du kannst das sehr aufwändig, aber auch eher einfach machen. Wichtig bei Eigenanfertigungen dafür: Nur Kleben, nicht verschrauben oder mit Metallwinkeln befestigen!

inka
20.07.2013, 19:36
@Dirk,

ich habe mir eine kleine vorrichtung für die kalibrierung gebaut, aus kunststoff, würfelförmig, ein gewinde für die platinenbefestigung und drei durchgangsbohrungen für die befestigung des würfels in 3 achsen. So kann der RP6 stehen bleiben und nur die platine wird jeweils gedreht. Befestigung mit messingschrauben. Schicke demnächst ein foto...

frage: bei der einstellung des beschleunigungsmessers und des magnetometers ist die rede von "negativem maximalwert". Wenn ich messe "-43" und "-173" ist der negativer maximalwert "-43", oder?

Dirk
20.07.2013, 20:09
@inka:
Wow, klingt gut. Ich schicke dir meinen RP6 zum Kalibrieren! ;)

Wenn ich messe "-43" und "-173" ist der negativer maximalwert "-43", oder?
Ja, MAX wäre dann -43 und MIN -173.

inka
20.07.2013, 20:45
@Dirk:
kann man den das in der anleitung nicht irgendwie userfreundlicher formulieren? Mann könte doch von dem

kleinsten absoluten wert mit einem "-" zeichen versehen

sprechen?
Vielleicht bin ich komisch, das würde ich aber auf anhieb verstehen...

Dirk
20.07.2013, 20:50
Hi inka,

Mann könte doch von dem

kleinsten absoluten wert mit einem "-" zeichen versehen

sprechen?
Ok.
Wie könnte man das in der Anleitung besser formulieren?

inka
20.07.2013, 21:04
Drehen Sie den RP6 mehrmals um 360 um die Z Achse und notieren Sie den kleinsten absoluten Wert der mit einem "-" versehen ist ( den grösten negativen Wert)??

Dirk
20.07.2013, 21:16
Aber:
Es können ja 3 Fälle auftreten:
MIN <-> MAX
-173 <-> -43 (beide Werte negativ)
-14 <-> +56 (ein Wert negativ, ein Wert positiv)
123 <-> 346 (beide Werte positiv)

Wie kann man das eindeutig beschreiben?
Eigentlich sind die Begriffe Minimal- und Maximalwert da ziemlich eindeutig. Oder?

inka
21.07.2013, 07:49
Du hast ja recht...

ein anders problem: ich habe nun mit meiner vorrichtung werte aufgenommen, problem habe ich - ich habs schon fast erwartet - beim magnetometer, da werden die "maximalen negativ-werte" garnicht negativ:


// 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 375 // Offset Y-axis
#define MAX_Z 20000 // Max. Z-axis value
#define MIN_Z -20000 // Min. Z-axis value
#define OFFSET_Z 1065 // Offset Z-axis

// L3GD20 temperature sensor definitions:
//#define GET_TEMP // Use temperature sensor
//#define OFFSET_TEMP 0 // Temperature offset [°C]

// LSM303DLHC accelerometer:
#define I2C_MULTIIO_LSM303DLHC_A_ADR 0x32 // Default

// LSM303DLHC accelerometer calibration data:
#define MAX_X_A -100 // Max. X-axis value 1019
#define MIN_X_A -1024 // Min. X-axis value -1057
#define MAX_Y_A -106 // Max. Y-axis value 1029
#define MIN_Y_A -1013 // Min. Y-axis value -1064
#define MAX_Z_A 1041 // Max. Z-axis value 965
#define MIN_Z_A 950 // Min. Z-axis value -1057
#define OFFSET_PITCH_A 0.0 // Offset Pitch [°]
#define OFFSET_ROLL_A 0.0 // Offset Roll [°]

// LSM303DLHC magnetometer:
#define I2C_MULTIIO_LSM303DLHC_M_ADR 0x3c // Default

// LSM303DLHC magnetometer calibration data:
#define MAX_X_M 533.0 // Max. X-axis value 420.0
#define MIN_X_M 25.0 // Min. X-axis value -94.0
#define OFFSET_X_M 0 // Hard iron X-axis offset
#define MAX_Y_M 258.0 // Max. Y-axis value 341.0
#define MIN_Y_M -2.0 // Min. Y-axis value -125.0
#define OFFSET_Y_M 0 // Hard iron Y-axis offset
#define MAX_Z_M 128.0 // Max. Z-axis value 467.0
#define MIN_Z_M -5.0 // Min. Z-axis value -30.0
#define OFFSET_Z_M 0 // Hard iron Z-axis offset
#define DECLINATION_M 0.0 // E at local position [°]


in der praxis äußert sich das so, dass der RP6 "grob" richtung NORD steht, zeigt WEST an und beim drehen ist der bereich zwischen N und S ca. 90 °, die restlichen 270 grad verteilen sich auf den rest...

Also ziemlich verschoben, und nun?

ich kann mich noch an den film "Die Schatzinsel" erinnern, wo ein gewisser captain Flint den schiffskompass mit einer drunter gelegten axt beeinflusst hat. Wo finde ich eine solche axt?

Ich möchte nun ein bischen mit den werten rumspielen: Kann man (unser guru?) zumindest andeuten welche von den gemessenen werten welche größe beeinflusst? Ich meine z.b. wenn ich den MAX_Y_M von 258 in -200 ändere verschiebt es die N-anzeige um 25° nach ost?

Dirk
21.07.2013, 09:53
Hi inka,

... "Die Schatzinsel" erinnern, wo ein gewisser captain Flint den schiffskompass mit einer drunter gelegten axt beeinflusst hat. Wo finde ich eine solche axt?

Ja, wozu braucht man eigentlich den ganzen neumodischen Kram ... :)

Zum Gyro:
Sieht gut aus. Der X-Offset scheint mir ein bissl hoch (oder lebst du auf einem Hausboot oder im schwankenden Hochhaus im 20.Stock)?

Zum Accelerometer:
Die Max-X, Max-Y und die Z-Werte sind nicht ok. Durch die Kalibrierung müßte jede Achse auf die volle Erdbeschleunigung zu kalibrieren sein. Das heißt:
Max und Min Werte sollten fast identisch im hohen 3-stelligen bis niedrigen 4-stelligen Bereich sein bis auf das Vorzeichen, das bei Min ein "-" ist und bei Max ein "+".
Typische Werte also z.B. bei allen Achsen:
MIN <-> MAX
-1100 <-> +1045
-967 <-> +1012
Woran kanns liegen?
Die Achsen zeigen evtl. bei der Kalibrierung nicht genau Richtung Erdmittelpunkt (Max-Werte) bzw. genau von ihm weg (Min-Werte).

Zum Magnetometer:
Die Min-Werte scheinen mir etwas zu hoch und der Max-Z-Wert zu niedrig.
Woran kanns liegen? Magnetfeldeinflüsse? Metalle in der Nähe?
Wie hast du den Sensor angebracht? Wieviel Abstand hat er zur MultiIO bzw. zum RP6? Stimmen die Sensorachsen mit denen des RP6 überein?

... vielleicht klappt das dann ohne die Axt ... ;)

inka
21.07.2013, 11:02
Zum Gyro:
Sieht gut aus. Der X-Offset scheint mir ein bissl hoch (oder lebst du auf einem Hausboot oder im schwankenden Hochhaus im 20.Stock)?

nein, erster stock, nicht schwankend. Ich habe probeweise der X-offset auf etwa die hälfte (1625) verringert, die anzeige des X-gyro-wertes schnellte sofort um fast 2000 hoch, die anderen bewegen sich im bereich +/- 10 um null herum
also lasse ich es erstmal...


Zum Accelerometer:
Die Max-X, Max-Y und die Z-Werte sind nicht ok. Durch die Kalibrierung müßte jede Achse auf die volle Erdbeschleunigung zu kalibrieren sein. Das heißt:
Max und Min Werte sollten fast identisch im hohen 3-stelligen bis niedrigen 4-stelligen Bereich sein bis auf das Vorzeichen, das bei Min ein "-" ist und bei Max ein "+".
Typische Werte also z.B. bei allen Achsen:
MIN <-> MAX
-1100 <-> +1045
-967 <-> +1012
Woran kanns liegen?
Die Achsen zeigen evtl. bei der Kalibrierung nicht genau Richtung Erdmittelpunkt (Max-Werte) bzw. genau von ihm weg (Min-Werte).

ich habe die werte probehalber geändert:


// LSM303DLHC accelerometer:
#define I2C_MULTIIO_LSM303DLHC_A_ADR 0x32 // Default

// LSM303DLHC accelerometer calibration data:
#define MAX_X_A 1000 // Max. X-axis value 1019 -100
#define MIN_X_A -1024 // Min. X-axis value -1057
#define MAX_Y_A 1060 // Max. Y-axis value 1029 -106
#define MIN_Y_A -1013 // Min. Y-axis value -1064
#define MAX_Z_A 1041 // Max. Z-axis value
#define MIN_Z_A -950 // Min. Z-axis value -1057 950
#define OFFSET_PITCH_A 0.0 // Offset Pitch [°]
#define OFFSET_ROLL_A 0.0 // Offset Roll [°]

die aufteilung auf die 360° ist besser, N ist noch um ca. 90° cw versetzt (bei der anzeige case3, also eigentlich magnetometer)...




Zum Magnetometer:
Die Min-Werte scheinen mir etwas zu hoch und der Max-Z-Wert zu niedrig.
Woran kanns liegen? Magnetfeldeinflüsse? Metalle in der Nähe?
Wie hast du den Sensor angebracht? Wieviel Abstand hat er zur MultiIO bzw. zum RP6? Stimmen die Sensorachsen mit denen des RP6 überein?

der sensor ist hinten, die befestigungsschraube der Multi_IO neben der sicherung habe ich durch eine messingsäule (conrad) ersetzt, höhe zu platine ca 70mm, die bestückung des sensors ist unten (richtung RP6), die anschlusspins liegen in fahrtrichtung vorne...


frage:
wenn ich die normalize-funktion auskommentiere, kümmert sich das kalibrierprogramm um die (noch alten) eingetragenen Offset-werte (alle drei sensoren), oder werden diese angaben ignoriert?

Dirk
21.07.2013, 12:15
Hi inka,
du willst es jetzt aber wissen.

(Zum Accelerometer: ) ...ich habe die werte probehalber geändert:
Ok. Das sollte aber auch problemlos zu kalibrieren sein!
Mach es doch so, dass du z.B. den RP6 in der Hand hältst und auf die rechte Seite neigst. Beobachte dabei den X-Wert und kippe den RP6 so lange in der Rechts-Seitenlage umher, bis der X-Wert maximal wird. ACHTUNG: Lies erst weiter unten den Text zur Ausrichtung des Sensors, die bei dir anders ist, sonst hast du ganz andere Achsen als ich!!


die aufteilung auf die 360° ist besser, N ist noch um ca. 90° cw versetzt (bei der anzeige case3, also eigentlich magnetometer)...
Die Werte des Accelerometers nehmen NUR Einfluss auf das TILT COMPENSATED Heading (Neigungs-kompensierte Richtung,- das ist der Wert in der 2. Zeile hinter "C" der Magnetometer-Ausgabe). Wenn die Richtungsangaben "versetzt" sind, kann das NUR am Magnetometer liegen.


der sensor ist hinten, die befestigungsschraube der Multi_IO neben der sicherung habe ich durch eine messingsäule (conrad) ersetzt, höhe zu platine ca 70mm, die bestückung des sensors ist unten (richtung RP6), die anschlusspins liegen in fahrtrichtung vorne...
1. Die Höhe ist ok, ich würde aber eher Plastikabstandhalter und eine Plastikschraube nehmen. Müßte aber auch mit den Messing-Dingern klappen, wenn da kein Eisenanteil drin ist.
2. Bestückung des Sensors nach UNTEN ist ok.
3. Anschlusspins in Fahrtrichtung vorn: Die Lib ist so geschrieben, dass die Anschlußpins der minIMU-9 v2 (hast du genau die auch??) in Fahrtrichtung RECHTS sind. Schaut man also von oben in Fahrtrichtung des RP6 (man steht also hinter dem RP6) auf den Sensor, dann kann man die Beschriftung aufrecht lesen, SDA/SCL sind rechts und die Y-Achsen-Beschriftung zeigt nach vorn, die der X-Achse nach links.


frage: 1) wenn ich die normalize-funktion auskommentiere, kümmert sich das kalibrierprogramm um die (noch alten) eingetragenen Offset-werte (alle drei sensoren), oder werden diese angaben ignoriert?
Die Normalize-Funktionen können immer drin bleiben, müssen also auch beim Kalibrieren nicht auskommentiert werden.
Nachdem du die Kalibrierungs-Werte ermittelt und in der RP6Control_Orientation.h geändert hast, muss das Programm neu kompiliert werden. Vorher unbedingt die .st und .o Dateien der Orientation-Lib löschen! Dann kannst du erst prüfen, ob deine Kalibrierung gelungen ist. Wenn nicht, müßtest du sie wiederholen.


frage: 2) in der magnetometeranzeige - die einzige, in der ich beim drehen des RP6 eine richtungsänderung erkenne - wird diese nur grob in himmelsrichtungen angezeigt. Wie müsste ich diese anzeige/den code verändern um beim drehen des RP6 zahlen zu sehen (N=0, E=90,....)? Dann hätte ein weiteres experimetieren mit willkürlichen änderungen an den offsets noch eine aussicht auf erfolg....Zumindest verspreche ich mir davon eine etwas genauere erkenntnis über abhängigkeiten...
In der 2. LCD-Zeile der Anzeige für das Magnetometer erscheint ja ein "H" für Heading, dahinter die Gradzahl und daneben die Grobrichtung als Buchstabe (N, SE, W ...). Dahinter erscheint das "C" für Tilt compensated Heading mit der Gradzahl, daneben wieder die Grobrichtung.
Da ist doch alles drin, oder?

- - - Aktualisiert - - -

Noch ne Ergänzung:

1. Die Ausgabe aller Werte auf dem LCD in der Demo liegt ja daran, dass das GPS-Modul den UART braucht. Wenn du NUR die minIMU testen willst, sende doch die Werte an das Terminal, da sind sie besser zu erkennen und zu beschriften.

2. Da der Gyro-Test erstmal nicht gebraucht wird, kommentier ihn doch in der Demo 05 aus, dann gibt es schon mal 1 Anzeige weniger.

inka
21.07.2013, 13:43
Hi Dirk,

ACHTUNG: Lies erst weiter unten den Text zur Ausrichtung des Sensors, die bei dir anders ist, sonst hast du ganz andere Achsen als ich!!
die frage hätte ich schon viel früher stellen sollen, ich hatte da was in erinnerung von der HDMM, dort hatte ich die anschlüsse vorne. Ist evtl. im RN-artikel ein bild auf dem man die lage der minIMU erkennen kann? Konnte jetzt keinen finden...



Anschlusspins in Fahrtrichtung vorn: Die Lib ist so geschrieben, dass die Anschlußpins der minIMU-9 v2 (hast du genau die auch??) in Fahrtrichtung RECHTS sind. Schaut man also von oben in Fahrtrichtung des RP6 (man steht also hinter dem RP6) auf den Sensor, dann kann man die Beschriftung aufrecht lesen, SDA/SCL sind rechts und die Y-Achsen-Beschriftung zeigt nach vorn, die der X-Achse nach links.
jetzt passen auch in etwa die ausgaben! Ich habe jetzt den RP6 auf einen holzdrehteller gestellt:
wenn ich ihn jetzt mit der frontseite in richtung N ausrichte und dann so drehe, als das das heck richtung N zeigt, wird im LCD nicht 180° sondern 192° angezeigt. Muss man damit leben, oder noch einmal kalibrieren? Hast Du mal mit Deinem so etwas getestet?




Die Normalize-Funktionen können immer drin bleiben, müssen also auch beim Kalibrieren nicht auskommentiert werden.

hast Du nicht mal sowas geschrieben?

Zu 2:
Wichtig ist, dass du dir die ROHWERTE, die der Sensor direkt ausgibt, ansiehst. Für den Gyro wären das also die Werte, die die Funktion readL3GD20() ausgibt. Wenn die Werte erst durch die Normalisierungsfunktion normalizeL3GD20() gejagt sind, kannst du sie für die Kalibrierung nicht mehr verwenden, weil die Normalisierungsfunktion ja genau die von dir angegebenen Kalibrierungswerte nutzt, um die Rohwerte anzupassen.


In der 2. LCD-Zeile der Anzeige für das Magnetometer erscheint ja ein "H" für Heading, dahinter die Gradzahl und daneben die Grobrichtung als Buchstabe (N, SE, W ...). Dahinter erscheint das "C" für Tilt compensated Heading mit der Gradzahl, daneben wieder die Grobrichtung.
Da ist doch alles drin, oder?
habe ich vor lauter kalibrieren übersehen :-)

Dirk
21.07.2013, 20:27
Hi inka,
klingt so, als wenn du inzwischen Land siehst.


Ist evtl. im RN-artikel ein bild auf dem man die lage der minIMU erkennen kann? Konnte jetzt keinen finden...
Stimmt. Es gibt in der Lib nur die Lagebeschreibungen der Sensoren in den Funktionen headingHDMM01() für den HDMM01 und headingLSM303DLHC_M() für die MinIMU-9 v2.
Ich werde die Lage noch in RN-Wissen übernehmen.


das heck richtung N zeigt, wird im LCD nicht 180° sondern 192° angezeigt. Muss man damit leben, oder noch einmal kalibrieren?
Nein, das ist zuviel. Eine absolute Abweichung von 3-4° ist ok. Die kann man noch etwas durch die Declination (Mißweisung) verbessern.
Auf welchen Wert beziehst du dich? H oder C?


(Die Normalize-Funktionen können immer drin bleiben, müssen also auch beim Kalibrieren nicht auskommentiert werden.) ... hast Du nicht mal sowas geschrieben?
Ja. Meine Schuld. Damals hatte ich noch normalize-Funktionen, die man zum Kalibrieren weglassen mußte. Das hat sich jetzt geändert (weil zu fehlerträchtig). Im RN-Wissen habe ich das dann auch schon rausgenommen.
Es hat aber auch nicht geschadet, wenn du sie fürs Kalibrieren auskommentiert hast: Das Kalibrieren funktioniert trotzdem.

inka
22.07.2013, 09:58
Hi Dirk,

klingt so, als wenn du inzwischen Land siehst.
Ja, dank Deiner hilfe...


Stimmt. Es gibt in der Lib nur die Lagebeschreibungen der Sensoren in den Funktionen headingHDMM01() für den HDMM01 und headingLSM303DLHC_M() für die MinIMU-9 v2. Ich werde die Lage noch in RN-Wissen übernehmen.
habe Dir zwei fotos geschickt, auch die kalibriervorrichtung, vielleicht kanns Du damit was anfangen...



Nein, das ist zuviel. Eine absolute Abweichung von 3-4° ist ok. Die kann man noch etwas durch die Declination (Mißweisung) verbessern.
Auf welchen Wert beziehst du dich? H oder C? hab es mit änderungen an den kalibrierdaten auf ca. 2° runterbekommen...

edit: - die H und C werte sind bei mir identisch...



Damals hatte ich noch normalize-Funktionen, die man zum Kalibrieren weglassen mußte. Das hat sich jetzt geändert (weil zu fehlerträchtig). Im RN-Wissen habe ich das dann auch schon rausgenommen.
Es hat aber auch nicht geschadet, wenn du sie fürs Kalibrieren auskommentiert hast: Das Kalibrieren funktioniert trotzdem.
wie unterscheidet der RP6, bzw. die IO platine ob ich kalibrieren oder mormal messen will (ich denke hier z.b. an die demo_05)?

Dirk
22.07.2013, 16:17
Hi inka,


wie unterscheidet der RP6, bzw. die IO platine ob ich kalibrieren oder mormal messen will (ich denke hier z.b. an die demo_05)?
Gar nicht. Die angezeigten X/Y/Z-Werte sind immer die Rohwerte aus dem Sensor.
Die kalibrierten X/Y/Z-Werte werden in der Demo 05 nicht angezeigt.

Jetzt habe ich auch die Ausrichtung der minIMU-9 v2 und des HDMM01 auf dem RP6 im RN-Wissen-Artikel dargestellt: Klick! (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Achsen_der_Kompasssensoren)

inka
22.07.2013, 16:43
Hi Dirk,


Gar nicht. Die angezeigten X/Y/Z-Werte sind immer die Rohwerte aus dem Sensor.
Die kalibrierten X/Y/Z-Werte werden in der Demo 05 nicht angezeigt.
ich habe diesen code nun weitgehends aus der demo_05 rauskopiert:

void magnetometer(void) // LSM303DLHC magnetometer
{
mSleep(1000);
task_I2CTWI();
readLSM303DLHC_M(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axism, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
#ifndef GET_TEMP_M
writeStringLCD_P(" Z");
writeIntegerLCD(z_axism, DEC);
writeStringLCD_P(" ");
#else
temperature_imu = (double) temperaturem / 8.0 + OFFSET_TEMP_M;
writeStringLCD_P("T");
writeDoubleLCD(temperature_imu, 5, 1);
#endif

normalizeLSM303DLHC_M(); // Normalize data
headingm = headingLSM303DLHC_M(); // Calculate heading
calculateDir(dir, headingm);
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("H");
writeIntegerLengthLCD(headingm, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
headingtc = headingLSM303DLHC_TC(); // Calculate TILT COMPENSATED
calculateDir(dir, headingtc); // heading
writeStringLCD_P(" C");
writeIntegerLengthLCD(headingtc, DEC, 3);
writeStringLCD_P(" ");
writeStringLCD(dir);
writeStringLCD_P(" ");
mSleep(1000);
// clearLCD();
task_I2CTWI();
}


Fragen:

1) sind die werte, die hier auf dem LCD-display angezeigt werden nun die rohwerte oder die normalisierten werte?

2) da nach dem was oben steht das normalisieren in der "RP6Control_MultiIO_05.c" nicht mehr stattfindet, was bedeutet die zeile
--------------------------------------
#ifdef IMU_9D
// 9D-IMU test:
// L3GD20 gyroscope:
task_I2CTWI();
readL3GD20(); // Get sensor values
normalizeL3GD20();
----------------------------------
????


Jetzt habe ich auch die Ausrichtung der minIMU-9 v2 und des HDMM01 auf dem RP6 im RN-Wissen-Artikel dargestellt: Klick! (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Achsen_der_Kompasssensoren)

super...

was sagst Du zu meinem kalibrierwürfel?

Dirk
22.07.2013, 18:14
Hi inka,


1) sind die werte, die hier auf dem LCD-display angezeigt werden nun die rohwerte oder die normalisierten werte?
Die Rohwerte.
Wenn du etwas in die Lib reingucken willst: Die Variablen "x_axis?" sind die X-Rohwerte. Wenn das "?" gleich "g" ist (also x_axisg), sind das die Rohwerte des Gyro, bei "a" die des Accelerometers und bei "m" die des Magnetometers.
Das bleiben auch nach der Kalibrierung die Rohwerte.
Wenn du die kalibrierten X/Y/Z-Werte ansehen willst, dann sind das die Variablen xg, yg, zg (Gyro), xa, ya, za (Accelerometer), xm, ym, zm (Magnetometer). Diese Werte werden von der jeweiligen normalize-Funktion ausgespuckt.


2) da nach dem was oben steht das normalisieren in der "RP6Control_MultiIO_05.c" nicht mehr stattfindet, was bedeutet die zeile normalizeL3GD20();
Warum findet kein Normalisieren mehr statt? Für jeden der 3 minIMU-Sensorern gibt es doch eine Normalisierungsfunktion. Ohne diese Funktionen würden die Kalibrierungswerte nicht genutzt.


was sagst Du zu meinem kalibrierwürfel?
Genial. Da fällt das Kalibrieren leicht und man kann ja den Würfel auch nach dem Kalibrieren drinlassen, um die Anpassung an die RP6-Achsen zu machen.
Klasse. :)

inka
22.07.2013, 19:57
Hi Dirk,

Die Rohwerte.
Wenn du etwas in die Lib reingucken willst: Die Variablen "x_axis?" sind die X-Rohwerte. Wenn das "?" gleich "g" ist (also x_axisg), sind das die Rohwerte des Gyro, bei "a" die des Accelerometers und bei "m" die des Magnetometers.
Das bleiben auch nach der Kalibrierung die Rohwerte.
Wenn du die kalibrierten X/Y/Z-Werte ansehen willst, dann sind das die Variablen xg, yg, zg (Gyro), xa, ya, za (Accelerometer), xm, ym, zm (Magnetometer). Diese Werte werden von der jeweiligen normalize-Funktion ausgespuckt.

das heisst ich muss im prinzip beim kalibrieren beide variablen ausgeben/sehen: x_axism und xm. Die x_axis_m messe ich zunächst, verändere (kalibriere) sie durch eintragen von MAX_X_M (und MIN_X_M) und nach erneutem kompilieren kann ich das ergebnis in xm erst sehen?




Genial. Da fällt das Kalibrieren leicht und man kann ja den Würfel auch nach dem Kalibrieren drinlassen, um die Anpassung an die RP6-Achsen zu machen.
Klasse. :)
um auf Deine frage aus der mail einzugehen: der würfel ist aus PVC, kantenlänge 10mm. Die drei sich kreuzenden 3mm löcher hätten etwas näher an die gemeinsame ecke sein können, in einer der drei positionen beim kalibrieren war es zu der 6kantstange etwas eng...

Dirk
22.07.2013, 20:12
Hi inka,

das heisst ich muss im prinzip beim kalibrieren beide variablen ausgeben/sehen: x_axism und xm. Die x_axis_m messe ich zunächst, verändere (kalibriere) sie durch eintragen von MAX_X_M (und MIN_X_M) und nach erneutem kompilieren kann ich das ergebnis in xm erst sehen?
Exakt.
Nur eine kleine Ergänzung: Zum Kalibrieren brauchst du nur die Rohwerte. Nach dem Kalibrieren und Neukompilieren kann mit den kalibrierten Werten zuverlässig Pitch, Roll, Heading, TC-Heading berechnet werden.

Also:
Mit den X/Y/Z-Werten (roh oder kalibriert) kann man ja eigentlich wenig anfangen.
Beim Accelerometer errechnet man daraus Pitch und Roll,
beim Magnetometer die Richtung und aus beiden die neigungskompensierte Richtung.
Mehr wird da draus nicht.

Der einzige Sensor, bei dem man i.d.R. mit den X/Y/Z-Werten weiter rechnet, ist der Gyro.

inka
23.07.2013, 15:29
Hi Dirk,

ich habe den code für den gyro um die ausgabe der normalisierten werte ergänzt, die funktion sieht jetzt so aus:


void gyroscope(void) // L3GD20 gyroscope

{
mSleep(1000);
task_I2CTWI();
readL3GD20(); // Get sensor values
normalizeL3GD20();
task_I2CTWI();
clearLCD();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisg, DEC);
setCursorPosLCD(0, 6); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axisg, DEC);
setCursorPosLCD(0, 12); // line1 pos 12
writeStringLCD_P("Z");
writeIntegerLCD(z_axisg, DEC);

setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("X");
writeIntegerLCD(xg, DEC);
setCursorPosLCD(1, 6); // line 2 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(yg, DEC);
setCursorPosLCD(1, 12); // line 2 pos 12
writeStringLCD_P("Z");
writeIntegerLCD(zg, DEC);


#ifdef GET_TEMP
temperatureg = calcTempL3GD20(temperatureg) + 5;
temperatureg += OFFSET_TEMP;
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("T");
writeIntegerLCD(temperatureg, DEC);
writeStringLCD_P(" ");
#endif
mSleep(2000);//3 sec
clearLCD();
task_I2CTWI();
}
ich habe Deine erklärungen so verstanden, dass die normalisierten werte sich durch die normalisierung von den rohwerten unterscheiden, in der ausgabe dieser funktion sind beide zeilen gleich, oben die rohwerte (x_axisg) unten die normalisierten (xg). Da ist doch irgendwas falsch, oder?

Dirk
23.07.2013, 16:50
Die Variablen xg, yg und zg sind Floating Points.
Du müßtest also die Funktion writeDoubleLCD() zur Ausgabe nehmen.
Das passt dann kaum noch aufs LCD: Ich würde die Werte über das Terminal ausgeben.

inka
24.07.2013, 07:32
ok, habe nun den code etwas verändert:



// setCursorPosLCD(1, 0); // line 2
// writeStringLCD_P("X");
writeString_P("x: ");
writeDouble(xg, 5, 5);
writeString_P("\n");


im terminal wird der wert der xg-variablen jetzt ausgegeben, ist aber immer noch identisch mit x_axis_g, nur mit angehängten 5 nullen hinterm koma...

ob die zwei zahlen 5, 5 nun passend sind weiss ich nicht so genau, auch bei 1, 1 verändert sich nur die zahl der nullen...

irgendwie habe ich erwartet, dass der unterschied zwischen x_axis_g und xg signifikanter ist?

Dirk
24.07.2013, 17:02
Hi inka,

du bist ja da beim Gyro:
Die "Normalisierung" geschieht in der Funktion normalizeL3GD20() zum einen durch eine Begrenzung der Werte nach oben/unten auf 20000/-20000.
Zum anderen wird ein OFFSET addiert (OFFSET_X/Y/Z).
Nach der Normalisierung werden sich die kalibrierten Werte (xg, yg, zg) nicht von den Rohwerten (x_axisg, y_axisg, z_axisg) unterscheiden.

inka
25.08.2013, 17:54
@Dirk,

die sache mit dem "make" und den "strukturen" scheine ich jetzt verstanden zu haben. Die kalibrierung des gyro mit der "demo_05_02" hat auch einigermassen geklapt, jetzt möchte ich weitermachen mit accelerometer und magnetometer.

Dieser code hier (als beispiel für den accelerometer):

#ifdef IMU_9D
// LSM303DLHC accelerometer:
task_I2CTWI();
readLSM303DLHC_A(); // Get sensor values
task_I2CTWI();
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("X");
writeIntegerLCD(x_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 5); // line 1 pos 6
writeStringLCD_P("Y");
writeIntegerLCD(y_axisa, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(0, 10); // line 1 pos 11
writeStringLCD_P(" Z");
writeIntegerLCD(z_axisa, DEC);
writeStringLCD_P(" ");
normalizeLSM303DLHC_A(); // Normalize data
positionLSM303DLHC_A(); // Calculate position
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("P");
writeDoubleLCD(pitch, 6, 1);
writeStringLCD_P(" ");
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("R");
writeDoubleLCD(roll, 6, 1);
writeStringLCD_P(" ");
task_I2CTWI();
mSleep(1000);
clearLCD();
#endif

sollte das "normalize" nun auskommentiert werden, oder nicht? Wie ist der letzter stand in der lib?

btw: meine kalibriervorrichtung, auf die ich soo stolz war taugt nicht viel. habe festgestellt, dass beim umschrauben 1° versatz reicht, um völlig andere werte zu bekommen. Eigentlich müsste man sich über eine genaue und zwar wiederholbar genaue befestigung der minIMU gedanken machen!

Dirk
25.08.2013, 19:41
@inka:

Beschleunigungssensor:
In der Funktion normalizeLSM303DLHC_A() werden die X/Y/Z-Rohwerte nur begrenzt. Außerdem erfolgt die Ausgabe in der Demo ja VOR Aufruf der normalizeLSM303DLHC_A()-Funktion, so dass du sie ruhig drin lassen kannst.
Aber: Pitch und Roll werden NACH Normalisierung berechnet, also aus den begrenzten Rohwerten.

Magnetfeldsensor:
Auch hier werden die Rohwerte in der Demo VOR der Normalisierungsfunktion ausgegeben, so dass sie unverändert sind.
Aber: Die Berechnung der Richtung erfolgt dann mit den normalisierten Rohwerten.

inka
31.08.2013, 17:14
@Dirk:

ich kämpfe immer noch mit dem begriff "negativer Maximalwert". Beim kalibrieren des magnetometers waren diese negativen maximalwerte werte alle drei (X,Y und Z) nahe null, oder sogar gleicn null. Die "negativen Minimalwerte" entsprachen in ihrem absolutwert aber in etwa dem absoluten wert der "positiven Maximalwerte". Irgendwie würde ich dazu tendieren für das "nullen" eines sensors die jeweils maximalen "ausschläge" in positiver wie auch negativer richtung zu verwenden. Gibt es eine allgemeinverständliche erklärung dafür, dass es hier anders ist?

Dirk
31.08.2013, 18:59
@inka:
Möglicherweise habe ich mich nicht mathematisch korrekt ausgedrückt:
Zur Kalibrierung wird der jeweils größte (MAX) und jeweils kleinste Wert (MIN) benötigt.

Beispiele:
a) -20 -14 -8 +2 +23 +177
==> MIN = -20 und MAX = +177

b) +44 +56 +126 +1244 +2833
==> MIN = +44 und MAX = +2833

c) -2833 -574 -233 -88 -12
==> MIN = -2833 und MAX = -12

So klarer?