1. Got a question or need help troubleshooting? Post to the troubleshooting forum or Search the forums!

Arduino related code questions (sketches).

Discussion in 'Off Topic' started by BrooklynBay, Jul 1, 2021.

  1. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
  2. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    I got rid of the 342 error but now the compute error is back.
     
  3. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    Again :)
    Post the entire error (at lest the one you are looking at -- compute in this case) and perhaps attach the code or perhaps put it in an online repository (like github) that I can get access to and look at it when you have questions. Will be faster and better feedback...
     
  4. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    This is the line in the code with the compute error: Timer1.attachInterrupt(Compute); with an error 'compute' was not declared in this scope.
     
  5. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    The compiler scans the source top to bottom and will not understand a variable or function if it is declared further down in the code than the compiler has already scanned. Move void Compute() declaration ABOVE the setup() and see what happens.

    In general always declare variables and functions further up in the code than your using them...
     
  6. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    This bracket { was missing in the code, so that took care of the compute error. Now I'm getting an error code on this line: pwmOut(output); //Change the analog write for the motor control. It says that 'pwnOut' was not declared in this scope.
     
  7. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    Same, exact problem ...

    Code:
      void Compute()
        setpoint = map(analogRead(0), 0, 1024, 1024, 0) * 110;        // setpoint position is made with a potentiometer but could be given by serial monitor or other...
        input = encoderPos;                                           // we get the data from the encoder interruption
        error = setpoint - input;
        iTerm += ki * error * sampleTime;
        if (iTerm > outMax) iTerm = outMax;                           // prevent that the I term from PID gets too big
        else if (iTerm < outMin) iTerm = outMin;
        dInput = (input - lastInput) / sampleTime;
        output = kp * error + iTerm - kd * dInput;                    // The PID output is the sum of P I and D values
        if (output > outMax) output = outMax;                         // limit output to 0 and 255 for the analog write
        else if (output < outMin) output = outMin;
        lastInput = input;                                            //Remember to save the last input value for the next loop
        pwmOut(output);                                               //Change the analog write for the motor control
      }
    
    { void pwmOut(int out) {                                          // to H-Bridge board
          if (out > 0) {
            analogWrite(Motor_CW, out);                                 // Rotate the motor CW
            analogWrite(Motor_CCW, 0);
          }
          else {
            analogWrite(Motor_CW, 0);
            analogWrite(Motor_CCW, abs(out));                           // Rotate the motor CCW
          }
    }
    
    You are calling pwmOut from the UPPER block and it does NOT KNOW about pwmOut because the function is declared below it.
    All functions/code only can reference the procedures/functions/variables declared ABOVE them.

    This is really just a design choice for the Arduino compiler, but for the Arduino hardware that is the best choice. Others can work with Arduino code (Visual Studio can) but the issue you have is simply make sure you code is written with the functions in the correct sequence
     
  8. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    Do I copy & paste the code from post number 87 to the section above define PID constants in my code then delete that code where it is now?
     
  9. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    At a minimum cut-and-paste pwmOut() and move it above Compute() and check the rest of your code for similar issues. If you are calling another function/subroutine it needs to be defined above the block where you call it. Functions that are in libraries are loaded at start (where the #include is located) so everything should be below them and the library will always be 'in scope'
     
  10. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    Moving the code to different sections didn't get rid of the error message. I put it in a couple of different locations, and tried putting sections of the code in different places.
     
  11. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    Well, without seeing it I am guessing so... no suggestions.
    Again if you really want to have some help move the code to a shared repository (GitHub, SourceForge, or even just a GoogleDrive) where I can see it.
     
  12. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    I could post the code here:

    Code:
    //Include the libraries which we need
    #include <PinChangeInterrupt.h>               //http://electronoobs.com/eng_arduino_PinChangeInterrupt.php
    #include <PinChangeInterruptBoards.h>
    #include <PinChangeInterruptPins.h>
    #include <PinChangeInterruptSettings.h>
    #include <TimerOne.h> // Timer one interrupts
    #include <Encoder.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h> (0x27,16,2);  // set the LCD address to 0x27 for a 16 character, 2 line display
    LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 columns and 2 rows
    
    //////////////////////////////////////////////////////////////
    /////////////////////DEFINE PID constants/////////////////////
    //////////////////////////////////////////////////////////////
    int kp = 2, ki = 0.01, kd = 0.02;
    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////
    
    int input, output, setpoint;
    int iTerm = 0, lastInput = 0, dInput = 0, error = 0;
    int outMin = -255, outMax = 255;
    int sampleTime = 10;                                 //This values is in milliseconds
    volatile long encoderPos = 0;
    int Encoder_OutputA_CLK  = 2;                       // Quadrature encoder A pin
    int Encoder_OutputB_DT   = 3;                       // Quadrature encoder B pin
    int Encoder_OutputC_CLK  = 0;                       // Quadrature encoder C pin
    int Encoder_OutputD_DT   = 1;                       // Quadrature encoder D pin
    int END_stop_SW          = 4;
    int Previous_Output;
    int Encoder_Count; 
    
    //////////////////////////////////////////////////////////////
    ////////////////////Define the pins we use////////////////////
    //////////////////////////////////////////////////////////////
    #define Encoder_A_CLK  2                                    // Quadrature encoder A pin
    #define Encoder_B_DT   3                                    // Quadrature encoder B pin
    #define Encoder_C_CLK  0                                    // Quadrature encoder C pin
    #define Encoder_D_DT   1                                    // Quadrature encoder D pin
    #define Motor_CW       8                                    // PWM outputs to L298N H bridge motor driver module
    #define Motor_CCW      9
    #define Motor_CW       10
    #define Motor_CCW      11
    #define END_stop_SW    4
               
    void setup (void)
    {
      lcd.init();                      // initialize the lcd
      lcd.begin(16, 2); //Initialize 16*2 LCD // Print a message to the LCD.
      lcd.backlight(); //wait for a second
      delay(1000); // tell the screen to write on the top row
      lcd.setCursor(0, 0); // tell the screen to write “Steer by wire.” on the top row
      lcd.print("Steer by wire.");
      lcd.setCursor(1, 0);
      lcd.print(" Rotary Encoder "); //Intro Message line 1
      lcd.setCursor(0, 1);
      lcd.print("  With Arduino  "); //Intro Message line 2
      delay(2000);
      lcd.clear();
      pinMode(Encoder_A_CLK, INPUT);                                // quadrature encoder input A
      pinMode(Encoder_B_DT,  INPUT);                                // quadrature encoder input B
      pinMode(Encoder_C_CLK, INPUT);                                // quadrature encoder input C
      pinMode(Encoder_D_DT,  INPUT);                                // quadrature encoder input D
      pinMode(END_stop_SW,   INPUT_PULLUP); // Input from the end stop switch
      attachPCINT(digitalPinToPCINT(Encoder_OutputA_CLK), Encoder_OutputA_CLK, FALLING); // We update encoder position for each falling edge detected in the interruption
      TCCR0B = TCCR0B & 0b11111000 | 1;                             // set 31Kh PWM to prevent motor whine (timer 2)
      Timer1.initialize(sampleTime * 1000);                         // setup timer 1
      Timer1.attachInterrupt(Compute);
      Serial.begin(115200);                                         //Just for debugging if you want to print values
    }
    void Compute() {
    setpoint = map(analogRead(0), 0, 1024, 1024, 0) * 110;        // setpoint position is made with a potentiometer but could be given by serial the monitor or other...
    input = encoderPos;                                          // we get the data from the encoder interruption
    error = setpoint - input;
    iTerm += ki * error * sampleTime;
    if (iTerm > outMax) iTerm = outMax;                           // prevent that the I term from PID gets too big
    else if (iTerm < outMin) iTerm = outMin;
    dInput = (input - lastInput) / sampleTime;
    output = kp * error + iTerm - kd * dInput;                    // The PID output is the sum of P I and D values
    if (output > outMax) output = outMax;                        // limit output to 0 and 255 for the analog write
    else if (output < outMin) output = outMin;
    lastInput = input;                                            //Remember to save the last input value for the next loop
    pwmOut (output);                                             //Change the analog write for the motor control
    }
    
    {void pwmOut(int out){                                      // to H-Bridge board
        if (out > 0) {
          analogWrite(Motor_CW, out);                          // Rotate the motor CW
          analogWrite(Motor_CCW, 0);
        }
        else {
          analogWrite(Motor_CW, 0);
          analogWrite(Motor_CCW, abs(out));                  // Rotate the motor CCW
        }
      }
      void encoder()                                      // pulse and direction, direct port reading to save cycles
      if (PINB & 0b00000001)    encoderPos++;             // if(digitalRead(encodPinB1)==HIGH)   count ++; //We increase steps by 1
      else                      encoderPos--;             // if (digitalRead(encodPinB1)==LOW)   count --; //We decrease steps by 1
    }
    
    void loop (void)
    {
      delay(1000); // tell the screen to write on the top row
      lcd.setCursor(0, 0); // tell the screen to write “Steer by wire.” on the top row
      lcd.print("Steer by wire.");
      lcd.setCursor(1, 0);
      lcd.print(" Rotary Encoder "); //Intro Message line 1
      lcd.setCursor(0, 1);
      lcd.print("  With Arduino  "); //Intro Message line 2
    
      while (digitalRead(END_stop_SW))
      {
        analogWrite(Motor_CW, 0);                                   // Rotate the motor CCW
        analogWrite(Motor_CCW, 255);
      }
      analogWrite(Motor_CW, 0);                                     // Stop the motor
      analogWrite(Motor_CCW, 0);
    }
    
     
  13. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    Make sure what you do in Setup() is One time initialization only. Keep it small and tight.
    Secondly I see an error here:

    Code:
    {void pwmOut(int out){                                      // to H-Bridge board
        if (out > 0) {
          analogWrite(Motor_CW, out);                          // Rotate the motor CW
          analogWrite(Motor_CCW, 0);
        }
        else {
          analogWrite(Motor_CW, 0);
          analogWrite(Motor_CCW, abs(out));                  // Rotate the motor CCW
        }
      }
    There is an extra { in there... that is a problem -- change that to:

    Code:
    void pwmOut(int out){                                      // to H-Bridge board
        if (out > 0) {
          analogWrite(Motor_CW, out);                          // Rotate the motor CW
          analogWrite(Motor_CCW, 0);
        }
        else {
          analogWrite(Motor_CW, 0);
          analogWrite(Motor_CCW, abs(out));                  // Rotate the motor CCW
        }
      }
    Probably other small errors -- I can't compile it because I don't have the same libraries installed, but the syntax error was pretty obvious.
     
  14. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    The extra { was a pair with the last }, so deleting the { created another error in the line starting with if.
     
  15. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    I went through each step, and compared it to a known good sketch with basic information, then pasted my updates from the damaged sketch into the known good sketch to get a working sketch. It seems like most of the errors were in the middle to lower section. I haven't tested it with the hardware so at this point I don't know if the LCD & interrupts for the encoders are good or if it still requires a potentiometer until the sketch is tested with working hardware. I know that the encoder ratio between both encoders will need to be set. Here's the updated sketch which doesn't contain errors:
    Code:
    //Include the libraries which we need
    #include <PinChangeInterrupt.h>               //http://electronoobs.com/eng_arduino_PinChangeInterrupt.php
    #include <PinChangeInterruptBoards.h>
    #include <PinChangeInterruptPins.h>
    #include <PinChangeInterruptSettings.h>
    #include <TimerOne.h> // Timer one interrupts
    #include <Encoder.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h> (0x27,16,2);  // set the LCD address to 0x27 for a 16 character, 2 line display
    LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 columns and 2 rows                        // Timer one interrupts
    
    //////////////////////////////////////////////////////////////
    /////////////////////DEFINE PID constants/////////////////////
    //////////////////////////////////////////////////////////////
    int kp = 2, ki = 0.01, kd = 0.02;
    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////
    
    int input, output, setpoint;
    int iTerm = 0, lastInput = 0, dInput = 0, error = 0;
    int outMin = -255, outMax = 255;
    int sampleTime = 10;                                 //This values is in milliseconds
    volatile long encoderPos = 0;
    int Encoder_OutputA_CLK  = 2;                       // Quadrature encoder A pin
    int Encoder_OutputB_DT   = 3;                       // Quadrature encoder B pin
    int Encoder_OutputC_CLK  = 0;                       // Quadrature encoder C pin
    int Encoder_OutputD_DT   = 1;                       // Quadrature encoder D pin
    int END_stop_SW          = 4;
    int Previous_Output;
    int Encoder_Count; 
    
    //////////////////////////////////////////////////////////////
    ////////////////////Define the pins we use////////////////////
    //////////////////////////////////////////////////////////////
    #define Encoder_A_CLK  2                                    // Quadrature encoder A pin
    #define Encoder_B_DT   3                                    // Quadrature encoder B pin
    #define Encoder_C_CLK  0                                    // Quadrature encoder C pin
    #define Encoder_D_DT   1                                    // Quadrature encoder D pin
    #define Motor_CW       8                                    // PWM outputs to L298N H bridge motor driver module
    #define Motor_CCW      9
    #define Motor_CW       10
    #define Motor_CCW      11
    #define END_stop_SW    4
    
    void setup (void)
    {
      lcd.init();                      // initialize the lcd
      lcd.begin(16, 2); //Initialize 16*2 LCD // Print a message to the LCD.
      lcd.backlight(); //wait for a second
      delay(1000); // tell the screen to write on the top row
      lcd.setCursor(0, 0); // tell the screen to write “Steer by wire.” on the top row
      lcd.print("Steer by wire.");
      lcd.setCursor(1, 0);
      lcd.print(" Rotary Encoder "); //Intro Message line 1
      lcd.setCursor(0, 1);
      lcd.print("  With Arduino  "); //Intro Message line 2
      delay(2000);
      lcd.clear();
      pinMode(Encoder_A_CLK, INPUT);                                // quadrature encoder input A
      pinMode(Encoder_B_DT,  INPUT);                                // quadrature encoder input B
      pinMode(Encoder_C_CLK, INPUT);                                // quadrature encoder input C
      pinMode(Encoder_D_DT,  INPUT);                                // quadrature encoder input D
      pinMode(END_stop_SW,   INPUT_PULLUP); // Input from the end stop switch
      attachPCINT(digitalPinToPCINT(Encoder_OutputA_CLK), Encoder_OutputA_CLK, FALLING); // We update encoder position for each falling edge detected in the interruption
      TCCR0B = TCCR0B & 0b11111000 | 1;                             // set 31Kh PWM to prevent motor whine (timer 2)
      Timer1.initialize(sampleTime * 1000);                         // setup timer 1
      Timer1.attachInterrupt(Compute);
      Serial.begin(115200);                                         //Just for debugging if you want to print values
    }
    
    void Compute()
    {
      setpoint = map(analogRead(0), 0, 1024, 1024, 0) * 110;        // setpoint position is made with a potentiometer but could be given by serial monitor or other...
      input = encoderPos;                                           // we get the data from the encoder interruption
      error = setpoint - input;
      iTerm += ki * error * sampleTime;
      if (iTerm > outMax) iTerm = outMax;                           // prevent that the I term from PID gets too big
      else if (iTerm < outMin) iTerm = outMin;
      dInput = (input - lastInput) / sampleTime;
      output = kp * error + iTerm - kd * dInput;                    // The PID output is the sum of P I and D values
      if (output > outMax) output = outMax;                         // limit output to 0 and 255 for the analog write
      else if (output < outMin) output = outMin;
      lastInput = input;                                            //Remember to save the last input value for the next loop
      pwmOut(output);                                               //Change the analog write for the motor control
    }
    
    void pwmOut(int out) {                                          // to H-Bridge board
      if (out > 0) {
        analogWrite(Motor_CW, out);                                 // Rotate the motor CW
        analogWrite(Motor_CCW, 0);
      }
      else {
        analogWrite(Motor_CW, 0);
        analogWrite(Motor_CCW, abs(out));                           // Rotate the motor CCW
      }
    }
    
    void encoder()  {                                     // pulse and direction, direct port reading to save cycles
      if (PINB & 0b00000001)    encoderPos++;             // if(digitalRead(encodPinB1)==HIGH)   count ++; //We increase steps by 1
      else                      encoderPos--;             // if (digitalRead(encodPinB1)==LOW)   count --; //We decrease steps by 1
    }
    void loop (void)
    {
      delay(1000); // tell the screen to write on the top row
      lcd.setCursor(0, 0); // tell the screen to write “Steer by wire.” on the top row
      lcd.print("Steer by wire.");
      lcd.setCursor(1, 0);
      lcd.print(" Rotary Encoder "); //Intro Message line 1
      lcd.setCursor(0, 1);
      lcd.print("  With Arduino  "); //Intro Message line 2
    
      while (digitalRead(END_stop_SW))
      {
        analogWrite(Motor_CW, 0);                                   // Rotate the motor CCW
        analogWrite(Motor_CCW, 255);
      }
      analogWrite(Motor_CW, 0);                                     // Stop the motor
      analogWrite(Motor_CCW, 0);
    }
    
     
    mark tomlinson likes this.
  16. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    While I can't compile it since I don't all of your libraries, I did load it into the IDE and have another look.
    It looks a lot better.
     
  17. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49
    Which part of my code shows the step ratio of each encoder (or do I have to add it)?
     
  18. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
    Yea, they are block start/finish markers and you can totally have arbitrary extra ones if you want. Even this will compile:

    {
    {
    {
    foo = 1;
    }
    }
    }
    This compiles:
    void setup() {
    // put your setup code here, to run once:
    {{{delay(2000);}}}
    }
    void loop() {
    // put your main code here, to run repeatedly:
    }

    They are required to delimit new functions or (like after an IF-ELSE) to delimit the code in the conditions if you have more than one line.

    One line:

    If (ThisisTrue) then
    foo = 1;
    else
    foo = 2;

    Multiple lines:

    If (ThisisTrue)
    {
    foo = 1;
    bar = 2;
    }
    else
    {
    foo = 2;
    bar = 3;
    }
     
  19. mark tomlinson

    mark tomlinson ༼ つ ◕_ ◕ ༽つ
    Staff Member

    Joined:
    Feb 21, 2013
    Messages:
    23,479
    Likes Received:
    7,303
  20. BrooklynBay

    BrooklynBay Active Member

    Joined:
    Apr 7, 2018
    Messages:
    414
    Likes Received:
    49

Share This Page