Ruderweg Messung mit Arduino

kalle123

User
Thorsten, wenn du solche Fragen hier stellst, mach Fotos (solche, wo man auch einen Überblick gewinnen kann und auch Details sieht) und stell die hier ein

(möglichst hier drüber ->)
nBNUDa7l.png


Das, was du dazu bisher an Bildern gepostet hast, war einfach nur grausig!

DA hilft Teamviewer auch nicht ;)

Gruß KH
 

pantau

User
Ruderweg mit OlED Display

Ruderweg mit OlED Display

Hallo zusammen,

Nun habe ich auch meine Messer fertig. Ich habe mich für die Oled Variante entschieden, da mir das Display besser gefällt und dieses insgesamt auch sehr kompakt ist.
Mit dem RC Groups Sketch komme ich auf ca. 0,2Grad Anzeigegenauigkeit. Die benötige ich auch, da ich teilweise sehr kleine Ruder habe. Bei meinem Biry ds habe ich für den Start das Höhenruder um ca. 0,3mm verändern müssen. Dieses kann ich jetzt auch gut messen.
Ich verwende ein OLED 128 x 32
20180422_064255.jpg


Hier der Sketch:


#include <U8g2lib.h> // Oled U8g2 library from https://github.com/olikraus/u8g2
#include <SparkFun_ADXL345.h> // SparkFun ADXL345 Library from https://github.com/sparkfun/SparkFun_ADXL345_Arduino_Library

int action = 0;
double corde, ref_angle;
const float pi = 3.1415926539; // PI definition.... could have been a standard value....
const int buttonPin = 2; // the input pin number of the pushbutton

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA); // pin remapping with ESP8266 HW I2C

