Switched from Easy Driver to Big Easy Driver - now my optical sensor misfires

Hi. I’m pretty new to all of this. Here’s the story:

I’m building an Arduino driven pickup winder. The idea of the design is to sync a stepper to a separate spinning driveshaft.

I have a DC motor turning shaft with faceplate on the end of it. I’m using an IR LED and a photo transistor that reads a painted black and white cross to monitor the speed and number of turns of the driveshaft. I have an attachInterrupt that tells the stepper to advance 1 increment each time the white and black transitions. The average working speed of the DC motor will be about 1000rpm

Originally, I built the machine using an Easy Driver, and it worked. But the stepper wasn’t quite strong enough to reliably turn the gearbox I built for the machine. So I got a 2A stepper and a Big Easy Driver.

What happened was really strange - now the optical transistor is seems to be sensing each transition from both light to dark and dark to light firing the attachInterrupt twice as often as it should! When I disconnect the Big Easy Driver, my optical sensor works perfectly.

Anyway here’s my current code I managed to cobble together. The only difference between the two is that I added the MS3 pin for 1/16 steps.

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

const int buttonPin = 2;

// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

#define step_pin 9   // Pin 9 connected to Steps pin on EasyDriver
#define dir_pin 8    // Pin 8 connected to Direction pin
#define MS1 10       // Pin 10 connected to MS1 pin
#define MS2 11       // Pin 11 connected to MS2 pin
#define MS3 13
#define SLEEP 12     // Pin 12 connected to SLEEP pin

//int ledPin = 13;
volatile byte windState = 0; // varible that will hopefully advance the stepper

volatile byte quarters; // Counts pulses for the tach

volatile long sampleCount = 0; // Raw count data
unsigned int windCount = 0; // the actual count

long previousCount_Millis = 0; // Stores the last time Wind Count was updated
long count_interval = 25; // Interval at which the Wind Count is updated

long previousRPM_Millis = 0; // Stores the last time RPM was updated
long rpm_interval = 400; // Interval at which the RPM is updated

long previousLCD_Millis = 0; // Stores the last time LCD was updated
long lcd_interval = 20; // Interval at which the LCD is updated

long previousCount = 0; // Stores the old count for the easydriver
long stepperInterval = 10;


void sample()
{
  quarters++;
  sampleCount++;
}

void setup()
{
  attachInterrupt(0, winder, FALLING);

  pinMode(MS1, OUTPUT);
  pinMode(MS2, OUTPUT);
  pinMode(MS3, OUTPUT);
  pinMode(dir_pin, OUTPUT);
  pinMode(step_pin, OUTPUT);
  pinMode(SLEEP, OUTPUT);

  digitalWrite(SLEEP, HIGH);
  delay(5);

  /* Configure type of Steps on EasyDriver:
    // MS1 MS2
    //
    // LOW LOW = Full Step //
    // HIGH LOW = Half Step //
    // LOW HIGH = A quarter of Step //
    // HIGH HIGH = An eighth of Step //
  */

  digitalWrite(MS1, HIGH);
  digitalWrite(MS2, LOW);
  digitalWrite(MS3, LOW);


  Serial.begin(9600);

  display.begin();
  // init done

  // you can change the contrast around to adapt the display
  // for the best viewing!
  display.setContrast(40);
  display.clearDisplay();// clears the screen and buffer
  
  display.display();
}


