How to run a dc motor for an exact number of rotations?

Hey guys,

I have a DC 3v motor without any encoder, etc. I am measuring the current the motor uses.
I have found this chart:
https://islproducts.com/wp-content/uploads/dc-motor-performance-curve-basics.png

From what I understand the relationship between current to speed is linear. I have measured my motor current and without load, it uses 12/14 amp, on stall 55 amp. I have assumed that it makes 10000RPM (i don't really care about the real number).

Now I want to do let's say 500 rotations, but I need exact (or close to) 500 no matter what load I have. Could be no load at all for all 500, could be something like from 100 no load, from 100 to 300 "normal" load (around 30 amps), and the last 200 rotations on almost full possible load (40-50 amps).

Am I going in a reasonable direction? I am doing something like this:

float ampersFromZero = estimated_ampers - 12; // -12 because 12-13 is no load ampers
float ampersStallPercent = (ampersDiffFromZero / 43); // 43 because 55 ampers = stall, so my range is 12-55
long rotations = lastMeasurementTime * (1.0 - ampersStallPercent );

But I cannot get any stable results, the results differ by 2/3%, so not much but I wanted to be as precise as possible.

Basically, the question is "How to run a dc motor for an exact number of rotations while a different load is applied?".

Thank you for reading this, I am sorry if the topic is messy, being honest I didn't write any "question topic" in years but I am fighting with this for so long and the answer might be easy.

To a poor approximation, if the load is constant.

To do what you want requires some way of counting revolutions, or fractions of revolutions. A shaft encoder is the simplest approach.

2 Likes

Welcome to the forum

It does not look like it. I find it very difficult to believe that the relationship between current to speed is linear when there is a varying load. For instance, the current will be at a maximum when the motor is stalled but the RPM will be at zero

You really do need some feedback on how many rotations the motor has made. This could be as simple as a spot of paint on a shaft whose passing is detected by a phototransistor or something more complicated if you have access to the shaft and room to fit an encoder

2 Likes

Thank you for your input guys, I wanted to make it on a dc motor mostly since it's very cheap compared to dc with encoder.

I have read this here:

And basically it "almost" works, for my motor is doing full speed at 12 amps, and stalls at 55 but the lack of precision is problematic (2/3% differences). I have programmed a motor to go full in one direction and the next full reverse (till stalling) and the results are:

18:46:03.035 -> === RESULTS FROM 7 MEASUREMENTS ===
18:46:02.972 -> 33888.00;33797.00;34133.00;34089.00;34060.00;34156.00;33901.00;
18:46:03.069 -> AVERAGE:
18:46:03.069 -> 34003.43
18:46:03.100 -> LOWEST:
18:46:03.100 -> 33797.00
18:46:03.100 -> HIGHEST:
18:46:03.132 -> 34156.00
18:46:03.132 -> DIFF:
18:46:03.132 -> 359.00

In this test, only a 1% difference between results so really good but it can be really random (from 1 to 3%). I am not sure about the "start number" of the range (I am using the 12-55 ampers range to calculate how much slower it runs). The stall is always at around 55 but the motor's normal work takes from 12 to 14 ampers no matter load.

I have one more question related to measuring ampers, I have a 3 Ohm resistor and I am measuring voltage before and after to calculate the current.

    int sum1 = 0;
    int sum2 = 0;

    for (byte count = 0; count < 20; count++) {
      int iValue1 = analogRead(A3); // before resistor
      int iValue2 = analogRead(A4); // after resistor
      sum1 = sum1 + iValue1;
      sum2 = sum2 + iValue2;
      delay(1);
    }

    float currentValueBeforeResistor = sum1 / 20;
    float currentValueAfterResistor = sum2 / 20;
    float voltage = abs(currentValueBeforeResistor - currentValueAfterResistor ) * 0.0048828125;
    float resistance = 3.4;
    float ampers = voltage / resistance * 1000;

Is this a proper way? I believe I have copied it from this forum haha but I was also researching "better ways", and found something like "Kalman Filter" (GitHub - TKJElectronics/KalmanFilter: This is a Kalman filter used to calculate the angle, rate and bias from from the input of an accelerometer/magnetometer and a gyroscope.). Is this a good way? Can you advise something?

I know it is not perfect but it's pretty close, could be enough for me if I would improve my reading of the voltages and calculate the current.

Thanks again.

PS: Maybe a stepper motor would be better for this?

The voltage across a resistor is proportional to the current, by Ohm's Law.

Avoid the TKJElectronics site, the code is nonsense. If you need to reduce noise, averaging some number of readings is mathematically correct, and works very well.

With a stepper motor, you can easily control the exact number of revolutions, provided that the stepper motor driver is properly powered and configured and the motor is not mechanically overloaded, so that it skips steps.

1 Like

Right... I believe CNC machines use stepper motors. But they don't normally go 10,000 RPM.

And there is inertia, acceleration, and deceleration so you probably won't get to 10,000 RPM in 500 revolutions and/or you won't be able to stop at exactly 500 revolutions.

If you count the revolutions it's possible to reverse if you overshoot (if that's acceptable).

