Magnetfeld überprüfen mit Hallsensor

Hallo, ich habe folgenden Code zur Messung eines Magnetfeldes an einem Rotor.
Er wir auf einen Drehteller gelegt und mittels Steppe-Motor angetrieben.
Mit der Referenzmessung soll ein Muster-Rotor eingemessen werden und die Messwerte sollen mit einer Toleranz abgespeichert werden um sie mit Prüflingen zu vergleichen.
Da der Rotor in beliebiger Position auf den Drehteller gelegt werden kann, dreht der Motor bewusst mehr als 360 Grad (18000 Steps) um sicherzustellen alle Nulldurchgänge sicher zu erfassen.

Die Referenzmessung lässt sich machen, die Toleranzzone wird gespeichert und ist im Plotter gut sichtbar.
Wenn der Rotor nun beabsichtigt etwas verdreht wird und die Messung startet, sieht man deutlich dass er aus der Toleranz fällt, weil die aufgenommenen Messkurve nicht auf den Nullpunkt gelegt wird um das Ergebnis zu vergleichen sondern zeitlich um das Stück, welches händisch verdreht wurde.
Vielleicht weiß jemand woran es liegen könnte ..

#include <AccelStepper.h>

// Pin-Konfiguration
#define STEP_PIN 16
#define DIR_PIN 17
#define ENABLE_PIN 15
#define GND_1 29
#define GND_2 31
#define REF_BUTTON_PIN 30
#define START_BUTTON_PIN 32
#define MEASURE_PIN_1 23
#define MEASURE_PIN_2 22
#define MEASURE_PIN_3 21

const int number_of_pins = 3;
const uint16_t measurement_blocks = 450;
const uint16_t steps_per_revolution = 18000;

uint16_t measurement_data[number_of_pins][measurement_blocks];
uint16_t reference_data[number_of_pins][measurement_blocks];
uint16_t upper_tolerance[number_of_pins][measurement_blocks];
uint16_t lower_tolerance[number_of_pins][measurement_blocks];
bool sensor_enabled[number_of_pins] = { true, true, true };
uint16_t virtual_zero[number_of_pins];  // dynamisch berechnet

bool is_referenced = false;
bool found_a_false = false;

AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);

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

  pinMode(GND_1, OUTPUT);
  pinMode(GND_2, OUTPUT);
  pinMode(REF_BUTTON_PIN, INPUT_PULLUP);
  pinMode(START_BUTTON_PIN, INPUT_PULLUP);
  pinMode(MEASURE_PIN_1, INPUT);
  pinMode(MEASURE_PIN_2, INPUT);
  pinMode(MEASURE_PIN_3, INPUT);
  pinMode(ENABLE_PIN, OUTPUT);

  digitalWrite(ENABLE_PIN, LOW);
  digitalWrite(GND_1, LOW);
  digitalWrite(GND_2, LOW);

  stepper.setMaxSpeed(10000);
  stepper.setAcceleration(6000);

  Serial.println(" System gestartet. Bitte zuerst referenzieren!");
}

void loop() {
  if (digitalRead(REF_BUTTON_PIN) == LOW) {
    delay(50); while (digitalRead(REF_BUTTON_PIN) == LOW); delay(50);
    setup_tolerances();
  }

  if (digitalRead(START_BUTTON_PIN) == LOW) {
    delay(50); while (digitalRead(START_BUTTON_PIN) == LOW); delay(50);

    if (!is_referenced) {
      Serial.println(" Fehler: Bitte zuerst referenzieren!");
      return;
    }

    Serial.println(" Starte Rotorprüfung...");
    measure_rotor();
  }
}

void take_measurement() {
  stepper.move(steps_per_revolution);
  uint16_t steps_per_block = steps_per_revolution / measurement_blocks;
  uint16_t next_measure_position = stepper.currentPosition() + steps_per_block;

  for (int block_index = 0; block_index < measurement_blocks; block_index++) {
    while (stepper.currentPosition() < next_measure_position) {
      stepper.run();
    }

    for (int pin_index = 0; pin_index < number_of_pins; pin_index++) {
      measurement_data[pin_index][block_index] = analogRead(MEASURE_PIN_1 + pin_index);
    }

    next_measure_position += steps_per_block;
  }

  while (stepper.isRunning()) {
    stepper.run();
  }
}

