Unstable value after exiting function

Hello i am creating a robotic arm and i have a problem with one of the joint angles…

My setup is and ADS1115 I2C ADC 2 joysticks and an arduino Mega.

I am driving the servos directly from the Analogue pins of the arduino. The problem is a coding based one the root of i cannot find. I am asking here because i have not seen this behavior before. The adc reading is normal the mapped value seems to be good but in the loop the value is reset to 1.

The code follows bellow. I am posting the whole code because i do not know what might affect the value honestly.

#include "VARIABLES.h"
#include <Wire.h>
#include <Servo.h>
#include <Arduino.h>
#include <Adafruit_ADS1015.h>
#include "Adafruit_MCP23017.h"
#include "DRV8825.h"
Adafruit_MCP23017 mcp;
Adafruit_ADS1115 ads;
DRV8825 stepper(MOTOR_STEPS, DIR, STEP, ENABLE, MODE0, MODE1, MODE2);
Servo servo[6];
void setup()
{
  Serial.begin(9600);
  ads.begin();
  ads.setGain(GAIN_TWOTHIRDS);
  mcp.begin();
  stepper.begin(RPM);
  stepper.enable();
  servo[0].attach(A0);
  servo[1].attach(A1);
  servo[2].attach(A2);
  servo[3].attach(A3);
  servo[4].attach(A4);
  servo[5].attach(A5 );
  for(int i=0; i<=15;i++)
  {
    mcp.pullUp(i,HIGH);
    mcp.pinMode(i,INPUT);
  }  
  timer=millis();
  //timer2=millis();
}
void loop()
{
  //--------------------DB----------------------//
  /*
  while(1)
  {
    read_controls();
  }
  */
 //--------------------DB--------------------------*/
  if(millis()-timer>100)
  {
    timer=millis();
    read_controls();
  }
  //---------------------------------------Joint 1--------------------------------//
  if(X1angle>85 || X1angle<83)
  {
    if(oldX1angle<X1angle)
    {
      
      for(int i=oldX1angle; i<=X1angle;i++)
      {
        
        servo[0].write(i);
        servo[1].write(i);
        delay(ServoMoveDelay);
        oldX1angle=i;
        }
    }
    if(oldX1angle>X1angle)
    {
      
      for(int i=oldX1angle; i>=X1angle; i--)
      {
        servo[0].write(i);
        servo[1].write(i);
        delay(ServoMoveDelay);
        oldX1angle=i;
      }
    }
  }
  //---------------------------------------Joint 2--------------------------------//
  if(Y1angle>90 || Y1angle<88)
  {
    if(oldY1angle<Y1angle)
    {
      for(int i=oldY1angle; i<=Y1angle;i++)
      {
        servo[2].write(i);
        delay(ServoMoveDelay);
        oldY1angle=i;
   }
    }
    if(oldY1angle>Y1angle)
    {
      for(int i=oldY1angle; i>=Y1angle; i--)
      {
        servo[2].write(i);
        delay(ServoMoveDelay);
        oldY1angle=i;
      }
    }
  }  
  //---------------------------------------Joint 3--------------------------------//
  if(X2angle>88 || X2angle<86)
  {
    if(oldX2angle<X2angle)
    {
      for(int i=oldX2angle; i<=X2angle;i++)
      {
        servo[3].write(i);
        delay(ServoMoveDelay);
        oldX2angle=i;
        }
    }
    if(oldX2angle>X2angle)
    {
      for(int i=oldX2angle; i>=X2angle; i--)
      {
        servo[3].write(i);
        delay(ServoMoveDelay);
        oldX2angle=i;
      }
    }
  }
  //---------------------------------------Joint 4--------------------------------//
  if(Y2angle>95 || Y2angle<93)
  {
    Serial.println(Y2angle);
    if(oldY2angle<Y2angle)
    {
      for(int i=oldY2angle; i<=Y2angle;i++)
      {
        servo[4].write(i);
        delay(ServoMoveDelay);
        oldY2angle=i;
        Serial.println(i);
      }
    }
    if(oldY2angle>Y2angle)
    {
      for(int i=oldY2angle; i>=Y2angle; i--)
      {
        servo[4].write(i);
        delay(ServoMoveDelay);
        oldY2angle=i;
        Serial.println(i);
        }
    }
  }
  //---------------------------------------Claw----------------------------------//
  if(buttonState[5]==LOW)
  {
    if(ClawAngle-1>=0)
    {
      ClawAngle=ClawAngle-1;
      servo[5].write(ClawAngle);
    }
  }
  if(buttonState[6]==LOW)
  {
    if(ClawAngle+1<=180)
    {
      ClawAngle=ClawAngle+1;
      servo[5].write(ClawAngle);
    }
  }
  //---------------------------------------Stepper--------------------------------//
   stepper.setMicrostep(microsteps);
  if(buttonState[4]==LOW) //While Switch to move is pressed and limit switch is not  buttonState[3]==LOW && buttonState[4]==HIGH (buttonState[4] === Terminal Switch (hall effect)
  {
    if(StepperPos-1 >=0)
    {
      StepperPos--;
      stepper.move(microsteps*MOTOR_STEPS/defaultStep);
    }    
  }
  if(buttonState[3]==LOW) //While Switch to move is pressed and limit switch is not  buttonState[3]==LOW && buttonState[4]==HIGH (buttonState[4] === Terminal Switch (hall effect)
  {
    if(StepperPos +1 <=360)
    {
      StepperPos++;
      stepper.move(-microsteps*MOTOR_STEPS/defaultStep);
    }
  }
 
  
}
void read_controls()
{
  adc0=ads.readADC_SingleEnded(0);
  //Serial.println(adc0);
  adc1=ads.readADC_SingleEnded(1);
  //Serial.println(adc1);
  adc2=ads.readADC_SingleEnded(2);
  //Serial.println(adc2);
  adc3=ads.readADC_SingleEnded(3);
  //Serial.println(adc3);

  X1angle=map(adc2,26936,1268,180,0);  // MIN 17 MAX 23902 IDLE 11643
  Y1angle=map(adc3,26936,13,180,0);// MIN 4150 MAX 23889 IDLE 11769
  X2angle=map(adc0,26939,43,180,0); // MIN 24 MAX 23891 IDLE 11389
  Y2angle=map(adc1,26935,16,180,0);  // MIN 19 MAX 23880 IDLE 12223
  //------------------DB----------------------//
  /*
   Serial.print("   ANGLES   ");
  Serial.print(X1angle);
  Serial.print(" ");
  Serial.print(Y1angle);
  Serial.print(" ");
  Serial.print(X2angle);
  Serial.print(" ");
  Serial.print(Y2angle);  
  Serial.print("     ADC   ");
  Serial.print(adc2);
  Serial.print(" ");
  Serial.print(adc3);
  Serial.print(" ");
  Serial.print(adc0);
  Serial.print(" ");
  Serial.println(adc1);
 */
 //---------------------MCP------------------//
  for(int i=2;i<=15;i++)
  {
    buttonState[i]=mcp.digitalRead(i);
  }
  buttonState[0]=mcp.digitalRead(0);
  buttonState[1]=mcp.digitalRead(1);
}