Servo motors are continuously checking & correcting their actual location against the target angle and they will reverse if they overshoot or are forced past the position, but they are slow so they don't normally overshoot and the gearing reduces the chance of being forced out of position.

It's also an issue if you try to accelerate/decelerate a stepper motor too fast. In most applications the stepper runs slow-enough to avoid this.

BTW - Precise speed control also requires feedback. You can adjust the voltage "blindly" to make a DC motor run at "high", "medium", and "low" speeds but you have to measure the speed if you want an exact RPM.

1 Like

Real industrial CNC machines use servo motors and can exceed 10,000 RPM. The machines will all use cooling, lubricating fluid in cutting.

1 Like

Hey guys,

once again thank you for your help, please help me understand one more thing, with a stepper motor, what is the best way to detect a stall?

Let's take a 3D printer as an example, X-axis, the driver set the printer in the maximum left position, then the maximum right position (with an assumption you cannot hardcore what is the length of the X-axis) and the result is for example 30k rotations. So 15k is the center, etc. But how to detect "the printer is on maximum left position"? I was doing something similar with the DC motor by measuring amps for stall detection but in the stepper motor when I am trying to google "stall detection" there is not much. There are some drivers that can detect stalls but I see comments they are hard to calibrate. Do you have any tips on how to deal with that?

What I am trying to basically achieve is similar to the 3d printer example:

  1. go full backward till stalling
  2. go full forward till stalling
  3. calculate the rotations it takes from beginning to end
  4. set the positions of the motors in % based on the total rotations from point 3

A "stall" with a stepper is identical to the stepper holding position. The only way to detect a stall with a stepper is to detect the stepper did NOT MOVE a step.

If you will use the normal stepper logic of first determining the starting point with some kind of position sensor, then counting the steps,+ and - in your program, you will always know the position.

1 Like

Use a simple limit switch

1 Like

There is usually no need to do so. It does not harm a stepper motor to run into an end stop, so many systems do just that to set the zero or home position.

To detect a stall or missed steps due to overloading the stepper, use a shaft encoder.

1 Like

Hey there,

as always thank you for your contribution, please help me understand the results of my work today because I have no idea why it's working. :slight_smile:

I have decided to go with a stepper motor, and found this one in a smart thermostat I was no longer using:

This is actually exactly what I needed, the ability to move forward (open) or backward (close) so all good now. It has 4 cables so I believe it is a bipolar stepper, fine for me.

I was using L293D H-Bridge for the DC motor, found some tutorial about a bipolar stepper motor and it turned out I can use the same module for the new stepper motor - again great.

I was a little curious about how many amps it takes when working and since I had my "amperemeter" built for DC, I run it on the stepper motor as well (on single pair of cables).

I noticed that the measured values change when it works with no load and on the stall (but they shouldn't right?). It was pretty weird for me so I wrote a simple code that runs one step per 2ms on the motor and sums amper values from the last 300 steps.

#include <Stepper.h>

const int stepsPerRevolution = 4; 
Stepper myStepper(stepsPerRevolution, 10,11,12,13);

void setup() {
  // initialize the serial port:
  Serial.begin(9600);
}

float results[300];
int resultsIndex = -1;

void loop() {
    myStepper.step(1);
    delay(2);

    float currentValueBeforeResistor = analogRead(A3);
    float currentValueAfterResistor = analogRead(A4);
    float voltage = abs(currentValueBeforeResistor - currentValueAfterResistor) * 0.0048828125;
    float resistance = 3.4;
    float ampers = voltage / resistance * 1000;

    resultsIndex += 1;
    results[resultsIndex] = ampers;

    if (resultsIndex == 299) {
      double total = 0;
      for(int i = 0; i < resultsIndex; i++) {
        total += results[i];
      }

      Serial.println(total);
      resultsIndex = -1;
   }
}

On serial output when the motor runs without any load I see results around 16000 (sum of 300 measurements over 600 ms). But when I stop the motor by hand it goes dramatically to around 26-28k. Take a look at the picture:

This result is something I wanted from the beginning but I don't understand why it works, is this fine? Is this because of bipolar stepper? Is this related to Arduino? Or maybe the driver?

Thank you once again!

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