Interrupts and wheel encoding... a beef with

EDIT (June, 25th 2012):

The headache just doesn't go away...

Despite the photo below now I have a tube of black heatshrink shielding the sensor. It increase the analog output, for both cases (black and white). Regardless, the behaviour remains the same as without the shield when I move unto digital pins. I've been trying to deal with debouncing for the past couple of days with no luck.

// Playing with encoder digital readings

 

const int sensorPin = 7;

 

int lastColor;

int currentColor;

int count;

 

long lastDebounceTime = 0;  // the last time the output pin was toggled

long debounceDelay = 2;    // the debounce time; [0,1] -> crazy bouncing, >= 2 silence!

 

void setup()

{  

  Serial.begin(19200);

  //pinMode(sensorPin, INPUT);          // 7-8 initial bounces on black when lastColor = HIGH;

  //digitalWrite(sensorPin, HIGH);      // and both these lines are commented.

 

  lastColor = digitalRead(sensorPin);

  delay(10);

  Serial.print("Starting color ");

  Serial.println(lastColor);

  //lastColor = HIGH;     // HIGH bouncing on white stripes; LOW bouncing on black stripes

}

 

 

void loop()

{

 

  readSensor();

  if (currentColor != lastColor)

  {

    count++;

    Serial.print("Click! ");

    Serial.println(count);

  }   

 

} //close loop()

 

void readSensor()

{

  int reading = digitalRead(sensorPin);

 

  if (reading != lastColor){

    lastDebounceTime = millis();

  }

  if( (millis() - lastDebounceTime) > debounceDelay){

    currentColor = reading;

  } 

}

 

The major implications of this code is by varying:
long debounceDelay = 2;    // the debounce time; [0,1] -> crazy bouncing, >= 2 silence!

Also the bouncing will happen with the oposite stripe of the starting one. That is, 1st read is of a white stripe, then whenever a black stripe goes by hundreds of clicks will happen, if debounceDelay is 0 ou 1. However if it's 2 or more.... only the first read is done, then forever silence... :( 


So the time has arrived where I've realized I can't go on without the use of wheel encoders. So I've made these:

IMG_20120616_161602.jpg

EDIT: Added TCRT5000-based encoder detector circuit below.
NEW EDIT: Replaced with corrected schematics.
NEW NEW EDIT: Yet again replaced the schematics, HOPEFULLY this time around I didn't leave any mistake on :P

tcrt5000basedencoder-corrected2.png



I understand how they are supposed to work, and when I do turn the wheels manually I do get/capture the black stripes lack of reflective power and the otherwise reflective power of the white stripes (rock on \m/)!

I do know, and been throught a number of quadrature posts here and elsewhere, but they only make my head hurt and for the time being I have not need of the advantages they offer, plus I’ve already done this single channel encoder detection apparatus.

So I was trying some code I’ve found in the interwebs:

// sample arduino code for getting relative speed from an encoder

// this code will print the # of encoder ticks each 1/2 second

volatile int counter = 0;

void setup(){

       attachInterrupt(0, count, RISING);

       Serial.begin(19200);

}

void loop(){

       counter=0;

       delay(500);

       Serial.print(counter);

       Serial.print("\n");

}

void count(){

       counter++;

}

 

 

My beef is that when the motors and consequently the wheels spin I get values in the serial port up to the ~500 and the comment in the code says:

"the # of encoder ticks each 1/2 second"

which either I’m thinking wrong, the wheels speed way faster than I can see or my poor encoding apparatus does not provide the resolution to keep up with the speed… my guess is “all of the above” :/ 

Remove the Delay

What use is the delay for? Remove it.

Do you expect to see the counter that increases one by one? If so (and you expect this output on the serial print: 0 1 2 3 4 5…) then: remove the delay.

Off course the counter could add 0 or more than one. So a real serial print could be: 0 0 0 1 1 2 4 5 6… . This depends on the wheel speed and so forth…