void loop()
{

  quarters = 0;
  unsigned int rpm_temp = 0;
  unsigned int rpm = 0;
  unsigned long timeOld = 0;

  while (1) {

    unsigned long current_Millis = millis();
    
    if (quarters >= 37) {
      // Update rpm_temp every 37 counts
      rpm_temp = 60000 * quarters / (4 * (current_Millis - timeOld));
      timeOld = current_Millis;
      quarters = 0;
    }

    // compare current time with the last time the RPM was updated
    if (current_Millis - previousRPM_Millis > rpm_interval) {
      rpm = rpm_temp;
      previousRPM_Millis = current_Millis;
    }

    // compare current time with the last time the Wind Count was updated
    if (current_Millis - previousCount_Millis > count_interval) {
      windCount = (sampleCount / 4);
      previousCount_Millis = current_Millis;
    }

    // compare current time with the last time the LCD was updated
    if (current_Millis - previousLCD_Millis > lcd_interval) {

      display.clearDisplay();
      display.setTextColor(BLACK);
      display.setCursor(0, 5);
      display.setTextSize(1);
      display.print("RPM: ");
      display.print(rpm);

      display.setCursor(0, 20);
      display.setTextSize(1);
      display.print("WIND COUNT:");
      display.setCursor(0, 30);
      display.setTextSize(2);
      display.print(windCount);

      display.display();
    }

  }
}

void winder() {
  windState = digitalRead(buttonPin);

  digitalWrite(dir_pin, LOW);   // HIGH = anti-clockwise / LOW = clockwise
  digitalWrite(step_pin, HIGH);
  delay(1);
  digitalWrite(step_pin, LOW);
  delay(1);

  sample();
}

Here's a quick image. I couldn't find an accurate representation of the Nokia 5110 screen, so I've omitted it for now. I'll keep looking. Fritzing also does not have the Big Easy Driver board, so I have substituted it with the Easy Driver - I have just omitted MS3 to pin 13

If you can make a simple pencil drawing of the connections and post a photo of the drawing it will be a lot more informative than the Fritzing picture. Please label all the connection points that are used.

Also, include the power supply(ies) in the drawing.

The symptoms you describe suggest to me that the bigger motor is interfering with the stability of the power supply for the LED or the sensor. Hence the need to see the power supply in the diagram.

…R

Could be direct pick up of spikes by the photosensor wiring - it would be best if it was shielded.
You also seem to be reading an analog photo sensor using a digital pin handled by an interrupt,
which is a situation best avoided completely, unless a schmitt-trigger is used to clean up the
analog signal to give definite logic transitions.

Thanks, guys. This is a big help and it makes sense.

Robin2:
If you can make a simple pencil drawing of the connections and post a photo of the drawing it will be a lot more informative than the Fritzing picture. Please label all the connection points that are used.

Also, include the power supply(ies) in the drawing.

The symptoms you describe suggest to me that the bigger motor is interfering with the stability of the power supply for the LED or the sensor. Hence the need to see the power supply in the diagram.

...R

OK. I'll try to get that pencil drawing posted later today or tomorrow.

Incidentally, the LED + sensor are currently (no pun intended) being powered from the Arduino which is in turn powered from my laptop. The motors are being powered by a 12V wall wart.

MarkT:
Could be direct pick up of spikes by the photosensor wiring - it would be best if it was shielded.
You also seem to be reading an analog photo sensor using a digital pin handled by an interrupt,
which is a situation best avoided completely, unless a schmitt-trigger is used to clean up the
analog signal to give definite logic transitions.

Schmitt-trigger? Those two cascading transistors? I think I know what you're talking about. I've seen some schematics on the i-net. I'll look into getting that happening. Ugh I suck at biasing transistors.

How would I approach shielding the photosensor wiring?

Schmitt-trigger as in 74HC14 or similar - logic speed.

MarkT:
Schmitt-trigger as in 74HC14 or similar - logic speed.

Cool. I ordered some of those chips and it looks like there’s a couple tutorials online. When I rig it up, I’ll post my findings.

Okey dokey. Here’s that pencil drawing. Hope that this is informative…

The connections to your sensor are not very clear and you don't give details of the actual parts used.

I am using a QRE1113 reflective optical sensor to detect a spot of white paint on a small disc attached to a small DC motor. I found that the detection is reliable on a breadboard Atmega 328 but not on my genuine Uno. I don't know enough about electronic circuits to know if this could be due to inductance or impedance (or something) on the Uno board.

And the physical layout of your wires may have the effect of allowing interference between your detector and another circuit.

