Magnetic encoder DC motor step counts HELP

I'm using the Arduino Uno and 100:1 microgear DC motors with magnetic encoders from Pololu.com. I'm trying to figure out how many "steps" correlate to one revolution of my 60x8mm wheels. The readings that are printing out are not consistent with my original step prediction. I guessed that the step count would be around 600 steps per wheel revolution since we are counting rising edges using an interrupt. The code that follows is kind of sloppy, please bare with me. I did not include all of the functions since they do not affect what's going on here.

#include <NewPing.h>
#define echoPin 4
#define trigPin 7
#define IRsensor_L A0
#define IRsensor_R A1

/***PINS***/
volatile unsigned char step_pin=2;     //encoder

const unsigned char motor1Forward=3;   //1A motor LEFT positive logic pin
const unsigned char motor1Reverse=5;   //2A motor LEFT negative logic pin

const unsigned char motor2Reverse=10; //1B motor RIGHT positive logic pin
const unsigned char motor2Forward=11; //2B motor RIGHT negative logic pin

/***VARIABLES***/
 byte logic=0;
volatile long stepCount=0;
const unsigned char power1 = 20;
const unsigned char power2 = 100;
const unsigned char power3 = 175;
const unsigned char powerMAX = 250;
unsigned int distSonor;            //Sonor 
unsigned int distIR_L;          //IR
unsigned int distIR_R;          //IR
float x;  //test raw Sonor data

NewPing sonar(trigPin,echoPin,200);  //sets up the sonar


void setup() {
  Serial.begin(9600);
  pinMode(step_pin,INPUT);
  pinMode(motor1Forward, OUTPUT);
  pinMode(motor1Reverse, OUTPUT);
  pinMode(motor2Forward, OUTPUT);
  pinMode(motor2Reverse, OUTPUT);
  pinMode(IRsensor_L, INPUT);
 pinMode(IRsensor_R, INPUT);
attachInterrupt(digitalPinToInterrupt(2), count, RISING);
  delay(3000);
}

/***MAIN***/
void loop() {
    interrupts();
drive();
  while (stepCount >= 300){ 
    halt();
  Serial.println(stepCount);
  stepCount = 0;
  Serial.println(stepCount);
  }
  delay(2000);
  /*
x=sonar.ping_cm();
distIR_L= irVal_L();
distIR_R = irVal_R();
Serial.print("IR LEFT Sensor value = ");
Serial.println(distIR_L);
Serial.print("IR RIGHT Sensor value = ");
Serial.println(distIR_R);
*/

//x=sonar.ping_cm();
//Serial.print("Sonar value = ");
//Serial.println(x);
//Serial.print("LOGIC is ");
//Serial.println(logic);   
//digitalWrite(step_pin, LOW);

}

