How to get the direction of a wheel with two hall-sensors?

Hello,

I have a wheel with 13 magnets attatched to it and I have two hall-sensors side by side that are reacting to the magnets.
Now I want to count up or down depending on the direction of the rotation.

For Example:
Counter is at 0
The wheel is rotated by 360 degrees
Counter is at 13

OR

Counter is at 0
The wheel is rotated by -360 degrees
Counter is at -13

I thought that something like checking which sensor detects first a magnet and depending on that you know the direction might work but I cannot get it to work :frowning:
Is there any example code or something that I can use or does someone have an idea on how to programm this?

PS: I need the 13 magnets to get a faster reaction time when the direction changed and by using 13 I can save me some math but I think this part is not relevant here.

Are the 2 hall sensors arranged like in a quadrature encoder (90 degrees out of phase)?

You want the sensor outputs to cycle like this:

00
10
11
01
00
10
11
01
00
10
11
01

ie the extent of their range overlaps. This sequence is different when reversed, which is how you detect direction. The counts will be 52 per rotation as their are 4 transistions per magnet.

The sensor spacing should be 1/4 or 5/4 or 9/4 (etc) of the magnet spacing to get good overlap, assuming a 50% mark-space ratio.

Ah okay. Sounds like a good solution! My output does look like this (prints both sensor states if one sensor state has changed)

11 01 11 10 11 01 11 10

1 = no magnet, 0 = magnet.

Since there is "00" missing I guess that I have to decrease the distance between the sensors a little bit. Is this correct?

You need to monitor for a change on one channel. Then when there's a change, if the other channel is the same as the (newly changed) first channel, that's one direction. If the other channel is different, that's the other way.

Scan down column 1 in MarkT's list, then up, looking for a change in column 1: you'll see column 2 is different going down, same going up, where column 1 has changed.

Do we have to guess that all 13 magnets are spaced EQUALLY around the wheel?

Paul

Paul_KD7HB: Do we have to guess that all 13 magnets are spaced EQUALLY around the wheel?

Paul

Sorry forgot to say that :D All magnets are spaced equally around the wheel :D

Ok, looks like the magnets are to small (2mm diameter) so I dont have a state where both sensors are detecting a magnet. Is there still a way to do it?

4400: Ok, looks like the magnets are to small (2mm diameter) so I dont have a state where both sensors are detecting a magnet. Is there still a way to do it?

Then you need to think about using an interrupt for each sensor to alert your program that at least one sensor has detected a magnet. If nothing detected, loop and do nothing.

Paul

4400: Ok, looks like the magnets are to small (2mm diameter) so I dont have a state where both sensors are detecting a magnet. Is there still a way to do it?

Yes. Put the sensors far enough apart that they detect different magnets at the same time. They could even be 179 degrees apart (with an even number of magnets.)

Paul_KD7HB:
Then you need to think about using an interrupt for each sensor to alert your program that at least one sensor has detected a magnet. If nothing detected, loop and do nothing.

Paul

But how do I get the direction of the rotation?

MorganS: Yes. Put the sensors far enough apart that they detect different magnets at the same time. They could even be 179 degrees apart (with an even number of magnets.)

I can only mount the hall-sensors on one position :(

So I think that buying bigger magnets and using the "90 degrees out of phase" method would be the best solution or? Or someone knows an other way to do it while the two sensors are still side by side at one position.

I'm still mulling this idea over in my brain, but I think it will work.

First, make sure that the angular distance between the two sensors is less than half of the angular distance between two consecutive magnets. Now, look at the sequence of sensor detections -- let's call them 1 & 2. It will always be:

……1 2 1 2 1 2 1 2 1 2 ……..

BUT, their timing will be different dependent upon the direction of rotation. In one direction of rotation, the time between the 1 2 detection will be shorter than the time between the 2 1 detection. The opposite is true when rotating in the other direction.

gfvalvo: BUT, their timing will be different dependent upon the direction of rotation. In one direction of rotation, the time between the 1 2 detection will be shorter than the time between the 2 1 detection. The opposite is true when rotating in the other direction.

Double but....

If it is slowing down to a stop and then reversing, you can't tell if the long gap is going left or slowly going right. If it stopped with the magnet over one sensor you won't get a "two in a row" on one sensor to identify the reverse point.

It is not required to put the sensors a long way apart. Just 3/4 of the interval between magnets will be enough.

My new magnets arrived today (3*2mm N52 (3mm diameter)) and it is working fine now! I'm using the "90 degrees out of phase" method.

Here is my script but it could be hard to read for others and there is probably a better and shorter way to program it but I'm just a beginner. If you have any questions just ask me :D

Thanks for your help!

const int hall_readpin_1 = 2;
const int hall_readpin_2 = 3;


int hall_incoming_1 = 1;
int hall_incoming_2 = 1;
int hall_last_1 = 2;
int hall_count = 0;
bool hall_stop = false;
String hall_direction = "left";
int hall_time_last = 0;
int hall_min_time = 4; 

void hall()
{
  hall_incoming_1 = digitalRead(hall_readpin_1);
  hall_incoming_2 = digitalRead(hall_readpin_2);
  if (hall_incoming_1 != hall_last_1)
  {
    hall_last_1 = hall_incoming_1;
    check_direction();
  }

  
  if (hall_incoming_1 == 0 and hall_stop == false)
  {
    hall_stop = true;
    if (hall_direction == "left")
    {
      hall_count++;
    }
    else if (hall_direction == "right")
    {
      hall_count--;
    }
    Serial.println(hall_count);
  }
  if (hall_incoming_1 == 1 and hall_stop == true)
  {
    hall_stop = false;
  }
}

void check_direction()
{
  if (millis()-hall_time_last > hall_min_time)
  {
    if (hall_incoming_1 == hall_incoming_2)
    {
      Serial.println("left");
      hall_direction = "left";
    }
    else if (hall_incoming_1 != hall_incoming_2)
    {
      Serial.println("right");
      hall_direction = "right";
    }
  }
  else
  {
    Serial.println("TO FAST!!!");
  }
  hall_time_last = millis();
}

void setup ()
{
  hall_incoming_1 = digitalRead(hall_readpin_1);
  hall_last_1 = hall_incoming_1;
  pinMode (hall_readpin_1, INPUT_PULLUP) ;
  pinMode (hall_readpin_2, INPUT_PULLUP) ;
  Serial.begin(9600);
}



void loop()
{
  hall();
}