Even more simple

I gotta tell ya, I have fought these things many, many, many times. Oh, there are so many things that can go wrong, you have to really go through them one by one.

First off, gotta be sure your high is high and your low is low. I would run your sensor into an ADC and spit out the numbers in your serial monitor. Although you are reading highs and lows (using a digital channel) --for my money, I would want to know exactly how high those highs are and how low your lows are. Your adc’s might be something like <100 and >800 for a good range. I have had to screw around with the pull up on the sensor as well (to get these good highs and lows). In the end, I have found myself use really funny values --3k9 for example. You can always use a pot for testing and once you get good numbers, read the value of the pot with a meter and replace it with a resistor of the same value.

Next, I would switch to a digital input, add a LED and do a simple digitalWrite(LED_Pin,digitalRead(Encoder_Pin));  This is about as fool-proof a test as you can get. Your LED should mirror your sensor and you should be able to see everything go by, blink by blink.

Assuming all of the above went well, then I would start playing around with the interrupts and shenanagans. I have been spoiled by Propeller chips so I have not really played with interrupts that much. Then again, if you get all the hardware super-solid and you can trust it, your code will be isolated as the problem and easy to fix.

Well I guess I understand

Well I guess I understand  what you’re saying, overall that is. Now the really dumb question, what’s a ADC? embarassed.

As for the LED thing I’ve already tried something like (actually) this:

int pin = 13;

volatile int state = LOW;

void setup()

{

  pinMode(pin, OUTPUT);

  attachInterrupt(0, blink, CHANGE);

}

void loop()

{

  digitalWrite(pin, state);

}

void blink()

{

  state = !state;

}

And with manual slow turns all was well, when the motor was running there was a lot of blinking… I accurate it was, well it was hard to say.

But overall you seem to confirm my suspicions that this issue will give plenty of trouble :P 

ADC = analog

An ADC is an analog input. You can read what is coming out of your sensor to see “how high” is your high and “how low” is your low. There is an example sketch under “examples” called “AnalogInOutSerial” for doing just this. Again, it would be great if your high was >800 and your low was say, <100 or so.

I can’t stress enough doing this test. Also, it would be very wise to repeat this test while your motors are running. You gotta get the high’s really high and the low’s really low. Wicked important.

 

well I used the code as I

well I used the code as I found it, but analyzing it my perception of it is that the “delay(500)” is what makes the code match its description on “the # of encoder ticks each 1/2 second” so it would be:

loop starts; counter is zero; there’s a delay of half a second, but meanwhile the interrupt is processing the count() function and thus incrementing the counter… what I find odd is getting values up to ~500 ticks. 

So the motor is specs are supposed to be:
Speed without load: 170RMP (3V) 

Considering my wheel encoders have 4 white + 4 black stripes I should have 4 ticks per revolution, right? So I should get 170x4 = 680 ticks PER MINUTE but the code is supposed to be reading per 1/2 second so… it would be 680/120 = 5.6 … so a reasonable number would be 5-6 ticks per half second @ 3V. Even considering I’m powering the motors with over 8V … the number shouldn’t increase that much I guess.

Still I guess I’m going to follow Chris’ “hardware debugging” strategy up until I revisit the code. 

Roger that, I guess now I

Roger that, I guess now I should be regretting cutting short on the arduino tutorial lessons cough I should have suspected the blinky program wasn’t enough for me to face all the challenges :slight_smile: I’ll try it then.

sensor = 31 output =

sensor = 31 output = 7

sensor = 31 output = 7

sensor = 31 output = 7

sensor = 31 output = 7

sensor = 34 output = 8

sensor = 721 output = 179

sensor = 407 output = 101

sensor = 29 output = 7

sensor = 33 output = 8

sensor = 630 output = 157

sensor = 31 output = 7

sensor = 430 output = 107

sensor = 470 output = 117

sensor = 31 output = 7

sensor = 765 output = 190