void count(){         //ISR
  logic=digitalRead(step_pin);

  if(logic==1){
  stepCount++;

  noInterrupts();
  }

PacRat16:

  1. please bare with me.
  2. I did not include all of the functions since they do not affect what's going on here.
  1. No way.

  2. You may catch heck for that. If nothing affects anything then why not do a barebones sketch, nothing but turning and counting?

You have not told us how many pulses per revolution come from the encoder or where the encoder is attached - is it attached to the motor shaft or to the shaft the wheel is attached to.

...R

So your ISR counts one pulse and then turns off interrupts so it can't count any more? But then at some time in the future, loop() turns them back on?

No, when the ISR returns interupts will be restored (they are disabled during the ISR anyway, automatically).

The code posted stops halfway through the ISR - how can we work from that?

okay, so here is the full code. the motors we are using is DC motor 100:1 gears with a dual shaft that each holds an magnetic encoder that has a CPR of 12. Sorry for the misinformation.

First time on a forum asking for help so if you can help me out, I will appreciate it very much.

#include <NewPing.h>
#define echoPin 4
#define trigPin 7
#define IRsensor_L A0
#define IRsensor_R A1

/***PINS***/
volatile unsigned char step_pin=2;     //encoder

const unsigned char motor1Forward=3;   //1A motor LEFT positive logic pin
const unsigned char motor1Reverse=5;   //2A motor LEFT negative logic pin

const unsigned char motor2Reverse=10; //1B motor RIGHT positive logic pin
const unsigned char motor2Forward=11; //2B motor RIGHT negative logic pin

/***VARIABLES***/
 byte logic=0;
volatile long stepCount=0;
const unsigned char power1 = 20;
const unsigned char power2 = 100;
const unsigned char power3 = 175;
const unsigned char powerMAX = 250;
unsigned int distSonor;            //Sonor 
unsigned int distIR_L;          //IR
unsigned int distIR_R;          //IR
float x;  //test raw Sonor data

NewPing sonar(trigPin,echoPin,200);  //sets up the sonar


void setup() {
  Serial.begin(9600);
  pinMode(step_pin,INPUT);
  pinMode(motor1Forward, OUTPUT);
  pinMode(motor1Reverse, OUTPUT);
  pinMode(motor2Forward, OUTPUT);
  pinMode(motor2Reverse, OUTPUT);
  pinMode(IRsensor_L, INPUT);
 pinMode(IRsensor_R, INPUT);
attachInterrupt(digitalPinToInterrupt(2), count, RISING);
  delay(3000);
}

/***MAIN***/
void loop() {
    interrupts();
drive();
  while (stepCount >= 300){ 
    halt();
  Serial.println(stepCount);
  stepCount = 0;
  Serial.println(stepCount);
  }
  delay(2000);
  /*
x=sonar.ping_cm();
distIR_L= irVal_L();
distIR_R = irVal_R();
Serial.print("IR LEFT Sensor value = ");
Serial.println(distIR_L);
Serial.print("IR RIGHT Sensor value = ");
Serial.println(distIR_R);
*/

//x=sonar.ping_cm();
//Serial.print("Sonar value = ");
//Serial.println(x);
//Serial.print("LOGIC is ");
//Serial.println(logic);   
//digitalWrite(step_pin, LOW);

}

/***FUNCTIONS***/

void maze(){
  think();
  delay(5);
  drive();
  }
  
void think(){
  if((distSonor > 10) && (distIR_R == distIR_L)){
    drive();
    }
  if(distIR_R < 40){
    right();
    }
  if(distIR_L < 40){
    left();
  }
  if((distIR_L) < 40 && (distIR_R < 40)){
    turnAround();
    }
  }
  
void drive(){             //function called for moving forward 
  distSonor = sonar.ping_cm();
  if(distSonor >= 100){
  forward(powerMAX);
 }
  if((distSonor >= 60) && (distSonor < 100)){
  forward(power3);
 }
 if((distSonor >= 30) && (distSonor < 60)){
  forward(power2);
 }
 if((distSonor >= 10) && (distSonor < 30)){
  forward(power1);
 }
 if(distSonor < 10){
  halt();
  }
}

void forward(unsigned char x){
analogWrite(motor1Forward,x);
 analogWrite(motor1Reverse,0);
 analogWrite(motor2Reverse,0);
 analogWrite(motor2Forward,x);   
 }

void reverse(unsigned char x){   //never going to use this!
  analogWrite(motor1Forward,0);
 analogWrite(motor1Reverse,x);
 analogWrite(motor2Reverse,x);
 analogWrite(motor2Forward,0);
  }

void left(){
 analogWrite(motor1Forward,0);
 analogWrite(motor1Reverse,25);
 analogWrite(motor2Reverse,0);
 analogWrite(motor2Forward,25);
 delay(50);
  }

void right(){
 analogWrite(motor1Forward,25);
 analogWrite(motor1Reverse,0);
 analogWrite(motor2Reverse,25);
 analogWrite(motor2Forward,0);
 delay(50);
  }

 void halt(){
  analogWrite(motor1Forward,0);
  analogWrite(motor1Reverse,0);
  analogWrite(motor2Reverse,0);
  analogWrite(motor2Forward,0);
  }

void turnAround(){
 if(distSonor < 10){
 right();
 }
}
  
int irTest_L(){
  int x = analogRead(IRsensor_L);
  distIR_L = 5.0639*pow(x/1000, -1.177);
  return distIR_L;
  }

int irVal_L(){
  unsigned char i;
  int val = analogRead(IRsensor_L);
  for(i=0; i<25; i++){
  val += analogRead(IRsensor_L);
  }
  return val/25;
}


int irVal_R(){
  unsigned char j;
  int val2 = analogRead(IRsensor_R);
  for(j=0; j<25; j++){
  val2 += analogRead(IRsensor_R);
  }
  return val2/25;
}


void count(){         //ISR
  logic=digitalRead(step_pin);

  if(logic==1){
  stepCount++;

  noInterrupts();
  }
}

PacRat16:
okay, so here is the full code. the motors we are using is DC motor 100:1 gears with a dual shaft that each holds an magnetic encoder that has a CPR of 12.

I'm trying to figure out how many "steps" correlate to one revolution of my 60x8mm wheels.

Now that we have the data the answer is either 12 or 1200 depending on whether the encoder is after or before the gearbox.

...R

Just tell us exactly what product you are using please - link to polulo's product page, not a
textual description.

Pololu magnetic shaft encoders

These encode motor shaft revolutions, so for the full quadrature case, with a 100:1 gearbox, it would be 1200 counts per gearbox output shaft revolution.

However, the OP appears to be counting a single rising transition on one channel only, for 300 counts per gearbox output shaft revolution, and even then for only one rotation direction.

jremington:
Pololu magnetic shaft encoders

These encode motor shaft revolutions, so for the full quadrature case, with a 100:1 gearbox, it would be 1200 counts per gearbox output shaft revolution.

However, the OP appears to be counting a single rising transition on one channel only, for 300 counts per gearbox output shaft revolution, and even then for only one rotation direction.

yes i only have one channel from the encoder that i am reading from. Is it necessary to have both channel connected? I'm assuming connecting the other channel from the encoder helps counts the opposite direction?

My main problem is controlling the step counts. For example: Making it stop at exactly 300 steps.

PacRat16:
My main problem is controlling the step counts. For example: Making it stop at exactly 300 steps.

That is a horse of a very different colour :slight_smile:

I don't know how to do that and I have not yet seen a Thread here which explains how to do it - although I think it is possible.

A lot will depend on the friction and the momentum within your system. High friction and low momentum will be easiest to deal with.

If you just power the motor directly from a battery does it stop instantly when you disconnect the power, or does it freewheel a little.

...R

I'm assuming connecting the other channel from the encoder helps counts the opposite direction?

Your code is wrong. It counts pulses in one direction only. Google for several examples of correct Arduino quadrature encoder code.

It is difficult to have the motor stop at, for example, exactly 300 counts, even if your code were correct and capable of counting backwards. You have to implement a PID position loop to do that.

jremington:
You have to implement a PID position loop to do that.

This is a question for my own edification ...
Does a PID system require the position to oscillate a little around the chosen positon - for example between 295 and 305?

...R

Does a PID system require the position to oscillate a little around the chosen positon - for example between 295 and 305?

In general not if properly tuned, in which case there might be a small overshoot.

However since the position measuring system is discrete in this case (with no fractional steps) it may be quite difficult to tune it to settle exactly on 300 without oscillation of +/- 1 or more.

well the purpose of this robot car im making is for the micromouse competition. We need a step counter to memorize the maze so when we run the car the second round, it would sue the pre-recorded steps to nagvigate through the maze to the destination.

If anyone have a better suggestion then this strategy, i wouldn't mind hearing it.

Wheels slip. They always slip. Even on solid surfaces, they slip. Slip is what generates traction. Without traction, you don't move.

Depending on the accuracy you require, this slip may be insignificant. But if it is significant then you need a more direct way of measuring distance. The sensors inside optical computer mice (is there any other kind except optical these days?) can be interfaced to an Arduino reasonably easy. The mouse sensor watches the ground move under the robot.

I agree with @MorganS that for high accuracy you need an independent measuring system.

However it may be worth experimenting with your encoder system to discover if it is sufficiently accurate and repeatable.

If the maze has walls maybe you could supplement / recailbrate your encoder system with an optical or ultrasonic system that can detect the walls.

...R

Wheels slip. They always slip. Even on solid surfaces, they slip. Slip is what generates traction.

What you really think?

Slipping is what loses traction, friction is what generates traction. Wheels do not always slip.
High grip tyres are often soft, which leads to motion loss through distortion of the tyre, rather
than via slip. The truism is that odometry can never be completely precise (but it can be very
accurate on the right surface with the right wheels, otherwise turtle graphics robots would not
work).

In icy/wet/leaf-strewn conditions sand is used on railway lines to increase grip (prevent
slip by increasing friction) and thus allow traction.

Tight turning circles can lead to slip on the edges of the tyre, with or without slip in the
centre, which means very narrow tyres/wheels are often a feature of high performing odometry.