Turning a stepper with an encoder, the right way.

We have a project in which we want a stepper to mimick the turning events of a rotary encoder.
When the encoder turns X degrees, the stepper has to turn the same X degrees.

We now have wired an additional power supply (6v), like this:

We used this code (lent from somebody else...):

#include <Bounce2.h>
#include <Stepper.h>

/* 
 DESCRIPTION
 ====================
 Reads the 2 switches in an encoder, 
 determines direction,
 updates counter.
 No interrupts.
 Switches debounced, didn't test first, just did it anyway.
 */


const byte ENCODER_PINA= 2;
//const byte LED_PINA= 12;
const byte ENCODER_PINB= 3;
//const byte LED_PINB= 11;

const int stepsPerRevolution = 2048;

Stepper myStepper(stepsPerRevolution, 1, 4, 5, 6);

int valueA; //debounced encoder switch reads
int valueB;

bool motionDetected = false;
int grossCounter = 0; // total steps
int nettCounter = 0;  // cw-ccw
int fullRevolutions = 0;
int surplusSteps = 0; //part revs
bool CW;

byte cyclesPerRev =20;  //check encoder datasheet

// Instantiate 2 Bounce object
Bounce debouncerA = Bounce(); 
Bounce debouncerB = Bounce(); 

// setup ********************************************
void setup() {
  Serial.begin(115200);
  Serial.println("Setup");
  // Setup the buttons
  pinMode(ENCODER_PINA,INPUT_PULLUP);
  pinMode(ENCODER_PINB,INPUT_PULLUP);


  // After setting up the button, setup debouncer
  debouncerA.attach(ENCODER_PINA);
  debouncerA.interval(5);
  debouncerB.attach(ENCODER_PINB);
  debouncerB.interval(5);

  //Setup the LED
 // pinMode(LED_PINA,OUTPUT);
 // pinMode(LED_PINB,OUTPUT);
  Serial.println("Setup done");
}

// loop *****************************************
void loop() {

  // Update the debouncers
  doDebounce();

  // Read the encoder switches
  doEncoderRead();

  // Update LEDs and serial print A, a, B, b
 // updateLEDs();

  //determine direction and update counter

  updateCounter();

} //loop

// my functions **************************************************
void doDebounce()
{
  debouncerA.update();
  debouncerB.update();
} //doDebounce

void doEncoderRead()
{
  valueA = debouncerA.read();
  valueB = debouncerB.read();
} //doEncoderRead

/*
void updateLEDs()
{

  if ( valueA == HIGH) {
    digitalWrite(LED_PINA, HIGH );
    //Serial.print("A");

  } 
  else {
    digitalWrite(LED_PINA, LOW );
    //Serial.print("a");
  }

  if ( valueB == HIGH) {
    digitalWrite(LED_PINB, HIGH );
    //Serial.println("B");
  } 
  else {
    digitalWrite(LED_PINB, LOW );
    //Serial.println("b");  
  }

} //updateLEDs
*/

void updateCounter()
{

  /*
  the possibilites are:
   
   AB: in a detent
   if just arrived, update counter, clear motiondetected
   otherwise do nothing
   Ab: start of CW or end of CCW
   if start, set CW bool and set motionDetected
   if at end (know becasue motionDetected already set), do nothing
   aB: start of CCW or end of CW
   if start, clear CW bool and set motionDetected
   if at end (know becasue motionDetected already set), do nothing
   ab: in middle of either CW or CCW, do nothing
   */

  if (valueA && valueB && motionDetected ) //in a detent and just arrived
  {
    if (CW)
    {
      grossCounter= grossCounter + 1;
      nettCounter= nettCounter + 1;
      
      myStepper.step(1);
    }
    else //CCW
    {
      grossCounter= grossCounter + 1;
      nettCounter= nettCounter - 1;
      
      myStepper.step(-1);
    }
    motionDetected = false;
    Serial.print("grossCounter: ");
    Serial.println(grossCounter);
    Serial.print("nettCounter: ");
    Serial.println(nettCounter);
    
    fullRevolutions = nettCounter / cyclesPerRev; 
    surplusSteps = nettCounter % cyclesPerRev;
    
    Serial.print("Nett position: ");
    Serial.print(fullRevolutions);
    Serial.print(" + ");
    Serial.println(surplusSteps);
    Serial.println(" ");
    
    


  }

  if (valueA && !valueB && !motionDetected ) // just started CW
  {
    CW= true;
    motionDetected=true;
    Serial.println("CW");

  }

  if (!valueA && valueB && !motionDetected )  //just started CCW
  {
    CW= false;
    motionDetected=true;
    Serial.println("CCW");

  }
} //updateCounter

This is the datasheet of the stepper we use:

This is the encoder we use.

When we run above code, we can feel the stepper reacts (little vibrations) but the stepper doesn't turn.

