Brushless 12v Motor Hall effect Pulse not counting correctly

Hi there, I am in need of some extra brain power to solve this issue I am facing with my project.

So the gist is, I'm using some 12v DC brushless motors that I purchased from AliExpress to convert my desk into a sit/stand desk as a project. These motors have been working fine so far, but I have been trying to use the motor's built-in hall effect sensor to count the pulses when the motor turns, and then use this determine the height that the desk is at.

The problem I am having is that the counts I am getting from the motors are very unreliable and prone to skip about quite a bit when changing direction, and I cannot work out why.

I have measured the square wave that the motor is outputting, and this seems to be fine.

Ill post the code below that I am running on an Arduino Mega to capture these pulses and keep track of them. I've

also posted a capture of the square wave on the oscilloscope.

Any suggestions would be great as I've been trying to solve this for a while now with no luck.

Thanks in advance,
Hayden.

const int DownButton = 10;
const int UpButton = 11;

const int MotorUp1 = 6;
const int MotorDown1 = 7;

const int DistanceButton = 9;
const unsigned int PulsePin1 = 2;

volatile unsigned long pulseCount;
volatile bool countChanged;

int DIRECTION = 1;

double MM_PER_PULSE = 0.016;

void isr ()  {
  countChanged = true;
  pulseCount = pulseCount + DIRECTION;
}

void setup()
{
  Serial.begin(9600);
  pinMode(DownButton, INPUT_PULLUP);
  pinMode(UpButton, INPUT_PULLUP);
  pinMode(MotorUp1, OUTPUT);
  pinMode(MotorDown1, OUTPUT);

  
    pinMode(PulsePin1, INPUT);
      pinMode(DistanceButton, INPUT_PULLUP);
       attachInterrupt(digitalPinToInterrupt(PulsePin1), isr, RISING);
  Serial.println("Start");

}

void loop() {

  static int lastUp = LOW;
  static int lastDown = LOW;
  static int lastDistance = HIGH;
  int Up = digitalRead(UpButton);
  int Down = digitalRead(DownButton);

  if (Up != lastUp || Down != lastDown)
  {
    lastUp = Up;
    lastDown = Down;
    if (Up == HIGH && Down == HIGH )    // neither button pressed
    {
      digitalWrite(MotorDown1, HIGH);
      digitalWrite(MotorUp1, LOW);

    }
    else if (Up == LOW && Down == HIGH) // UpButton pressed
    {
      DIRECTION = 1;
      digitalWrite(MotorDown1, HIGH);
      digitalWrite(MotorUp1, HIGH);

    }
    else if (Up == HIGH && Down == LOW) // DownButton pressed
    {
    DIRECTION = -1;
      digitalWrite(MotorDown1, LOW);
      digitalWrite(MotorUp1, HIGH);

    }
    else // Both buttons pressed
    {
      // undefined, no effect
    }
  }
   int Distance = digitalRead(DistanceButton);
  if (Distance != lastDistance) {
    lastDistance = Distance;
    if (Distance == LOW) {
      double distance = pulseCount * MM_PER_PULSE;
      Serial.println(distance); 
    }
  }
}

Schematics please, and links to the datasheets of the stuff You refer to.

One thing, when you read 'pulseCount' it is a critical section, you didn't provide protection for that (disabling interrupts, making a copy, enabling interrupts again).

Another weird thing about 'pulseCount', you declared it as unsigned, but you subtract 1 from it many times via DIRECTION. Is there not a possibility that it can become negative?

You declared a capture flag, 'countChanged' but you never use it or reset it anywhere in your main code.

Your button code has no switch debounce that I can see.

The scope shows a 2.6V p-p signal. Why? What voltage is the processor running on?

1 Like

These are all valid points, thanks for your response.
'pulseCount' should be signed you are right. 'countChanged' is a remnant from something else I was trying, and I just didn't get round to adding any debounce to that button yet as it was just a temporary feature to allow me to compare counts.

