2 Hall-Sensoren sollen Drehung und Position erkennen

Der Pin kann doch floaten, deshalb besser sofort float smoothPin = A2 schreiben.
duck und..... :innocent:

Okay, ich habe nun aus throttle und maxenccount ein int gemacht. Damit wird Joystick.setRyAxis(throttle/maxenccount*1023); immer NULL.

Sieht dann so aus:

#include <Encoder.h>
#include <Joystick.h>
bool report = true;
//bool report = false;
int maxenccount = 150; // max 154
/*      Joystick      */
uint8_t hidReportId = 0x03; // - Default: 0x03 - Indicates the joystick's HID report ID. This value must be unique if you are creating multiple instances of Joystick. Do not use 0x01 or 0x02 as they are used by the built-in Arduino Keyboard and Mouse libraries.
uint8_t joystickType = JOYSTICK_TYPE_JOYSTICK; // - Default: JOYSTICK_TYPE_JOYSTICK or 0x04 - Indicates the HID input device type. Supported values:
uint8_t buttonCount = 10; //- Default: 32 - Indicates how many buttons will be available on the joystick.
uint8_t hatSwitchCount = 0; // - Default: 2 - Indicates how many hat switches will be available on the joystick. Range: 0 - 2
bool includeXAxis = 0; // - Default: true - Indicates if the X Axis is available on the joystick.
bool includeYAxis = 0; // - Default: true - Indicates if the Y Axis is available on the joystick.
bool includeZAxis = 0; // - Default: true - Indicates if the Z Axis (in some situations this is the right X Axis) is available on the joystick.
bool includeRxAxis = 1; // - Default: true - Indicates if the X Axis Rotation (in some situations this is the right Y Axis) is available on the joystick.
bool includeRyAxis = 1; // - Default: true - Indicates if the Y Axis Rotation is available on the joystick.
bool includeRzAxis = 0; // - Default: true - Indicates if the Z Axis Rotation is available on the joystick.
bool includeRudder = 0; // - Default: true - Indicates if the Rudder is available on the joystick.
bool includeThrottle = 0; // - Default: true - Indicates if the Throttle is available on the joystick.
bool includeAccelerator = 0; // - Default: true - Indicates if the Accelerator is available on the joystick.
bool includeBrake = 0; // - Default: true - Indicates if the Brake is available on the joystick.
bool includeSteering = 0; // - Default: true - Indicates if the Steering is available on the joystick.

/*      Gyro      */
float smooth = 50;
float sPitch=0, j=10;
float smoothPin = A2;

void Filtern(float &FiltVal, int NewVal, int FF){ // https://forum.arduino.cc/t/verstandnisfrage-code-messwerte-glatten/265055/3
  FiltVal= ((FiltVal * FF) + NewVal) / (FF +1.0);
}
#include <Wire.h>
#include <Adafruit_MCP23X17.h>
#include<ADXL345_WE.h> // https://wolles-elektronikkiste.de/adxl345-teil-1
#define ADXL345_I2CADDR 0x53
ADXL345_WE myAcc = ADXL345_WE(ADXL345_I2CADDR);
Adafruit_MCP23X17 mcp1;
Joystick_ Joystick(hidReportId, joystickType, buttonCount, hatSwitchCount, includeXAxis, includeYAxis, includeZAxis, includeRxAxis, includeRyAxis, includeRzAxis, includeRudder, includeThrottle, includeAccelerator, includeBrake, includeSteering);

bool reportpitch = false;

int throttle = 0;
int HSTPinA = 5;
int HSTPinB = 6;
Encoder myEnc(HSTPinA, HSTPinB); // RotaryEncoder 154 Steps

void setup() {
  pinMode(HSTPinA,INPUT_PULLUP);
  pinMode(HSTPinB,INPUT_PULLUP);
  pinMode(smoothPin,INPUT);
  Wire.begin();
  while(!myAcc.init()){
    Serial.println("ADXL345 not connected!");
    delay(1000);
  }
  if (report) Serial.println("ADXL345 connected...");

  myAcc.setCorrFactors(-266.0, 285.0, -268.0, 278.0, -291.0, 214.0);
  myAcc.setDataRate(ADXL345_DATA_RATE_50); // 50 Hz
  myAcc.setRange(ADXL345_RANGE_2G); // 2g

  if (!mcp1.begin_I2C()) {
    Serial.println("MCP23017 not connected!");
    while (1);
  } else
    if (report) Serial.println("MCP23017 connected");

  mcp1.begin_I2C(0x20); // Init MCP23017 at address 0x20
  Joystick.begin();
  Joystick.setRxAxisRange(0, 1023);
  Joystick.setRyAxisRange(0, 1023);
  Joystick.sendState();
  for (int i=0; i<10; i++) { // 10 Button & Switches
    mcp1.pinMode(i, INPUT_PULLUP);
  }
  if (report) Serial.println("los gehts...");
}