And the variables header file

#ifndef VARIABLES_H
#define VARIABLES_H
//----ADC---//
int adc0, adc1, adc2, adc3; // ADC Readings
int X1angle,Y1angle,X2angle,Y2angle; //Joystick Angle Variables
int ClawAngle;
//--------Servos------//
int ServoMoveDelay=50;
//--------MCP-------//
int buttonState[14];
unsigned long timer;

//---------------Stepper---------------//
int microsteps=32; //Stepper Microstepping Value
int StepperPos;
int RPM=50; //Stepper Speed
int MOTOR_STEPS=200;
int defaultStep=32; //MOTOR_STEPS/defaultStep=200/360=1 degrees/Step    MOTOR_STEPS/200=1.8 degrees/Step
int oldX1angle,oldY1angle,oldX2angle,oldY2angle;
#define ENABLE 7
#define STEP 3
#define DIR 2
#define MODE0 6
#define MODE1 5
#define MODE2 4
#endif

The value i am referring to is Y2angle (adc1) and the joint controlled by this value is Joint 4

Thank you in advance.

  1. Describe what you expect to happen, and what happens instead.

  2. Post a wiring diagram. Inadequate power supplies account for 95% of the "servo misbehaving" posts on this forum.

How can ANYTHING possibly be getting "reset to 1" in loop, when the ONLY code you ever execute in loop is this:

while(1)
{
    read_controls();
}

Regards,
Ray L.

Are you sure?

  /*
  while(1)
  {
    read_controls();
  }
  */

Steve

//--------MCP-------//

int buttonState[14];






for(int i=2;i<=15;i++)
  {
    buttonState[i]=mcp.digitalRead(i);
  }

Oops. When values change “impossibly”, always look for array bounds errors…

Thank you for your replies.

The problem is not with the servo but with the value of the Y2angle variable.

All other servos and the variables driving them behave just fine.

I expect Y2angle to be 94 after mapping the adc1 value but instead i get 1 in the main loop.

The MCP IO expander has nothing to do with this issue it just reads button states.