Do you think that 'pulseCount' having no protection could be leading to skipped counts?

Im not sure why the Signal p-p is 2.5 v tbh, the motors run on 12v but have an internal circuit that controls the motor and reads the sensor, all I can access is the signal wire.

The motor has some slightly tricky I/O. How have you connected all the pins? Where did you get the connection instructions?

with the connections shown, you will need voltage level translation to read the pulses reliably.

Connection instructions are from the suppliers website here, (slightly broken English).
The motors run 12v. I was expecting the built-in sensor to run between 0-5v, but when it's at idle it sits at 9v, and the square wave goes between 0-2.5v. The black & blue pin are connected to the drain of a MOSFET and the source to ground, same with the white pin. These control CW and CCW rotation. The red pin is connected to a 12v power supply, and the yellow pins are connected straight into the Arduino. All the grounds are tied.

Testing the motors in this format, they mostly work really well (small disparity between counts) while going in one direction, but when changing direction, they will often run out by a fair bit.

Just to be sure, do you have Type A or Type B motor? It will save us some head scratching and rule out doubts.

Looking at your diagram and treating the motor as a "black box", the question arises, where is the ground current path when neither PWM input is active? There doesn't appear to be any. In that case, 12V and an unknown current can be injected into what you call "pulse pin 1" on the diagram. That could damage the Arduino pin. Even if the pulse train stops when the motor stops, it is still a mystery where it gets its ground reference when it's on. This is a little strange...

Also it looks like you don't drive the motors with PWM, they are driven with constant power. That would stabilize the ground path (maybe) when the motor is on, but might preclude the use of speed control in future. Is that acceptable to you?

Type B.
That is a good point that you make about the grounds, maybe if I try to reconfigure the wiring so that I have a permanent ground it might improve the performance.

Blockquote
Also it looks like you don't drive the motors with PWM, they are driven with constant power. That would stabilize the ground path (maybe) when the motor is on, but might preclude the use of speed control in future. Is that acceptable to you?
Blockquote

Do you mean is not using PWM acceptable to me? I did intend to use PWM in the future, but I will just go with constant power if that solves this issue.

Both this solution and leaving the door open for later PWM depend on understanding the motor connections better. Unfortunately the badly written documentation reads more like a how-to guide than a reference, like "when you connect the black wire, it..." and the English is not good as you pointed out.

The motor instructions do not mention any "ground" per se. That makes what you say difficult to implement directly.

I have two of those motors but I haven't used them yet. Unfortunately this is not a good time for me to be fooling around with them.

I have played around with connecting the black to ground and just having the blue wire and white wires controlled by the MOSFETs, it doesn't seem to have many any difference performance wise, but I think it's a more logical solution considering the point you made earlier.

What I have done is changed the pulse input pins to input_pullup which seems to have made a massive difference to the accuracy! The fact that the square wave being produced was only 2.5v got me thinking that it might benefit from some help being pulled up to 5v.

This seems to be quite reliable now, do you still think its worth disabling and enabling interrupts to make a copy?

My creed, eliminate any problems you can foresee. It's 10x easier then troubleshooting them later when the cause is unknown or forgotten.

That particular issue would register a fault maybe 1 time out of 1000's of accesses. However it's easy to avoid, so why not just avoid it?

Have you scoped it again, now that the wiring is different? What does it look like? If the input pullup helped, it's possible that the pulse pin is some kind of "open collector" output. It sure would be nice to see actual documentation on the motor.

Scoped it and it looks like the idle voltage sits around 3.5v and the p-pV is at the same. I agree, it would be very interesting to see docs for these motors. Sure would remove some guess work.

Thanks for going back and forth with me on this, it really helped. cheers.

That's a more encouraging voltage, it makes it over the input high threshold of a 5V device with a small noise margin. To be really sure, you could use some translator like a transistor circuit. But it should work.

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