int lastButtonState[10] = {0,0,0,0,0,0,0,0,0,0};

void checkPitch() {
  xyzFloat corrAngles = myAcc.getCorrAngles();
  float pitch = ( (myAcc.getRoll()-90) /40 *1023);
  if(pitch<0) pitch=0;
  if(pitch>1023) pitch=1023;
//  smooth = analogRead(smoothPin)/10;
  Filtern(sPitch,pitch,smooth);
  Joystick.setRxAxis(sPitch);
  if (reportpitch) {
    Serial.print("Pitch:");
    Serial.print(pitch);
    Serial.print(", ");
    Serial.print("sPitch:");
    Serial.print(sPitch);
    Serial.print(", ");
    reportpitch = false;
  }
}

void loop() {
  for (int i=0;i<10;i++) {
    bool currentButtonState = !mcp1.digitalRead(i);
    if (currentButtonState != lastButtonState[i]) {
      Joystick.setButton(i, currentButtonState);
      lastButtonState[i] = currentButtonState;
    }
  throttle = myEnc.read();
  if ( throttle < 0 ) {
    myEnc.write(0);
    throttle = 0;
  } else if ( throttle > maxenccount ) {
    myEnc.write(maxenccount);
    throttle = maxenccount;
  }
  Joystick.setRyAxis(throttle/maxenccount*1023);

    if (report) {
      if ( i == 9 )
        reportpitch = true;
      Serial.print("Btn");
      Serial.print(i);
      Serial.print(":");
      Serial.print(currentButtonState);
      Serial.print(", ");
    }
    checkPitch();
  }
  if (report) {
    Serial.print("Thr:");
    Serial.print(throttle/maxenccount*1023);
    Serial.println();
  }
}

Ein Pin ist eine feste Ganzzahl oder hast Du halbe Pins?
Du hast da Einiges noch nicht wirklich verstanden, willst aber unbedingt Recht behalten.

Gruß Tommy

Ich will kein Recht behalten, ändere ja auch einiges was angemerkt wurde.
Ich habe nur nicht verstanden was ich an A2 verbessern kann :woman_shrugging:
Ich nehme es mal ganz raus und teste...

Du hast den Unterschied zwischen dem Pin A2 (also der Anschlussnummer), dem Inhalt, der von dort gelesen wird (auch das ist eine ganze Zahl zwischen 0 und 1023) und dem, was Du evtl. daraus berechnest, nicht verstanden.

Gruß Tommy

Ja :smile: jetzt seh' ich's auch :poop:

#define smoothPin A2

Besser?

Die Schrittverluste bekomme ich aber nicht weg.
Ich habe noch int in bool geändert in der Hoffnung das dies Ressourcenschonender und schneller zu berechnen ist. Erfolglos:

bool lastButtonState[10] = {0,0,0,0,0,0,0,0,0,0};

Wenn maxenccount > als throttle ist, ist das zwingend so, wenn die Formel in der Folge so abgearbeitet wird...
Du könntest aber throttel zuerst mit 1023 multiplizieren und dann durch maxenccount dividieren.

uint16_t  throttle = 111;
uint16_t  maxenccount = 154;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  Serial.println(((throttle * 102300) / maxenccount)/100);
}

void loop() {
  // put your main code here, to run repeatedly:
}

Keine Division durch 0 mehr, wenn throttel != 0.
Die Vergrößerung um die zwei Stellen braucht es...

Mit uint16_t throttle = 0; gibt es einen Sprung unter NULL auf 1023. Mit int throttle = 0; nicht.
Ideen?

[...]
uint16_t throttle = 0;
int HSTPinA = 5;
int HSTPinB = 6;
Encoder myEnc(HSTPinA, HSTPinB); // RotaryEncoder 154 Steps

void setup() {
  pinMode(HSTPinA,INPUT_PULLUP);
  pinMode(HSTPinB,INPUT_PULLUP);
  pinMode(smoothPin,INPUT);
  Wire.begin();
  while(!myAcc.init()){
    Serial.println("ADXL345 not connected!");
    delay(1000);
  }
  if (report) Serial.println("ADXL345 connected...");

  myAcc.setCorrFactors(-266.0, 285.0, -268.0, 278.0, -291.0, 214.0);
  myAcc.setDataRate(ADXL345_DATA_RATE_50); // 50 Hz
  myAcc.setRange(ADXL345_RANGE_2G); // 2g

  if (!mcp1.begin_I2C()) {
    Serial.println("MCP23017 not connected!");
    while (1);
  } else
    if (report) Serial.println("MCP23017 connected");

  mcp1.begin_I2C(0x20); // Init MCP23017 at address 0x20
  Joystick.begin();
  Joystick.setRxAxisRange(0, 1023);
  Joystick.setRyAxisRange(0, 1023);
  Joystick.sendState();
  for (int i=0; i<10; i++) { // 10 Button & Switches
    mcp1.pinMode(i, INPUT_PULLUP);
  }
  if (report) Serial.println("los gehts...");
}