...R

Robin2:
The connections to your sensor are not very clear and you don't give details of the actual parts used.

I am using a QRE1113 reflective optical sensor to detect a spot of white paint on a small disc attached to a small DC motor. I found that the detection is reliable on a breadboard Atmega 328 but not on my genuine Uno. I don't know enough about electronic circuits to know if this could be due to inductance or impedance (or something) on the Uno board.

And the physical layout of your wires may have the effect of allowing interference between your detector and another circuit.

...R

Here's a more detailed look at the IR/Photosensor wiring:

Honestly, the LED and photosensor are cheap generic parts I bought on ebay. 2 bucks for a bag of 10. No part #, no documentation, no nuthin'. They look like this:

Oddly enough, I'd originally tried using some QRD1114's, but I couldn't get the circuit to work so I went with the cheap-o parts

That looks very like the circuit I am using with my QRE1113. I copied the schematic for this SparkFun analog version. And, just to be clear, I have it connected to an external interrupt pin.

I am using the bare QRE1113 device because I have no space for the breakout board.

...R

Robin2:
That looks very like the circuit I am using with my QRE1113. I copied the schematic for this SparkFun analog version. And, just to be clear, I have it connected to an external interrupt pin.

I am using the bare QRE1113 device because I have no space for the breakout board.

...R

Yeah, that's pretty much the way to do it. I have mine wired up on veroboard. I might change the LED resistor to like, 290R or something. Just judging from looking at it on the back camera of my iPhone, it looks pretty dim. I was having trouble with blowing those little IR's, so I wanted to make sure that I didn't give it too much power. They seem to be less forgiving than say a red or white LED.

I'm reading up on that Schmitt trigger thingy and it looks pretty simple to implement. I was having some trouble with weird readings before which effected the RPM read out. Tracking the RPM is not crucial, so at first I didn't worry about it. It's possible that the increased load with the bigger motor is causing more interference and making this weirdness worse. Hopefully cleaning up the signal from the photoresistor will help.

I also realized that one of the belts on my gearbox it a little tight. I ordered a larger belt, and I could try the smaller motor again if the new belt provides enough relief to let the smaller motor work.

While I have your guy's ear, I know it's kind of a no-no putting that delay(1) inside my interrupt, but the larger motor wouldn't work without it. Is there a way around this? Should I post this question in a separate thread?

And one (or two) more question(s) - I'm looking at opto-isolators.

Would it be a good idea to use one to isolate the stepper motor from the board?

If so, looking at one of the boards linked below, what pins would I need to hookup between my driver and the Arduino?

Thx.

I doubt if your step pulse needs to be longer than 10 microsecs.

DO NOT WAIT in the ISR for the duration between step pulses. I00 µsecs would be a long time to stay in an ISR.

In any case, if your ISR only does one step then your second delay(1) is not doing anything useful.

Put the code from the sample() function directly into the ISR and you won’t waste the time required to call the function.

This

windCount = (sampleCount / 4);

should be done like this to prevent the ISR changing the value while you are reading it

noInterrupts();
    windCount = sampleCount;
interrupts();
windCount = windCount / 4;

…R

Hi,
Have you got any sleeving around the LED and photodiode so that only the ends emit and receive energy?

Tom.... :slight_smile:

Robin2:
I doubt if your step pulse needs to be longer than 10 microsecs.

DO NOT WAIT in the ISR for the duration between step pulses. I00 µsecs would be a long time to stay in an ISR.

In any case, if your ISR only does one step then your second delay(1) is not doing anything useful.

Put the code from the sample() function directly into the ISR and you won't waste the time required to call the function.

This

windCount = (sampleCount / 4);

should be done like this to prevent the ISR changing the value while you are reading it

noInterrupts();

windCount = sampleCount;
interrupts();
windCount = windCount / 4;




...R

OK. That makes a lot of sense. Thanks! I'll make that happen.