void setup_tolerances() {
  Serial.println(" Referenzierung läuft...");
  take_measurement();

  // virtuelle Null pro Sensor bestimmen
  for (int pin_index = 0; pin_index < number_of_pins; pin_index++) {
    long sum = 0;
    for (int i = 0; i < measurement_blocks; i++) {
      sum = sum+measurement_data[pin_index][i];
    }
    virtual_zero[pin_index] = sum / measurement_blocks;

    sensor_enabled[pin_index] = false;

    for (int i = 1; i < measurement_blocks; i++) {
      if (measurement_data[pin_index][i - 1] < virtual_zero[pin_index] &&
          measurement_data[pin_index][i] >= virtual_zero[pin_index]) {
        sensor_enabled[pin_index] = true;
        break;
      }
    }

    if (!sensor_enabled[pin_index]) {
      Serial.print(" Warnung: Kein Magnetfeld erkannt bei Sensor ");
      Serial.println(pin_index + 1);
    }
  }

  // Toleranzen und Referenzdaten speichern
  for (int block_index = 0; block_index < measurement_blocks; block_index++) {
    for (int pin_index = 0; pin_index < number_of_pins; pin_index++) {
      uint16_t value = measurement_data[pin_index][block_index];
      reference_data[pin_index][block_index] = value;
      upper_tolerance[pin_index][block_index] = value * 1.10;
      lower_tolerance[pin_index][block_index] = value * 0.90;
    }
  }

  is_referenced = true;
  Serial.println(" Referenzierung abgeschlossen. Anlage bereit.");
  plot_reference_data();
}

void plot_reference_data() {
  Serial.println(" Sende Daten für Plotter...");
  Serial.println("P1_REF,P1_UP,P1_LOW,P2_REF,P2_UP,P2_LOW,P3_REF,P3_UP,P3_LOW");

  for (int i = 0; i < measurement_blocks; i++) {
    for (int pin_index = 0; pin_index < number_of_pins; pin_index++) {
      Serial.print(reference_data[pin_index][i]);
      Serial.print(",");
      Serial.print(upper_tolerance[pin_index][i]);
      Serial.print(",");
      Serial.print(lower_tolerance[pin_index][i]);
      if (pin_index < number_of_pins - 1) Serial.print(",");
    }
    Serial.println();
  }

  Serial.println(" Ende der Plotdaten.");
}