bool lastButtonState[10] = {0,0,0,0,0,0,0,0,0,0};

void checkPitch() {
  xyzFloat corrAngles = myAcc.getCorrAngles();
  float pitch = ( (myAcc.getRoll()-90) /40 *1023);
  if(pitch<0) pitch=0;
  if(pitch>1023) pitch=1023;
  Filtern(sPitch,pitch,smooth);
  Joystick.setRxAxis(sPitch);
  if (reportpitch) {
    Serial.print("Pitch:");
    Serial.print(pitch);
    Serial.print(", ");
    Serial.print("sPitch:");
    Serial.print(sPitch);
    Serial.print(", ");
    reportpitch = false;
  }
}

void loop() {
  for (int i=0;i<10;i++) {
    bool currentButtonState = !mcp1.digitalRead(i);
    if (currentButtonState != lastButtonState[i]) {
      Joystick.setButton(i, currentButtonState);
      lastButtonState[i] = currentButtonState;
    }
  throttle = myEnc.read();
  if ( throttle < 0 ) {
    myEnc.write(0);
    throttle = 0;
  } else if ( throttle > maxenccount ) {
    myEnc.write(maxenccount);
    throttle = maxenccount;
  }
  Joystick.setRyAxis(((throttle*102300)/maxenccount)/100);

    if (report) {
      if ( i == 9 )
        reportpitch = true;
      Serial.print("Btn");
      Serial.print(i);
      Serial.print(":");
      Serial.print(currentButtonState);
      Serial.print(", ");
    }
    checkPitch();
  }
  if (report) {
    Serial.print("Thr:");
    Serial.print(((throttle*102300)/maxenccount)/100);
    Serial.println();
  }
}

Ja.
Stichwort Wertebereich.

uint16_t kann nicht unter NULL gehen. Meinst Du das? Wie löse ich das?

int16_t ? / bzw. int ist auf dem UNO auch 16bit breit.
Kommst Du denn höher als 32000 oder niedriger als -32000

Hallo,

ich denke dein Encoder funktioniert sowieso nicht wie gewollt. Die Sensoren sind unipolar, heißt sie arbeiten rein im positiven Magnetfeld. A3144 Datasheet
Wenn du im Magnetring abwechselnde Magnetfeldpolungen verbaut hast ist jeder zweite Magnet Wirkungslos. Deswegen wird überhaupt irgendwas gezählt. Denn wenn alle Magneten mit gleicher Polung zu den Sensoren zeigen würden, dann sehen die Magneten ständig ein Magnetfeld im gleichen Bereich und würden nicht mehr umschalten. Das zeigen mir die Bilder, die Abstände der Magneten und Sensoren.
Die aktuell umgedrehte Polung und der Abstand sorgt aktuell dafür das der Sensor auch einmal wieder kein für ihn passendes Magnetfeld sieht und damit umschalten kann. Er kommt aus seiner Hysterese raus. Damit hast du aktuell nur die halbe Auflösung.

Du kannst den eigentlich schönen Magnetring retten indem du zwei bipolare latch Hallsensoren verbaust. Die schalten erst um wenn sich die Polarität des Magnetfeldes ändert. Während den Übergängen wird das Signal beibehalten. Damit sind die Abstände praktisch egal. Die Positionierung ist optimal wenn ein Sensor genau unter einem Magnet steht und der andere Sensor genau zwischen 2 Magneten. Dann ist der Signalversatz rein mechanisch schon perfekt vorgegeben. Die Abstände der Magneten (bzw. der Abstand der Sensoren) müssen dafür Sorgen das die Signale der Sensoren versetzte Taktsignale erzeugen. Es darf sich immer nur ein Signal beider abwechselnd ändern. Aus der zeitlichen Abfolge ergibt sich die Richtung. Eine leichte Überlappung der Signale lässt sich nie vermeiden. Das ist auch egal, Hauptsache der Großteil der Signaländerung ist zeitlich unterschiedlich damit man das sicher detektieren kann. Mit Oszi oder Logikanalyzer kann man sich das anschauen.

Der Sensoren sollten auch richtig beschalten sein mit Stützkondensator und ggf. Pullup laut Datenblatt.

