Archiv verlassen und diese Seite im Standarddesign anzeigen : HDMM01 und die orientierungslib von Dirk
hi allerseits,
ich habe mir ein kleines progrämmchen zusammengestöpselt
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
#include "RP6Control_I2CMasterLib.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
uint16_t heading;
void I2C_requestedDataReady(uint8_t dataRequestID) //macht was?
{
checkRP6Status(dataRequestID);
}
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
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);
}
int main(void)
{
initRP6Control();
initLCD();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);//macht was?
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen
showScreenLCD(" RP6Control M32", " gyro_test_2");
mSleep(2500);
clearLCD();
orientation_init();
while(true)
// task_I2CTWI();
{
task_I2CTWI();
intreg2dm = readHDMM01(); // holt sersorwerte
if(!intreg2dm)
{ // daten gültig?
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
setCursorPosLCD(0, 0);
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
setCursorPosLCD(1, 0);
writeStringLCD_P("direction ");
calculateDir(dir, heading); //berechnung der richtung (N,S,W,E)
writeCharLCD(dir[0]); //ausgabe der ersten stelle des richtungswertes - es wird grundsätzlich nur "N" ausgegeben...
// writeCharLCD(dir[1]); //ausgabe der 2ten stelle des richtungswertes -funktioniert nicht...
}
// move(60, 0, 1000, 1);
move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(300);
rotate(50, 3, 90, 1); //wendet um 90°
clearLCD();
task_I2CTWI(); //macht was?
}
return 0;
}
es macht nicht viel: fährt im viereck (ungefähr) und gibt auf dem LCD die headingwerte des 2D kompasses aus.
Es werden auch noch die himmelsrichtungen berechnet, die ausgabe funktioniert aber schon mal nicht korrekt: es wird grundsätzlich nur ein "N" ausgegeben. Diese "himmelsrichtungen" sind zwar nicht wichtig, für die bestimmung und änderung der fahrtrichtung sind sie zu grob, aber für die ausgabe am display wäre es für mich schon wichtig was da nicht stimmt...
im weiteren verlauf möchte ich folgendes versuchen zu realisieren:
- fahren in bestimmte himmelsrichtungen, evtl. nach abfrage der taster oder anderen vorgaben
- richtungswechsel nach der erkennung eines hindernises
- abfrage der momentaner fahrtrichtung und korrektur mit taster li/re oder um eine gradzahl, (per RC?)
im moment verstehe ich vieles im code nicht, deshalb habe ich als kommentare fragen eingefügt, wäre schön, wenn mir jemand ein paar tipps zum verständnis geben könnte...
@inka:
Die Anzeige der 1/8-Richtung ist mit einem String aus 2 Zeichen gemacht.
Die Ausgabe kann man so machen:
writeStringLCD(dir);
Unabhängig davon müßte die Funktion so aufgerufen werden:
calculateDir(dir, heading2dm);
Die Funktion/Task task_I2CTWI() wird beim I2C-Master eigentlich nur gebraucht, wenn man Daten im Hintergrund vom Slave lesen möchte. In der Anleitung zum RP6 kann man das in "4.6.11.2. I²C Master" nachlesen. Da wir solche Funktionen (in der jetzigen Lib- und Demo-Version) nicht nutzen, muss diese Task nicht eingebaut werden.
Aber: Das ist ja genau eine Aufgabe als Programmer des RP6! Nehmen wir an, der Headingwert beträgt aktuell 180° (S), du möchtest aber nach Osten (90°, E) fahren. Dann must du deinem Rotate-Befehl sagen, dass der RP6 um 90° nach links rotieren muss. Danach must du wieder den Headingwert bestimmen und erneut mit Rotate korrigieren oder durch den move-Befehl den neuen Kurs halten, indem du jeweils eine Kette etwas langsamer machst, wenn eine Abweichung von deiner Zielrichtung erkannt wird.
Das ist schon eine nette Herausforderung!! :)
da gib ich dir uneingeschränkt recht!! :-)
der folgender code soll bewirken, dass sie der RP6 - je nachdem welcher headingwert gemessen wurde - nach norden ausrichtet und das auf dem kürzesten weg, also nicht immer nur rechtsherum. Die headingswerte werden ausserhalb des bereiches für case1 gemessen, deshalb hier auskommentiert...
case 1://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
{
/*
intreg2dm = readHDMM01(); // holt sersorwerte
if(!intreg2dm) //daten gültig?
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
*/
setCursorPosLCD(0, 0);
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
mSleep(1000);
setCursorPosLCD(1, 0);
writeStringLCD_P("direction ");
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
writeStringLCD(dir); //ausgabe der richtung
}
if (heading2dm < 180) rotate (100, 2, heading2dm, 1);
else rotate (100, 3, 360-heading2dm, 1);
// move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(1000);
// rotate(50, 3, 90, 1); //dreht um 90°
clearLCD();
ich habe auch die move befehle hier auskommentiert, ich lasse ihn erstmal nur auf der stelle drehen.
- nach links funktioniert es, auch wenn sehr ungenau - da müsste ich also die zweite messung und korrektur einbauen, das mache ich noch.
- hat die genauigkeit etwas mit der geschwindigkeit des drehens zu tun? Ich habe den eindruck, dass er, wenn er schneller ist, weit mehr übers ziel hinausgeht...und wenn er langsammer ist, das ziel nicht erreicht!
- nach rechts, also wenn der gemessener headingwert > 180° ist, dreht er sich im kreis ohne anzuhalten und ich komme nicht drauf warum!?!?
@inka:
Du must etwas mehr Aufwand treiben, um das "Problem" zu lösen.
1. Du kannst z.B. eine Variable definieren, in der du die ZIELRICHTUNG angibst, nennen wir sie int16_t new_dir .
2. Den gemessenen Heading Wert (also die aktuelle Richtung des RP6!) tun wir in eine weitere Variable: int16_t old_dir .
3. Dann muss eine "Formel" her (nicht getestet!!!), um die Abweichung zu berechnen:
int16_t temp;
temp = new_dir - old_dir;
if (new_dir < old_dir) temp += 360;
Wenn du ein Test-Prog schreibst, würde ich das auch so machen, wie du. Als Test stellt man den RP6 in eine beliebige Richtung auf und läßt ihn in die Zielrichtung (new_dir) auf der Stelle drehen. Die Variable temp kann man dann in Rotate einsetzen. Je nach Vorzeichen (+ -) dreht man nach links oder rechts.
Wenn man das gut gemacht hat, müßte sich der RP6 immer auf kürzestem Weg zur Zielrichtung drehen.
Wahrscheinlich wird ein EINMALIGES Drehen nicht zum Ziel führen, weil Rotate ziemlich ungenau ist. In deinem Prog solltest du also noch 2-3 Korrekturschleifen einbauen.
@dirk:
was ich in dem code nicht verstehe ist das ende der zweiten zeile: "temp += 360;
sollte nicht je nach ergebnis der if abfrage 360 abgezogen, oder dazugezählt werden? Also + oder -?
@inka:
Ja, kann sein, dass die Formel so noch nicht stimmt! Ich habe sie nur nur mal schnell zusammen geschustert und nicht geprüft.
Am besten machst du dir mal ein Testprog, bei dem du Ziel- und Ausgangsrichtung eingeben kannst und das dir die korrekte Drehrichtung ausgibt.
@dirk:
ein weiteres phänomen, für mich völlig unerklärlich:
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_MultiIOLib.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
uint16_t new_dir; //neue richtung
uint16_t old_dir; //gemessene richtung
uint16_t temp; //berechnung korrektur richtung
void I2C_requestedDataReady(uint8_t dataRequestID) //macht was?
{
checkRP6Status(dataRequestID);
}
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
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);
}
/*******************sensorwerte holen*************************/
void sensorwerte_holen(void)
{
intreg2dm = readHDMM01(); // holt sersorwerte
if(!intreg2dm) //daten gültig?
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
}
/******************heading auf LCD schreiben**************/
void heading_ausgeben(void)
{
setCursorPosLCD(0, 0); //headingwerte werden auf LCD geschrieben
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
}
/*******************berechnung der richtungswerte***********/
void richtung_berechnen(void)
{
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
}
/**************ausgabe der richtungswerte*******************/
void richtung_ausgeben(void)
{
setCursorPosLCD(1, 0);
writeStringLCD_P("direction ");
writeStringLCD(dir); //ausgabe der richtung
}
int main(void)
{
initRP6Control();
multiio_init();
initLCD();
orientation_init();
COMPASS_2D_init();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);//macht was?
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen
showScreenLCD(" RP6Control M32", " gyro_quadrat");
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://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
{
new_dir = 257;
sensorwerte_holen();
heading_ausgeben();
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeStringLCD_P("dir ");
writeIntegerLCD(old_dir, DEC);
writeStringLCD_P(" ");
writeIntegerLCD(new_dir, DEC);
mSleep(1000);
}
// move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(1000);
// rotate(50, 3, 90, 1); //dreht um 90°
clearLCD();
break;
case 2:
setLEDs(0b0010);
break;
case 3:
setLEDs(0b0100);
break;
case 4:
setLEDs(0b1000);
break;
}
}
}
return 0;
}
im case1:
das programm startet normal, die ausgabe "button 0" erscheint, nach dem drücken des button 1 erscheinen alle ausgaben:
"heading" in erster zeile, "old_dir" und "new_dir" in der zweiten - auch mit den richtigen werten.
beim 2ten mal drücken des button 1 erscheint aber der wert von "new_dir" entweder als "0", wenn er vorher auf einen wert bis 256 festgelegt wurde, alles darüber erscheint als "256".
verstehe ich echt nicht....:-(
Ich habe mal ein paar kleinere Änderungen gemacht. Ich habe das NICHT geprüft, weil ich die M32 nicht an die MultiIO angeschlossen habe:
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
//#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_MultiIOLib.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
//uint16_t new_dir; //neue richtung
//uint16_t old_dir; //gemessene richtung
//uint16_t temp; //berechnung korrektur richtung
int16_t new_dir; //neue richtung
int16_t old_dir; //gemessene richtung
int16_t temp; //berechnung korrektur richtung
/*
void I2C_requestedDataReady(uint8_t dataRequestID) //macht was?
{
checkRP6Status(dataRequestID);
}
*/
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
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);
}
/*******************sensorwerte holen*************************/
void sensorwerte_holen(void)
{
intreg2dm = readHDMM01(); // holt sersorwerte
if(!intreg2dm) { //daten gültig? <=== KLAMMER AUF!!!
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
} // <=== KLAMMER ZU!!!
}
/******************heading auf LCD schreiben**************/
void heading_ausgeben(void)
{
setCursorPosLCD(0, 0); //headingwerte werden auf LCD geschrieben
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
}
/*******************berechnung der richtungswerte***********/
void richtung_berechnen(void)
{
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
}
/**************ausgabe der richtungswerte*******************/
void richtung_ausgeben(void)
{
setCursorPosLCD(1, 0);
writeStringLCD_P("direction ");
writeStringLCD(dir); //ausgabe der richtung
}
int main(void)
{
initRP6Control();
multiio_init();
initLCD();
orientation_init();
//COMPASS_2D_init();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initMaster(100);
//I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);//macht was?
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen
showScreenLCD(" RP6Control M32", " gyro_quadrat");
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();
uint8_t key = pressedMultiIOButtonNumber;
/********************funktion der buttons*********************/
if(key)
{
switch(key)
{
case 1://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
{
new_dir = 257;
sensorwerte_holen();
heading_ausgeben();
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeStringLCD_P("dir ");
writeIntegerLCD(old_dir, DEC);
writeStringLCD_P(" ");
writeIntegerLCD(new_dir, DEC);
mSleep(1000);
}
// move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(1000);
// rotate(50, 3, 90, 1); //dreht um 90°
clearLCD();
break;
case 2:
setLEDs(0b0010);
break;
case 3:
setLEDs(0b0100);
break;
case 4:
setLEDs(0b1000);
break;
}
}
}
return 0;
}
Schau dir mal die Änderungen an:
1. RP6Control_I2CMasterLib nicht eingebunden
2. Variablen new_dir, old_dir und temp als int16_t
3. I2C_requestedDataReady weg
4. In sensorwerte_holen() KLAMMERN ergänzt
5. COMPASS_2D_init() weg (wird in der Lib aufgerufen)
6. I2CTWI_setRequestedDataReadyHandler() weg
7. getMultiIOPressedButtonNumber() nicht 2x aufgerufen, weil die Funktion nur EINMAL die gedrückte Taste ausgibt
Du must gucken, ob das jetzt ok ist. Ein allg. Problem ist sicher, dass die Ausgabe nur 1x erfolgt, nachdem du gedrückt hast. Vielleicht änderst du das z.B. noch so, dass die Ausgabe erfolgt, SOLANGE keine andere Taste als die 1 gedrückt wurde.
Um die Rotation zu errechnen, um von old_dir zu new_dir zu kommen, habe ich jetzt auch eine passende Formel:
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
int16_t dev, rot;
dev = new_dir - old_dir;
rot = dev;
if (abs(dev) > 180) {
if (dev < 0) {
rot = 360 + dev;
}
else {
rot = -360 + dev;
}
}
Der Drehwinkel zu new_dir ist danach in rot, wobei positive Werte für Rechtsdrehung stehen und negative für Linksdrehung.
Du must also nur den Absolutwert von rot an die rotate-Funktion übergeben und je nach Vorzeichen links oder rechts drehen lassen.
Teste das mal!
hi Dirk,
alle änderungen ausgeführt, beim ersten drücken des buttons 1 stimmt die ausgabe (diesmal dir_neu = 360), beim 2ten drücken immer noch 256...
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
//#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_MultiIOLib.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
int16_t new_dir; //neue richtung
int16_t old_dir; //gemessene richtung
int16_t temp; //berechnung korrektur richtung
/*
void I2C_requestedDataReady(uint8_t dataRequestID) //macht was?
{
checkRP6Status(dataRequestID);
}
*/
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
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);
}
/*******************sensorwerte holen*************************/
void sensorwerte_holen(void)
{
intreg2dm = readHDMM01(); // holt sersorwerte
if (!intreg2dm) //daten gültig?
{
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
}
}
/******************heading auf LCD schreiben**************/
void heading_ausgeben(void)
{
setCursorPosLCD(0, 0); //headingwerte werden auf LCD geschrieben
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
}
/*******************berechnung der richtungswerte***********/
void richtung_berechnen(void)
{
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
}
/**************ausgabe der richtungswerte*******************/
void richtung_ausgeben(void)
{
setCursorPosLCD(1, 0);
writeStringLCD_P("direction ");
writeStringLCD(dir); //ausgabe der richtung
}
int main(void)
{
initRP6Control();
multiio_init();
initLCD();
orientation_init();
//COMPASS_2D_init();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initMaster(100);
//I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);//macht was?
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen
showScreenLCD(" RP6Control M32", " gyro_quadrat");
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://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
{
new_dir = 360;
sensorwerte_holen();
heading_ausgeben();
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeStringLCD_P("dir ");
writeIntegerLCD(old_dir, DEC);
writeStringLCD_P(" ");
writeIntegerLCD(new_dir, DEC);
mSleep(1000);
}
// move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(1000);
// rotate(50, 3, 90, 1); //dreht um 90°
clearLCD();
break;
case 2:
setLEDs(0b0010);
break;
case 3:
setLEDs(0b0100);
break;
case 4:
setLEDs(0b1000);
break;
}
}
}
return 0;
}
irgendwie haben die 256 mit der definition der variablen zu tun, aber wie?
@Dirk:
ich habe jetzt die 3 variablen old_dir, new_dir und temp von "int16_t" in "int32_t" geändert und nun ist die ausgabe richtig!
Soll ich es nun so lassen (weil es funktioniert) oder gibt es eine alternative zu "long"...(und evtl. eine erklärung die ich verstehen würde?)
@inka:
Die Long-Variablen brauchst du eigentlich nicht. Insofern verstehe ich nicht, warum das so dann läuft.
irgendwie beruhigend :-) gruss inka
Um die Rotation zu errechnen, um von old_dir zu new_dir zu kommen, habe ich jetzt auch eine passende Formel:
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
int16_t dev, rot;
dev = new_dir - old_dir;
rot = dev;
if (abs(dev) > 180 {
if (dev < 0) {
rot = 360 + dev;
}
else {
rot = -360 + dev;
}
}
Der Drehwinkel zu new_dir ist danach in rot, wobei positive Werte für Rechtsdrehung stehen und negative für Linksdrehung.
Du must also nur den Absolutwert von rot an die rotate-Funktion übergeben und je nach Vorzeichen links oder rechts drehen lassen.
Teste das mal!
habe es ein bischen (optisch) für mich angepasst :-)
void korrekrur_richtung(void)
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
//int16_t dev, rot;
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
int32_t dev, rot; //weil die new und old_dir jetz auch long sind...
dev = new_dir - old_dir; //das ist die zeile 91...
rot = dev;
if (abs(dev) > 180 //fehlt da nicht eine klammer?
{
if (dev < 0)
{
rot = 360 + dev;
}
else
{
rot = -360 + dev;
}
beim compilieren bekomme ich diese fehlermeldung:
gyro_quadrat.c|91|error: expected declaration specifiers before ‘dev’|
liegt das nur an der fehlenden(?) klammer oder an noch was anderem?
liegt das nur an der fehlenden(?) klammer oder an noch was anderem?
Ja, an den fehlenden Klammern.
Und zwar:
1. Nach void korrekrur_richtung(void) eine geschweifte KLAMMER AUF
2. Am Ende deines Ausschnitts ZWEI geschweifte KLAMMERN ZU
3. Eine runde KLAMMER ZU an der Stelle, die du markiert hast
{
dev = new_dir - old_dir;
rot = dev;
if (abs(dev)) > 180
{
{
if (dev < 0)
{
rot = 360 + dev;
}
else
{
rot = -360 + dev;
}
}
}
}
also ich glaube jetzt sind alle klammern richtig, code:blocks hat zumindest alle paarweise gefunden, trotzdem kommt bei der ersten if abfrage "abs(dev)" eine fehlermeldung:
gyro_quadrat.c|90|error: expected expression before ‘>’ token|
das mit dem daueranzeigen der werte habe ich geschafft:
case 1://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
while(true)
{
{
new_dir = 180;
sensorwerte_holen();
heading_ausgeben();
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeStringLCD_P("dir ");
writeIntegerLengthLCD(old_dir, DEC, 3);
writeStringLCD_P(" ");
writeIntegerLengthLCD(new_dir, DEC, 3);
mSleep(1000);
/*
if (key)
{
break;
}
*/
}
}
// move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(1000);
// rotate(50, 3, 90, 1); //dreht um 90°
clearLCD();
break;
nach der zweiten abfrage der variablen key (hier auskomentiert) springt das programm fast sofort (nachdem die werte einmal angezeigt wurden) wieder auf die stelle wo "button 0" angezeit wird, also vor die erste key abfrage - da wollte ich eigentlich, dass es erst auf das zweite drücken eines beliebigen buttons passiert...
Thorben W
16.04.2013, 20:48
Hallo,
bei
if (abs(dev)) > 180
sollte das > 180 mit in die Klammer: if (abs(dev) > 180)
Thorben
@inka:
bei der ersten if abfrage "abs(dev)" eine fehlermeldung: gyro_quadrat.c|90|error: expected expression before ‘>’ token|
Die Zeile müßte so aussehen:
if (abs(dev) > 180)
nach der zweiten abfrage der variablen key (hier auskomentiert) springt das programm fast sofort (nachdem die werte einmal angezeigt wurden) wieder auf die stelle wo "button 0" angezeit wird, also vor die erste key abfrage
Willst du denn dort, wo die key-Abfrage auskommentiert ist, die Tastatur abfragen? Wenn ja, müßtest du eine der Funktionen da einfügen, mit denen die Tastatur abgefragt wird, z.B.: key = getMultiIOPressedButtonNumber();
@Dirk:
das mit dem kontiniuerlichen anzeigen der werte und dem abbruch per zweiten tastendruck funktioniert jetzt so weit :-)
die fuktion:
void korrekrur_richtung(void)
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
{
dev = new_dir - old_dir;
rot = dev;
if (abs(dev) > 180)
{
{
if (dev < 0)
{
rot = 360 + dev;
}
else
{
rot = -360 + dev;
}
}
}
}
berechnet und legt in der variablen "rot" den wert ab und die richtung der drehung sollte durch das vorzeichen von "rot" bestimmt werden. In der funktion:
void rotate(uint8_t desired_speed, uint8_t dir, uint16_t angle, uint8_t blocking)
werden ja die parameter speed, dir, angle und blocking eingesetzt und ausgeführt. Der parameter für die drehrichtung ist aber per vorzeichen schon in der variablen "rot" enthalten. Wie "trixe" ich nun den befehl rotate aus?
@inka:
Wie "trixe" ich nun den befehl rotate aus?
Die Parameter desired_speed und blocking sind ja klar.
Für angle setzt du abs(rot) ein.
Für den Parameter dir testest du rot auf das Vorzeichen:
uint8_t rdir;
if (rot < 0) rdir = LEFT;
else rdir = RIGHT;
Dann kannst du rotieren:
rotate(80, rdir, (abs(rot)), true);
also, das programm tut "im großen und ganzen" in den bereichen die mir wichtig waren was es soll. Ich habe den ganzen code hier noch einmal kopiert, weil einzelne abschnitte sicher nicht so übersichtlich wären, es ist sicher noch eine ganze menge "müll" drinnen, auch viel zu viele "mSleeps", aber ich wollte mitlesen auf dem display...
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
//#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
int32_t new_dir; //neue richtung
int32_t old_dir; //gemessene richtung
int32_t temp; //berechnung korrektur richtung
int16_t dev, rot, i;//berechnung rotation
char rdir;
/***********************calculate_dir************** ********/
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
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);
}
/*******************sensorwerte holen*************************/
void sensorwerte_holen(void)
{
intreg2dm = readHDMM01(); // holt sersorwerte
if (!intreg2dm) //daten gültig?
{
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
}
}
/*******************berechnung der richtungswerte***********/
void richtung_berechnen(void)
{
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
}
/*************korrektur richtung*****************************/
void korrekrur_richtung(void)
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
{
dev = new_dir - old_dir;
rot = dev;
if (abs(dev) > 180)
{
{
if (dev < 0)
{
rot = 360 + dev;
}
else
{
rot = -360 + dev;
}
}
}
}
/*******************werte schreiben************************/
void werte_schreiben(void)
{
setCursorPosLCD(0, 0);
writeStringLCD_P("HEA ODR NDR ROT");
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeIntegerLengthLCD(heading2dm, DEC, 3);
setCursorPosLCD(1, 4);
writeIntegerLengthLCD(old_dir, DEC, 3);
setCursorPosLCD(1, 8);
writeIntegerLengthLCD(new_dir, DEC, 3);
korrekrur_richtung();
if (rot<0)
{
setCursorPosLCD(1, 12);
writeStringLCD_P("-");
}
else
{
setCursorPosLCD(1, 12);
writeStringLCD_P(" ");
}
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
}
/**********************test rdir**************************/
void test_rdir(void)
{
if (rot < 0)
rdir = LEFT;
else rdir = RIGHT;
}
/**********************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", " gyro_quadrat");
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://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
while(true)
{
{
new_dir = 360;
sensorwerte_holen();
werte_schreiben();
mSleep(1000);
korrekrur_richtung();
test_rdir();
werte_schreiben();
mSleep(1000);
rotate(60, rdir, ((abs(rot)/2)), 0);
werte_schreiben();
mSleep(1000);
// if ((rot < 2) || (rot > -2)) break;
// if (rot == 0) break;
for (i= 0; i<3; i++);
{
sensorwerte_holen();
werte_schreiben();
mSleep(1000);
korrekrur_richtung();
test_rdir();
werte_schreiben();
mSleep(1000);
}
uint8_t key = getMultiIOPressedButtonNumber();
if (key)
{
break;
}
}
}
break;
case 2:// richtung OST
setLEDs(0b0010);
break;
case 3:// richtung SÜD
setLEDs(0b0100);
break;
case 4:// richtung WEST
setLEDs(0b1000);
break;
}
}
}
return 0;
}
erste frage:
der RP6 arbeitet sich durch den halbierten "rotate-satz" recht langsam an sein ziel, hier die nordrichtung, heran, tänzelt dann so in meistens immer kleineren schritten hin und her auf die "0" hin, die drehungen fallen aber auch manchmal völlig unerwartet größer aus. So werden aus 3° plötzlich wieder 7° - und ich weiss nicht warum. Liegt das nur an der ungenauigkeit des getriebes?
zweite frage:
er schafft auch schon mal die "0" zu erreichen, die erscheint dann auch im display, statt aber - wie ihm das "break" (jetzt auskomentiert) eigentlich befehlen sollte - sofort stehen zu bleiben, dreht er noch um 7, manchmal aber um bis zu 9° nach rechts. Und das ist verifizierbar...
Da bin ich auch noch am rätseln welche wariable mir dort einen streich spielt...
ansonsten muss ich wieder die arbeit an der platine und der lib loben, an mein "gebastle" in der vergangenheit darf ich gar nicht denken. Sauber...
Hi inka:
Glückwunsch zum funktionierenden Programm! Hoffentlich wird deinem RP6 nicht schwindelig vom vielen Drehen! :)
zu 1 und 2)
Wenn die etwas größeren "Sprünge" nicht durch tatsächliche "Ausreißer" einerseits des Kompass-Richtungswerts, andererseits durch ungenaues Drehen auf der Stelle, verursacht werden (das würdest du ja in deiner Werte-Ausgabe merken!), dann kann das Phänomen auch daran liegen, dass du ja "nicht-blockierend" drehst, d.h. dass sich Drehbefehle "überlappen", weil bei einem neuen Drehbefehl noch evtl. der alte aktiv ist.
hi Dirk,
schwindelig sicher nicht, er dreht ja hin und her :-), allerdings beim ändern des blocking-parameters dreht er nur einmal und bleibt stehen. Im handbuch:
An diesem Beispiel sieht man, wie die beiden Funktionen benutzt werden können:
#include "RP6RobotBaseLib.h"
int main(void)
{
initRobotBase();
setLEDs(0b111111);
mSleep(1500);
powerON(); // Encoder und Motorstromsensoren anschalten!
}
while(true)
{
setLEDs(0b100100);
move(60, FWD, DIST_MM(300), true); // 30cm Vorwärts fahren
setLEDs(0b100000);
rotate(50, LEFT, 180, true); // um 180° nach links drehen
setLEDs(0b100100);
move(60, FWD, DIST_MM(300), true); // 30cm Vorwärts fahren
setLEDs(0b000100);
rotate(50, RIGHT, 180, true); // um 180° nach rechts drehen
}
return 0;
Hier fährt der Roboter zunächst 30cm Vorwärts, dreht dann um 180° nach links, fährt die 30cm zurück,
dreht um 180° nach rechts und das Spiel beginnt von neuem.
Würde man den blocking Parameter von allen Funktionen false anstatt true setzen,
würde das Programm überhaupt nicht funktionieren, da aus der Main Funktion nicht die task_motionControl Funktion
aufgerufen wird und alle Funktionsaufrufe direkt hintereinander stehen.
Ändert man auch nur einen der blocking Parameter in false um, wird das Programm ebenfalls nicht mehr
wie gewünscht funktionieren – es wird dann eine der Bewegungsphasen komplett übersprungen.
Für solche rein sequentiellen Abläufe muss man den blocking Parameter also immer auf true setzen!
das würde den abbruch der drehungen nach der ersten drehung erklären, es wird auch wieder die "task_motionControl Funktion" erwähnt. Wird die automatisch in dem base-slave-programm aufgerufen?
Hi inka,
nein, die "task_motionControl Funktion" brauchst du nicht, wenn du mit der M32 als I2C-Master die Base ansteuerst.
Der Grund, warum das rotate blockierend nur 1x ausgeführt wird, liegt wohl daran, dass dein rotate-Block innerhalb der if(key) Abfrage liegt.
Du müßtest dein Programm so umschreiben, dass die Richtungsmessung, -korrektur und (blockierendes) rotate in der while(true)-Schleife unabhängig vom Tastendruck immer durchlaufen kann bis zu einer Abbruchbedingung (z.B. +- 5° vom Zielwert).
Die Tastaturabfrage würde dann parallel laufen und nur ausgewertet, wenn die "richtige" Taste gedrückt wird.
hi Dirk,
ich kann mir vorstellen das programm so umzuschreiben dass die abfrage der 4 tasten (himmelsrichtungen) bestandteil von der while(true) schleife ist, also umgekehrt zu derm wie es jetzt ist. Ist es das was du meinst?
Den letzten satz mit der paralellel-lauf und abfrage der tasten - wie meinst du das mit dem parallelem lauf?
Hi inka,
vergiß es einfach. Ich hatte nicht gesehen, dass du innerhalb der Haupt-while(true)-Schleife noch eine 2. while(true)-Schleife hast, in der dann die Drehung stattfindet. So kann man es natürlich auch gut machen.
hi Dirk,
aber woran könnte dann die letzte drehung nach dem break bei "0" liegen?
Keine Ahnung.
Wenn du rotate nicht blockierend einsetzt, können alle möglichen Effekte eintreten, weil die Drehungen "im Hintergrund" und zeitlich parallel zu deinem Master-Programm auf der M32 ablaufen.
hi,
habe heute meinen RP6 eingeschaltet und folgenden code geladen:
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_MultiIOLib.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
uint16_t heading;
void I2C_requestedDataReady(uint8_t dataRequestID) //macht was?
{
checkRP6Status(dataRequestID);
}
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
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);
}
int main(void)
{
initRP6Control();
multiio_init();
initLCD();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);//macht was?
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen
showScreenLCD(" RP6Control M32", " gyro_test_2");
mSleep(2500);
clearLCD();
orientation_init();
COMPASS_2D_init();
while(true)
{
task_I2CTWI();
intreg2dm = readHDMM01(); // holt sersorwerte
if(!intreg2dm)
{ // daten gültig?
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
setCursorPosLCD(0, 0);
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
setCursorPosLCD(1, 0);
writeStringLCD_P("direction ");
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
writeStringLCD(dir); //ausgabe des richtungswertes
mSleep(100);
clearLCD();
}
/*
move(150, FWD, DIST_MM(500), true); //fährt 50cm
mSleep(300);
rotate(50, 3, 90, 1); //wendet um 90°
clearLCD();
*/
}
return 0;
}
das entpricht bis auf die auskomentierte stelle dem selbstest_05...
auf dem display erscheint Heading 269 und in der zweiten zeile direction W, egal wie ich den roboter harumdrehe...
woran kann das liegen? ist der kompass defekt?
Edit:
ich habe jetzt noch den selbsttest 05 aus dem letzten softwarepaket genommen,
auf dem LCD display erscheint Heading 269 (verändert sich bei drehung des RP6 nicht), in der zweiten zeile die werte X und Y, die verändern sich allerdings...
Fragen:
1. Zeigen die Demos auch dann EINMALIG 269° an, wenn dein RP6 vor dem Programmstart in eine andere Richtung gedreht wurde?
2. Was passiert, wenn du die globale Definition von "uint16_t heading;" rausnimmst (die doppelt sich mit heading in der Funktion calculateDir)?
Fragen:
1. Zeigen die Demos auch dann EINMALIG 269° an, wenn dein RP6 vor dem Programmstart in eine andere Richtung gedreht wurde?
sie zeigen wenn ich den RP6 vor dem programmstart um ca 90° drehe "270", der wert ändert sich beim zurückdrehen (bei laufendem programm) wieder in 269.
2. Was passiert, wenn du die globale Definition von "uint16_t heading;" rausnimmst (die doppelt sich mit heading in der Funktion calculateDir)?
es ändert sich nichts...
@inka:
1. Hat der HDMM01 denn vorher funktioniert?
2. Wenn ja: Mit welchem Programm?
3. Kannst du ein älteres Programm reintun und damit testen (wenns vorher damit geklappt hat)?
4. Probier mal, noch irgendeinen anderen I2C-Sensor an denselben I2C-Bus zu hängen. Änderung?
5. Mach das mit 5. und lies den anderen Sensor VOR dem HDMM01 über I2C aus (must nix anzeigen!). Läuft der HDMM01 jetzt bzw. zeigt Werte an?
1+2:
ja, mit diesem programm:
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_OrientationLib.h"
//#include "RP6Control_I2CMasterLib.h"
#include "RP6Control_MultiIOLib.h"
#include "RP6Control_I2CMasterLib.h"
//#include "RP6RobotBaseLib.h"
//#include "inka.h"
#define I2C_RP6_BASE_ADR 10
uint8_t ch;
char item[12];
char dir[3];
int32_t new_dir; //neue richtung
int32_t old_dir; //gemessene richtung
int32_t temp; //berechnung korrektur richtung
int16_t dev, rot, i;//berechnung rotation
char rdir;
/***********************calculate_dir************** ********/
void calculateDir(char* dir, uint16_t heading) //setzt headingwerte grob in himmelsrichtungen um
{
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';}
}
/*********************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);
}
/*******************sensorwerte holen*************************/
void sensorwerte_holen(void)
{
intreg2dm = readHDMM01(); // holt sersorwerte
if (!intreg2dm) //daten gültig?
{
normalizeHDMM01(); // daten werden "normalisiert"
heading2dm = headingHDMM01(); // berechnung der headingwerte
}
}
/*******************berechnung der richtungswerte***********/
void richtung_berechnen(void)
{
calculateDir(dir, heading2dm); //berechnung der richtung (N,S,W,E)
}
/*************korrektur richtung*****************************/
void korrekrur_richtung(void)
// Wertebereich new_dir und old_dir: 0..359
// Ergebnis in rot! Positiv: Rechtsdrehung, negativ: Linksdrehung!
{
dev = new_dir - old_dir;
rot = dev;
if (abs(dev) > 180)
{
{
if (dev < 0)
{
rot = 360 + dev;
}
else
{
rot = -360 + dev;
}
}
}
}
/*******************werte schreiben************************/
void werte_schreiben(void)
{
setCursorPosLCD(0, 0);
writeStringLCD_P("HEA ODR NDR ROT");
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeIntegerLengthLCD(heading2dm, DEC, 3);
setCursorPosLCD(1, 4);
writeIntegerLengthLCD(old_dir, DEC, 3);
setCursorPosLCD(1, 8);
writeIntegerLengthLCD(new_dir, DEC, 3);
korrekrur_richtung();
if (rot<0)
{
setCursorPosLCD(1, 12);
writeStringLCD_P("-");
}
else
{
setCursorPosLCD(1, 12);
writeStringLCD_P(" ");
}
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
}
/**********************test rdir**************************/
void test_rdir(void)
{
if (rot < 0)
rdir = LEFT;
else rdir = RIGHT;
}
/**********************hauptprogramm*************** ******/
int main(void)
{
initRP6Control();
multiio_init();
initLCD();
orientation_init();
COMPASS_2D_init();
resetCoilHDMM01();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError); //aktiviert I2C fehlermeldungen
showScreenLCD(" RP6Control M32", " gyro_quadrat");
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://richtung NORD
setLEDs(0b0001); //LED 1 leuchtet
COMPASS_2D_init();
while(true)
{
{
new_dir = 360;
sensorwerte_holen();
setCursorPosLCD(0, 0);
writeStringLCD_P("HEA ODR NDR ROT");
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeIntegerLengthLCD(heading2dm, DEC, 3);
setCursorPosLCD(1, 4);
writeIntegerLengthLCD(old_dir, DEC, 3);
setCursorPosLCD(1, 8);
writeIntegerLengthLCD(new_dir, DEC, 3);
korrekrur_richtung();
test_rdir();
if (rot<0)
{
setCursorPosLCD(1, 12);
writeStringLCD_P("-");
}
else
{
setCursorPosLCD(1, 12);
writeStringLCD_P(" ");
}
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
mSleep(1000);
// rotate(60, rdir, ((abs(rot)/2)), 0);
mSleep(1000);
for (i= 0; i<3; i++);
{
sensorwerte_holen();
old_dir = heading2dm;
korrekrur_richtung();
test_rdir();
if (rot<0)
{
setCursorPosLCD(1, 12);
writeStringLCD_P("-");
}
else
{
setCursorPosLCD(1, 12);
writeStringLCD_P(" ");
}
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
mSleep(1000);
// rotate(60, rdir, ((abs(rot)/2)), 0);
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
mSleep(1000);
}
// if (rot == 0) break;
uint8_t key = getMultiIOPressedButtonNumber();
if (key)
{
break;
}
}
}
break;
case 2:// richtung OST
setLEDs(0b0010);
while(true)
{
{
new_dir = 270;
sensorwerte_holen();
setCursorPosLCD(0, 0);
writeStringLCD_P("HEA ODR NDR ROT");
old_dir = heading2dm;
setCursorPosLCD(1, 0);
writeIntegerLengthLCD(heading2dm, DEC, 3);
setCursorPosLCD(1, 4);
writeIntegerLengthLCD(old_dir, DEC, 3);
setCursorPosLCD(1, 8);
writeIntegerLengthLCD(new_dir, DEC, 3);
korrekrur_richtung();
test_rdir();
if (rot<0)
{
setCursorPosLCD(1, 12);
writeStringLCD_P("-");
}
else
{
setCursorPosLCD(1, 12);
writeStringLCD_P(" ");
}
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
mSleep(1000);
// rotate(60, rdir, ((abs(rot)/2)), 0);
mSleep(1000);
for (i= 0; i<3; i++);
{
sensorwerte_holen();
old_dir = heading2dm;
korrekrur_richtung();
test_rdir();
if (rot<0)
{
setCursorPosLCD(1, 12);
writeStringLCD_P("-");
}
else
{
setCursorPosLCD(1, 12);
writeStringLCD_P(" ");
}
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
mSleep(1000);
// rotate(60, rdir, ((abs(rot)/2)), 0);
setCursorPosLCD(1, 13);
writeIntegerLengthLCD(abs(rot), DEC, 3);
mSleep(1000);
}
// if (rot == 0) break;
uint8_t key = getMultiIOPressedButtonNumber();
if (key)
{
break;
}
}
}
break; case 3:// richtung SÜD
setLEDs(0b0100);
break;
case 4:// richtung WEST
setLEDs(0b1000);
break;
}
}
}
return 0;
}
3: mit dem code von oben funktioniert der kompass nicht mehr, beim betätigen von button 1 wird angezeicht:
HEA ODR NDR ROT / zeile2: 269 269 360 091
bei button2: 269 269 270 001
4: habe ich leider nicht (einen anderen I2C sensor)...
Ok, ich würde die Verbindung zum HDMM01 prüfen (Spannung ok?, SDA/SCL verbunden?). Wenn da auch alles ok ist, weiß ich nicht weiter ... :(
@Dirk: 5V und masse liegen an der HDMM01 platine an, auch SDA/SCL scheint verbunden (zwischen stiften der I/O platien un d der HDMM01), würde auf einen defekt an der HDMM01 deuten, oder? Gibt es sonst noch möglichkeiten die kompassplatine zu testen?
@fabqu: gibt es auf die HDMM01 garantie? Es wurde ja schon gelötet...
- - - Aktualisiert - - -
@inka:
5. Mach das mit 5. und lies den anderen Sensor VOR dem HDMM01 über I2C aus (must nix anzeigen!). Läuft der HDMM01 jetzt bzw. zeigt Werte an?
- was bedeutet "Mach das mit 5."?
- ich hätte noch einen SRF02, der wird doch auch über I2C ausgelesen? Wie müsste ich den anschließen? Muss ich da auch softwaremäßig was tun, oder ging es bei dem versuch nur darum den "blockierten(?)" I2C wieder zu aktivieren?
@inka:
- was bedeutet "Mach das mit 5."?
Oh, ich meinte "Mach das mit 4.", also das Anschließen eines weiteren I2C-Slaves.
Der Grund ist: Ich konnte bei meinen Tests auch den HDMM01 einmal nicht mehr auslesen, als er allein am I2C-Bus hing. Ich wollte nur sichergehen (bevor du dir einen neuen kaufst), dass das bei dir nicht der Fall ist. Wenn du den SRF02 hast, häng ihn doch einfach an den I2C-Bus und lies in derselben Schleife wie den HDMM01 z.B. auch die Firmware-Version aus (SRF02_getFirmware).
Wenn das nicht klappt: Vielleicht ist der HDMM01 kaputt.
@Dirk,
der SRF 2 ist angeschlossen an dem 4er block, direkt an der beschriftung, dann habe ich in der schleife "SRF02_getFirmware(CH_SRF02_1);" und auch die zeile "#include "RP6Control_LFSBumperLib.h" hinzugefügt. Beim starten des programms leuchtet/blinkt die rode LED am SRF, die anzeige am LCD ändert sich nicht...
habe bereits einen neuen HDMM01 bestellt...
Hi Inka,
ich denke mal, wenn mans verlötet hat, verfällt die Garantie. Aber teste doch mal, ob Kontakte alle richtig sind, also ob vielleicht beim Löten was schief ging.
@fabqu: dachte ich mir, mit der garantie...
@Dirk:
den neuen HDMM01 habe ich vor zwei tagen bereits bestellt gehabt, heute kam er...
aufgebaut, lötstellen (beim alten wie neuen) durchgemessen, sie gehen BEIDE NICHT! Heading von 269 wird angezeigt und schluss...
@fabqu: sind auf der IO pltine irgendwelche stellen/bauteile die als ursache in frage kämen?
@Dirk: was ich nun bräuchte wäre ein kurzes, simples testprogramm, kannst du mir da bitte helfen?
ich habe zu beginn meiner letzten tests versucht die änderungen, die ich schon vor wochen an den standard-libs durchgeführt habe in die neu heruntergeladenen zu übertragen. z.b. habe ich die aktivierung des HDMM01 aus der Orientation.h rausgenommemn/dort deaktiviert gehabt und die aktivierung in eine separate datei (inka.h und inka.c) eingetragen. Es hat nicht hingehauen, deshalb habe ich es wieder zurückgeändert. Daran kann es wohl jetzt nicht liegen, oder?
das hier wäre der letzter aktueller stand meiner hardware, bei abgezogenem SCL oder SDA kommt eine I2C fehlermeldung:
"I2C ERROR -> X 0 TWI STATE 0x20"
wobei dann das programm weiterläuft
Anzeige im LCD display:
1.zeile: Heading 227
2.zeile: X 0 TATY 0 48
---------------------------------------------
verbinde mal VCC, GND und SDA/SCL vom i2c. Dann überprüfe diese Leitungen auf durchgang (im ausgeschalteten zustand deines rp6) von ihrem Ursprung aus. Also: klappt die Verbindung GND des hdmm zum GND von der rp6base?bei ausgeschaltetem RP6 gemessen zu M32/XBUS2/pin 14, durchgang ok, zum pin GND am lochfeld der BASE, durchgang ok
Klappt VCC hdmm zu VCC der Multi-IO, oder woher du auch immer deine Versorgung nimmst?
HDMM wird von der I/O versorgt, die ersten 4 kontakte der pinreihe für gyro (VCC/GND/SDA/SCL), bei eingeschaltetem RP6 liegen am HDMM, direkt an den anschlüssen, 5V an.
klappt SDA und SCL vom hdmm zu deinem Master-Modul? bei ausgeschaltetem RP6 auf durchgang gemessen zu der M32/XBUS2 pins 10 und 12(unterhalb des LCD), durchgang ok
@inka:
Ich probiere das in den nächsten Tagen mal.
In welcher Konfiguration der Lib klappt es denn nicht?
Hast du nur COMPASS_2D aktiviert und GPS, IMU_9D nicht?
Also: Betreibst du NUR den HDMM01 mit der Lib?
Probieren kann ich es z.Zt. aber nur mit der M256, weil ich die M32 zur Zeit nicht greifbar habe.
@inka:
Ich habe noch mal die Lib mit der M256 getestet. Die M32-Lib müßte eigentlich genauso funktionieren.
Den "Fehler" mit der fixen Richtungsanzeige von ~270° kann ich nachvollziehen,- und zwar dann, wenn der Sensor noch nicht kalibriert wurde.
Du müßtest also die Definitionen MAX_X_2DM, MIN_X_2DM, MAX_Y_2DM und MIN_Y_2DM in der RP6M256_Orientation.h an deine Hardware anpassen, d.h. den Sensor kalibrieren.
@Dirk:
das mit der kalibrierung werde ich probieren, sobald ich an meine daten komme, habe momentan probleme mit meiner netzwerkplatte - nach einem heftigen gewitter war sie auf einmal weg :strom
@Dirk:
habe jetzt die kalibrierung durchgeführt. nach dem eintragen in die "RP6Control_Orientation.h":
// 2D-Compass (HDMM01):
// MMC2120MG magnetometer:
#define I2C_MULTIIO_HDMM01_ADR 0x60 // Default
// MMC2120MG magnetometer calibration data:
#define MAX_X_2DM 2016.0 // Max. X-axis value 2042.0
#define MIN_X_2DM 1831.0 // Min. X-axis value 1863
#define BIAS_X_2DM (MAX_X_2DM + MIN_X_2DM) / 2.0
#define SF_X_2DM 2.0 / (MAX_X_2DM - MIN_X_2DM)
#define MAX_Y_2DM 2228.0 // Max. Y-axis value 2220
#define MIN_Y_2DM 2028.0 // Min. Y-axis value 2040
#define BIAS_Y_2DM (MAX_Y_2DM + MIN_Y_2DM) / 2.0
#define SF_Y_2DM 2.0 / (MAX_Y_2DM - MIN_Y_2DM)
nach einer neukompilierung der "RP6Control_MultiIO_05.c" sind aber die ausgaben auf dem display fast identisch mit denen ohne kalibrierung. Auch die 270. So langsam bin ich am aufgeben...
kann man in der "RP6Control_Orientation.h" irgendwelche extremwete eingeben um zu sehen ob es überhaupt eine reaktion des HDMM gibt?
@inka:
2 Fragen:
1. Kalibrierung wie hier (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Configuration_Header_2) beschrieben durchgeführt?
2. Vor dem Neukompilieren "Make clean" gemacht bzw. die Files RP6Control_OrientationLib.lst und .o gelöscht?
kann man in der "RP6Control_Orientation.h" irgendwelche extremwete eingeben um zu sehen ob es überhaupt eine reaktion des HDMM gibt?
Ja, wäre möglich. Du kannst probeweise auch anders kalibrieren: Neige den RP6/Sensor in alle Richtungen und notiere dir die Min./Max.-Werte der beiden Achsen. Die trägst du dann in die RP6Control_Orientation.h ein.
Andere Möglichkeit zur Fehlersuche: Die normalizeHDMM01() Funktion nicht nutzen, sondern die nicht normalisierten Werte direkt verwenden.
@Dirk:
ich teste jetzt nur noch mit der RP6Control_MultiIO_05.c, die zeile mit "normalize" habe ich auskomentiert, statt Heading 270, wird Heading 0 angezeigt, ansosnten keine änderung zum positiven...
#ifdef COMPASS_2D
// 2D-Compass test:
task_I2CTWI();
SRF02_getFirmware(CH_SRF02_1);
intreg2dm = readHDMM01(); // Get sensor values
task_I2CTWI();
if(!intreg2dm) { // Data valid?
// normalizeHDMM01(); // Normalize data
heading2dm = headingHDMM01(); // Calculate heading
setCursorPosLCD(0, 0); // line 1
writeStringLCD_P("Heading ");
writeIntegerLCD(heading2dm, DEC);
writeStringLCD_P(" ");
writeStringLCD(dir);
writeStringLCD_P(" ");
setCursorPosLCD(1, 0); // line 2
writeStringLCD_P("X ");
writeIntegerLCD(x_axis2dm, DEC);
writeStringLCD_P(" ");
setCursorPosLCD(1, 8); // line 2 pos 9
writeStringLCD_P("Y ");
writeIntegerLCD(y_axis2dm, DEC);
writeStringLCD_P(" ");
}
task_I2CTWI();
mSleep(3000);
#endif
1. Kalibrierung wie hier (http://www.rn-wissen.de/index.php/RP6_Multi_IO_Projekt_-_Software#Configuration_Header_2) beschrieben durchgeführt?
ja
2. Vor dem Neukompilieren "Make clean" gemacht bzw. die Files RP6Control_OrientationLib.lst und .o gelöscht?
alle dateien gelöscht...
Ja, wäre möglich. Du kannst probeweise auch anders kalibrieren: Neige den RP6/Sensor in alle Richtungen und notiere dir die Min./Max.-Werte der beiden Achsen. Die trägst du dann in die RP6Control_Orientation.h ein.
Andere Möglichkeit zur Fehlersuche: Die normalizeHDMM01() Funktion nicht nutzen, sondern die nicht normalisierten Werte direkt verwenden.
siehe oben, btw. der Y wert wird negativ (mit -) angezeigt...
@inka:
...die zeile mit "normalize" habe ich auskomentiert, statt Heading 270, wird Heading 0 angezeigt, ...
So einfach geht es nicht, weil normalizeHDMM01() die Variablen x_axis2dm, y_axis2dm nutzt, um daraus die double Variablen x2dm, y2dm zu berechnen. Mit x2dm, y2dm wird dann die Richtung errechnet.
@inka:
So einfach geht es nicht, weil normalizeHDMM01() die Variablen x_axis2dm, y_axis2dm nutzt, um daraus die double Variablen x2dm, y2dm zu berechnen. Mit x2dm, y2dm wird dann die Richtung errechnet.
schaue ich mir an, scheint aber nicht so ganz trivial zu sein...
der Y wert wird negativ (mit -) angezeigt...
wie ist es damit? ok?
@inka:
Zitat von inka: der Y wert wird negativ (mit -) angezeigt... wie ist es damit? ok?
Ja, die x_axis2dm, y_axis2dm Werte können auch negativ werden.
Bei der Kalibrierung müßte man negative Minimal-Werte dann natürlich auch unter MIN_X_2DM und MIN_Y_2DM eintragen.
@Dirk:
ich habe jetzt diese werte für X_2dm un Y_2dm eingetragen:
// MMC2120MG magnetometer calibration data:
#define MAX_X_2DM 2015.0 // Max. X-axis value 2042.0
#define MIN_X_2DM 1840.0 // Min. X-axis value 1863
#define BIAS_X_2DM (MAX_X_2DM + MIN_X_2DM) / 2.0
#define SF_X_2DM 2.0 / (MAX_X_2DM - MIN_X_2DM)
#define MAX_Y_2DM -2038.0 // Max. Y-axis value 2220
#define MIN_Y_2DM -2228.0 // Min. Y-axis value 2040
#define BIAS_Y_2DM (MAX_Y_2DM + MIN_Y_2DM) / 2.0
und bekomme auch in der LCD die headingwerte angezeigt, diese verändern sich auch entsprechend der position in die ich den RP6 drehe. So weit so gut...
wenn ich ihn aber in die richtung NORD drehe (ausgerichtet nach einem uralten analogen kompass) dann zeigt er nicht 360 (oder so) sondern ein wert um die 250. Das der RP in fahrtrichtung NORD steht, konnte ich anhand der umgebung verifizieren, der analoge kompass ist also ok...
Wurden schon die abhängigkeiten der angezeigten/berechneten himmelsrichtungen zu den in der orientation.h eingetragenen werten (s.o.) hier irgendwo erklärt? Oder könnte ich bei irgendeinem der werte einen bestimmten bertrag ab-/hinzu-addieren um auf die 360/NORD zu kommen? Wie komme ich zu diesem wert?
@inka:
bekomme auch in der LCD die headingwerte angezeigt, diese verändern sich auch entsprechend der position in die ich den RP6 drehe.
Das ist schon mal gut.
Was aber auffällt:
Deine Min-/Max-Werte sind auffällig: Die Amplitude der Y-Achse bleibt im neg. Bereich und die der X-Achse im pos. Bereich.
Das könnte dafür sprechen, dass dein Sensor in einem stark von Magnetfeldern oder in einem (durch Metalle) verfälschten Erdmagnetfeld arbeitet. Dadurch kriegst du auch keine richtige Richtungsanzeige und bei der Kalibrierung keine sinnvollen Min-/Max-Werte.
Wichtig ist:
- Auf dem RP6 sollte er möglichst weit weg von den Motoren sitzen
- In der direkten Nähe sollten auch keine Metallteile sein (Stahlschrauben, Abstandhalter, Kabel ...)
- In der weiteren Umgebung (>2m) genauso (Handy, PC, Tisch mit Stahlbeinen, Netzteil, Kabel ...)
Deine Min-/Max-Werte sind auffällig: Die Amplitude der Y-Achse bleibt im neg. Bereich und die der X-Achse im pos. Bereich.
Das könnte dafür sprechen, dass dein Sensor in einem stark von Magnetfeldern oder in einem (durch Metalle) verfälschten Erdmagnetfeld arbeitet. Dadurch kriegst du auch keine richtige Richtungsanzeige und bei der Kalibrierung keine sinnvollen Min-/Max-Werte.
ich habe jetzt versuchsweise ein paar sachen verändert, die metallschraube (platinenbefestigung ca. 1cm vom HDMM entfernt) durch kuststoffschraube ersetzt, die platine höhergesetzt (2 abstandssäulen, gesamthöhe 60mm, messing), die kompassplatine sitz jetzt ungefähr über dem ADC-Mxxx stecker. Habe dann die ganze kalibrierung neu ausgeführt:
/ MMC2120MG magnetometer calibration data:
#define MAX_X_2DM 1933.0 // Max. X-axis value 2042.0
#define MIN_X_2DM 1737.0 // Min. X-axis value 1863
#define BIAS_X_2DM (MAX_X_2DM + MIN_X_2DM) / 2.0
#define SF_X_2DM 2.0 / (MAX_X_2DM - MIN_X_2DM)
#define MAX_Y_2DM -1888.0 // Max. Y-axis value 2220
#define MIN_Y_2DM -2090.0 // Min. Y-axis value 2040
an der ca. 90° versetzung hat sich kaum etwas geändert...
Wichtig ist:
- Auf dem RP6 sollte er möglichst weit weg von den Motoren sitzen
- In der direkten Nähe sollten auch keine Metallteile sein (Stahlschrauben, Abstandhalter, Kabel ...)
- In der weiteren Umgebung (>2m) genauso (Handy, PC, Tisch mit Stahlbeinen, Netzteil, Kabel ...)
du hast recht, ich bin erschrocken, als ich gesehen habe was passiert, wenn ich mein handy über den HDMM halte. Nur: wir können den kompass nicht in einen faradayischen käfig stecken, dann verliert er ja seinen sinn.
Deshalb stellt sich für mich die frage:
gibt es eine möglichkeit den kompass nicht an ideale, reine bedingungen zu kalibrieren, sondern an die bestehenden bedingungen und störungen - die von der unmittelbaren umgebung ausgehen - anzupassen?
Hi inka:
gibt es eine möglichkeit den kompass nicht an ideale, reine bedingungen zu kalibrieren, sondern an die bestehenden bedingungen und störungen - die von der unmittelbaren umgebung ausgehen - anzupassen?
Ja, wenn die "Profis" einen solchen Sensor z.B. in ein Handy-Design einpassen, dann werden mit zusätzlichen Funktionen die sog. "Hard-Iron" und evtl. auch "Soft-Iron" Effekte ausgeglichen.
Wie das geht, zeigen diese Links (http://www.rn-wissen.de/index.php?title=Bascom_und_Kompass_LSM303DLH#Liter atur:) im RN-Wissen.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.