//----------------------------------------------------------------------------------------------------------------------------------
ADXL345 adxl = ADXL345(); // USE ADXL345 I2C COMMUNICATION
//----------------------------------------------------------------------------------------------------------------------------------
double read_angle() { // Function returning the current rotation value along X axis - in degrees
//----------------------------------------------------------------------------------------------------------------------------------
int x, y, z;
double l_angle = 0;
double ll_angle = 0;
int mm = 250;

for (int nn = 1; nn <= mm; nn++) { // Average value computed over roughly 100ms
adxl.readAccel(&x, &y, &z); // Read the accelerometer values and store them in variables declared above x,y,z
l_angle = atan2(y, z) * 57.3; // Compute rotation angle along X axis of ADXL345
ll_angle = ll_angle + (l_angle);
}
return ll_angle / mm;
}
//----------------------------------------------------------------------------------------------------------------------------------
void init_angle() {
//----------------------------------------------------------------------------------------------------------------------------------
double ra = 0;
delay(500);
ra = read_angle();
delay(500);
ra = read_angle(); // Initialize the actual angle as the reference angle
ref_angle = ra;
}
//----------------------------------------------------------------------------------------------------------------------------------
void setup() {
//----------------------------------------------------------------------------------------------------------------------------------
corde = 25; // Chord width value
Serial.begin(9600);
// Serial.println("Init done");
u8g2.begin(); // Start Oled
affiche_init();
adxl.powerOn(); // Power on the ADXL345
adxl.setSpiBit(0); // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
adxl.setRangeSetting(2); // Give the range settings
pinMode(buttonPin, INPUT); // define the Push Button input
init_angle();
ref_angle = ref_angle - 0.2; // 0.2 original
}
//----------------------------------------------------------------------------------------------------------------------------------
String cnv_flt2str(float num, int car, int digit) { // Convert a float variable into a string with a specific number of digits
//----------------------------------------------------------------------------------------------------------------------------------
float tmp_num, expo;
String str = "";
switch (digit) {
case 0: expo = 1; break;
case 1: expo = 10; break;
case 2: expo = 100; break;
case 3: expo = 1000; break;
case 4: expo = 10000; break;
default: expo = 0; break;
}
if (expo != 0) {
str = String(int(num));
if (expo > 1) {
tmp_num = abs(num) - int(abs(num));
str = str + "." + String(int(tmp_num * expo));
}
}
while (str.length() < car) {
str = " " + str;
}
return str;
}
bool bp_pushed() {
return (digitalRead(buttonPin) == LOW);
}
//----------------------------------------------------------------------------------------------------------------------------------
void aff_menu() {
//----------------------------------------------------------------------------------------------------------------------------------
int action = 0, l_pas = 1;
double l_ang = 0, l_act = 0, l_posi = 0, l_ref = 0;

while (bp_pushed()) {
delay(10);
}

l_ref = read_angle();

do {

u8g2.firstPage(); // Display values
do {
u8g2.setFontDirection(0);
u8g2.setFont(u8g2_font_t0_14_tf);
u8g2.setCursor(18, 15);
u8g2.print("Tiefe : " + cnv_flt2str(corde, 4, 1) + "mm");

u8g2.drawBox(64 - 7, 22, 14, 10);
u8g2.drawFrame(64 - 20, 22, 40, 10);
u8g2.drawFrame(64 - 45, 22, 90, 10);
u8g2.drawFrame(0, 22, 128, 10);
u8g2.setFont(u8g2_font_micro_tr);
u8g2.setCursor(64 - 1, 30);
u8g2.print("0");
u8g2.setCursor(64 - 19, 30);
u8g2.print("-.1");
u8g2.setCursor(64 - 45 + 12, 30);
u8g2.print("-1");
u8g2.setCursor(64 - 63 + 5, 30);
u8g2.print("-10");
u8g2.setCursor(64 + 19 - 9, 30);
u8g2.print(".1");
u8g2.setCursor(64 + 45 - 14, 30);
u8g2.print("1");
u8g2.setCursor(64 + 63 - 14, 30);
u8g2.print("10");
u8g2.drawLine(l_pas, 18, l_pas, 34);
u8g2.drawLine(l_pas-1, 18, l_pas-1, 20);
u8g2.drawLine(l_pas+1, 18, l_pas+1, 20);
} while ( u8g2.nextPage() );

l_ang = read_angle() - l_ref; // read current angle
if (abs(l_ang) >= 7) { // If angle over 7 degrees
if (abs(l_ang) < 20) {
l_act = 0.1;
}
else {
if (abs(l_ang) < 35) l_act = 1; //Winkel original 45
else {
l_act = 10;
}
}
if (l_ang > 0) l_pas = 1; else l_pas = -1;
}
else l_act = 0;
// Serial.println("angle :" + String(abs(ang)) + " act " + String(act));
if (l_act != 0) {
corde = corde + (l_act * l_pas);
}

l_posi = l_ang;

if (l_posi >= 64) {
l_posi = 64;
}
else {
if (l_posi < -64) {
l_posi = -64;
}
}

l_pas = 64 + l_posi;
// Serial.println("angle :" + String(l_ang) + " posi "+ String(l_posi) + " pas " + String(l_pas));
delay(250); // delay 200 original
} while (not( bp_pushed()));
while (bp_pushed()) {
delay(10);
}
}
//----------------------------------------------------------------------------------------------------------------------------------
void affiche_init() {
//----------------------------------------------------------------------------------------------------------------------------------
u8g2.firstPage(); // Display values
do {
u8g2.setFontDirection(0);
u8g2.setFont(u8g2_font_t0_14_tf);
u8g2.setCursor(18, 24);
u8g2.print("INITIALISIEREN");
} while ( u8g2.nextPage() );
}
//----------------------------------------------------------------------------------------------------------------------------------
void affiche(String l_angle, String l_corde, String l_debat) {
//----------------------------------------------------------------------------------------------------------------------------------
u8g2.firstPage(); // Display values
do {
u8g2.setFontDirection(0);
u8g2.setFont(u8g2_font_t0_11_tf);
u8g2.setCursor(1, 10);
u8g2.print("Winkel Grad >");
u8g2.setFont(u8g2_font_crox4tb_tn);
u8g2.setCursor(78, 15);
u8g2.print(l_angle);
u8g2.setFont(u8g2_font_t0_11_tf);
u8g2.setCursor(1, 21);
u8g2.print("Tiefe " + l_corde + "mm");
u8g2.setCursor(1, 31);
u8g2.print("Weg mm >");
u8g2.setFont(u8g2_font_crox4tb_tn);
u8g2.setCursor(78, 32);
u8g2.print(l_debat);
} while ( u8g2.nextPage() );
}
//----------------------------------------------------------------------------------------------------------------------------------
void loop() { // Main loop
//----------------------------------------------------------------------------------------------------------------------------------
float x_rot = 0, aff_angle = 0, angle = 0, debat = 0;
int act = 0;

if (bp_pushed()) action = 1;

switch (action) {
case (1):
aff_menu();
action = 2;
break;
case (2):
affiche_init();
init_angle();
action = 0;
break;
default:
break;
}
x_rot = read_angle(); // read current angle
x_rot = ref_angle - x_rot; // compute angle variation vs. reference angle
angle = (x_rot / 180) * pi; // angle value converted into radian
debat = sqrt(2 * sq(corde) - (2 * sq(corde) * cos(angle))); // throw computation in same units as chord
affiche(cnv_flt2str(x_rot, 6, 1), cnv_flt2str(corde, 4, 1), cnv_flt2str(debat, 6, 1));
}