Das andere Problem bei dir ist mit größerer Drehzahl das Serial das einlesen und Encodierung der beiden Signale ausbremst. Entweder auf Serialausgabe weitgehend verzichten oder mittels Timer Interrupt zyklisch aller 1ms die Signale einlesen und verarbeiten. Die Signale mit Pin Interrupt einzulesen darauf würde ich verzichten. Da man immer beide Signale möglichst zeitgleich bzw. direkt nacheinander einlesen muss. Wenn loop() nicht ausgebremst wird geht alles ohne Timer Interrupt rein mit Polling.

Lass erstmal Joystick usw. weg und konzentriere dich rein auf den Encoder.

Nochwas. Die Magneten sind nur 1x1mm groß. Deswegen haben die sicherlich ein schwaches Magnetfeld. Die müssen dann schon sauber über dem Sensor stehen und möglichst mit sehr geringen Abstand vorbei schweben damit der das erkennt. Je höher die Drehzahl wird um so kürzer werden die Signaländerungen zeitlich welche man schnell genug einlesen muss. Da würde ich dann erstmal mit Oszi messen über welche Zeiten/Signallängen wir da reden.

Das ich die halbe Auflösung habe weiß ich und das reicht mir auch. Ich wollte ja auf analoge Hall-Sensoren setzen, da habe ich aber keinen Code gefunden. Und bei Bipolaren Sensoren hätte ich vermutlich das gleiche Problem.

Die Magnete sind, wie Du schon richtig erkannst hast, deshalb abwechselnd montiert um den Sensor abfallen zu lassen. Sonst hätte ich ein großes Magnetfeld ohne jegliche Messbarkeit.

Und ja, die Sensoren sind optimal zu den Magneten ausgerichtet: Wenn einer über einem Magenten schwebt, schwebt der andere exakt über die Mitte der Lücke zwischen zwei Magneten.

Pullup ist aktiviert im Code. Von Stützkondensator konnte ich aber nichts finden.

Die Serialausgabe ist nur für Testzwecke. Auch wenn ich die deaktiviere tritt das Problem auf.

Ich befürchte leider, dass die 1x1mm Magnete zu schwach sind. Wurde ja aber weiter oben dementiert. Der Abstand Magnet zu Sensor ist zwischen 0,1mm und null.

Ich werde jetzt mal wie empfohlen den Joystick rausnehmen.

Hallo,

analoge Hallsensoren machen hier keinen Sinn. Du möchtest ja keine Position räumlich gesehen bzw. keinen Abstand zum Sensor wissen. Du brauchst nur definierte Werte ob Magnet da oder nicht da. Warum brauchst du mit bipolaren statt unipolaren Hallsensoren anderen Code?

Es genügt wenn ein richtig gepolter Magnet einen Sensor abdeckt und etwas weiter gedreht zwei richtig gepolte Magnete beide Sensoren abdecken und nochmal etwas gedreht ein richtig gepolter Magnet nur den letzten Sensor abdeckt und nochmal etwas gedreht kein Magnet irgendwas abdeckt und der Spass von vorn. Hast du die Signale der Sensoren schon auf einem Oszi angeschaut? Wenn nicht ist das an der Stelle jetzt einfach notwendig. Es könnte sein auf Grund der Minimagneten das ihr Magnetfeld für die Sensoren nicht ausreichend ist. Bzw. nicht stabil ausreichend. Es gibt viele Sensoren die unterschiedliche Schwellwerte haben. Dein A3144 ist nun leider einer der von Haus aus einen großen Range im Datenblatt aufweist. 70 bis 350 Gauss sind 7mT bis 35mT. Der max. 25°C Schwellwert unter 15mT Pi mal Daumen wäre schon nicht verkehrt besser noch kleiner. Der A3141 wäre erstmal besser gewesen. Dann ist der Sensor empfindlicher was förderlich für die Minimagneten wäre.

Weil das Magnetfeld im Abstand nicht linear abfällt/zunimmt muss man da sowieso etwas probieren. Ich hatte mir für mein Vorhaben verschiedene Neo Magnetgrößen bestellt und einfach ausprobiert welche Abstände erforderlich sind.

Bspw. habe ich 3x3x0,5mm Magneten und da muss ich an einen Sensor mit max. 16mT Schwellwert den schon praktisch auflegen damit der Sensor reagiert.

Zur Not einen neuen Ring bauen für größere Magneten und die Sensoren auf 2 Radien versetzt angeordnet.

Wegen Stützkondensator. Okay im Datenblatt gibts dafür nirgends eine Erwähnung, scheinbar benötigt der wirklich keinen. Im Zweifelsfall und bei unklaren Problemen würde ich einen verbauen. Momentan bist du voll in der Fehlersuche.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.