Let me ask you this: right now I'm only doing one step. Pretty straightforward. If sometime down the line, I wanted to do say, 3 eighth steps instead of 1 quarter step, would it be copacetic to put a for loop inside the interrupt to advance it by 3 smaller increments? Is there a better way to approach that?

TomGeorge:
Hi,
Have you got any sleeving around the LED and photodiode so that only the ends emit and receive energy?

Tom.... :slight_smile:

Thanks for your suggestion!

The answer is no, I haven't put a sleeve around the LED and photodiode. Right now, I have a basically a spaghetti bowl full of wires and a bunch of loose components. I was thinking last night that now that I've moved past the "let see if this will work" phase to the "this is happening" phase, I should probably affix my components to a base and clean up the wires a bit. That'll involve physically shielding the LED, the photodiode as well as the other wires. I'll prolly use a piece of hardboard lined with a sheet of 20ga aluminum and offset my various boards with screws and nylon spacers to insulate them from the base. Placing the LED/photodiode will be tricky since I have moving parts virtually everywhere. I had one good spot for it, but I had to remove it when I installed the larger stepper.

So you guys aren't feeling the opto-isolator vibe?

freekmagnet:
If sometime down the line, I wanted to do say, 3 eighth steps instead of 1 quarter step, would it be copacetic to put a for loop inside the interrupt to advance it by 3 smaller increments? Is there a better way to approach that?

I never came across the word "copacetic" before, but my dictionary has :slight_smile:

The answer to your question is not simple. I can conceive of circumstances where that may be necessary because any alternative would not perform well.

However I would prefer a system in which the ISR sets a flag - for example stepDue = true; and then the code in some other part of your program regularly checks that variable and does the necessary steps. Something like

void moveStepper() {
   noInterrupts();
   if (stepDue == true) {
     stepDue = false; // so you don't do the same steps twice
     interrupts();
     // code to cause the necessary steps to happen
   }
   else {
    interrupts();
   }
}

...R

Robin2:
I never came across the word "copacetic" before, but my dictionary has :slight_smile:

The answer to your question is not simple. I can conceive of circumstances where that may be necessary because any alternative would not perform well.

However I would prefer a system in which the ISR sets a flag - for example stepDue = true; and then the code in some other part of your program regularly checks that variable and does the necessary steps. Something like

void moveStepper() {

noInterrupts();
  if (stepDue == true) {
    stepDue = false; // so you don't do the same steps twice
    interrupts();
    // code to cause the necessary steps to happen
  }
  else {
    interrupts();
  }
}




...R

OK here's where I get confused. Am I correct in reading the above code as "if a condition is true then execute this function" but defaults to "execute this function" anyway? But I could see how moving the function out of the ISR could be advantageous.

You bring up another good point however; once I try to use one event to tell the stepper to do more than one movement, I may run into weird timing issues.

Maybe what I'm looking for is a hardware solution. Right now I have 4 white bars painted on my spinning wheel. Perhaps instead I could print out a black and white disc with say, 5 or 6 or 7 bars, affix the appropriate disc to the back and then change the divisor in my equation. It wouldn't be as elegant programmatically, but "hard wiring" it may be a better way to ensure accuracy.

Robin2:
I never came across the word "copacetic" before, but my dictionary has :slight_smile:

Ha-ha- my dad had a degree in English. I guess you could say it rubbed off.:wink:

freekmagnet:
but defaults to "execute this function" anyway?

I don't see how you think that, or even what you have in mind?

Ha-ha- my dad had a degree in English. I guess you could say it rubbed off.:wink:

If you hang around here for long you will see "english" that would make your dad ill. It's nice to see a strange word that is legit.

...R

Robin2:
I don't see how you think that, or even what you have in mind?
If you hang around here for long you will see "english" that would make your dad ill. It's nice to see a strange word that is legit.

...R

My brain is just short circuiting. I'll figure it out.

Thanks for your help! I'll try out your coding suggestions, install that Schmitt trigger and start mounting/shielding my components. I'll post my results once I get some of it rolling.