Gruß
Detlef
 

pantau

User
Genauigkeit

Genauigkeit

Hallo zusammen,

habe gerade nochmal meinen Messer mit dem RC Group Sketch getestet.
Habe festgestellt, dass dieser zwar in der Nulllage kaum schwankt, aber die Ausgabe des Winkels bei 90° nur knapp 87° ergibt.

Den Werten nach zu urteilen, wird der Abstand Ruderspitze Neutrallage zur Ruderspitze Ausschlag ausgegeben. (90°: 25mm Ruder - 35mm Anzeige)

Also da ist auch noch ein wenig Korrekturbedarf!

Gruß
Detlef
 

kalle123

User
Ja, Detlef. Da gibt es noch ein Problemchen bei dir ;)

Hab mal schnell einen Sensor an ein Geodreieck gehalten.

rRJxVqul.png


und anders rum

ADr0l7Vl.png


Vielleicht noch was Grundsätzliches ...

Die ADXL 345 haben ihre Grenzen. Schau dir mal den MMA 8451 an.

Gruß KH
 

pantau

User
Anzeige angepasst.

Anzeige angepasst.

So,
habe mir den Sketch nochmal angeschaut.
in folgender Zeile ist der Faktor anzupassen um bei 90° auch 90 ° anzuzeigen.
l_angle = atan2(y, z) * 57.3; // Compute rotation angle along X axis of ADXL345.

Dazu einfach 90 durch den angezeigten Wert teilen und das Ergebnis mit dem Faktor ( hier 57,3) multiplizieren und den Faktor dann ersetzen.

Mir ist zudem aber aufgefallen, das Spannungsabhängig auch verschiedene Werte angezeigt werden. Es fiel auf, weil ich mit verschiedenen 1s die Schaltung befeuert habe. Der Unterschied ist nicht groß (2-3%) aber er ist da. Es waren mal knapp 4V und das andere mal nur 3,7V.

Wie handelt ihr das mit der Spannungsversorgung?
Gruß
Detlef
 

kalle123

User
Wie handelt ihr das mit der Spannungsversorgung?

Hallo Detlef.

Ich nehm ja Pro minis und speise in Vcc ein. Wenn ich da "sauber" sein will, speise ich mit einem Schaltnetzteil 5V 2A. Ansonsten nehm ich die Akkupacks, die liegen um die 5V. Der Sensor arbeitet mit 3.3V über einen LDO und der liefert ein digitales Signal -> Arduino.

Kann deine Denkweise da nicht nachvollziehen ....

Wenn ich in das Datenblatt des LDOs (MIC5205) rein schaue, finde ich
Electrical Characteristics: V IN = V OUT +1V;

Bei 1S ist das schon nicht mehr in dem o.a. Bereich. Sollte schon 4.3V oder mehr sein.

Hast du eigentlich mal die Sensoren kalibriert? Und warum speist du nicht den Nano über die USB Buchse?

Gruß KH
 

pantau

User
Hallo Kalle,

