Switching between joystick mode in real time using a push button

Hello! I am currently working on a project where I have a pan and tilt mechanism. In this mechanism I have two modes, one where you control the joystick in real time, ie move it to the left, the mechanism rotates to the left, to the right, to the right and so on. It reverts to standard positioning when you let go of the joystick.

I also have a mode which is the same, except it holds positioning when you let go of the joystick. My question is how can I switch between these two modes using either the analog joystick button, or an external button.

Currently I have it hooked up to an external push button with what I assume is correct switch code, and this is what I got so far, but its not realy working

//add the servo libary
#include <Servo.h>

//define our servos
Servo servo1;

int pin_switch = 2;

//define joystick pins (Analog)
int joyX = 0;
int joyY = 1;

//variable to read the values from the analog pins 
int joyVal;
int readPin;
 
// variables to hold the new and old switch states
boolean oldSwitchState = LOW;
boolean newSwitchState = LOW;
 
boolean status = LOW;
 
void setup() 
{
    Serial.begin(9600);
    servo1.attach(9);
    pinMode(pin_switch, INPUT); 
}
 
void loop()
{
    newSwitchState = digitalRead(pin_switch);
 
    if ( newSwitchState != oldSwitchState ) 
    {
       // has the button switch been closed?
       if (newSwitchState == HIGH )
       {
           if (status == LOW ) {joyVal = analogRead(joyX);
            joyVal = map(joyVal, 0, 1023, 0, 180); //servo value betven 0-180
            servo1.write(joyVal); //set the servo position acording to the joystick value
            delay(0);  status = HIGH;  
           }
           else { 
           servo1.write(180);
           status = LOW;}
       }
       oldSwitchState = newSwitchState;
    }   
}

For testing, as I have it set up right now, the first one is just the first mode, and the second is just moving the servo on one side, but the first mode is not working, and it works odd. When I push the button, the servo goes 90 degrees to the left, and to the right… and that’s it. The joystick is unresponsive.

How would I go about this?

Do you have a pulldown resistor keeping the switch input LOW when the switch is not closed or is it floating at an unknown, possibly HIGH value ?

UKHeliBob: Do you have a pulldown resistor keeping the switch input LOW when the switch is not closed or is it floating at an unknown, possibly HIGH value ?

Well, I have a resistor connected but im new to arduino and am not sure what a pulldown resistor is. But I do have a one in the circuit with the regular push button.

It's odd as I adapted this code from a LED light and with the LED light it works, turns it off and on again, but nothing with the servo... if you change the code to just Servo.write(0) and (180) it works that way too but not with my intended code with the joystick...

If you have wired the push button to take the pin HIGH when pressed then it would be normal to wire a resistor, say 10K, between the Arduino pin and GND (hence a pulldown resistor). This ensures that the pin is normally LOW and goes HIGH when the button is pressed with never any doubt as to its state.

You can avoid the need for an external resistor by using a pinMode() of INPUT_PULLUP to activate the internal pullup resistor and wiring the pushbutton to take the pin to GND when pressed and adjusting the program logic accordingly.

UKHeliBob: If you have wired the push button to take the pin HIGH when pressed then it would be normal to wire a resistor, say 10K, between the Arduino pin and GND (hence a pulldown resistor). This ensures that the pin is normally LOW and goes HIGH when the button is pressed with never any doubt as to its state.

You can avoid the need for an external resistor by using a pinMode() of INPUT_PULLUP to activate the internal pullup resistor and wiring the pushbutton to take the pin to GND when pressed and adjusting the program logic accordingly.

Thank you, I have rewired and edited the code with pullup now, however, my problem is still the same...

OK, that has eliminated a possible problem. Please post your code as it is now

Ok! Hopefully I have done it correctly.

//add the servo libary
#include <Servo.h>

//define our servos
Servo servo1;

int pin_switch = 2;

//define joystick pins (Analog)
int joyX = 0;
int joyY = 1;

//variable to read the values from the analog pins 
int joyVal;
int readPin;
 
// variables to hold the new and old switch states
boolean oldSwitchState = LOW;
boolean newSwitchState = LOW;
boolean status = LOW;
 
void setup() 
{
    Serial.begin(9600);
    servo1.attach(9);
    pinMode(pin_switch, INPUT_PULLUP); 
}
 