void measure_rotor() {
  found_a_false = false;
  take_measurement();

  // Null-Durchgangs-Offset ermitteln
  uint16_t zero_crossing_offset = 0;
  for (int idx = 1; idx < measurement_blocks; idx++) {
    if (measurement_data[0][idx - 1] < virtual_zero[0] &&
        measurement_data[0][idx] >= virtual_zero[0]) {
      zero_crossing_offset = idx;
      break;
    }
  }

  // Um den Null-Durchgang als Bezugspunkt zu verschieben, werden alle Messdaten um den Offset verschoben.
  Serial.print(" Start-Offset: ");
  Serial.println(zero_crossing_offset);

  Serial.println(" Messdaten für Plotter...");

  for (int block_index = 0; block_index < measurement_blocks; block_index++) {
    for (int pin_index = 0; pin_index < number_of_pins; pin_index++) {
      if (!sensor_enabled[pin_index]) continue;

      // Verschiebe den Block-Index um den Null-Durchgangs-Offset
      int shifted_index = (block_index + zero_crossing_offset) % measurement_blocks;
      
      uint16_t current_value = measurement_data[pin_index][shifted_index];
      uint16_t ref_value = reference_data[pin_index][shifted_index];
      uint16_t upper_tol = upper_tolerance[pin_index][shifted_index];
      uint16_t lower_tol = lower_tolerance[pin_index][shifted_index];

      // Überprüfe, ob der Wert außerhalb der Toleranz ist
      if (current_value < lower_tol || current_value > upper_tol) {
        Serial.print("[FEHLER] ");
        found_a_false = true;
      }

      // Ausgabe der Messwerte
      Serial.print("Sensor ");
      Serial.print(pin_index + 1);
      Serial.print(" Block ");
      Serial.print(block_index);
      Serial.print(": ");
      Serial.print(current_value);
      Serial.print(" (Ref: ");
      Serial.print(ref_value);
      Serial.print(", Up: ");
      Serial.print(upper_tol);
      Serial.print(", Low: ");
      Serial.print(lower_tol);
      Serial.println();
    }
  }

  Serial.println(" Sende Messdaten für den Plotter...");
  Serial.println("P1_MEASURE,P1_UP,P1_LOW,P2_MEASURE,P2_UP,P2_LOW,P3_MEASURE,P3_UP,P3_LOW");

  for (int i = 0; i < measurement_blocks; i++) {
    for (int pin_index = 0; pin_index < number_of_pins; pin_index++) {
      int shifted_index = (i + zero_crossing_offset) % measurement_blocks;
      Serial.print(measurement_data[pin_index][shifted_index]);
      Serial.print(",");
      Serial.print(upper_tolerance[pin_index][shifted_index]);
      Serial.print(",");
      Serial.print(lower_tolerance[pin_index][shifted_index]);
      if (pin_index < number_of_pins - 1) Serial.print(",");
    }
    Serial.println();
  }

  if (found_a_false) {
    Serial.println(" Ergebnis: Fehlerhafter Rotor");
  } else {
    Serial.println("Ergebnis: Fehlerfreier Rotor");
  }
}

Die einfachste Lösung dürfte sein, wenn Du auf dem Drehteller markierst, wie das Teil abzulegen ist.

Gruß Tommy

Wenn Du den Rotor verdrehst dann ist die vorhergehende Referenzfahrt nicht mehr gültig. Du kannst aber während der Meßfahrt den Homepunkt kontrollieren und dann entweder die Meßfahrt am Homepunkt neu starten oder die Meßpunkte um den Offset zwischen vorhergehenden und aktuellen Homepunkt verschieben.

Grüße Uwe

Hallo,
eigentlich habe ich Deine Messanordnung nicht verstanden in meinem Kopf ist allerdings ein Bild entstanden wie das aussehen könnte. Das Bild kann völlig falsch sein. Ein Foto oder eine Skizze von Dir würde da Sinn machen.

D.h eigentlich funktioniert Deine "Nulllage Messung nicht" ??

"Etwas verdreht" meint das die Lage des Rotors auf dem Drehtisch oder "der Rotor ist axial verdreht in einer anderen Position", oder der Drehtisch ist verdreht.

Im ersten Fall musst Du doch nur dafür sorgen das der Rotor immer im selben Winkel zum Referenzpunkt des Drehtisches liegt. Dazu kannst Du den Rotor in axialer Richtung mechanisch reproduzierbar hinlegen. z.B die Wellenenden des Rotors in zwei konischen Auflager (Böckchen) legen. Dann liegt der Rotor immer zentriert in der gleichen Position.

Im zweiten Fall könnte ich mir eine mech. Vorrichtung vorstellen die dafür sorgt das man den Rotor so dreht das ein Blechpaket oder der Schlitz zwischen zwei Packeten immer exakt an der selben Stelle liegt. z.B eine kleine Spitze senkrecht unter dem Rotor.

Letztlich musst Du dafür sorgen das jeder Prüfling gleich und genau so wie der Referenz- Rotor da liegt. und zwar bezogen auf den Hallsensor. D.h. Bei jedem Messvorgang muss auch der Drehtisch eventuell neu den Referenzpunkt anfahren.

Danke für die Hinweise, habe nun eine etwas andere Lösung gefunden, unabhängig von der Lage des Rotors. Grüße

Habe ich mir schon gedacht, als ich mir nochmal deine anderen Threads angesehen habe.
Erwartungshaltung erfüllt!
Danke.