Dynamische Auswuchten in einer Ebene.....Hilfe!!!!!!

Hallo

Ich darf mich erst einmal kurz vorstellen. Ich heiße Jens, komme aus Hessen, und bin leidenschaftlicher RC-Modellbauer. Hauptsächlich beschäftige ich mit Powerbooten (Rennbooten) die bis zu 180 km/h schnell sind. Aber auch einige Flugmodelle gehören dazu, unter anderem auch ein Quadrocopter.

Mit Elektronik und diversen Programmiersprachen habe ich wenig bis kaum Erfahrung. Ich habe zwar für meinen Copter mittels eines Arduinos das LED Signal der Naza-Steuerung abgegriffen um LED´s in den Auslegern schalten zu können. Das war/ist so mein Einstieg mit dem Arduino gewesen. Das Projekt hat zwar lange gedauert, aber schlussendlich funktioniert alles. Und Spaß hat es auch gemacht. Daher bin ich schon seit einiger Zeit an einem neuen Projekt, bei dem ich nun aber so langsam an meine Grenzen stoße. Daher brauche ich Hilfe und hoffe dass ich hier diese finden kann.

Es geht um folgendes (vielleicht schon ein alter Hut für den Einen oder Anderen hier). Ich möchte meine Propeller (2-5 Blätter) dynamisch wuchten. Mir reicht hierbei ein Auswuchten in einer Ebene. Im Prinzip möchte ich den Propeller auf einen BL Motor montieren und dann soll mir der Arduino in einem LCD anzeigen wo die Unwucht liegt. Darüber hinaus sollte es auch eine Aussage über die Größe der Unwucht gemacht werden. Die Theorie hinter dem Auswuchten ist mit soweit bekannt und auch verständlich. Nun habe ich angefangen die Hardware Step by Step aufzubauen. Ich habe im Augenblick folgende Komponenten: Arduino Uno CNY 70 Reflexlichtschranke ADXL 335 Beschleunigungssensor. 30 A BL Regler inkl. 3s Lipo Oszi und Multimeter stehen auch zur Verfügung.

Ich bin so weit, das ich den BL Motor über zwei Taster ein und ausschalten kann und die Drehzahl per Poti einstellen kann. Auch den ADXl 335 und die Reflexlichtschranke habe ich soweit zum Laufen gebracht. Nun mein Problem: Ich muß ja den maximalen Wert des ADXL 335 bei jeder Umdrehung einer Position des Rotors zuweisen. Und genau da hört es bei mir auf…es stellen sich (zu mindestens mir) folgende Fragen:

• Über die Markierung auf dem Rotor weiß ich ja, wo „Null“ ist. Aber wie kann ich damit eine beliebige Rotorpostion ermitteln?? • Wie kann ich pro Umdrehung den max. Wert des ADXL 335 einer Position zuweisen? • Wie Speicher ich die Daten? • Wie kann ich es so gestalten, dass nach einer gewissen Hochlaufzeit des Motors, für ca. 50 Umdrehungen die Werte analysiert werden und aus diesen dann ein Mittelwert gebildet wird? Vielleicht kann mir jemand von euch helfen. Ich komme aus dem klassischen Maschinenbau und habe wie oben schon gesagt, keine/wenig Erfahrung mit C++ und Elektronik. Daher brauch ich eure Hilfe.

Vielen Dank schon mal. Mfg Jens

üblicherweise hast du bei solchen Systemen nicht nur eine Markierung, sondern bis zu 36+1, also alle 10° eine Markierung und eine Zusatzmarkierung für den "Anfang". (die kann auf einem 2. Geberrad sitzen)

Wenn du nun auf jeden Impuls des Gebers einen Interrupt setzt, der die Beschleunigung an dieser Stelle abfragt, hat du alle 10° einen Wert.

Speichern: die Werte in Array[36] schreiben.

Mittelwert bilden: Stichwort "gleitender Mittelwert" Ich habs schon mal beschrieben, Reply Nr 3

Das ist aber recht anspruchsvoll zu programmieren. Du mußt z.B. sehr auf die Laufzeit und die Echtzeitfähigkeit achten.

