Pages: [1]   Go Down
Author Topic: Simple example for Encoder interrupt counting  (Read 474 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all. I'm planning to do my work with several motors, and they need to change their angles at times.
I'm gonna use PID position control (with Arduino code).

To do so, first of all, I'm trying to use encoder but I'm not sure it works.
The motor is Maxon DCX geared brushed motor with encoder. Gear ratio is 16:1 and the resolution is 1024, so I'm a little afraid that arduino can miss the interrupt signal when motor rotates.
So, I'm trying to test if the encoder works well(if counting works), but not sure with which code to use.
Can anyone recommend the link or simple code?
Thanx.

*This is code for 10 degree position control when the button on the breadboard is pressed. But it doesn't work at all.. the motor rotates over 10 degree and it is supposed to rotate whenever I press the button but it is not.
I think there's a lot of problems, but don't know where to start.

Code:
#define encA 2
#define encB 3

volatile int enc0 = 0;
int en1 = 5; // motor1 enable
int dir1 = 4; // motor1 direction
int pwm1 = 6; // motor1 pwm
int btn1 = 10; // digital pin 10

int btn_state1 = 0;

unsigned long preMillis = 0;
int sample = 50;
double dt = sample*0.001;
double u, pwm = 0;
double dpp = 360/1024; // degree per pulse
double pos1 = dpp/10; // movement of 10'
double theta = 0;

// position control
double error1 = 0;
double error1_old = 0;
double error1_dot = 0;
double error1_sum = 0;
double theta1_dum = 0;

// PID Coefficient
double kp1 = 1.15;
double kd1 = 0.08;
double ki1 = 0.8;
double kp2 = 1.0;
double kd2 = 0.03;
double ki2 = 0.1;

void setup()
{
  pinMode(btn1, INPUT);
  pinMode(en1, OUTPUT);
  pinMode(dir1, OUTPUT);
  pinMode(encA, INPUT);
  digitalWrite(encA, HIGH);
  pinMode(encB, INPUT);
  digitalWrite(encB, HIGH);
  attachInterrupt(0, doEncoder_Expanded, CHANGE);
  Serial.begin(9600);
  Serial.println("start");
}

void loop()
{
  btn_state1 = digitalRead(btn1);
 
  unsigned long currentMillis = millis();
  if (currentMillis - preMillis >= sample)
  {
    preMillis = currentMillis;
   
    theta = enc0;
   
    // movement of 10' //
    if(btn_state1 == HIGH)
    {
      error1 = (pos1-theta);
      error1_dot = (error1-error1_old)/dt;
      error1_sum = error1_sum + error1*dt;
     
      digitalWrite(en1,HIGH);
     
      if (error1 >= 0){
        digitalWrite(dir1,HIGH);
        u = kp1*error1 + (kd1*error1_dot) + ki1*error1_sum;}
     
      else if (error1 < 0) {
        u = kp2*error1 + (kd2*error1_dot) + ki2*error1_sum;}
       
        pwm = constrain(u,0,150);
        analogWrite(pwm1,pwm);
        error1_old = error1;
        theta1_dum = theta;
    }
   
    else {
      digitalWrite(en1,LOW);
      error1, error1_dot, error1_sum, enc0, u = 0;}
     
  }
}

void doEncoder_Expanded() {
  if (digitalRead(encA) == HIGH) {
    if (digitalRead(encB) == LOW) {
      enc0 = enc0 -1;
    }
    else {enc0 = enc0 + 1;}
  }
  else {
    if (digitalRead(encB) == LOW) {
      enc0 = enc0 + 1;
    }
    else {enc0 = enc0 - 1;}
  }
}
Logged

East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 114
Posts: 4267
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am not clear what actually happens when you run the program.
Does the motor run before you press the button ? If so, for how long ?

If you press and hold the button what happens and what should happen ?

If you press the button for a moment then release it what happens and what should happen ?

How is the button wired, pullup/pulldown resistor ?

How is the motor powered ?  From the Arduino directly or external power ?

Have you tried putting some serial prints in the code to show you the state of variables when the code is running ?

As to testing the encoder, I would simply add to a counter on every interrupt then print the counter value every second.  Alternatively, add to the counter on every interrupt and stop the motor when the count reaches 1024 and see how far the motor has rotated.

Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 616
Posts: 49444
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I think there's a lot of problems, but don't know where to start.
How about starting with a sketch that does ONE thing. Don't add 47 more things to that sketch until you know something works. Any one thing.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Both of you above, THANX for the comments.
I will try from the beginning (the smallest things) first. You are right that I'm trying too much things at once. THANX again.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I started with the simpler example to check whether the counting is working.
The motor is supposed to stop after the counting reaches 100, but the serial monitor shows that the counting number doesn't increase/decrease.. it stays 0 and motor keeps rotating.
Is there any problem in the code counting with the encoder? Resolution is 1024 and geared ratio is 16:1. THX

Code:
#define encA 2 // encoder channel A
#define encB 3 // encoder channel B

volatile int enc0 = 0; // initial encoder count #
int en1 = 5; // motor1 enable
int dir1 = 4; // motor1 direction
int pwm1 = 6; // motor1 pwm

void setup() {
  pinMode(en1, OUTPUT);
  pinMode(dir1, OUTPUT);
  pinMode(encA, INPUT);
  attachInterrupt(0, doEncoder_Expanded, CHANGE); // do counting if encA CHANGE
  pinMode(encB, INPUT);


  Serial.begin(9600);
  Serial.println("start");
 
}

void loop(){

  Serial.println(enc0);
  analogWrite(pwm1, 150);
  digitalWrite(en1, HIGH);
  digitalWrite(dir1, HIGH);
 
  if (enc0>100){
  analogWrite(pwm1, 0);
  delay(1000);
  enc0 = 0; 
}
}

void doEncoder_Expanded() {
  if (digitalRead(encA) == HIGH) {
    if (digitalRead(encB) == LOW) {
      enc0 = enc0 + 1;
    }
    else {enc0 = enc0 - 1;}
  }
  else {
    if (digitalRead(encB) == LOW) {
      enc0 = enc0 - 1;
    }
    else {enc0 = enc0 + 1;}
  }
}
Logged

East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 114
Posts: 4267
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Make your test program even simpler.
Code:
void doEncoder_Expanded()
{
  enc0++;
}
Now does enc0 change ?
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes it does THX.
With my last code, it worked depending on pwm value/ counting limit value.

But with your simpler code it works for every values above, (though it's still not that accurate.)

THX
Logged

East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 114
Posts: 4267
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My simple version is only reading one encoder output so will give only half the number of pulses and you cannot tell which way the wheel is rotating, but it proves that the interrupts are happening and are being recorded.

Check the logic of your original doEncoder_Expanded() function.  I suspect that there are flaws in it.
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I added your code.
Quote
void doEncoder_Expanded()
{
  enc0++;
}

And the following is the code with pwm & enable = 0 & LOW which means motor doesn't rotate and just keeps still. But in serial com. window, the en0 value increases even though the motor doesn't rotate.
Is it normal thing that the interrupt pin has signal from the encoder even at the stationary state?? I think this can be the main problem.

Or I thought that RISING option in attachinterrupt function can be the problem but it wasn't (CHANGE option made the same situation.).
I don't think doEncoder_Expanded has problem but it seems it has. Any idea?


Code:
#define encA 2 // encoder channel A
#define encB 3 // encoder channel B

volatile int enc0 = 0; // initial encoder count #
int en1 = 5; // motor1 enable
int dir1 = 4; // motor1 direction
int pwm1 = 6; // motor1 pwm

void setup() {
  pinMode(en1, OUTPUT);
  pinMode(dir1, OUTPUT);
  pinMode(encA, INPUT);
 
  pinMode(encB, INPUT);


  Serial.begin(9600);
  Serial.println("start");
  
}

void loop(){
 attachInterrupt(0, doEncoder_Expanded, RISING); // start counting
  Serial.println(enc0);
  analogWrite(pwm1, 0);
  digitalWrite(en1, LOW);
  digitalWrite(dir1, HIGH);
  
  if (enc0>100){
  analogWrite(pwm1, 0);
  delay(1000);
  enc0 = 0;  
}
}

void doEncoder_Expanded()
{
  enc0++;
}
« Last Edit: May 15, 2013, 08:28:16 am by J Young » Logged

East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 114
Posts: 4267
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If there are no interrupts then the value of enc0 should not be changing.  How is the connection to the interrupt pin wired ?  It is not, perhaps floating and not tied to either 5V or ground, is it ?
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Pages: [1]   Go Up
Jump to: