Ardunio Hallsensor m. TLE 4095L - Drehzahlsprünge

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:

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.

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.

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

1k

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.

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?

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.

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

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.

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.

von Gunther

Filterfaktor entsprechend verkleinern. Vielleicht auf 10-30 ...

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); 
}

(deleted)

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.

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:

#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?

(deleted)

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. :confused:
Nach ein paar Stunden sollte man so ein Projekt wohl erstmal in die Ecke werfen :slight_smile:

besten dank schonmal für die ganze Hilfe.

Hallsensor.JPG

Hallo,

die Schaltung bzw. Beschaltung des TLE gefällt mir nicht. Vorallendingen der jeweils 10 Ohm Längswiderstand am Ausgang ist etwas seltsam. Was viel interessanter wäre fehlt leider. Die Versorgung des TLE und die weitere Beschaltung am Ausgang des TLE.

Den TLE versorge ich über 5V vom Arduino. Gnd zu Gnd und Signal-Ausgang auf Pin2 (interrupt 0).

Da ich sorge hatte, dass es an der Versorgung liegt, habe ich den TLE auch schon am Labornetzteil gehabt. Ohne wirklich einen Unterschied festzustellen.

Über 5V und Signalausgang des TLE's habe ich einen Widerstand gezogen. 1kOhm. Jetzt einen 470Ohm Widerstand(läuft besser).

Hallo,

Okay. Dann ist die Beschaltung etwas unangemessen dafür.
Der Eingangswiderstand R1 soll die TVS Diode vor zu hohen Strom schützen, wenn Überspannungen "reinknallen" soll die diese ableiten/begrenzen. Hast du nicht. Im Grunde kann der Widerstand und die TVS raus. Der Ausgangswiderstand R2/R3 erschließt sich mir nachwievor nicht so richtig. Stellt ein RC Glied dar, nur wofür? Was hing da früher dran? Eigentlich müssten diese auch raus und der Pullup direkt an den Ausgang/Kondensator C2 bzw. C3. Da würde aktuell nur ein Oszi helfen um zu sehen wie die Impulse/Flanken aussehen.

Mir lässt aber keine Ruhe das du Probleme hast beim starten und stoppen. Die Arduino Versorgung ist getrennt vom Motor? Wieviele Magneten sind an dem Motor die der TLE sieht? Nicht das durch eine Art kurze Pendelbewegung hast die dann zu Fehlerkennungen führen. Gegen generelle Problem spricht ja das du keine Problem hast wenn er schneller dreht wie losdrehen.

Du schreibst auch die Platine sitzt auf dem Motor? Ich meine wenn der losdrehen will gibts Stromspitzen. Ob es dabei kurzzeitige Magnetfeldstreuungen gibt kann ich nicht beurteilen. Aber bau die Platine mal räumlich entfernt vom Motor auf. Wo sitzen die Magenten eigentlich? Oder sollen die TLE die Motormagneten zählen? Mach am Besten paar Fotos wo man das alles erkennen kann.