void loop()
{
    newSwitchState = digitalRead(pin_switch);
 
    if (newSwitchState != oldSwitchState) 
    {
       if (newSwitchState == HIGH )
       {
           if (status == LOW ) {
            joyVal = analogRead(joyX);
            joyVal = map(joyVal, 0, 1023, 0, 180); //servo value betven 0-180
            servo1.write(joyVal); //set the servo position acording to the joystick value
            Serial.print(status);
            status = HIGH;  
           }
            else { 
            servo1.write(180);
            Serial.print(status);
            status = LOW;
           }
       }
       oldSwitchState = newSwitchState;
    }   
}

Hopefully I have done it correctly.

That depends on what you want to do

As it stands, if the switch goes from closed (LOW) to open (HIGH) and status is LOW then the servo will move to a position dictated by the current position of the joystick but it will not track the position of the joystick because the switch state will not change until it is released at which point the servo will move to 180.

Is that what you want ?

UKHeliBob: Is that what you want ?

Ah yes, you seem to have described my problem, no that is not what I want.

but it will not track the position of the joystick ...

I want for it to be track the joystick position, and translate that to the serov, in real time once the button is pressed.

As I described in the first post, I have a separate code on a different file which I intend to combine with this code and have the button switch act as a toggle between the two modes. In pseudo code, I imagine something like

if low = activate mode where it tracks the joystick movement and reverts back to neutral position if you let go of th ejoystick

if button pressed, change to high and through that activate mode 2, whatever that may be (for this code, it is just to move the servo to 180, but in my intended code it will activate the other code where it will follow the joystick movement, and hold the position if the joystick is let go)

then further, if you press the button again, either the joystick SW button or external button, it changed state to low again which, in turn, activates the previous joystick control mode.

Does that make sense?

I want for it to be track the joystick position, and translate that to the serov, in real time once the button is pressed.

The program can be in one of two states. state = 0 - servo is driven to 180 and stays there state = 1 - servo responds to joystick input

Write the code that alternates between state = 0 and state = 1 when the button becomes pressed. Put this at the start if loop() Then in loop(), if state == 0 move the servo to 180. Don't worry if this is done repeatedly else read the joystick, derive the servo angle using map() and write it to the servo

UKHeliBob:
The program can be in one of two states.
state = 0 - servo is driven to 180 and stays there
state = 1 - servo responds to joystick input

Write the code that alternates between state = 0 and state = 1 when the button becomes pressed. Put this at the start if loop()
Then in loop(),
if state == 0 move the servo to 180. Don’t worry if this is done repeatedly
else read the joystick, derive the servo angle using map() and write it to the servo

Hmm I see, but being a newbie I still cannot figure out how to have it act like a switch, this external push button. I have wired both intended codes, and they switch modes depending if the button is pressed or not, however how would I go about it saving the last button press, like I mentioned?

Now it’s just basically if pressed, do X, if not, do Y…

Take a look at the StateChangeDetection example in the IDE and revise it to switch states on every change of input state

UKHeliBob:
Take a look at the StateChangeDetection example in the IDE and revise it to switch states on every change of input state

Hello!

Thank you, I have looked into it and modified my code, to what I think is correct, yes. However, it is giving me weird automatic readings? Strangely, it activates the push button to high without any input every second or so

ie according to the serial monitor it gives “000000010000000001000000001000000” etc and so on.
Do you know perhaps where the problem lies? I know its very messy, and i’ll fix it eventually, apologies.

//Add the servo libary
#include <Servo.h>

//The servos
Servo myServo;
Servo myServoTwo;

//Digital Pins for the Servos
byte servoPin = 2;  
byte servoPinTwo = 9; 

//Initial Servo Positions
int servoPos = 90;
int servoPosTwo = 90;

//Max, min, movement for the servos
int servoMax = 180; //Max Servo Position
int servoMin = 0; // Min Servo Position
int servoMove = 10;  // Degrees per movement

//Joystick Analog Pins
byte potPin = A0;   
byte potPinTwo = A1; 

//Values
int potValue = 0;
int potValueTwo = 0;

int potCentre = 512; // Centre value of the jostick
int potDeadRange = 50; // Movements of this degree on either side which can be ignored

//Time, change readinterval for speed difference
unsigned long curMillis;
unsigned long readIntervalMillis = 50;
unsigned long lastReadMillis;

unsigned long curMillisTwo;
unsigned long readIntervalMillisTwo = 50;
unsigned long lastReadMillisTwo;

//Pin for the button
int pin_switch = 2;

//define joystick pins (Analog)
int joyX = 0;
int joyY = 1;

//variable to read the values from the analog pins
int joyVal;
int readPin;

// variables to hold the new and old switch states
int buttonState = LOW;
int lastButtonState = LOW;
int servoState = LOW;