Datenblatt habe ich nicht angeschaut. einfach mit verschiedenen 1s versucht und auch mal 2s drangehängt.
Die Spannungsversorgung läuft über VCC! (Arduino nano)

Kalibrieren ist beim dem Sketch in dem Sinne nicht vorgesehen.
Man kann nur über einen Faktorn den Ausgabewert anpassen (man könnte hier auch kalibrieren sagen)

Gruß
Detlef
 
Liebe Modellbaufreunde!
Erst einmal möchte ich mich bei allen hier für die hervorragende Arbeit bedanken, wirklich schön zu sehen, was man gemeinsam erreichen kann! Ich möchte mich kurz vorstellen, mein Name ist Ivo, ich bin seit früher Kindheit Modellbau- und Elektronikfan und habe auch recht gute elektrotechnische Kenntnisse. Mit dem Arduino habe ich noch nicht so sehr viel Erfahrung, fange gerade erst damit an. Um so interessanter finde ich das hier beschriebene Projekt, ich habe wirklich alle 30 Seiten des Threads gelesen und im Detail versucht zu verstehen, ich muss allerdings sagen, dass ich jetzt am Ende etwas mehr verwirrt als aufgeklärt bin.
Ich möchte ein paar dieser sehr nützlichen Helfer bauen und an gute Freunde zu Weihnachten verschenken. Ich möchte folgendes realisieren:
Messung mit zwei Sensoren (ggf. mit MMA 8451 statt ADXL 345) und die gemeinsame Anzeige auf einem OLED Display. Ist das so überhaupt möglich und bringt der Einsatz des MMA 8451 wirklich Vorteile? Ist das Projekt für einen Anfänger überhaupt möglich und könntet ihr mir eventuell mit den Sketch helfen? Ich freue mich auf Eure Anregungen und Kommentare!

Liebe Grüße und Danke für eure tolle Arbeit! Ivo
 

kalle123

User
Hallo Ivo.

Ja, m.E. ist der MMA "besser" als der ADXL. Schau einfach mal in die Datenblätter der Sensoren rein.

Ich hab selber mal ein paar Tests mit dem MMA gemacht.


Was du da vor hast, sollte kein Problem sein. Zwei Sensoren ist ja schon da und Oled auch.

Nur momentan mach ich da nix dran. Vielleicht wieder im Herbst/Winter.

Wenn du Interesse hast, hol dir die Teile (Arduino, Sensoren und Display) und fang an. Kostet ein paar Euros ....

Learning by doing!! Einfach mal selber machen ......

Gruß KH
 
Vielen Dank KH (nehme an, dass steht für Karl Heinz?)!

Darf ich Dich noch mal um Deinen Rat fragen? Meinst Du, ein 128x32 OLED langt aus, um zwei Wertepaare gemeinsam vernünftig darstellen und ablesen zu können, oder sollte das das Display größer sein? Ich würde jetzt zum Testen folgendes bestellen:
Arduino Nano V3, 2x MMA 8541, OLED Display 128x32 ggf. größer, Kleinkram wie Taster, Lochraster, hochflexibles Kabel. Habe ich noch etwas gravierendes vergessen und hast Du eventuell einen Tipp, wo man am Besten bestellt?
Freue mich schon auf das Basteln!

LG Ivo
 

kalle123

User
(nehme an, dass steht für Karl Heinz?)

Bitte mit Bindestrich dazwischen :D , aber Kalle geht schneller ....

Darf ich Dich noch mal um Deinen Rat fragen? Meinst Du, ein 128x32 OLED langt aus, um zwei Wertepaare gemeinsam vernünftig darstellen und ablesen zu können, oder sollte das das Display größer sein?

Au! Ein 128x32 ist m.E. verdammt klein. Ich bin Fan von den LCDs 1602 oder 2004. Schöne große Schrift und einfach zu integrieren. Ich verwende die LCDs. Wegen OLEDs, da müssen andere dir helfen oder du musst dich da selbst einarbeiten.

