Joystick Sensor Value Threshold - Actuator Control - PLEASE HELP

I am working on a code to make a Firgelli Automation OS Series linear actuators move a certain distance based on the position of a joystick. I have been able to successfully move the actuator a fixed distance on its own. But, when I attempt to make it move based on the joystick input, it is very jumpy. I was able to determine that this jumpiness was due to the minor instability of the inputs provided by this joystick. My solution was to create a threshold, i.e. only move the actuator if the joystick value has changed by x amount from where it was. My code is below:

//pulse count variables
volatile unsigned long count = 0;
unsigned long copyCount = 0;
unsigned long lastRead = 0;
unsigned long interval = 250;
volatile int pulses = 0;

//pin definitions
int rawStickX = analogRead(A0);
int rawStickY = analogRead(A5);
#define encoder 2

// motor one
#define throttle 10
#define Tin1 9
#define Tin2 8

//other variables
float aLength = 0;
float aLastLength = 0;
boolean thresh = false;
float play;
int lastSticky = 0;

//joystick map variables
//y axis
int sticky = map(rawStickY, 120, 850, 0, 500); //map to usable ranges for throttle
int minY[] = { 0, 101, 201, 301, 401 };         //arrays for max and min joystick values for every inch, actual is calculated later using "play"
int maxY[] = { 100, 200, 300, 400, 500 };

void setup()
{

  pinMode(encoder, INPUT_PULLUP);
  pinMode(throttle, OUTPUT);
  pinMode(Tin1, OUTPUT);
  pinMode(Tin2, OUTPUT);
  pinMode(rawStickX, INPUT);
  pinMode(rawStickY, INPUT);

  Serial.begin(115200);
  Serial.println("start...");

  attachInterrupt(digitalPinToInterrupt(encoder), countISR, RISING); //interrupt signal to pin 2
  pulses = 0;
  count = 0;
  aLength = 0;
}

void countISR()
{ //increment or decrement pulses, based on actuator direction

  if (digitalRead(Tin1) == HIGH && digitalRead(Tin2) == LOW)
  {
    count++;
  }
  else if (digitalRead(Tin1) == LOW && digitalRead(Tin2) == HIGH)
    count--;
}

void pulseCount()
{ //code to read encoder pulses... about 46 per inch

  if (millis() - lastRead >= interval) //read interrupt count every 250ms
  {
    lastRead += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    // count = 0;
    interrupts();

    //Serial.println(count);
    delay(5); //buffer

    pulses = copyCount;
    return pulses; //make pulses global
  }
}

void extendThrottle(float aLength)
{
  float reqPulses = aLength * 46;
  int movePulses = ceil(reqPulses);

  digitalWrite(Tin1, HIGH); //set forward direction
  digitalWrite(Tin2, LOW);
  //Serial.print("eMovePulses = ");
  //Serial.println(movePulses);
  //Serial.println(movePulses);

  if (pulses < movePulses)
  {
    analogWrite(throttle, 127);   //run at half speed for testing purposes
  }
  else
  { //then turn off
    analogWrite(throttle, 0);
  }

  return movePulses;
}

void retractThrottle(float aLength)
{
  float reqPulses = aLength * 46;
  int movePulses = floor(reqPulses);

  digitalWrite(Tin1, LOW); //set reverse direction
  digitalWrite(Tin2, HIGH);

  if (pulses > movePulses)
  {
    analogWrite(throttle, 127);
  }
  else
  { //then turn off
    analogWrite(throttle, 0);
  }

  return movePulses;
}

void threshold() {
  int change = (aLength - aLastLength);
  thresh = false;
  if (abs(change) >= 0.07) { //change threshold here
    thresh = true;
    Serial.println("1");
  }
  else {
    thresh = false;
    Serial.println("0");
  }
  delay(500);
  //Serial.println(change);
  return thresh;
  //return change;
}