sensor = 31 output = 7

sensor = 40 output = 9

sensor = 680 output = 169

sensor = 30 output = 7

sensor = 558 output = 139

sensor = 32 output = 7

sensor = 33 output = 8

sensor = 791 output = 197

sensor = 31 output = 7

sensor = 520 output = 129

sensor = 561 output = 139

sensor = 31 output = 7

sensor = 727 output = 181

sensor = 30 output = 7

sensor = 31 output = 7

sensor = 631 output = 157

sensor = 31 output = 7

sensor = 691 output = 172

sensor = 42 output = 10

sensor = 31 output = 7

sensor = 768 output = 191

sensor = 31 output = 7

sensor = 31 output = 7

sensor = 727 output = 181

sensor = 30 output = 7

sensor = 38 output = 9

sensor = 644 output = 160

sensor = 31 output = 7

sensor = 756 output = 188

sensor = 34 output = 8

sensor = 31 output = 7

sensor = 773 output = 192

sensor = 31 output = 7

sensor = 32 output = 7

sensor = 709 output = 176

sensor = 29 output = 7

sensor = 440 output = 109

sensor = 63 output = 15

sensor = 31 output = 7

sensor = 770 output = 191

sensor = 31 output = 7

sensor = 33 output = 8

sensor = 734 output = 182

sensor = 31 output = 7

sensor = 475 output = 118

sensor = 245 output = 61

sensor = 29 output = 7

sensor = 564 output = 140

sensor = 30 output = 7

sensor = 32 output = 7

sensor = 773 output = 192

sensor = 31 output = 7

sensor = 183 output = 45

sensor = 676 output = 168

sensor = 31 output = 7

sensor = 709 output = 176

sensor = 31 output = 7

sensor = 29 output = 7

sensor = 598 output = 149

sensor = 30 output = 7

sensor = 37 output = 9

sensor = 746 output = 185

sensor = 31 output = 7

sensor = 667 output = 166

sensor = 117 output = 29

sensor = 30 output = 7

sensor = 720 output = 179

sensor = 30 output = 7

sensor = 30 output = 7

sensor = 609 output = 151

sensor = 30 output = 7

sensor = 351 output = 87

sensor = 624 output = 155

sensor = 31 output = 7

sensor = 735 output = 183

sensor = 32 output = 7

sensor = 31 output = 7

sensor = 719 output = 179

sensor = 29 output = 7

sensor = 33 output = 8

sensor = 660 output = 164

sensor = 30 output = 7

sensor = 690 output = 171

sensor = 42 output = 10

sensor = 31 output = 7

sensor = 746 output = 185

sensor = 31 output = 7

sensor = 31 output = 7

sensor = 715 output = 178

sensor = 29 output = 7

 

that’s a sample of the output with the motor running… as it seems, my high isn’t high enough :s  while turning the wheel manually I got values in the range of 32-44 and as for the highest high I’ve seen was 796 but up from 500 and some I guess up until that one. So does this means I have to handcraft a more sensity sensor?

Bingo.

Your high is not high. It is around 2.5v --dead smack in the middle of high/low. Your low looks really good actually.

Now, I have to do some guessing on how you have this hooked up. I would assume you have the IR sensor going to ground and the pull-up resistor is going to +. If this is the case, then the pull-up resistor is not pulling hard enough. You may want to switch to a resistor with a smaller value.

An even better idea is to use a pot for your pull-up resistor. This way, you can run your sensor into an ADC channel (like you did above) and then adjust the pot until you get numbers you like. When you do, disconnect the pot, measure it and replace it with a resistor of equal value.

Beyond this, you may also want to play with the distance the sensor is away from your encoder disc. Basically, your black is not black enough. If you pull your sensor away, you may still get the low you have now (when reflecting off of white) but reflecting even less on the black (to get your high higher).

No good way of doing all this --Just gotta play with distance, just gotta play with the value of the pull up.

 

Ugg… Interrupts

#define sensorPin 1 //whatever pin you are using

int remColor;
int colorNow;
int count;

void setup()
{
  pinMode(sensorPin,INPUT);
  Serial.begin(19200);
  remColor=digitalRead(sensorPin);
}

void loop()
{
  colorNow=digitalRead(sensorPin);
  if (colorNow != remColor)
  {
    count++;
    Serial.print("Click! ");
    Serial.println(count);
    remColor=colorNow;
  }
}

What the hell, let’s try analog.

// be sure you are plugging into one of the analog sensors! Double check the pin you use in #define yadda-yadda

#define sensorPin A1 //whatever pin you are using (analog)

#define white 100 // below this we will consider white (you can play with changing this number)
#define black 900 // above this we will consider black (play with this too)

int remColor;
int colorNow;
int count;


void setup()
{

  Serial.begin(19200);
  readSensor();
  delay(1000);
}

void loop()
{
  readSensor();
  if (colorNow != remColor)
  {
    count++;
    Serial.print("Click! ");
    Serial.println(count);
    remColor=colorNow;
  }
}

void readSensor()
{
  int temp;
  temp=analogRead(sensorPin);
  if (temp<white)
  {
    colorNow=0;
  }
  if (temp>black)
  {
    colorNow=1;
  }
}

Your schematic is wrong.

Your schematic is wrong. Change the photo transistor pins with the IR LED pins. The IR LED needs the smaller resistor, and the output of the photo transistor should be connected to Data pin. I totally agree with CtC in using the A/D input instead of a interrupt pin.

ahh it’s just the the

EDIT: Uploaded corrected schematics. :slight_smile:

ahh it’s just the the original picture I’ve scavenged has the TCRT5000 drawn wrong, in truth the IR LED & phototransistor are indeed switched around. I’ll correct the drawing after lunch (at the other computer were the original is).

Ok, the code is pretty

Ok, the code is pretty simple to get (last night I was just using it based on copy/paste faith). So, define color threshold values, and then check for them, each change given the chosen limits adds one up to the counter.

That said, I’ve remasked the sensor with black tape, and although I get lower highs (500-600) using this strategy I could pinpoint the lower bound for the HIGH and if there’s no crossover between that bound and the higher bound for the LOW, there should not be a problem, right? That’s what you were trying to achieve I guess, no?

Also, this code translate into “final” code, right? I mean I can use both digital and analogue pins at the same time, or not really? or I can but there might be some possible troublesome caveats?

Based on your schematic, I

Based on your schematic, I think you have your detector wired incorrectly. V+ and GND should be swapped.

A quck test to see if your IR LED is emitting is to look at it with a digital camera. Most cameras will pick up IR LEDs as a blue glow.

Nevermind: Apparently you know the drawing is wrong, but you have it hooked up right.

Indeed, as it seems I’m

Indeed, as it seems I’m getting quite good at doing things wrong :wink: This time around (3rd, 2nd correction) hopefully everytime is now well, in that it actually mirrors what I’ve done, not that it’s appropriate :slight_smile:

I am using the TCRT5000 as a

I am using the TCRT5000 as a distance sensor for my R2D2 clone. The readings are best in 5 to 15mm distance. Below or above that it’s messy. Try to adjust the distance to the wheel encoder disk.

adjusted it, however now my

adjusted it, however now my current problem as it seems is dealing with bouncing signals… oh the pain

Analog or digital?

A question somewhat on topic for lumi… I’m trying to use the TCRT5000 as a distance sensor too. Is your’s hooked up to an analog pin or are you using it as a digital sensor? I’m lacking ADC pins so I’m looking for that sweet on/off distance as well.

Well, I had only one pin

Well, I had only one pin left and this was the (sneeking in my code :slight_smile: ) analog pin 1 (leg #7). I did not try to hook it up as a digital sensore and I believe you can’t without setting up a A/D circuit.