Go Down

Topic: Ardunio Hallsensor m. TLE 4095L - Drehzahlsprünge (Read 697 times) previous topic - next topic

bens0r

Hallo alle zsm,

ich baue grad eine Drehzahlmessung für einen kleinen Prüfstand. Ich verwende einen TLE  4095L welcher direkt auf dem Motor fertig montiert war. (2x auf Motorplatine)

Derzeit möchte ich nur einen der Hallsensor auslesen um die Drehzahl zu bestimmen.

Soweit so gut, ich erhalte einigermaßen vernünftige Ergebnisse. Jedoch springen die Drehzahlwerte beim kurzzeitigen Start sowie beim Anhalten des Motors ins unermessliche (8000, 14000, 58000 umd).
Auch ohne Motordrehung erhalte ich kurzzeitig ganz irre Werte.


Der Motor kann aber maximal 4900 umd und ist mechanisch mit einer Mimik Verbunden die keinen Schlupf zulässt. (Zahnradverbindung)

Im Anhang die Werte in Gut und die Werte beim Starten und Bremsen mit den Ausreißern.

Hier der Code:

Code: [Select]



volatile byte  count = 0;
volatile boolean validA = false;//kontroller ob a zu b folgt

volatile unsigned long startTimeA;
volatile unsigned long endTimeA;
unsigned long copy_startTimeA;
unsigned long copy_endTimeA;

volatile unsigned long startTimeB;
volatile unsigned long endTimeB;
unsigned long copy_startTimeB;
unsigned long copy_endTimeB;

volatile boolean finishPulseA = false;
volatile boolean finishPulseB = false;

float periodA;
float periodB;

unsigned int rpmA = 0;
unsigned int rpmB = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println("starting......");


  pinMode(2, INPUT_PULLUP);//interrupt pin
  attachInterrupt(digitalPinToInterrupt(2), isrCount, FALLING);//interrupt on pin2

}

void loop()
{
  if (finishPulseA == true )
  {
    // interrupts abbrechen
    noInterrupts();
    finishPulseA = false;//reset flag
    copy_startTimeA = startTimeA;
    copy_endTimeA = endTimeA;
    interrupts();

    periodA = (copy_endTimeA - copy_startTimeA);
    rpmA = 60000000UL / periodA; //ein puls pro umdrheung
    Serial.print("RPMA = ");
    Serial.println(rpmA);
  }
 
  if (finishPulseB == true)
  {
    // interrupts abbrechen
    noInterrupts();
    finishPulseB = false;//reset flags
    copy_startTimeB = startTimeB;
    copy_endTimeB = endTimeB;
    interrupts();

    periodB = (copy_endTimeB - copy_startTimeB);
    rpmB = 60000000UL / periodB; //ein puls pro umdrehung
    Serial.print("RPMB = ");
    Serial.println(rpmB);
  }
}

void isrCount()
{
  if (count == 0)//ersteintrag
  {
    startTimeA = micros();
    endTimeB = micros();
    if (validA)  //anfangspuls A, b nicht gestartet
      finishPulseB = true;
    count = 1;
  }

  else if (count == 1)//zweiter eintrag
  {
    endTimeA = micros();
    startTimeB = micros();
    finishPulseA = true;
    validA = true;
    count = 0;
  }
}





Ich habe verschiedene Sachen ausprobiert. Der Hallsensor läuft über V=5V Arduino GND=GND Arduino Signal=Pin2.
Über 5V und Pin2 habe ich verschiedene Widerstände gezogen. Bringt aber keine Verbesserung.

Die Spannungsversorgung des Hallsensors habe ich zum Versuch über einen Labornetzteil gezogen. Bringt aber auch keine Verbesserung.
Solangsam verstehe ich nicht wo mein fehler liegt.




DrDiettrich

Der open-collector Ausgang braucht einen Pullup-Widerstand nach +. Nicht zu groß, sonst fängt das Kabel zu viele Störungen ein, und nicht so klein, daß der Ausgang überlastet wird.

bens0r

Was wäre den ein guter Wert an Widerstand zum testen?


bens0r

Also bei 1k ohm kommen garkeine Daten mehr raus. Ich bin jetzt runter auf 470Ohm und das Ergebnis ist deutlich besser. Nichts desto trotz hab ich beim Motor anlauf und beim Bremsen immernoch Ausreißer.

Wenn der Motor konstant fährt kommen saubere Daten an...


Vielleicht hat ja noch jmd eine Idee.

DrDiettrich

Die Qualität der Signale kann man nur mit einem Scope überprüfen. Die Verkabelung kann da schon Probleme bereiten.

Ich würde die Zeitdifferenz gleich in der ISR berechnen, statt zwei Zeiten abzuspeichern. Wie hoch werden denn die Werte über den vorgesehenen Drehzahlbereich?

bens0r

Ich werde die Verkabelung nochmal prüfen. Wie oben beschrieben:


Start sowie beim Anhalten des Motors ins unermessliche (8000, 14000, 58000 umd).
siehe Auch die angehängten Fotos im ersten Post.

Ich werde mal mein Oszi auspacken...Leider kann ich den Motor derzeit nur maximal 3-4Sekunden drehen lassen. Da meine Mechanik nicht mehr hergibt.

Das mit der interenen Berechnung ist eine gute Idee. Jedoch verstehe ich nicht warum ich nur am Start und Ende die falschen Werte bekomme. Wenn der Motor einige Sekunden dreht, sehen die Daten super aus.

bens0r

Ich bin jetzt mit dem Oszi nicht so bewandert. Aber man sieht schon, dass ich am Anfang und am Ende Ausreisser im Signal habe. Gibt es eine möglichkeit die zu "glätten" ?