void loop()
{ // main loop
  //thresh = false;
  int rawStickY = analogRead(A5);
  int rawStickX = analogRead(A0);
  int sticky = map(rawStickY, 80, 850, 0, 500); //map to usable ranges for throttle
  pulseCount();
  threshold();
  //delay(1000); //debugging wait
  //Serial.println(pulses);
 /* if (thresh == true) {
    Serial.println("1");
  }
  else {
    Serial.println("0");
  }*/

  if (thresh == true) {
    if (sticky > minY[0] && sticky <= maxY[0])
    {
      play = (sticky - minY[0]); //play variable calculates how far within a range the joystick is
      aLength = (play / 100);
      //Serial.println(aLength);
    }
    if (sticky > minY[1] && sticky <= maxY[1])
    {
      play = sticky - minY[1];
      aLength = 1 + (play / 100); //calculate play, then add one inch (move the actuator 1 and some fraction of an inch)
    }
    if (sticky > minY[2] && sticky <= maxY[2])
    {
      play = sticky - minY[2];
      aLength = 2 + (play / 100);
    }
    if (sticky > minY[3] && sticky <= maxY[3])
    {
      play = sticky - minY[3];
      aLength = 3 + (play / 100);
    }
    if (sticky > minY[4] && sticky <= maxY[4])
    {
      play = sticky - minY[4];
      aLength = 4 + (play / 100);
    }
    delay(2);
    sticky = map(rawStickY, 80, 850, 0, 500);
    if (aLength > aLastLength)
    {
      extendThrottle(aLength);
      delay(10);
      // Serial.println(F("MOVING"));
    }
    else if (aLength < aLastLength)
    {
      retractThrottle(aLength);
      delay(10);
      // Serial.println(F("MOVING"));
    }
  else
  {
    analogWrite(throttle, 0); // else don't move the "throttle" actuator
  }
  }
  else
  {
    analogWrite(throttle, 0); // don't move the "throttle" actuator if thresh != true
  }
  


  //Serial.println(rawStickY);
  //Serial.print(F("aLength = "));
  //Serial.println(aLength);
  if (thresh == true) {
    Serial.println("1");
  }
  else {
    Serial.println("0");
  }
  //delay(500);
  aLastLength = aLength;
  //delay(500);
  //Serial.println(aLength - aLastLength);
  lastSticky = rawStickY;
}

The issue I’m running into is that the code in constantly updating the value of the joystick as it moves, therefore it can never break the specified threshold. How do I make it so that it will break this threshold and only move the actuators when that happens? While still keeping my code running as fast as possible…

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Have you got any bypass capacitors on the joystick output to minimise noise?

Tom... :slight_smile:

//pin definitions
int rawStickX = analogRead(A0);
int rawStickY = analogRead(A5);

The hardware is useless at compile time. So the initial values you are trying to assign to these variables are meaningless.

int sticky = map(rawStickY, 120, 850, 0, 500); //map to usable ranges for throttle

Garbage in, garbage out.

int minY[] = { 0, 101, 201, 301, 401 };         //arrays for max and min joystick values for every inch, actual is calculated later using "play"
int maxY[] = { 100, 200, 300, 400, 500 };

Having arrays where the values are all constant functions of the index is silly.

    return pulses; //make pulses global

That is NOT what that code does.

  return movePulses;
}

The function return type is void. It makes no sense to try to return a value from a void function.

  if (abs(change) >= 0.07) { //change threshold here

If the absolute value of an int is greater than 0.07... Does THAT make sense?

  return thresh;

The function return type is void. It makes no sense to try to return a value from a void function.

void loop()
{ // main loop
  //thresh = false;
  int rawStickY = analogRead(A5);
  int rawStickX = analogRead(A0);

Why do you have local variables with the same name as global variables?

You should have ONE function to move the actuator. The distance to move it should be the input - positive to extend, negative to retract.

You should NOT be switching between length and "pulses". The term pulses is meaningless, since your actuator does not appear to be controlled by pulses. If it IS, you are not controlling how many pulses are generated.