Move a DC Motor "one step"

Hello Forum members,
I have a pololu dual mc 33926 shield (arduino) and a pololu 131:1 gear motor. I can run it fine, and vary its
speed using a pot, etc. Is there a way to “step” this motor - one small incrment at a time - like a stepper motor?

I can run it slow with the pot, but I would like to move it like a stepper.

Any ideas on this?

Thanks,
ewholz

You will need a shaft angular position encoder and PID control for that.

Hello Jim,
Thanks, I have an encoder on the shaft - I need to check in to the PID.
Also the encoder - needless to say - only outputs data when the shaft turns.

Thanks,

Eric

What sort of encoder do you have – can you post a link? The ones useful for motor control present logic levels on the output terminals at all times, however those levels change only during shaft rotation.

Hello Jim,
Thanks, Any suggestions on programming this? I can count pulses on the encoder - but not
sure how to do that when I get the PID controller - currently using an MC33926 dual controller and an Arduino Uno.
I am using an interrupt to count pulses on the encoder - on one of the encoder outputs. I actually use the
interrupt to count when the shaft rotates, run the speed at 150, and stop the motor when the count goes higher
than 25 - this gives approx one cog turn on the belt. Clearly a stepper in microstep mode is better for this, but
we have found the stepper motor does not have enough power to drive our payload ( 40 pound goal)

Here are the motor specs - a pololu item 1447
Pololu item #: 1447
131:1 Metal Gearmotor 37Dx57L mm with 64 CPR Encoder

This 2.71" × 1.45" × 1.45" gearmotor is a powerful 12V brushed DC motor with a 131.25:1 metal gearbox and an integrated quadrature encoder that provides a resolution of 64 counts per revolution of the motor shaft, which corresponds to 8400 counts per revolution of the gearbox’s output shaft. These units have a 0.61"-long, 6 mm-diameter D-shaped output shaft. This gearmotor is also available without an encoder.

Key specs at 12 V: 80 RPM and 300 mA free-run, 250 oz-in (18 kg-cm) and 5 A stall.

I am checking other motors, as we need a planetary gear system - the gearbox on the motor above is way too noisy.

thanks,
ewholz
(Eric)

If you are using Arduino, the most straightforward approach is to use the Arduino PID library playground.arduino.cc/Code/PIDLibrary. The setpoint is the desired motor position in counts and the “input” is the current count. However, you must make sure that your encoder routine properly handles forward and backward motion without skipping a single count.

The simplest and most elegant approach to that end is to use a pin change interrupt on one of the encoder outputs, and to read the other output with another pin on the same port. This method gives you half the theoretical resolution of the encoder, but I have verified that it works very well and counts correctly up and down, no matter how the encoder shaft gyrates. See reply #9 by cattledog in this thread here: forum.arduino.cc/index.php?topic=267426.0

For completeness, the code is here (encoder A and B on digital pins 8 and 9):

[code]//Enable Pin Change Interrupt on Pin 8
PCICR |= (1<<PCIE0); //enable group interrupts on PORTB PCINT[7:0]
PCMSK0 |= (1<<PCINT0); //enable interrupt pin 8
//…

//ISR for Pin 8
ISR (PCINT0_vect) // handle pin change interrupt for D8-D13; triggered by 8
{
if(bitRead(PINB,0)== bitRead(PINB,1)) {//(PINB, x) is the syntax to read the input state from PORTB, bit x
encoderValue++;
} else {
encoderValue–;
}
}
[/code]

Of course, you will need to tune the PID algorithm correctly, but there are lots of tutorials on line for how to do that.

Hello Jim,

Thanks so much, and thanks for taking the time to respond. I did not know that there was an arduino PID library.
I will check that out. Thanks for the sample code. I do not have my PID
driver as yet, but my starter code is using an interrupt to read one of the
encoder outputs.

Thanks again

ewholz,
eric

Hello Again,
I have the encoder code above - it does seem to work - sort of.
My problem is that the motor will not run. I am using the MC33926 motor shield,
with commands to just run the motor (md.init(), md.setM1Speed(speed), speed = 100, etc).

I put the motor init command in setup(), and the speed value and md.setM1Speed in the “loop” along with the
encoder print statements.

One strange thing - I added the motor include .h file, etc, created an motor object “md” - but without any code for motor
in “loop”, I had the init and the speed setting in setup, when the program loaded, the motor ran, and the counts printed out!
but only once. I have do disconnect everything, and then reload code to Arduino Uno, and it runs??

Any Ideas on how to do this correctly?

ewholz

Hello Jim,
I have been trying to get the correct use for the PID library
just to turn a dc motor. so far no luck - I have some sample code from the Arduino forum that
is all manual coded (no pid library, etc), and the pwm value is calculated using error, Kp, and Kd values,
this works - and the speed of motor can be changed by entering data in the serial monitor.

the pwm val is calculated like this:
error = abs(targetValue) - abs(currentValue);
pidTerm = (Kp * error) + (Kd * (error - last_error));

the pidTerm is converted into a PWM, and the written to the analog pin in the loop. I figure I should be able to emulate that
with the Pid Library Here is a link to the forum in arduino: forum.arduino.cc/index.php/topic,8652.0.html.
This is nicely done, but I would like to try similar functionality using the PID library.

ewholz

Did you get your motor working correctly for simple motor commands?
Are you sure that the encoder is working properly?

Re PID problems: for informed help, post your code using code tags (“Code” button) and describe what happens when you try to use the PID library.

The best way to help yourself is to put print statements throughout the code, so you can see what variables are changing and what decisions the program is making.

By the way, this line won’t work correctly for many cases of positive and negative target positions. error = abs(targetValue) - abs(currentValue); Get rid of the abs() function call. Note that you may have to change the sign of error for the PID algorithm to work correctly.

Hello and Thanks,
I have got the encoder working (OK i hope) using the pin change interrupt.
I have had to use different pins, as the vnh5019 shield uses pins.

I can use the “stock” code for the shield to move the motor back and forth. I have added the pid library to my code. I will attach code below this. I would like to be able to vary the motor speed using the pid library code.
Maybe this is wrong idea, as I see where Setpoint should be fixed, the Input is the shaft rotation from the encoder,and the output is from the myPid.computer() method. I can look at the Output, it starts low, and
ramps up to 255.0 no matter what the speed of the motor is. I know I am missing something basic as far as my understanding of the Pid library. I am appreciative of the reply on my stuff!
Here is the code: And I have also added the code that uses no libraries. I found this code on Arduino forum,
and it works fine, i tried code from this same guy, that moves the motor back and forth depending on encoder counts - like lets say 100 counts, but the position of the motor shaft creeps - the motor does not really move to an exact position (glad I do not need this feature)
Autotune.ino (9.72 KB)
pidcontrol.ino (7.23 KB)