//Setup
void setup()
{
  Serial.begin(9600);
  //Pinmode for the button
  pinMode(pin_switch, INPUT_PULLUP);
  
  //Servos
  myServo.attach(servoPin);
	myServo.write(servoPos);
	
	myServoTwo.attach(servoPinTwo);
	myServoTwo.write(servoPosTwo);
}

void loop()
{
  
  curMillis = millis();
	curMillisTwo = millis();
  
  buttonState = digitalRead(pin_switch);

  // check if the button is pressed or released
  // by comparing the buttonState to its previous state 
  if (buttonState != lastButtonState) {
    // change the state of the led when someone pressed the button
    if (buttonState == 1) { 
      if(servoState==1) servoState=0;
      else            servoState=1;         
    }
    
    // remember the current state of the button
    lastButtonState = buttonState;
  }
  
    // ( debouncing )
  delay(50);
  
  if (servoState == LOW) {
    readJoystick();
	  readJoystickTwo();
	  moveServo();
	  moveServoTwo();
	  
  } else if(servoState = HIGH) {
    joyVal = analogRead(joyX);
    joyVal = map(joyVal, 0, 1023, 0, 180);
    myServo.write(joyVal);
    joyVal = analogRead(joyY);
    joyVal = map (joyVal, 0, 1023, 0, 180);
    myServoTwo.write(joyVal);
    

  }
  Serial.print(buttonState);
}

//Function to read the joystick
void readJoystick() {
			// Check the time
	if (curMillis - lastReadMillis >= readIntervalMillis) {
		lastReadMillis += readIntervalMillis;
			// Read the joystick
		potValue = analogRead(potPin);
			// See if movement is required
		if (potValue > potCentre + potDeadRange) {
			servoPos += servoMove;
		}
		if (potValue < potCentre - potDeadRange) {
			servoPos -= servoMove;
		}
			// Check if the values 
		if (servoPos > servoMax) {
			servoPos = servoMax;
		}
		if (servoPos < servoMin) {
			servoPos = servoMin;
		}
	}
}

// The same but with joystick 2, this could prob be one function...
void readJoystickTwo() {
		
	if (curMillisTwo - lastReadMillisTwo >= readIntervalMillisTwo) {
		lastReadMillisTwo += readIntervalMillisTwo;
			
		potValueTwo = analogRead(potPinTwo);
			
		if (potValueTwo > potCentre + potDeadRange) {
			servoPosTwo += servoMove;
		}
		if (potValueTwo < potCentre - potDeadRange) {
			servoPosTwo -= servoMove;
		}
			
		if (servoPosTwo > servoMax) {
			servoPosTwo = servoMax;
		}
		if (servoPosTwo < servoMin) {
			servoPosTwo = servoMin;
		}
	}
}

//Move the servos...
void moveServo() {
	myServo.write(servoPos);
}
void moveServoTwo() {
	myServoTwo.write(servoPosTwo);
}

It is never a good idea to use pin 2 for your servo pin and your switch pin

You have vastly complicated your program by reading 2 joysticks, using 2 servos and introducing the idea of deadbands. My advice would be to go back to basics, ie 1 joystick and 1 servo, no deadband and get that working first

Here is something to build on

const byte buttonPin = A3;
const byte joystickPot = A7;
byte currentButtonState;
byte previousButtonState;
byte systemState;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.println("starting");
}
void loop()
{
  currentButtonState = digitalRead(buttonPin);
  if (currentButtonState != previousButtonState)
  {
    if (currentButtonState == LOW)  //button became pressed
    {
      systemState = !systemState; //change state
      Serial.print("system state : ");
      Serial.println(systemState);
    }
    previousButtonState = currentButtonState;
  }
  switch (systemState)
  {
    case 0: 
      Serial.println("servo to 180");
      break;
    case 1:
      Serial.print("joystick value : ");
      Serial.println(analogRead(joystickPot));
      break;
  }
}

Thanks mates, problem solved. blh64’s advice solved it for me, just switched the button pin from 2 to 3, no errors!

That's good

You might still like to look at my skeleton program as it uses techniques that you may not be familiar with. I am particularly fond of switch/case as to my mind it easier to see what is going on as well as o maintain. It is surprising how often a program can be written as a state machine as here.

Good luck with your future projects

UKHeliBob: That's good

You might still like to look at my skeleton program as it uses techniques that you may not be familiar with. I am particularly fond of switch/case as to my mind it easier to see what is going on as well as o maintain. It is surprising how often a program can be written as a state machine as here.

Good luck with your future projects

Yes of course, that will help a lot, and thank you, hopefully it will go well! Cheers.