What could be going wrong there?
Previously we could let the stepper make full turns step by step, using the arduino 5v pin and an example code, so the stepper should work.

PS we're not completely sure the power wire from the stepper driver is wired correctly to the arduino 5V pin. Maybe it also has to be connected to the battery?

This was the output in the serial monitor:

Code 24 output:
àªW5
Setup done
CW
grossCounter: 1
nettCounter: 1
Nett position: 0 + 1
 
CW
grossCounter: 2
nettCounter: 2
Nett position: 0 + 2
 
CW
grossCounter: 3
nettCounter: 3
Nett position: 0 + 3
 
CW
grossCounter: 4
nettCounter: 4
Nett position: 0 + 4
 
CW
grossCounter: 5
nettCounter: 5
Nett position: 0 + 5
 
CW
grossCounter: 6
nettCounter: 6
Nett position: 0 + 6
 
CW
grossCounter: 7
nettCounter: 7
Nett position: 0 + 7
 
CCW
grossCounter: 8
nettCounter: 6
Nett position: 0 + 6
 
CCW
grossCounter: 9
nettCounter: 5
Nett position: 0 + 5
 
CCW
grossCounter: 10
nettCounter: 4
Nett position: 0 + 4
 
CCW
grossCounter: 11
nettCounter: 3
Nett position: 0 + 3
 
CCW
grossCounter: 12
nettCounter: 2
Nett position: 0 + 2
 
CCW
grossCounter: 13
nettCounter: 1
Nett position: 0 + 1
 
CCW
grossCounter: 14
nettCounter: 0
Nett position: 0 + 0
 
CCW
grossCounter: 15
nettCounter: -1
Nett position: 0 + -1

Are you saying that with that implementation that you have run a simple motor routine (rotate clockwise, rotate counter-clockwise)?

If not, you should get that right and then move on to the position control.

IC Pin 9 should go to motor +V (not Arduino +5). That's not halting your progress, but IC pin 9 is the common diode for each driver output and so should go to motor +V.

Your stepper motor controller is connected to the hardware serial pin that you are using to talk to the PC. Of course that's going to f**k with the stepper motor.

You could of course, use an H-bridge to connect the stepper directly to the encoder since the quadrature encoding is exactly what the stepper uses. :sunglasses:

Do you mean we should first try to make it turn clockwise and counter-clockwise?

PaulS:
Your stepper motor controller is connected to the hardware serial pin that you are using to talk to the PC. Of course that's going to f**k with the stepper motor.

Do you mean the TX 1 pin? Yeah, I think you're absolutely right. We'll change that.

Paul__B:
You could of course, use an H-bridge to connect the stepper directly to the encoder since the quadrature encoding is exactly what the stepper uses. :sunglasses:

That sounds kind of simple. But I'm already getting tangled up in all the wires going everywhere, so I think we should stick for the moment to this set-up.

But how would that work? I have to know which wires from the stepper receive that encoding, and how to use a H-bridge in that. I have trouble finding that on google, though.

Stick with the setup you have for now, but get the chip off the hardware serial pin (pin 1). See if that solves your problem. If so, great. If not, post a new schematic, a picture of the implementation of that schematic, and some description of what actually happens (and the code, of course).

Paul__B:
You could of course, use an H-bridge to connect the stepper directly to the encoder since the quadrature encoding is exactly what the stepper uses. :sunglasses:

The stepper in the picture is a 4 pole unipolar stepper motor, so I don't think you can drive it with an H bridge,

Here is some code to drive it either way.

PHPirates:
Do you mean we should first try to make it turn clockwise and counter-clockwise?

Yes, especially if I were asking the questions that you have.

Outline:

  1. stepper routine and stepper circuit work
  2. analogRead routine works
  3. integration of 1 & 2 work

Bad plan?

PaulS:
Stick with the setup you have for now, but get the chip off the hardware serial pin (pin 1). See if that solves your problem. If so, great. If not, post a new schematic, a picture of the implementation of that schematic, and some description of what actually happens (and the code, of course).

Actually, I think that helped us solving this one. The stepper now turns if we set the rotation speed below 300rpm and the amount of steps not too big (the bigger the more inaccurate the stepper turns). We also changed ic pin 9 to the motor +V, as RP suggested.
Now the next step.

I would add decoupling capacitor(s) on the supply to the ULN2803/ULN2003, perhaps 100uF
electrolytic or so. This should soak up the inductive kick-back better than the battery alone
and reduce electrical noise (should this be an issue).

MarkT:
I would add decoupling capacitor(s) on the supply to the ULN2803/ULN2003, perhaps 100uF
electrolytic or so. This should soak up the inductive kick-back better than the battery alone
and reduce electrical noise (should this be an issue).

For example something like this? Electrolytic Decoupling Capacitors - 100uF/25V - COM-00096 - SparkFun Electronics
I understand that wiring one between the battery 5V and the stepper should 'smoothen' the power delivery, is that right?