Ich würde jetzt zum Testen folgendes bestellen:
Arduino Nano V3, 2x MMA 8541, OLED Display 128x32 ggf. größer, Kleinkram wie Taster, Lochraster, hochflexibles Kabel. Habe ich noch etwas gravierendes vergessen und hast Du eventuell einen Tipp, wo man am Besten bestellt?

Wenn du bei Arduino einsteigen willst, Arduino UNO und Steckbrett und Jumper-wire.

Bevor du zusammen lötest, ist es besser, die Schaltung "fliegend" aufzubauen.

Das sieht dann so hier bei mir aus ;)

Z0C6v6il.png


Dann bestelle dir auch

tkbV7cll.png


Ich ordere hauptsächlich bei Aliexpress. Und für den ADXL 345 gibt es hier wohl auch Beispielprogramme mit OLEDs.

Ich mach z.Z. mit dem MMA 8451 nix. Vielleicht im nächsten Winter wieder ....

Grüße KH
 

jweber

User
Hallo an Alle,

das Thema Rudereinstellung find ich prima, insbesondere, da mir dabei immer eine Hand fehlt.
Leider habe ich nicht so schicke Klammern mit Skala und mache das immer mit Geodreieck oder Lineal, dann verrutscht man wieder und muss von vorne anfangen...

Also Interesse ist da, einen Arduino habe ich auch schon mal zum arbeiten bekommen (openXsensor).
Jetzt habe ich mir den Fred durchgelesen/überflogen und schon kommen die Fragen:

Die erste und wichtigste ist: welche Variante ist die sinnvollste?
Ich würde gerne normale LCD-Module verwenden, ob 16x2 oder 20x4 kommt gleich.
Für meinen Anwendungsfall würden die ADXL345 reichen, angesichts der Kosten in Relation zur Arbeit kann man aber auch gleich die MMA8451 verwenden.
Für die gleichmäßige Einstellung re/li würde ich gerne 2 Sensoren gleichzeitig verwenden können

Welche Variante hat sich am sinnvollsten im Handling herausgestellt:
a. 2x Arduino, 2x Stromversorgung (z.B. 9V-Block) 2x 1602 Display, 2 kleine Gehäuse jeweils mit einem kürzeren Kabel einen Sensor dran.
b. 1 Arduino, 1 Stromversorgung (Netzteil oder 4xAA oder so) ein Größeres Gehäuse in der Mitte mit einem Display 2004, etwas längere Kabel und zwei Sensoren angeschlossen.
c. Variante a. aber in einem Gehäuse zusammengefasst.

Vielen Dank und viele Grüße
Jörn
 

kalle123

User
das Thema Rudereinstellung find ich prima, insbesondere, da mir dabei immer eine Hand fehlt.
Leider habe ich nicht so schicke Klammern mit Skala und mache das immer mit Geodreieck oder Lineal, dann verrutscht man wieder und muss von vorne anfangen...

Hallo Jörn. Es geht doch auch ohne Elektronik vernünftig! Mit diesen "Bastellösungen" kriegt ich auch eine vernünftige Einstellung hin.

rZfQu5jl.png


Zu der Frage, ob Variante a, b oder c. Das musst du für dich selber entscheiden.

LCD1602 und 2004 sind für den Laien (wie mich ;)) am einfachsten zu handeln. Ob ADXL345 oder MMA8451, ich hab letzten Winter mal mit dem MMA8451 angefangen, aber im Sommer war da Ruhe, nix gemacht.

Jörn, wenn dich das Thema interessiert, bestelle dir mal die Teile. LCD, Arduino (auch einen Uno), Steckbrett, Sensoren .... Kosten sind ja überschaubar und finde raus, ob das was für dich ist. Dann wird sich auch die Frage a, b oder c von alleine lösen ;)

Gruß KH
 

kalle123

User

jweber

User
Ich find die Spielerei mit Arduino einfach schön.

Eigentlich gings jetzt ja auch schon viele Jahre nur mit einem Lineal, auch vernünftig, aber wo bleibt da der Spieltrieb....
Ich hatte lange Zeit keinen Servotester, ging auch, aber mit gehts einfacher.

Jörn
 
Ansicht hell / dunkel umschalten
Oben Unten