The adc readings seem fine in the read_controls function i have tested them with another ADC (i had one before that had a busted input so i checked if that's the case)

As you mentioned when troubleshooting i was running only the while function in the main loop and got a solid reading but after i commented this part out and let the whole loop code run the value was just 1

The MCP IO expander has nothing to do with this issue it just reads button states

Yeah, but you're storing the state of button15 into the 16th location of a 14-element array.
Do you want to bet that the button state isn't 1, and that you're not overwriting your y2angle variable instead of an array element?
(This, BTW, is one of the "buffer overflow" errors that gain so much fame for causing security bugs. C, and C++'s "core", has NO PROTECTION (and few warnings) for writing past the end of an array...)

If you write outside an array everything can happen. Aka, that CAN cause problems with completely different parts or even crashes. So it's BS to say it has nothing to do with it :wink:

Oh … i did not put much thought into this…
So considering these changes i should be fine right ?

for(int i=2;i<=14;i++)
  {
    buttonState[i]=mcp.digitalRead(i);
  }
  buttonState[0]=mcp.digitalRead(0);
  buttonState[1]=mcp.digitalRead(1);
int buttonState[14];

Well i’m awed … its seems fixed … the angle output is what was expected … but i seem to face another minor problem…

When the value changes (lets say the joystick moved and the output is 107) the angle jumps to 1 and then rises as planned to 107 but why it jumps… i had not this problem before…

I think the problem lies in this part of the code

if(Y2angle>95 || Y2angle<93)
  {
    
    if(oldY2angle<Y2angle)
    {
      for(int i=oldY2angle; i<=Y2angle;i++)
      {
        servo[4].write(i);
        delay(ServoMoveDelay);
        oldY2angle=i;
        Serial.println(i);
      }
    }
    if(oldY2angle>Y2angle)
    {
      for(int i=oldY2angle; i>=Y2angle; i--)
      {
        servo[4].write(i);
        delay(ServoMoveDelay);
        oldY2angle=i;
        Serial.println(i);
        }
    }
  }

To make it clear lets say that the motor is idling at 94 degrees. When i move the joystick to 160 degrees the motor will jump to 1 degrees and reach 160 slowly. The slow movement is caused by the delay and its nothing out of the ordinary. The jump from the motor current position to 1 is what worries me.

An array with 14 entries has them addressed as array[0] to array[13]. You're still using buttonState[14], which presumably is overwriting something other than your angle.

Steve

Sorry pasted the wrong code…

int buttonState[15];
 for(int i=2;i<=14;i++)
  {
    buttonState[i]=mcp.digitalRead(i);
  }
  buttonState[0]=mcp.digitalRead(0);
  buttonState[1]=mcp.digitalRead(1);

By uploading the code everything works as planned... i cant believe that an array caused this ... i owe to be careful in the future... anyway thank you very much for your support!

But i still do not understand how this became an issue now ... this code was working fine but i guess i had more unused variables that got altered.

For the future:
That’s why most people write:

int buttonState[15];
for(int i = 2; i < 15; i++)
  {
    buttonState[i] = mcp.digitalRead(i);
  }

Now both places can use the same number aka 15. Also added some space, they are free and make it more readable :wink:

Or automated

int buttonState[15];
const byte NrButtonStates = sizeof(buttonState)/sizeof(buttonState[0]);

for(int i = 2; i < NrButtonStates; i++)
  {
    buttonState[i] = mcp.digitalRead(i);
  }

Extra bonus:
An int is pretty overkill to simply store HIGH/LOW / 1/0. Also, to in remind yourself of what is an array it’s common to make the variable name plural for arrays:

bool buttonStates[15];
const byte NrButtonStates = sizeof(buttonStates)/sizeof(buttonStates[0]);

for(byte i = 2; i < NrButtonStates; i++)
  {
    buttonStates[i] = mcp.digitalRead(i);
  }

ChristosS:
But i still do not understand how this became an issue now … this code was working fine

Thing is, the compiler packs the variables in a way he seems fit. Changes to the code may change the place in memory because of the “dark ways” of the compiler.

For example (and it is really that!). If you write:

byte myArray[5];
byte someUselessVariable;
byte someVeryImportantVariable;

The compiler may pack it like:

**Variable ** Memory address
myArray[0] #0
myArray[1] #1
myArray[2] #2
myArray[3] #3
myArray[4] #4
someUselessVariable #5
someVeryImportantVariable #6

So writing to ‘myArray[5]’ will write to address #5 thus effectively write into ‘someUselessVariable’. Why that variable is useless isn’t important.

But the compiler might also think it’s better to do:

**Variable ** Memory address
myArray[0] #0
myArray[1] #1
myArray[2] #2
myArray[3] #3
myArray[4] #4
someVeryImportantVariable #5
someUselessVariable #6

And now all of a sudden writing to ‘myArray[5]’ writes to ‘someVeryImportantVariable’ and causes the program to act weird or crash.

And yeah, in the first place it might work, it’s still a bad thing as you can see.