Can't compile motor PID code

Hi

I have problems (note the plural) getting my sketch to compile. I am using an L298N driver to drive a motor, a speed encoder to calculate the rotations per second and a potentiometer to change the speed. This was all fine but then I changed the code a lot to try to add PID code. Could someone help out with adapting the code at http://playground.arduino.cc/Code/PIDLibaryBasicExample please? (broken code below)

The log says:
L298N_apr08b:14: error: ‘Setpoint’ was not declared in this scope

PID myPID(&Setpoint, &Input, &Output,2,5,1, DIRECT); // DO I LEAVE IT LIKE THIS?

^

L298N_apr08b:14: error: ‘Input’ was not declared in this scope

PID myPID(&Setpoint, &Input, &Output,2,5,1, DIRECT); // DO I LEAVE IT LIKE THIS?

^

L298N_apr08b:14: error: ‘Output’ was not declared in this scope

PID myPID(&Setpoint, &Input, &Output,2,5,1, DIRECT); // DO I LEAVE IT LIKE THIS?

^

L298N_apr08b.ino: In function ‘void setup()’:

L298N_apr08b:64: error: ‘analogPinToInterrupt’ was not declared in this scope

attachInterrupt(analogPinToInterrupt(2), potval, CHANGE); // adjust speed when pot pin changes

^

L298N_apr08b:66: error: ‘Input’ was not declared in this scope

Input = rotation;

^

L298N_apr08b:67: error: ‘Setpoint’ was not declared in this scope

Setpoint = desired;

^

L298N_apr08b.ino: In function ‘void loop()’:

L298N_apr08b:73: error: ‘Input’ was not declared in this scope

Input = analogRead(2);

^

exit status 1
‘Setpoint’ was not declared in this scope

#include <PID_v1.h>
#include <TimerOne.h>

float maxrpsCW = 3.60; // the desired max revs per second for the CW motion as measured under current load
float maxrpsACW = 3.80; // the desired max desired revs per second for the ACW motion as measured under current load

unsigned int counter = 0; // counts the encoder holes I think (to calculate rotation)
int c = 0;  // counter that delays Serial display of desired rotation (variable: desired)

//Define Variables we'll be connecting to      //float Setpoint, Input, Output;
float desired, rotation, motorspeed;
//Specify the links and initial tuning parameters
PID myPID(&Setpoint, &Input, &Output,2,5,1, DIRECT); // DO I LEAVE IT LIKE THIS?

void docount() {  // counts from the speed sensor
  counter++;  // increase +1 the counter value
} 

void timerIsr() {
  Timer1.detachInterrupt();  //stop the timer
  Serial.print("Motor Speed: "); 
  float timeadjust = 6.00;  // I had to adjust the rotation to make it approximately correct (not sure why it is inaccurate)
  float rotation = counter / 20.00 / timeadjust;  // divide by number of holes in Disc and again by timeadjust
  Serial.print(rotation); Serial.println(" rps"); 
  counter = 0;  //  reset counter to zero
  Timer1.attachInterrupt( timerIsr );  //enable the timer
}