Hallo Danke für die Rückmeldung. Die Überlegung hatte ich auch schon, mit mehreren Markierung pro Umdrehungen. Nur wie sieht es dann aus, wenn mal eine Markierung nicht richtig erkannt wird? Dann zählt er doch falsch, oder? Mit nur einer Markierung hat der doch zu mindestens eine Postion zweifelsfrei zugeordnet. Außerdem denke ich das eine 10 Grad Teilung zu ungenau ist. Daher habe ich nach einem schnellen Drehgeber gesucht und bin auf den AS5045 gestoßen. Von der Auflösung und der max. Geschwindigkeit ist der Sensor ausreichend. Nur ist mir noch nicht klar, wie ich (bei einer Auflösung von 360 Messungen pro Umdrehung) bei jedem Grad den ADXL auslesen kann und wie ich dann die Informationen speichern kann. Im Grund stelle ich mir eine X-Y Liste vor, bei dem jedem Grad (X) genau ein ein Wert vom ADXL (Y) zugeordnet wird. Also eine Liste mit 360 "Wertepaaren". Ich hoffe ihr habt mich verstanden......bin halt Laie.....

Mfg Jens

Hallo,

die ausgelesenen Werte kann man hintereinander in ein Array speichern und dann in Ruhe auslesen, Mittelwert bilden oder sonstwas machen und dann erneut beschreiben.

Meine Frage wäre nur, wieviel Zeit hat den der µC zum auslesen eines Wertes wenn er aller 1 Grad auslesen soll?
Also bei welcher max. Drehzahl möchtest Du messen?
Wie lange dauert das auslesen des Sensors? Ggf. Wartezeit beachten.
Und wo und wie befestigst Du den ADXL 335?

Hallo Mein Wunsch wäre, mit max. 600 U/min zu wuchten, also mit 10 Hz. Bei 360 Messungen pro Umdrehung wären das also 3600 Messungen pro Sekunde. Also würde das Messintervall bei 2,7*10^-4s liegen.

Zur Zeit habe ich einen BL Motor auf eine 3mm Aluplatte geschraubt und habe den ADXL ebenfalls auf diese Platte geschraubt. Diese Einheit, bestehend aus Motor,ADXL und Platte habe ich dann auf eine große Holzplatte geschraubt. Zur Zeit noch eine steife Anbindung. Es wäre aber auch ohne weiteres möglich noch Schwingelemente zwischen der Aluplatte und der Holzplatte unter zu bringen.

Wenn ich das Datenblatt von dem ADXL richtig gelesen habe, liegt die FREQUENCY RESPONSE bei 1600 Hz.

Mfg Jens

Hallo,

bei 3600 Messungen pro Sekunde darf eine komplette Messung mit speichern und allen max. 0,27ms dauern. Dazu mußt Du 3 analoge Werte in der Zeit einlesen. Ich glaube das wird nichts. Sagt mir mein Gefühl.

Bastel Dir mal einen Sketch, in dem Du 100 Werte an 3 analogen Eingängen ohne Pause einliest und dazu den micros Zeitstempel. Wenn die 100 voll sind, läßt du sie dir seriell anzeigen. Dann wirst Du sehen an Hand der "Zeiten" wie lange das dauert und ob Du Luft hast oder doch nicht.

Die 1600Hz gelten nur für X und Y Achse. Die Z Achse kann nur 550Hz.

Doc_Arduino: Hallo,

bei 3600 Messungen pro Sekunde darf eine komplette Messung mit speichern und allen max. 0,27ms dauern. Dazu mußt Du 3 analoge Werte in der Zeit einlesen. Ich glaube das wird nichts. Sagt mir mein Gefühl.

Bastel Dir mal einen Sketch, in dem Du 100 Werte an 3 analogen Eingängen ohne Pause einliest und dazu den micros Zeitstempel. Wenn die 100 voll sind, läßt du sie dir seriell anzeigen. Dann wirst Du sehen an Hand der "Zeiten" wie lange das dauert und ob Du Luft hast oder doch nicht.

Die 1600Hz gelten nur für X und Y Achse. Die Z Achse kann nur 550Hz.

3 analoge Werte? Einen für den Drehwinkel, einen für die Beschleunigung, und den dritten? Mfg Jens

Hallo,

der ADXL gibt dir 3 Werte aus, je einen für x, y und z. Brauchst Du nicht alle 3 davon?

Man kann den ADC auch ohne direkte Register-Programmierung schneller machen. Das geht etwas auf Kosten der Genauigkeit, aber es geht: http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/

Doc_Arduino: Hallo,

der ADXL gibt dir 3 Werte aus, je einen für x, y und z. Brauchst Du nicht alle 3 davon?

In diesem Fall reicht mir die Beschleunigung in einer Richtung. Ob X oder Y ist da dann erstmal zweitrangig. Theoretisch kann man die Genauigkeit der Messung erhöhen, wenn man in zwei Richtungen die normal zu einander sind die Beschleunigung protokolliert. Die müssen nämlich genau 90 Grad Phasenverschoben sein.....aber wie gesagt. Nur in der Theorie und hier sicherlich nicht nötig. Daher: Messen nur in einer Richtung.

Mfg Jens

Doc_Arduino: ........

Bastel Dir mal einen Sketch, in dem Du 100 Werte an 3 analogen Eingängen ohne Pause einliest und dazu den micros Zeitstempel. Wenn die 100 voll sind, läßt du sie dir seriell anzeigen. Dann wirst Du sehen an Hand der "Zeiten" wie lange das dauert und ob Du Luft hast oder doch nicht.

Die 1600Hz gelten nur für X und Y Achse. Die Z Achse kann nur 550Hz.

Tja, und da hört es schon so langsam auf bei mir. Was meinst du mit "ohne Pause"?

Mfg Jens

Hallo,

mit “ohne Pause” meinte ich du sollst 100 mal Werte einlesen hintereinander weg.
Dabei fällt mir ein, es gibt doch eine loop Dauer Meßfunktion. Auf die schnelle einen Sketch zusammengeschustert, damit werden 10x zwei analoge Werte eingelesen. Nach 100 Loop Durchläufen wird die Zeit in ms ausgegeben die die loop benötigt hat. Den Wert durch besagte 10 geteilt und Du hast die Dauer der 2 analogen Einlesungen.

Wenn die ms zu grob sind, tauschst Du millis mit micros aus in der Meßfunktion.

int sensorPin0 = A0;    
int sensorValue0 = 0; 
int sensorPin1 = A1;   
int sensorValue1 = 0;  


void setup() {
  Serial.begin(9600);     

}

void loop() {
  LoopTiming();

  for(int i=0; i<10; i++) {
    sensorValue0 = analogRead(sensorPin0);
    sensorValue1 = analogRead(sensorPin1);
  }  

  LoopTiming();
}


/*********************************************************************************
** LoopTiming() v05 by GuntherB & Doc_Arduino @ german Arduino Forum        	**
**********************************************************************************
** Funktion um die Dauer der Loop-Zeiten zu ermitteln				**
** wird in der Loop am Anfang und Ende aufgerufen				**
** benötigt ca (AL * 4 + 16) Byte RAM						**
*********************************************************************************/
void LoopTiming()
{
  const int AL = 200;        // Arraylänge, NUR GERADE Zahlen verwenden!
  static unsigned long LoopTime[AL];
  static unsigned int Index=0, Messung=0, Min=0xFFFF, Max, Avg;
  
  if (Messung % 2 == 0)     // wenn Messung X gerade (0,2,4,6 usw.), entspricht immer Anfang der Loop
    {
     LoopTime[Index] = millis();
     Messung++;
     Index++;    
     return;	            // Funktion sofort beenden, spart bestimmt Zeit
    }

  if (Messung % 2 == 1)     // wenn Messung X ungerade (1,3,5,7 usw.), entspricht immer Ende der Loop
    {
     LoopTime[Index] = millis();
     LoopTime[Index-1] = LoopTime[Index] - LoopTime[Index-1];  	// Loopdauer einen Index niedriger einspeichern wie aktuell
     Messung++;
    }	
	    
  if (Index >= AL) 	// Array voll, Daten auswerten
    {  
     for (int i = 0; i<AL; i++)
       {
        Min = min(Min, LoopTime[i]);
        Max = max(Max, LoopTime[i]);
        Avg += LoopTime[i];
       }
	
     Avg = Avg / AL;
     Serial.print(F("Minimal       "));Serial.print(Min);Serial.println(" ms");
     Serial.print(F("Durchschnitt  "));Serial.print(Avg);Serial.println(" ms");
     Serial.print(F("Maximal       "));Serial.print(Max);Serial.println(" ms");
     Min = 0xFFFF;
     Max = 0;
     Avg = 0;
     Messung = 0;
     Index = 0;
    }
}

Hallo,

wenn ich jetzt keinen Müll geschrieben habe, dauern 3 analoge Einlesungen ca. 350µs.
2 analoge Einlesungen dauern ca. 230µs.
Wenn Du nur 270µs Zeit hast, wird das schon mal nichts oder sehr sehr knapp. Der µC muß noch etwas mehr machen während der Zeit.

Jetzt müßte man das vom Serenifly’s Link angehen. Kannste ja mal probieren. Ist ja Dein Projekt. :smiley:

int sensorPin0 = A0;    
int sensorPin1 = A1;   
int sensorPin2 = A2; 
int Index;

unsigned long Min=0xFFFF, Max, Avg, aReadTime;
const int AL = 100;                     //Arraylänge
static unsigned int analogWerte0[AL];   //Array für analog Werte
static unsigned int analogWerte1[AL];   //Array für analog Werte
static unsigned int analogWerte2[AL];   //Array für analog Werte
static unsigned long Zeitstempel[AL];   //Array für Zeitstempel

void setup() {
  Serial.begin(9600);     

}

void loop() {

  for(Index=0; Index<AL; Index++) {
    analogWerte0[Index] = analogRead(sensorPin0);
    analogWerte1[Index] = analogRead(sensorPin1);
    //analogWerte2[Index] = analogRead(sensorPin2);
    Zeitstempel[Index] = micros();
  }  
  
  
  // Daten auswerten
   for (Index=1; Index<AL; Index++)  {
     
     aReadTime = Zeitstempel[Index] - Zeitstempel[Index-1];  	// Differenzbildung
     
     Min = min(Min, aReadTime);
     Max = max(Max, aReadTime);
     Avg += aReadTime;
   }
	
     Avg = Avg / AL;
     Serial.print(F("Minimal       "));Serial.print(Min);Serial.println(" µs");
     Serial.print(F("Durchschnitt  "));Serial.print(Avg);Serial.println(" µs");
     Serial.print(F("Maximal       "));Serial.print(Max);Serial.println(" µs");
     Min = 0xFFFF;
     Max = 0;
     Avg = 0;
     
  
  
}

270µs reicht dicke für ein normales Arduino analogRead (120µs) und knapp für zwei ( x / y )

Ich nehme mal an das Auswuchten soll Beschleunigungen in radialer Richtung minimieren und keine wechselnden Rotationsgeschwindigkeiten. Ein einziges analogRead reicht also.

Das Aufsummieren / Ablegen in einem Feld geht flott, im Vergleich dazu.

Problem ist eher, die ca. 360 Messungen mit dem Sync-Impuls zu synchronisieren. Wie genau lässt sich die Drehzahl regeln ? Wie sehr stört der millis - Timer0 Interrupt ? ( Jitter-Effekt )

( Mein Tip: die 1° Auflösung ist für die Katz, weil die Unwucht-Messung beim Mitteln über viele Umdrehungen auch den Speicher-Index "verschmiert". Z.B. ist evtl. die maximale Beschlunigung mal bei der 55. Messung, mal bei der 56. und mal bei der 57. Messung -> 3° Ungenauigkeit. Lieber doppelt so schnell drehen mit größeren Unwucht-Kräften und nur alle 2° messen )

Hallo,

wenn eine Achse reicht ist gut. Ich dachte man mißt die Vibration vom gesamten Aufbau von allen Richtungen. Ich weis aber nicht welche Auswirkungen das wuchten hat und ob die anderen Achsen überhaupt relevant sind oder ob die flattern können wie sie wollen.

weitermachen ... ;)

Hallo
Vielen Dank für die Rückmeldungen und die Hilfe.
Ich habe folgende Überlegung zur Bestimmung der Rotorposition und würde gerne eure Meinung dazu hören.

Wie oben schon erwähnt habe ich einen CNY 70 in Gebrauch und auf der Glocke des Motors eine Markierung. Das Auslesen der Markierung klappt. Nun war meine Überlegung: Wenn die Markierung vor dem Sensor ist (Pegel auf High) lese ich mit millis() die Zeit aus. Wenn der Pegel auf low springt( Markierung nicht mehr vor dem Sensor) lese ich wiederum die Zeit mit millis() aus. Wenn die Markierung nach einer Umdrehung wieder vor dem Sensor ist, dann lese ich nochmals die Zeit mit millis() aus. So kann ich:
a) die “Breite” der Markierung bestimmen (Sekunden)
b) und wie lange eine Volle Umdrehung in Sekunden ist

damit kann ich doch dann einfach die Drehzahlberechnen.
Wenn ich es jetzt noch irgend wie schaffe den Maximalen Sensorwert des ADXL 335 einer Zeit zu zu weisen, ( also noch wieviel Sekunden nach dem die Markierung vor den CNY 70 war) dann kann ich doch (theoretisch) den Winkel ermitteln den die Markierung sich weiter gedreht hat bis der Sensorwert Maximal wird.

