Arduino encoder wheel missing counts at startup.

Go To Last Post
72 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tldr: The question is: why am I getting missing counts for the first encoder wheel movement?

 

I have an Arduino related question that I am asking on avrfreaks because I think the problem may be something deeper than is usually dealt with on the Arduino forum.

 

I am designing a robot that will use the Arduino to drive motor speed using PWM and will control that speed by reading a DIY 32 slot encoder made from 3mm plywood and cut out with a laser cutter.

 

32 slot encoder wheel

 

 

CUBOT bottom view

 

This is a not very good photo that shows that the wheel is on one side of the motor and the encoder wheel is on the other side in the middle of the robot. Not visible are two slot photo interrupters that measure the encoder wheel movement. At this point, I am only testing the left wheel/encoder.

 

The problem is that when I run the code listed next, which runs the wheel forward 64 counts (two per slot - rising and falling) then reverse 64 and forward again 64, the wheel will very precisely do the second and third move, but the first move will be off randomly between 5 and 15 or so counts. That is I'll start the motor with the encoder at 0, the first turn which should come round to zero instead stops at say 10, then the next turn in reverse brings it right back to 10 and the next forward turn again goes right round to 10. So the system is capable of precisely counting the 64 rise and fall pulses, it just can't get the first turn correct. Here is the code:

 

#include <Arduino.h>

// Motor_Command_Tester Joe Pardue 3/26/16

#define LEFTSPEEDPIN 10 // PWM pins connected to H-Bridge enable pins
#define LEFTDIRECTIONPIN 8 // Digital pins connected to schmitt trigger 7414
#define INT0 0 // INT0 is on pin 2 in the UNO
#define FORWARD 0
#define REVERSE 1

volatile int leftDirection = FORWARD;
volatile int leftSpeed = 127;
volatile int leftDone = true;
volatile int leftCount = 0;
volatile int leftSteps = 0;

int once = true;
int count = 0;
int loopCount = 0;

void setup()
{
   // set up the serial port
   Serial.begin(9600);
   Serial.println("Motor_Command_Test rev. 0.10");

   // Left motor drive pins
   pinMode(LEFTDIRECTIONPIN, OUTPUT);
   
   // Left motor encoder
   pinMode(2, INPUT); 
   attachInterrupt(INT0,interrupt0,CHANGE);
}

void loop()
{
  // Run left motor back and forth and back
  if(once){
   
    leftDone = false;
    goLeft(64, FORWARD, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000); 
   
    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000);
   
    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000); 
   
  }
  once = 0;
}

void goLeft(int lStps, int leftDir, int leftSpd)
{
    leftDone = false;
    leftSteps = lStps;
    setLeftMotor(leftSpd, leftDir);  
}

// Set Motors Directions and Speeds
/**********************>0<************************/
boolean speedInRange(int speed)
{
  if ( speed <= 255 && speed >= 0){ return true;}
  else return false;
}

void setLeftMotor(int leftSpeed, int leftDirection)
{
  if ( speedInRange(leftSpeed) )
  {
    digitalWrite(LEFTDIRECTIONPIN, leftDirection);
    analogWrite(LEFTSPEEDPIN, leftSpeed);
  }
  else
  {
   if ( !speedInRange(leftSpeed) ) Serial.println("Left Speed not in 0 to 255 range.");
  }
}

// This function is called when an external interrupt
// occurs on the pin indicated by attachInterrupt
void interrupt0()
{
  leftCount++;
  if(leftCount >= leftSteps)
  {
    digitalWrite(LEFTSPEEDPIN, LOW);               
    leftDone = true;
  }
}

 

And here is a the eagle schematic: 

 

The question is: why am I getting missing counts for the first wheel movement?

 

I think I've tried all the obvious stuff.

 

First, I thought it was the hardware and went to great lengths as you can see from the schematic to quieten the circuit. Not shown in the schematic are the four diodes I added to lessen motor kickback. I've looked at the circuit with a good digital scope and it is very quiet when running.

 

I have spent several days rewriting the code with every thing I could think of or find on the Internet that might fix the problem. The only thing I've seen that might be helpful was a post on how to cure the missing encoder count problem that the author writes a new library and modifies some low-level Arduino timer stuff. It is a fairly dense solution and can't be used with a raw Arduino.

 

My tendency at this point is to declare that this is due to something under the hood in the Arduino, likely in how it handles timers, that if fooling around in the background when a program starts that interferes with the interrupt count. Once the program has start and run for a moment, the background stuff is all set and the problem doesn't happen again.

 

If I am correct, then this sort of thing can't be done with a standard Arduino and rather than try to shoe-horn in a solution that breaks the Arduino, I'd be inclined to just write my own code from scratch and load it to the Atmega328p on the Arduino board and completely ignore/remove the Arduino code.

 

However, before I take that drastic cure, I would like to see if anyone has any ideas that I've missed that might make this work with the standard Arduino. So for anyone just waking up:

 

tldr: The question is: why am I getting missing counts for the first encoder wheel movement?

This topic has a solution.
Last Edited: Mon. Apr 11, 2016 - 04:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The first thing I see different between the first attempt and the others is the motor direction.  What happens if you go reverse the first time and forward the second two loops?  Does it still get the error only the first time?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the input. However, I tried that and it didn't make any difference. I even tried spoofing it by first ticking it back and forth 1 step for 5 to 10 steps then going full bore at 64 and it still makes the first 64 randomly larger. I also set it to rising and went 32 steps and falling and went 32 steps - same problem. And I've tried smaller turns, like 10 or 20 steps. Each time the first turn screws up. 

 

I'd give up, but the turns after the first one are scary precise for a slapped together thing like this, so it seems worth figuring out.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not sure how it works, it looks like you have defined the interrupt on pin 0 (D0), but only pins 2 or 3 (D2, D3) are usable for external interrupts?

 

 

Board Digital Pins Usable For Interrupts

Uno, Nano, Mini, other 328-based

2, 3

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

I'm not sure how it works, it looks like you have defined the interrupt on pin 0 (D0), but only pins 2 or 3 (D2, D3) are usable for external interrupts?

 

 

Board Digital Pins Usable For Interrupts

Uno, Nano, Mini, other 328-based

2, 3

The attachInterrupt function sets the pin based on the interrupt number. This is done under the hood and the pin depends on the Arduino. In the UNO, interrupt 0 is located on pin 2. Yeah, real intuitive...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I'm not sure what's wrong, but in the interest of carrying the ball a bit further…

 

The leftDone assignments in loop() are not needed: leftDone is reset in goLeft() anyway.

  // Run left motor back and forth and back
  if(once){
   
    leftDone = false;
    goLeft(64, FORWARD, 190);
void goLeft(int lStps, int leftDir, int leftSpd)
{
    leftDone = false;

 

leftDone is used to communicate between normal (loop) and interrupt (interrupt0) context, yet it is not accessed atomically. Try using a byte instead if an int.

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

smileymicros wrote:
but the first move will be off randomly between 5 and 15 or so counts. That is I'll start the motor with the encoder at 0, the first turn which should come round to zero instead stops at say 10, then the next turn in reverse brings it right back to 10…

Is the error always in the same direction? In other words, does the "first turn" always stop short or does it sometimes overshoot?

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I have seen many bad SW encoders, so just to see if it's HW or SW.

 

Is that at boot, or from any standstill ?

 

Are the output of the 7414 correct when it count is wrong?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

netizen wrote:

I'm not sure what's wrong, but in the interest of carrying the ball a bit further…

 

The leftDone assignments in loop() are not needed: leftDone is reset in goLeft() anyway.

  // Run left motor back and forth and back
  if(once){
   
    leftDone = false;
    goLeft(64, FORWARD, 190);
void goLeft(int lStps, int leftDir, int leftSpd)
{
    leftDone = false;

 

leftDone is used to communicate between normal (loop) and interrupt (interrupt0) context, yet it is not accessed atomically. Try using a byte instead if an int.

Thanks for catching this. I rewrote the code about a thousand times leaving in all kinds of commented out crap. At the last minute before posting here I striped it down to the basics, hoping it would make things clearer. 

 

Also, your idea to make leftDone atomic is very good. I'm not sure how that would create the problem I'm seeing, but it is a good practice that I missed, so I will add that and hope it makes a differenct.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I have seen many bad SW encoders, so just to see if it's HW or SW.

 

Is that at boot, or from any standstill ?

 

Are the output of the 7414 correct when it count is wrong?

I think I did all my tests as one go through the loop() function. This lead me at one point to think that entry into the loop() function is causing something hinky to go on in the background when it first starts up, so I moved the code to the startup() function with the same results. However, I'm not sure if I ran the forward backward sequence, then pause for a while before running it again. I'll try that with a one minute delay before repeating and see if I get the same results. 

 

The 7414 looked clean on a digital scope, but I am going to borrow a logic analyzer from a friend to see if I can capture the first few seconds of the signal.

 

Thanks for looking at this. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Is the robot moving when you run this test?  Or are the wheels jacked up?

 

If it's moving, do you always start from the same location?  Is the lighting always the same?

 

Where I'm headed here is back in the day when I was doing things like mini-sumo, the sunlight shining through windows could change the operation of some of the robots, mine included.  The IR reflective senors reacted differently depending on where the sunlight was hitting the arena rings.  I learned to pick the shadow side or block the sunlight with my body, while the bots were running.

 

So is it possible the robot moves into a different lighting condition during the run?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I noticed the failure when I programmed it to run a square. First run was off, while the rest seemed spot on. I took it apart and am now testing it on a table under a really bright shop light that probably leaks all kinds of modulated IR. I am using slot photo interrupters which are transmissive, not the reflective kind. I tried those a few years ago and dropped them in favor of increased mental health. They are great for line following, but couldn't get them to work with a reflective encoder and I may not have tried hard enough. I'll go ahead and seal up my test and try it in the dark to see if that makes a difference. 

 

Thanks for the suggestions.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Sorry to insist, but you haven't answered this question:

netizen wrote:

smileymicros wrote:
but the first move will be off randomly between 5 and 15 or so counts. That is I'll start the motor with the encoder at 0, the first turn which should come round to zero instead stops at say 10, then the next turn in reverse brings it right back to 10…

Is the error always in the same direction? In other words, does the "first turn" always stop short or does it sometimes overshoot?

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

My first instinct was "uninitialised automatic".  However, you don't have >>any<< automatics at all.

 

The problem is that when I run the code listed next, which runs the wheel forward 64 counts (two per slot - rising and falling) then reverse 64 and forward again 64

Are you sure?:

 

    leftDone = false;
    goLeft(64, FORWARD, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000);

    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000);

    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000);

 

I'm also suspicious of the non-atomic accesses to:

leftSteps

leftDone (already mentioned)

leftCount

 

 

There is also potential for confusion with the global LeftSpeed and the local by the same name (although that's a separate issue).

 

There is also insufficient handling of 'run-on' after the motor is commanded off, in that the value of LeftCount is zeroed in loop(), but can still be incremented by the ISR before the next motor move is commanded.  I suspect this the most.

 

In general, I think the division of labour between loop() and the interrupt handler is confusing i.e. loop() initiates the motor move, but the handler stops it.  Flags and counters are also handled asymetrically in this way.  If it were me, I'd only ever use the handler to count encoder pulses.  All of the other logic (checking count against a limit, waiting for motor to spin down, resetting counters, etc.) should be handled in loop().

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Apr 6, 2016 - 08:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

joeymorin wrote:
There is also insufficient handling of 'run-on' after the motor is commanded off, in that the value of LeftCount is zeroed in loop(), but can still be incremented by the ISR before the next motor move is commanded. I suspect this the most.

Agreed, this could minimally be dealt with something like this:

void interrupt0()
{
  if (leftdone) return;
  leftCount++;
  if(leftCount >= leftSteps)
  {
    digitalWrite(LEFTSPEEDPIN, LOW);               
    leftDone = true;
  }
}

… because reseting leftCount in ISR would not prevent it from being incremented again when the event next triggers.

However, I don't see any reason for this problem to trigger on the first "run" any more than on any subsequent one…

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

joeymorin wrote:

The problem is that when I run the code listed next, which runs the wheel forward 64 counts (two per slot - rising and falling) then reverse 64 and forward again 64

Are you sure?:

That is most likely a typo, and very unlikely related to the random "first run" issue.

ɴᴇᴛɪᴢᴇᴎ

Last Edited: Wed. Apr 6, 2016 - 09:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

That is most likely a typo, and very unlikely related to the random "first run" issue.

Yes, but it suggests the OP is re-typing, rather than copy/pasting... so I ask again:  Are you sure?

 

Agreed, this could minimally be dealt with something like this:

That doesn't address run-on.  It simply eliminates any counting thereof.

 

However, I don't see any reason for this problem to trigger on the first "run" any more than on any subsequent one…

If run-on is resulting in inaccurate counts, it would be due to the inertia of the motor/wheel system.  That inertia would be constant for a constant speed i.e. PWM value.  After the error on the initial leg, subsequent legs would be similarly offset by the same error, making them appear accurate when in reality they suffer from the same run-on also.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Joe, I found a flaw in the encoder hardware: when the gap passes the photo interrupter at low speed, the output oscillates. Since you are using interrupts (as far as I can see, and that's not much right now .... different chapter), that could explain the behaviour,

My HW uses a comparator, yours uses a Schmitt trigger LS14 with 680k pull-up on the opto transistor: I suggest to hook the output up to a Logic Analyzer; choose a high samplerate, 20 ~ 50 MHz

 

Another issue may be: The rush-in current of the DC-motor could make the battery voltage dip so hard that Vcc dips too.

 

My 2 4 cents

 

Nard

 

Edit: No HC14 but LS14, and supply issues added

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

Last Edited: Wed. Apr 6, 2016 - 10:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Plons wrote:
Joe, I found a flaw in the encoder hardware: when the gap passes the photo interrupter at low speed, the output oscillates.

That's interesting. That's the kind of behavior my question about "same direction error" was meant to enlighten. I suspected it would only run short (as opposed to overshoot) because of hardware/software "bouncing".

 

joeymorin wrote:

That is most likely a typo, and very unlikely related to the random "first run" issue.

Yes, but it suggests the OP is re-typing, rather than copy/pasting... so I ask again:  Are you sure?

OP has explained he tried many different things and the current code might have a few glitches like this, not accurately representing the described behavior. Worth asking though. :)

 

joeymorin wrote:
That doesn't address run-on.  It simply eliminates any counting thereof.

Yes, it's only a short-sighted solution to specifically address the current "first run" issue. I'm not sure I understand what you mean by "run-on"? Inertia making wheels turn after motor is turned off?

 

joeymorin wrote:

However, I don't see any reason for this problem to trigger on the first "run" any more than on any subsequent one…

If run-on is resulting in inaccurate counts, it would be due to the inertia of the motor/wheel system.  That inertia would be constant for a constant speed i.e. PWM value.  After the error on the initial leg, subsequent legs would be similarly offset by the same error, making them appear accurate when in reality they suffer from the same run-on also.

In this hypothesis you'd see systematic overshoot on first run, am I right?

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I'm not sure I understand what you mean by "run-on"? Inertia making wheels turn after motor is turned off?

Correct.

 

Yes, it's only a short-sighted solution to specifically address the current "first run" issue.

If I'm onto the root cause, your addition check might reveal this by causing >>all<< legs to exhibit overshoot.  That would be progress, of a kind.

 

In this hypothesis you'd see systematic overshoot on first run, am I right?

Systematic, yes.  Reproducible, not necessarily.  OP sees overshoot of between 5 and 15 counts, although how that's determined hasn't been shown.  The current serial reporting would be made before the motor had come to a stop.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Apr 6, 2016 - 11:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

joeymorin wrote:
OP sees overshoot of between 5 and 15 counts

I couldn't conclude as you did from the initial description:

smileymicros wrote:
the first move will be off randomly between 5 and 15 or so counts

To me, this does not imply overshoot only. But perhaps my limits in understanding English have been reached.

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

joeymorin wrote:
If I'm onto the root cause, your addition check might reveal this by causing >>all<< legs to exhibit overshoot. That would be progress, of a kind.

I would definitely call that a progress indeed, as it would then make clear it is a run-on issue (not specifically tied to the first leg). I believe we're still trying to get that first hint as to what the hell the problem is. When the core issue is clear, I expect the solution to be rather easy.

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

netizen wrote:

I couldn't conclude as you did from the initial description:

 

smileymicros wrote:

The problem is that when I run the code listed next, which runs the wheel forward 64 counts (two per slot - rising and falling) then reverse 64 and forward again 64, the wheel will very precisely do the second and third move, but the first move will be off randomly between 5 and 15 or so counts. That is I'll start the motor with the encoder at 0, the first turn which should come round to zero instead stops at say 10, then the next turn in reverse brings it right back to 10 and the next forward turn again goes right round to 10. So the system is capable of precisely counting the 64 rise and fall pulses, it just can't get the first turn correct. Here is the code:

i.e.: 0, 1, 3, ... 62, 63, 64(0), 1, 2, 3, ... 8, 9, 10

 

If it were (possibly also) undershoot, I'd expect the report to be worded as "instead stops at say 54".

 

I infer overshoot.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

What about 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10? It wouldn't have come round to zero either and would have stopped at 10 too.

So we currently have two hypothesis: one (Plons') based on a hardware glitch which, if I understand correctly, would imply systematic undershoot, and one based on (excessive) inertia which would imply systematic overshoot.

And perhaps we have them both and a random, non direction biased error. I, for one, cannot tell from the above wording.

ɴᴇᴛɪᴢᴇᴎ

Last Edited: Thu. Apr 7, 2016 - 12:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

What about 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10?

That would be off by 54-64, not off by 5-15 as reported.

 

So we currently have two hypothesis

Remember Hickam's dictum ;-)

 

We'll just have to wait for Joe.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow, thanks guys for all the analysis.

 

The two reverses are a typo due to cleaning up the code for showing here. It actually is forward, reverse, forward and etc. I ran this out a bunch of times to make sure it stays accurate.

 

The problem is the same for starting in either directions.

 

I did a bunch of tests where all I did in the interrupt was increment the count, but now love there.

 

I'm not sure how atomicity would make this happen, but it is indeed bad coding on my part to omit it and I will make that change and test to see if it helps.

 

Plons: the circuit was initially noisy and I added the schmitt triggers and diodes (not show) and now have what appears to be a fairly clean signal. I will be borrowing a logic analyzer to take a hard look at the initial sequence. Also, I'll look into the comparator solution. And your statement implies that you got one if these working. If so, was it with an Arduino? If so or not would you care to share your solution?

 

If I missed anything, I apologize. I will reread all this tomorrow and take notes to make sure I got everything, then start some new tests.

Last Edited: Thu. Apr 7, 2016 - 03:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Of course I am willing to share the solution. Tomorrow I hope to have full sight back (had an eye surgery last week) and look up what I have: it's in my first robot project and it has been on hold for a while. Bot's brain is an Arduino but I program in BascomAVR, not Arduino C++. For the solution the language is irrelevant. Of course.

Since you have nothing else to do: hook up a scope to Vcc and use a port-pin to trigger the scope on the second channel the moment you engage the engine wink

Very likely you'll see a dip or spikes on Vcc. It looks like you use the same motorcontroller board as I do: small, nice, stay cool but brute on current spikes on Vmotor. PWM drive

 

Glad to see your face again. I still remember your own comment when you started using this picture. And that brings a smile on my face. You'd never guessed that !

 

Nard,

I'll be back in 10 hours

(and should be asleep now)

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

Last Edited: Thu. Apr 7, 2016 - 03:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Nard,

I'll be back in 10 hours

(and should be asleep now)

You most certainly should! ;-)

 

 

 

(taken 23 minutes after your edit)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Slept just 1 hour. It's gonna be a tough day.

 

Found the schematic of the speedsensor:

 

 

I attach my Bascom program: as you can see it's still in preliminary HW test phase.

 

My bot uses just 1 speedsensor per wheel. I wanted to use 2 but mechanically that was hard to do. Since it's my first one, I could and still can live with that.

 

-------------------------------------------------------------

 

Back to Joe's problem:

 

If it is really a 74LS14 you are using, the Voh may be on the edge of what the AVR sees as a high.

Easy fix: replace 74LS14 with 74HCT14.

Or add 4k7 ~ 10k pull-up on the LS14 outputs.

 

The 680k to Vcc on the transistor of the photo interrupter: I recommend 10k to 3.3V provided by the Arduino.

1. 680k is very high as collector impedance and 2.  the Arduino 3.3V will be much quieter than the 5V.

 

I see no reason to move to a comparator, Joe. Not yet. Try the small modifications I suggested and then let's see what happens.

You mentioned earlier a diode that was not shown in the schematic. Where did you put it ?

 

If I am not mistaken, you have 2 speed sensors per wheel. That allows you to detect direction. But did you adjust the distance between the 2 photo interrupters to achieve a 90 degrees shift between the 2 outputs ?  Yeah, I reread.

 

Nard

 

 

Edit: added picture of modified speed sensor

Attachment(s): 

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

Last Edited: Thu. Apr 7, 2016 - 09:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I looked at the schematic, the 680k pull ups on the opto collectors, are perhaps 200 times greater than my gut would use. The result could be poor noise immunity, and sluggish rise, times, or failure to rise.

It all starts with a mental vision.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oops, too late, our posts crossed.

It all starts with a mental vision.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is getting long and dense so I am going to summarize some of my answers to queries and the results of the suggestions I tried. If I missed anything, please forgive me.

 

The four diodes not shown in the schematic: two on the motor power line, one to ground and one to Vcc. Likewise for the motor ground line. I added these thinking there may be motor induction spikes, but they made no difference.

 

The motor driver circuits are on a separate 6 volt supply (well, 4 fresh AA batteries anyhow). However, the first set of tests were using the Arduino powered from a PC and had the same results.

 

The problem occurs whether the motor is started FORWARD or REVERSE.

 

Turning off the house lights doesn't do anything.

 

Disabling interrupts before shutting down the motor had no effect.

 

I just tested this with a 60 second delay at the beginning of the loop() function, then I ran the forward reverse cycle twice with 2 second pauses so I could see the count on the wheel, then the loop() went to the top and paused 60 seconds, and repeat forever. I observed that a 60 second delay causes the problem to repeat each time for the first run. So it probably isn't something happening in the background when the loop() first starts.

 

Each of the four runs reports a count of 64, even though the encoder wheel doesn't agree on the first turn.

 

30 second wait, less of a problem than after reset or 1 minute.

 

10 second wait, problem only happens on reset. NO, while I was typing this it got off a couple of steps. Again, this was a gain in position.

 

Also, it seems the slower the speed, the less is the first turn offset.

 

The Schmitt trigger inverter is 74HC14 - from a very old junk box - but the signal looks good on a scope.

 

Plons suggested adding 10k pullup to 74HC14 outputs. Tried it and no luck.

Plons suggested that instead of the 680k pullup on the 74HC14 input, I try 10k to the Arduino 3.3 volt. Tried it and no luck.

I noticed that when the 680k resistor was absent, it made no difference to the behavior.

Somebody suggested substituting a 10k pullup for the 680k. Tried it and the thing went crazy. Every circuit was off random amounts. This got me excited so I tried a bunch of different pullup values but nothing fixed the problem.

 

So, next step is to take it over to a friend's lab that is better equipped than mine (as is his brain) and see what we can see or think up.

 

Thanks for all the help so far.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I just tested this with a 60 second delay at the beginning of the loop() function, then I ran the forward reverse cycle twice with 2 second pauses so I could see the count on the wheel, then the loop() went to the top and paused 60 seconds, and repeat forever. I observed that a 60 second delay causes the problem to repeat each time for the first run. So it probably isn't something happening in the background when the loop() first starts.

 

Each of the four runs reports a count of 64, even though the encoder wheel doesn't agree on the first turn.

 

30 second wait, less of a problem than after reset or 1 minute.

 

10 second wait, problem only happens on reset. NO, while I was typing this it got off a couple of steps. Again, this was a gain in position.

All of this suggests to me you might be getting false edges on the encoder.  The longer you wait, the more false edges you see, the greater the observed offset.

 

So your loop is:

void loop() {

    delay(60000);

    leftDone = false;
    goLeft(64, FORWARD, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000); 

    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000);

    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("count = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000); 

}

I would propose:

void loop() {

    delay(60000);

    Serial.print("1st: count before = ");
    Serial.println(leftCount);
    leftDone = false;
    goLeft(64, FORWARD, 190);
    while(!leftDone);
    Serial.print("1st: count after  = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000); 

    Serial.print("2nd: count before = ");
    Serial.println(leftCount);
    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("2nd: count after  = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000);

    Serial.print("3rd: count before = ");
    Serial.println(leftCount);
    leftDone = false;
    goLeft(64, REVERSE, 190);
    while(!leftDone);
    Serial.print("3rd: count after  = ");
    Serial.println(leftCount);
    leftCount = 0;
    delay(2000); 

}

This, combined with a scope/LA, may help to reveal some gremlins.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Thu. Apr 7, 2016 - 07:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Joey, I'll try your suggestion.

 

And I forgot to add that I've modified the code based on ya'll's observations, mainly to have the interrupt only count and to simplify things slightly:

#include <Arduino.h>

// Motor_Command_Tester Joe Pardue 3/26/16

#define LEFTSPEEDPIN 10 // PWM pins connected to H-Bridge enable pins
#define LEFTDIRECTIONPIN 8 // Digital pins connected to schmitt trigger 7414
#define INT0 0 // INT0 is on pin 2 in the UNO
#define FORWARD 0
#define REVERSE 1
#define STEPS 64
#define SPEED 190

volatile int leftDirection = FORWARD;
volatile int leftSpeed = 127;
volatile int leftDone = true;
volatile byte leftCount = 0;
volatile byte leftSteps = 0;

int once = true;
byte count = 0;
byte loopCount = 0;

void setup()
{
   // set up the serial port
   Serial.begin(9600); 
   Serial.println("Motor_Command_Test rev. 0.10"); 

   // Left motor drive pins 
   pinMode(LEFTDIRECTIONPIN, OUTPUT);
    
   // Left motor encoder
   pinMode(2, INPUT);  
   attachInterrupt(INT0,interrupt0,CHANGE); 
}

void loop()
{ 
  // Run left motor back and forth and back
  //if(once){
    // Run three times then delay for one minute. Repeat
    
    for(int i = 0; i <= 5; i++)
    {
      goLeft(STEPS, REVERSE, SPEED);
      delay(2000);  
      
      goLeft(STEPS, FORWARD, SPEED);
      delay(2000);
    }
    delay(10000); // delay 10 seconds    

}



void goLeft(int lStps, int leftDir, int leftSpd)
{
    leftSteps = lStps;
    setLeftMotor(leftSpd, leftDir);   

    // Do nothing until steps are finished
    while(leftCount < leftSteps);

    digitalWrite(LEFTSPEEDPIN, LOW); 
     
    Serial.print("count = ");
    Serial.println(leftCount); 
                     
    leftCount = 0;

 
}

// Set Motors Directions and Speeds
/**********************>0<************************/
boolean speedInRange(int speed)
{
  if ( speed <= 255 && speed >= 0){ return true;}
  else return false;
}

void setLeftMotor(int leftSpd, int leftDirection)
{
  if ( speedInRange(leftSpd) )
  {
    digitalWrite(LEFTDIRECTIONPIN, leftDirection);
    analogWrite(LEFTSPEEDPIN, leftSpd);
  }
  else
  {
   if ( !speedInRange(leftSpd) ) Serial.println("Left Speed not in 0 to 255 range.");
  }
}

// This function is called when an external interrupt
// occurs on the pin indicated by attachInterrupt
void interrupt0()
{
  leftCount++;
}


 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

A 74HC14 behaves different than a 74LS14. Especially in a design where it is the front-end of an analog event (a photo-interrupter is an analog beast)

My recommendations are based on the information you provide. If the info is not correct .....

A pull-up of 10k tot 3.3V supply is a correct advice for both a 74LS14 and a 74HCT14. Not for a 74HC14. There you must use a pull-up to 5V supply.

 

So now we know that the motors have their own supply. Where do the grounds of Arduino board, motor batteries and motor controller meet ? IOW: where did you put the ground-starpoint ?

Is the 74HC14 close to the photo interrupter fork ? It should be. Proper decoupling is crucial in a noisy environment like this.

 

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 mainly to have the interrupt only count

Which is good.  It simplifies things, including the things which can go wrong.

 

This bit here:

    // Do nothing until steps are finished
    while(leftCount < leftSteps);

    digitalWrite(LEFTSPEEDPIN, LOW);

    Serial.print("count = ");
    Serial.println(leftCount);

    leftCount = 0;

... may prove interesting.  You'll be waiting for leftCount to reach a threshold value (64), after which you will:

  1. stop the motor
  2. Print out a report
  3. reset the count to 0

 

Those three steps will take at most a few dozen microseconds.  Meanwhile, the motor's momentum will (likely) result in several additional pulses coming in via the encoder until it comes to a complete stop.  The code I proposed earlier may reveal this.

 

This doesn't preclude to possibility that there are other issues, including the hardware issues which have already been discussed.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

THANK YOU JOEY MORIN!!!

 

The problem isn't fully solved, but your suggestion totally changed things and allowed me to make the system much more repeatable (not to say accurate, but may come later). I used your suggestion and got:

 

 

This says that as some have suggested, the count is getting incremented while the motor isn't supposed to be moving. So I added a line to clear the count just before starting the motor:

void goLeft(int lStps, int leftDir, int leftSpd)
{
    leftSteps = lStps;
    setLeftMotor(leftSpd, leftDir);   

    // Do nothing until steps are finished
    leftCount = 0; // ADDED THIS PER JOEYMORIN SUGGESTION
    while(leftCount < leftSteps);

    digitalWrite(LEFTSPEEDPIN, LOW); 
     
    Serial.print("count = ");
    Serial.println(leftCount); 
                     
    leftCount = 0;
}

And now it is very accurate between each rotation. However, in order to get the thing to accurately rotate one full turn, I have to set the steps to 52. And while that is cause for WTF! - it none the less provides an entirely different view of the problem and gives me further avenues to explore.

 

So, as a reward, I'd like to send you an AVR Butterfly (if you want one) just message me the address. 

 

Off to try new stuff... yeah!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A new observation:

The 52 steps only works at a speed of exactly 190.

At a speed of 250 it needs 48 steps.

At a speed of 140 it needs 58 steps.

 

So there is a speed dependent, but constant number of missed steps for each full rotation.

At a faster speed, it misses more steps.

 

Unlike earlier, this happens the same way with each turn. We no longer have the problem of the start up inaccuracy. In fact, based on Joey's suggestion, we see that the later turns were also inaccurate, but just happen to land on the correct wheel position. 

 

It misses fewer steps at slower speeds, but unfortunately it won't run reliably at less than a PWM of 140. This suggest to me that the interrupt is missing steps based on the speed of the wheel, which further suggests that this isn't noise that would cause more steps to be detected. It looks to me like maybe the Arduino interrupts just can't keep up with the input - it is missing steps.

 

I've read somewhere that the Arduino external interrupt is way slower than polling in the loop(), so that suggests an alternate way to handle this - if I'm willing to do nothing but run the motor when the motor is running. That isn't ideal, but maybe it will be the only way to fix this. 

 

Or maybe even better, I can drop the Arduino attachInterrupt() and just write my own that is hardwired to the pin I'm using - that makes even more sense. Anyway, that is where I'll look next.

 

And if this new info suggests anything to anyone, I'm all ears.

Last Edited: Thu. Apr 7, 2016 - 09:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

However, in order to get the thing to accurately rotate one full turn, I have to set the steps to 52.

I'm still suspicious of run-on.  After you receive the last count (now 52), you turn the motor off, but the motor's momentum will carry it a bit further.  That is, the motor doesn't stop instantaneously.  How much further it moves after being commanded off will depend on lots of things.  The gear-down ratio, the mass of the motor, whether your driver circuitry treats 'off' as 'freewheel' or as 'brake', etc.

 

With a commanded step count of 52 yielding an observed rotation of 64 (i.e. 32 encoder slots), this suggests the motor is has a run-on equal to 12 edges, or 6 slots.  Only you know whether this seems reasonable, based on how long you assess it takes the motor to 'spin down', and how fast it is going w.r.t. the slots.

 

My next step would be to instrument the code some more, perhaps capturing and reporting events in finer detail.  For example, you could capture a timestamp for each edge, and for the 'motor-on' and 'motor-off' commands.  You could do this with millis() or micros().  After each leg, report all of the edge timestamps, as well as the timestamps 'motor-on' and 'motor-off'.  A review of that report in table form may reveal what's happening in greater detail.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The 52 steps only works at a speed of exactly 190.

At a speed of 250 it needs 48 steps.

At a speed of 140 it needs 58 steps.

This supports the 'run-on' theory.  Faster speed means greater overshoot, requiring fewer commanded steps in order to hit your intended target.  Conversely, slower speed means less overshoot, requiring more commanded steps in order to hit your target.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

but unfortunately it won't run reliably at less than a PWM of 140. This suggest to me that the interrupt is missing steps based on the speed of the wheel, which further suggests that this isn't noise that would cause more steps to be detected. It looks to me like maybe the Arduino interrupts just can't keep up with the input - it is missing steps.

I'm not certain about that.  What does 'won't run reliably' mean?  Does it mean the motor speed is unsteady at that pwm duty?  Or does it mean that you can't hit your target reliably?

 

The theory that Arduino interrupts can't keep up with a slower pulse rate doesn't really add up.  In any event, although it's true that attachInterrupt() is slower than your own ISR or even polling, in this case it should still be orders-of-magnitude faster than required for your purposes.

 

Remember that some of this may still be hardware i.e. analog sensor related.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
 What does 'won't run reliably' mean?  Does it mean the motor speed is unsteady at that pwm duty?  Or does it mean that you can't hit your target reliably?

There are very cheap motors with cheap gears. The motor stalls at below 140. You can give it a shove and it will run, but doesn't seem to be able to kick over the inertia. I've tended to think that the over run would be unlikely since these things are so sluggish I've not observed anything like coasting. Maybe I could hit it with a reverse speed of 120 that won't run the motor but might make it stop quicker? Something to try anyway.

 

And thanks again for all the help. I'll try these new ideas tomorrow.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, in case anyone on the planet didn't hear me screaming a little while ago...

 

I rewrote the code with no Arduino library support. I used pure C with avrlibc funcions. And I got EXACTLY the same problem. It isn't the Arduino functions.

 

So Joey was correct again.

 

And I'll have to wait to get access to my friends more capable electronics lab.

 

I think I'll go eat some ice cream.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Are you 100% sure that there aren't an ISR that takes so long that you can miss counts, and the chance(read risk), get's bigger, at higher speed.

And perhaps it's even your own ISR that is a part of the problem :(

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Are you 100% sure that there aren't an ISR that takes so long that you can miss counts, and the chance(read risk), get's bigger, at higher speed.

Anything is possible.

 

However, by the sounds of it, OP is using a hobby motor something like this:

https://www.creatroninc.com/product/120-1-gear-motor-5v-83pm/

 

That motor has an unloaded speed of 83 rpm @ 5V.  The OP's homebrew encoder has 32 slots per revolution, for 64 edges.  At 83 rpm, that's 1.383 rps, and 88.53 pps, or an edge every 11.3 ms.  Even if we assume a 200 rpm motor, that's still 4.69 ms between pulses.

 

That's 75,000 cpu cycles.

 

I doubt interrupt response is at the root of the problem.

 

 

There are very cheap motors with cheap gears. The motor stalls at below 140. You can give it a shove and it will run, but doesn't seem to be able to kick over the inertia.

When you get past the current hurdle, you may consider reducing the PWM frequency to improve motor torque at low duty cycles.  Default analogWrite() duty on pin 10 (TIMER1) is 490 Hz, using phase correct PWM.  If you changed the TIMER1 prescaler from /64 (CS1[2:0] = 0b011) to /256 (CS1[2:0] = 0b100) or /1024 (CS1[2:0] = 0b101), you could try 122.5 Hz and 30.6 Hz, respectively.  Changing to fast PWM, you could get 244 Hz and 61 Hz, respectively.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Apr 8, 2016 - 09:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Since you have two HC14 gates unused, modify you frontend as follows:

 

 

As far as the cheap motor+gear is concerned: those are not the cause for your problem: I use the very same.

 

When I started on my bot, I found the same issues as OP. But instead of trying to fix it in SW, I reverse-engineered the photo-interrupter circuit and modified it as previously posted. Since then, the counts from the wheel speed sensors are rock solid.

 

Testing is quite simple with an oscilloscope, normal mode, triggerlevel 2.5V, falling edge, timebase set to 2us/div, and wiggle the wheel around the point where the scope triggers. Vary the timebase setting in steps from 2us/div to 2ms/div. Do all this once more with the trigger set to rising edge.

I think it's a good idea to do these scope-tests on the current design first: that may reveal the problem.

 

I am pretty sure the circuit above will make yours work as well. But I haven't tested it. That is up to you.

 

Oh, and did you remove the protective paper on the sensor wheel ? The paper edges around the slits may cause false triggers a well.

quote:

3mm plywood lasercut

end quote

Are the edges clean ?

 

Edited: test procedure extended and added note on the protective paper on the encoder wheel

 

Nard

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

Last Edited: Sat. Apr 9, 2016 - 02:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

If the encoder is still unwilling, check Vcc when motor is started. I described that in an earlier post.

 

Attached another improvement: it will cause a kind of edge lockout of appr. 1ms. Should be okay unless you make your bot do 20+ mph. The extra network makes the positive feedback stronger, but with limited duration, timewise.

The cap is 100 nF, in case my handwriting is not clear.

 

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clean edges? They look clean to me. The cut is burned but very sharp edged.

 

I tried the improved circuit and it didn't help.

 

I'll be taking this to my friends lab tomorrow and will report those results afterward.

 

Thanks Nard

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Your friend's lab will hopefully prove enlightening.  In the meantime you may want to instrument your code a bit more.  I don't know what your current code looks like but, based on what you've posted already, here's a suggestion:

 

#include <Arduino.h>

// Motor_Command_Tester Joe Pardue 3/26/16

#define LEFTSPEEDPIN 10 // PWM pins connected to H-Bridge enable pins
#define LEFTDIRECTIONPIN 8 // Digital pins connected to schmitt trigger 7414
#define INT0 0 // INT0 is on pin 2 in the UNO
#define FORWARD 0
#define REVERSE 1
#define STEPS 64
#define SPEED 190

volatile int leftDirection = FORWARD;
volatile int leftSpeed = 127;
volatile int leftDone = true;
volatile byte leftCount = 0;
volatile byte leftSteps = 0;
volatile uint32_t edge[256];

int once = true;
byte count = 0;
byte loopCount = 0;

void setup()
{
   // set up the serial port
   Serial.begin(9600);
   Serial.println("Motor_Command_Test rev. 0.10");

   // Left motor drive pins
   pinMode(LEFTDIRECTIONPIN, OUTPUT);

   // Left motor encoder
   pinMode(2, INPUT);
   attachInterrupt(INT0,interrupt0,CHANGE);
}

void loop()
{
  // Run left motor back and forth and back
  //if(once){
    // Run three times then delay for one minute. Repeat

    for(int i = 0; i <= 5; i++)
    {
      goLeft(STEPS, REVERSE, SPEED);
      delay(2000);
      reportEdges();

      goLeft(STEPS, FORWARD, SPEED);
      delay(2000);
      reportEdges();
    }
    delay(10000); // delay 10 seconds

}


void reportEdges()
{
    int i;
    byte count = leftCount;
    
    for (i=0; i<count; i++)
    {
	Serial.print("Edge ");
	Serial.print(i);
	Serial.print(": ");
	Serial.println(edge[i]);
    }

}

void goLeft(int lStps, int leftDir, int leftSpd)
{
    leftSteps = lStps;
    setLeftMotor(leftSpd, leftDir);

    // Do nothing until steps are finished
    leftCount = 0; // ADDED THIS PER JOEYMORIN SUGGESTION
    while(leftCount < leftSteps);

    digitalWrite(LEFTSPEEDPIN, LOW);
    Serial.print("Off at: ");
    Serial.println(micros());

    Serial.print("count = ");
    Serial.println(leftCount);

    leftCount = 0;


}

// Set Motors Directions and Speeds
/**********************>0<************************/
boolean speedInRange(int speed)
{
  if ( speed <= 255 && speed >= 0){ return true;}
  else return false;
}

void setLeftMotor(int leftSpd, int leftDirection)
{
  if ( speedInRange(leftSpd) )
  {
    digitalWrite(LEFTDIRECTIONPIN, leftDirection);
    analogWrite(LEFTSPEEDPIN, leftSpd);
    Serial.print("On at: ");
    Serial.println(micros());
  }
  else
  {
   if ( !speedInRange(leftSpd) ) Serial.println("Left Speed not in 0 to 255 range.");
  }
}

// This function is called when an external interrupt
// occurs on the pin indicated by attachInterrupt
void interrupt0()
{
  edge[leftCount++] = micros();
}

 

Untested.

 

I expect what you'll see is that the timestamps of edges will extend beyond the timestamp of the motor off command, and that the time between edges will gradually get longer until the motor actually stops moving.  I think you'll also find that the time between edges immediately after the motor on command will initially be longer, gradually getting shorter until the motor reaches its steady-state speed.

 

You can capture the serial output, copy/paste it into a spreadsheet or other analytical tool, and then plot the events.  If you manage to run the above (or similar) instrumented code, post your output here and I'll whip up a graph.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Physics: Is plywood translucent for InfraRed ??

.... testing ....

No, not for the 2 different photo interrupters I tested with.

 

I scoped directly on the collector of the photo interrupter transistor, and even without extra circuitry I get decent decent 0V and 5V levels on the 10k pullup when I move the 3mm plywood in or out. 330R in series with the IRdiode to +5V

 

So ..... what's left ? Oscillation of the HC14 ? Did you put a 100nF between pin7 and pin14 ? Vcc stable and glitch free ? Did you ground the unused inputs ? Is there no short ? Correct pin numbers used ?

Long wires used ?

 

I am curious what you will find tomorrow in the lab.

 

Edit n: ambient light may disturb the signal as well. Fluorescent light and certain led lamps interfere quite happily surprise

A GIF is worth a thousend words   She is called Sylvia (2018), lives at Mint18.3 https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

Last Edited: Sun. Apr 10, 2016 - 03:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Joe. This digikey encoder has 24 ppr and is only a buck PEC12R-4025F-N0024.

 

Imagecraft compiler user

Pages