void potval() {
  int potvalue = analogRead(2);  // Potentiometer connected to Pin A2
  Serial.print("potvalue: ");
  Serial.println(potvalue);
  
  if (potvalue <= 685/2-30) {       // ACW rotation
    digitalWrite(8, LOW); digitalWrite(7, HIGH); digitalWrite(5, LOW); digitalWrite(4, HIGH);
    float desired = map(potvalue, 0.00, 685.00/2.00-30.00, maxrpsACW, 0.00); 
  }
  
  if (potvalue >= 685/2+30) {       // CW rotation
    //do later
  }
  
  if (potvalue > 685/2-30 && potvalue < 685/2+30) {       // no rotation
    //do later
  
  c = c + 1;
  if (c > 5000) {
    Serial.print("Desired rps: "); 
    Serial.print(desired); Serial.println(" rps"); 
    c = 0;
  }
} 

void setup() {
  Serial.begin(9600);
  pinMode(7, OUTPUT); pinMode(8, OUTPUT); pinMode(9, OUTPUT); //motor 1
  pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); //motor 2
  Timer1.initialize(1000000); // set timer for 1sec
  attachInterrupt(digitalPinToInterrupt(0), docount, RISING);  // increase counter when speed sensor pin goes High
  Timer1.attachInterrupt( timerIsr ); // enable the timer
  attachInterrupt(analogPinToInterrupt(2), potval, CHANGE);  // adjust speed when pot pin changes
  //initialize the variables we're linked to
  Input = rotation;
  Setpoint = desired;
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop() {
  Input = analogRead(2);
  myPID.Compute();
  if (potvalue <= 685/2-30) {       // ACW rotation
    //float desired = map(potvalue, 0.00, 685.00/2.00-30.00, maxrpsACW, 0.00); 
    float motorspeed = map(desired, 0.00, maxrpsACW, 240, 0); 
  }
  if (potvalue <= 685/2+30) {       // CW rotation
    //do later
  }
  if (potvalue > 685/2-30 && potvalue < 685/2+30) {       // no rotation
    //do later
  }
  
  analogWrite(6, motorspeed);  // set speed of motor (0-255)
}

This is the declaration from the example code

//Define Variables we’ll be connecting to
double Setpoint, Input, Output;

This is the declaration from your code

//Define Variables we’ll be connecting to //float Setpoint, Input, Output;
float desired, rotation, motorspeed;

If you want to change the variable names in the declaration, you need to change them where you use them too.

Please use code tags (</> button on the toolbar) when you post warning/error messages, as you did with your code. The reason is that the forum software can interpret parts of it as markup, leading to confusion, wasted time, and a reduced chance for you to get help with your problem. This will also make it easier to read them.

bodkin77:
L298N_apr08b.ino: In function ‘void setup()’:

L298N_apr08b:64: error: ‘analogPinToInterrupt’ was not declared in this scope

attachInterrupt(analogPinToInterrupt(2), potval, CHANGE); // adjust speed when pot pin changes

Where did you come up with this “analogPinToInterrupt”? Did you just assume that since there is a digitalPinToInterrupt there would be an analogPinToInterrupt also? You can just use digitalPinToInterrupt with the analog pin name (A2).

Vince: I do have desired, rotation and motorspeed in my code, but didn't do it properly.
Pert: Thanks for letting me know about putting the errors in code tags. Yes I did make an assumption on the analogPinToInterrupt, thinking it would be wrong. I was confused about methods of using the Arduino's analog comparator (such as using ISR(ANALOG_COMP_vect )), so I just put it analogPinToInterrupt. Glad I did because you then told me I can just use digitalPinToInterrupt with the analog pin name (A2).

I'll have another play with it now. I'm guessing that switching to a rotary encoder dial might make it easier, but I'll try the potentiometer again first, cutting back the code first to get the analog interrupt working before the PID.

I put the code attachInterrupt(digitalPinToInterrupt(A2), potval, CHANGE);
Is this correct? I also defined a bunch of variables to float variable = 0.00 to get rid of the compiling errors. I have no motor spinnage. I couldn’t get the potentiometer to interrupt the loop and display it’s value so I threw it in with the timer interrupt. Also, the value for desired rps (revs per second) is showing up as integer values with 2 dec points, like 1.00, 2.00 and 3.00. I have set every value to floats so shouldn’t it be given the calculation to 2 decimal points (with real 2 decimal point precision)? I removed the feedback code for the time being. A long road ahead!

#include <TimerOne.h>

float maxrpsCW = 3.60; // the desired max revs per second for the CW motion as measured under current load
float maxrpsACW = 3.80; // the desired max desired revs per second for the ACW motion as measured under current load
float timeadjust = 6.00;  // I had to adjust the rotation to make it approximately correct (not sure why it is inaccurate)
float counter = 0.00; // counts the encoder holes
float rotation = float(counter / 20.00 / timeadjust);  // divide by number of holes in Disc and again by timeadjust
float desired = 0.00;
float motorspeed = 0.00;
float potvalue = 0.00;

//void pciSetup(byte pin) { //to set up pin A2 as interrupt

void docount() {  // counts from the speed sensor
  float(counter++);  // increase +1 the counter value
} 

void timerIsr() {
  Timer1.detachInterrupt();  //stop the timer
  Serial.print("Motor Speed: "); Serial.print(float(rotation)); Serial.println(" rps"); 
  counter = 0.00;  //  reset counter to zero
  potvalue = analogRead(2);  // Potentiometer connected to Pin A2
  Serial.print("potvalue: ");
  Serial.println(potvalue);
  float desired = map(potvalue, 0.00, 685.00/2.00-30.00, maxrpsACW, 0.00); 
  Serial.print("Desired rps: "); 
  Serial.print(desired); Serial.println(" rps"); 
  Timer1.attachInterrupt( timerIsr );  //enable the timer
}

void potval() {
  
  if (potvalue <= 685.00/2.00-30.00) {       // ACW rotation
    digitalWrite(8, LOW); digitalWrite(7, HIGH); digitalWrite(5, LOW); digitalWrite(4, HIGH);
    float desired = map(potvalue, 0.00, 685.00/2.00-30.00, maxrpsACW, 0.00); 
  }
} 

void setup() {
  Serial.begin(9600);
  pinMode(7, OUTPUT); pinMode(8, OUTPUT); // Motor direction signal pins
  pinMode(9, OUTPUT); //motor 1 PWM
  pinMode(4, OUTPUT); pinMode(5, OUTPUT); // Motor direction signal pins
  pinMode(6, OUTPUT); //motor 2 PWM
  pinMode(A2, INPUT); //potentiometer
  Timer1.initialize(1000000); // set timer for 1sec
  attachInterrupt(digitalPinToInterrupt(0), docount, RISING);  // increase counter when speed sensor pin goes High
  Timer1.attachInterrupt( timerIsr ); // enable the timer
  attachInterrupt(digitalPinToInterrupt(A2), potval, CHANGE);  // adjust speed when pot pin changes
}

void loop() {
  if (potvalue <= 685.00/2.00-30.00) {       // ACW rotation
    //float desired = map(potvalue, 0.00, 685.00/2.00-30.00, maxrpsACW, 0.00); 
    float motorspeed = map(desired, 0.00, maxrpsACW, 240.00, 0.00); 
    analogWrite(6, motorspeed);  // set speed of motor (0-240)
    analogWrite(9, motorspeed);  // set speed of motor (0-240)
  }
}

Make sure the board you're using supports interrupts on the pin you're using. Please see:
https://www.arduino.cc/en/Reference/AttachInterrupt
I didn't see that you had mentioned which board anywhere so I can't say whether it's possible to use A2.

I’m using the UNO. I changed to a rotary encoder dial instead of a potentiometer, so now I’m using a digital interrupt pin. Not sure if A2 is ok for an interrupt.

I got both the rotary encoder dial and the rotary encoder wheel working separately on interrupts (digital pins 1 and 2), but combine them together and Arduino thinks that the encoder wheel is me turning the encoder dial! I mean that the motor speed in the Serial monitor is increasing when I manually spin the encoder wheel in the sensor. The motor is not turning at all. The interrupts are interfering with each other somehow. I have the encoder wheel sensor and encoder dial on Arduino’s 5V output. Not sure if that is the problem. Everything is on common ground.

An interesting point is there is no mention that the timer for the encoder sensor uses D2, although it works on that when run separately to the encoder dial. I followed the wiring diagram at https://brainy-bits.com/blogs/tutorials/speed-sensor-with-arduino to know to put it on D2. Maybe I need to set this at the top of the code.

Here is the code that I’m using now. Then I still want to add in feedback for speed control and add another motor too.

How do I stop the interrupts them interfering with each other?

// for motors
    #define Motor1Dir1 7 
    #define Motor1Dir2 8
    #define Motor1PWM 9

//for timer
    #include <TimerOne.h>
    unsigned int counter=0;

//for rotary encoder dial
    volatile boolean TurnDetected;  // need volatile for Interrupts
    volatile boolean up;

    const int PinCLK=1;   // Generating interrupts using CLK signal
    const int PinDT=5;    // Reading DT signal
    const int PinSW=4;    // Reading Push Button switch

    // Interrupt routine runs if CLK goes from HIGH to LOW
    void isr ()  {
     //detachInterrupt(digitalPinToInterrupt (1));
     delay(4);  // delay for Debouncing
     if (digitalRead(PinCLK))
       up = digitalRead(PinDT);
     else
       up = !digitalRead(PinDT);
     TurnDetected = true;
     attachInterrupt(0,isr, RISING);
    }

//for timer
    void docount()  // counts from the speed sensor
    {
      counter++;  // increase +1 the counter value
    } 

    void timerIsr()
    {
      Timer1.detachInterrupt();  //stop the timer
      Serial.print("Motor Speed: "); 
      int rotation = (counter / 20);  // divide by number of holes in Disc
      Serial.print(rotation,DEC);  
      Serial.println(" Rotation per seconds"); 
      counter=0;  //  reset counter to zero
      Timer1.attachInterrupt( timerIsr );  //enable the timer
     }

void setup ()  {
     Serial.begin (9600);

//for timer
     Timer1.initialize(1000000); // set timer for 1sec
     attachInterrupt(0, docount, RISING);  // increase counter when speed sensor pin goes High
     Timer1.attachInterrupt( timerIsr ); // enable the timer

//for rotary encoder dial
     pinMode(PinCLK,INPUT);
     pinMode(PinDT,INPUT);  
     pinMode(PinSW,INPUT);
     digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
 
     attachInterrupt (0,isr,FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO

     Serial.println("Start");
     pinMode(Motor1Dir1, OUTPUT ); pinMode(Motor1Dir2, OUTPUT );
     pinMode(Motor1PWM, OUTPUT );
     digitalWrite(Motor1Dir1, LOW ); digitalWrite(Motor1Dir2, LOW );// Set motor to off
     digitalWrite(Motor1PWM, LOW );
}

void loop ()  {
 static long RotaryPosition=0;    // STATIC to count correctly

 if (!(digitalRead(PinSW))) {   // check if button is pressed
   if (RotaryPosition == 0) {  // check if button was already pressed
   } else {
       RotaryPosition=0; // if YES, then reset position to ZERO
       digitalWrite( Motor1Dir1, LOW ); digitalWrite( Motor1Dir2, LOW );// turn motor off
       analogWrite( Motor1PWM, LOW ); 
       Serial.print ("Reset = ");
       Serial.println (RotaryPosition);
   }
 }
 
 // Runs if rotation was detected
 if (TurnDetected)  {
   if (up) {
     if (RotaryPosition >= 100) { // Max value set to 100
       RotaryPosition = 100;
     }
     else {
         RotaryPosition=RotaryPosition+2;
     }
   }
   else {
     if (RotaryPosition <= -100) { 
       // Max value set to -100        
       RotaryPosition = -100;
     }        
     else {          
       RotaryPosition=RotaryPosition-2;
      }
    }    
    TurnDetected = false;  // do NOT repeat IF loop until new rotation detected
    Serial.print ("Speed = "); 
    Serial.println (RotaryPosition);     
    
    if (RotaryPosition >= 0) { 
      digitalWrite( Motor1Dir1, HIGH ); digitalWrite( Motor1Dir2, LOW ); // turn motor off 
      analogWrite( Motor1PWM, RotaryPosition*2);
    } 

    if (RotaryPosition <0) {
      digitalWrite( Motor1Dir1, LOW ); digitalWrite( Motor1Dir2, HIGH); // direction = forward
      analogWrite( Motor1PWM, -RotaryPosition*2 );
    }
}}

Apparently an external RC circuit or software debouncing might help according to the last few posts at this Arduino forum link here.