Anbei findet Ihr einmal den Code von dem was ich bis jetzt mir so zusammen gebastelt habe. Für Tipps und Anregungen bin ich dankbar…
Ich hoffe Ihr schlagt nicht die Hände über dem Kopf zusammen wenn ihr meinen Versuch seht…

Frohe Ostern :slight_smile:

Servotester_mit_Tasten_und_Poti_und_LCD_test.ino (4.25 KB)

Danke, auch frohe Ostern!

dropps: a) die "Breite" der Markierung bestimmen (Sekunden) b) und wie lange eine Volle Umdrehung in Sekunden ist

Mir ist nicht klar, wozu Du die Breite der Markierung brauchst. Ich denke, die Flanke "LOW" nach "HIGH" oder umgekehrt sollte reichen. Eine Umdrehung ist von "LOW->HIGH" bis zum nächsten "LOW->HIGH", oder?

Du fragst nach Tipps, bitteschön:

const int buttonRun = 6;            //Eingang des Run-Tasters an Pin 6
const int buttonStopp = 7;          //Eingang des Stop-Tasters an Pin 7
const int pot = A3;                       //Eingang des Potentiometers für ESC an Eingang A3     
const int CNY_70 = A5;                    //Eingang des CNY_70 Eingang A5
const int LED = 13;                        //Led an ausgang 13, dient der Kontrolle des CNY_70

Spart Variablen und freut den Leser.

const int buttonRun = 6;            //Eingang des Run-Tasters an Pin 6
const int buttonStopp = 7;          //Eingang des Stop-Tasters an Pin 7

 pinMode(buttonRun, OUTPUT);        //Lesen des Tasters "Run"
 pinMode(buttonStopp, OUTPUT);      //Lesen des Tasters "Stopp"

Ein Taster am Ausgang, das geht gut? Anstelle "OUTPUT" lieber "INPUT" oder "INPUT_PULLUP".

int CNY_70 = A5;                    //Eingang des CNY_70 Eingang A5
...
cny_wert = analogRead(CNY_70);    //lese den Analogen Wert am Eingang A1

A5 oder A1?

Ich hoffe, bei den vielen Umdrehungen wird Dir nicht schwindelig :)

Wenn ich an den Praktikums-Versuch zum Auswuchten in 2 Achsen zurückdenke, dann wurden dort Lager verwendet, die in einer Richtung weich waren, also Schwingungen (Auslenkungen) zuließen. Wenn man so ein analoges Signal hat, egal ob Kraft oder Auslenkung, dann läßt sich das auch analog differenzieren, und daraus ein Interrupt beim Wechsel der Polarität erzeugen. Oder man nimmt das Signal direkt, triggert beim Nulldurchgang und rechnet 90° drauf (plus Kalibrierungsfaktor). Dann hat man zusammen mit der Referenzmarke den Winkel der Unwucht. Den Betrag kann man aus dem Spitzenwert des Signals ermitteln, und diesen Teil der Schaltung nach dem Auslesen wieder zurücksetzen (für die Ermittlung des nächsten Spitzenwerts). Damit wären alle zeitkritischen AD-Wandlungen eliminiert.

Eine Lösung in dieser Art wurde hier (auf Englisch) schon zur Messung der Kompression eines Wankel-Motors durchdiskutiert und realisiert. Eine vollständig digitale Lösung wäre zwar schöner, aber wenn die wegen Zeitproblemen keine brauchbaren Werte liefert, muß man eben auch mal in die (Un-)Tiefen der Analogtechnik hinabsteigen.

dropps: Außerdem denke ich das eine 10 Grad Teilung zu ungenau ist.

Moderne Motorsteuergeräte für PKW Verbrennungsmotoren arbeiten mit 6°-10° Auflösung des Drehgebers und erreichen damit Genauigkeiten besser als 0,5°.

Ausserdem bezweifle ich, dass du dein Ausgleichsgewicht mit 1° Genauigkeit aufkleben kannst. Wenn du wirklich einen Drehgeber mit 1° Auflösung nehmen willst, dann brauchst du einfach einen schnellerer Rechner. Der DUE sollte es dann schon sein.

Was machen Profis hier: sie bilden auf einem internen Timer ein 360° modell ab und korrigieren das nur mit den Sensorsignalen.

Da du bei deinem Fall eine sehr gleichförmige Bewegung hast, sollte es sogar reichen, wenn du die interne 360° Simulation nur einmal pro Umdrehung korrigierst, also nur eine Markierung hast.