Im Anhang ein Screenshot vom Oszi

Doc_Arduino

Hallo,

ich würde in der ISR nur immer stur die Differenz zum vorherigen Wert bilden. Ohne deine count = 1 Lösung. Danach zu kleine und zu große Werte rausfiltern (Drehzahlband) und danach den Wert einer permanenten Mittelwertbildung zuführen. Die maximale Drehzahl ist dabei nicht einmal das Problem sondern die minimale Drehzahl. Ich vermute auch einen Logikfehler in deinem ISR Code mit deinen bool Flag Änderungen. Wenn du derzeit nur einen Sensor nutzt, kannste nicht den zweiten mit einbeziehen. Desweiteren schreibst du ständig auf die serielle ohne Pause, dann kommen sich die Interrupts ins Gehege, was zu Fehlmessungen führen wird.

Vorschlag.
Code: [Select]

void isrCount()
{
    static unsigned long old_SensA = 0;
    
    unsigned long newSensA = micros();
    time_SensA = newSensA - old_SensA;
    old_SensA = newSensA;
}

time_SensA global volatile, den Wert mitteln (oder auch nicht) und nur aller 0,5 oder 1 Sekunde ausgeben lassen. Also Berechnung und Ausgabe auftrennen.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

von Gunther

Filterfaktor entsprechend verkleinern. Vielleicht auf 10-30 ...
Code: [Select]

float Val;

void setup() {
  Serial.begin(9600);
  Serial.print("IN\t"); Serial.print("OUT\t\n");
}

void loop() {  
  int Eingangswert = analogRead(A0);
  Serial.print(Eingangswert); Serial.print("\t");
  Filtern(Val, Eingangswert, 100);
  Serial.print(Val); Serial.print("\t\n");
}


/*****************************************************************************************
** Funktion Filtern()  by GuntherB                                                      **
******************************************************************************************
** Bildet einen Tiefpassfilter (RC-Glied) nach.                                         **
** FF = Filterfaktor;  Tau = FF / Aufruffrequenz                                        **
**                                                                                      **
** Input: FiltVal der gefilterte Wert, NewVal der neue gelesene Wert; FF Filterfaktor   **
** Output:  FiltVal                                                                     **
** genutzte Globale Variablen: Val  (call by Reference)                                 **
******************************************************************************************/

void Filtern(float &FiltVal, int NewVal, int FF){
  FiltVal= ((FiltVal * FF) + NewVal) / (FF +1);
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

anwofis

Verwendest du abgeschirmte Kabel? Wenn es nicht am Code liegt, wüsste ich jetzt auch nicht wie du eine Störung reinbekommst.

Sonst vllt. erstmal ein einfaches Programm testen:

Code: [Select]
#include <INTERVAL.h>

const uint8_t pin_hall = 2;
const uint32_t my_interval = 2000;

const double factor = 30.0;// (revs/my_interval) * 60000UL

volatile uint32_t revs = 0;

void setup(void) {
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(pin_hall), do_stuff, FALLING);
}

void loop(void) {
  INTERVAL(my_interval) {
    Serial.print(revs);
    Serial.print(" ");
    Serial.println(revs * factor);
    revs = 0;
  }

}

void do_stuff(void) {
  revs++;
}

DrDiettrich

Die Kabel zum Motor und zu den Sensoren sollten möglichst weit getrennt verlegt werden. Und keinesfalls ein Aufbau mit fliegenden Strippen, nur mit mehradrigen Kabeln.

bens0r

Verwendest du abgeschirmte Kabel? Wenn es nicht am Code liegt, wüsste ich jetzt auch nicht wie du eine Störung reinbekommst.

Sonst vllt. erstmal ein einfaches Programm testen:

Code: [Select]
#include <INTERVAL.h>

const uint8_t pin_hall = 2;
const uint32_t my_interval = 2000;

const double factor = 30.0;// (revs/my_interval) * 60000UL

volatile uint32_t revs = 0;

void setup(void) {
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(pin_hall), do_stuff, FALLING);
}

void loop(void) {
  INTERVAL(my_interval) {
    Serial.print(revs);
    Serial.print(" ");
    Serial.println(revs * factor);
    revs = 0;
  }

}

void do_stuff(void) {
  revs++;
}

also das Programm läuft recht stabil. Keine Ausreisser... Jedoch passen die Werte so garnicht.
Maximal kommen 2190 Umdrehung bei raus.

Würde es eigentlich Sinn machen, das ich die Darstellung der Drehzahl über I2C auf einem Display vornehme zur Kontrolle? (also anstelle der Seriell Monitors?)

@DrDiettrich - fliegende Strippen gibt es nicht mehr. Macht aber keinen Unterschied.

Kann ich mit einem Kondensator, Diode etc? noch was ausrichten?

anwofis

@bens0r:

Hast du's so wie im Datenblatt verkabelt?

Liegt's jetzt am Code oder an der Elektronik?

Mein kleiner Sketch zählt nur die Impulse / 2 Sek. - wären also 2190 rpm = 30 * 73 (Impulse = Umdrehungen?).

bens0r

Also soweit ich das sagen kann, ist das richtig verkapelt. Den Hallsensor selber kann ich nicht einzelnd ansteuern, da er auf einer Platine fest verbaut ist und im Motorgehäuse eingebaut ist.

Im Anhang ein Foto, wie die Schaltung im inneren angeblich sein soll.

Bezügliche der Impulse werde ich heute nichtmehr schlau. :smiley-confuse:
Nach ein paar Stunden sollte man so ein Projekt wohl erstmal in die Ecke werfen :)

besten dank schonmal für die ganze Hilfe.

Go Up