Trying to get a servo to go back to center upon button press

Hello guys! I want to start off by saying my Arduino programming skills leave much to be desired! Here's what I need help with:

I have a 1-Man Pontoon boat (about 8' long) that has a 12V Marine Deep Cycle battery and a 30lb. thrust Minn Kota Endura C30 electric trolling motor on it. I removed the head of the motor and relocated it to the right of the seat so I can control forward and reverse speeds. Initially, I was using the swivel seat to steer the motor (turn left in seat, go left, etc.) and this was accomplished via 2 stainless steel 1/16" cables in a X fashion attached to the back top Left and Right of my seat with 2 Eyebolts (port and starboard) attached to a clamp on the motor shaft. This worked okay, but I found I couldn't go in a straight line to save my life!

Hence, my new project!! :slight_smile: Here's what I have so far:

1 60kg waterproof servo motor (3 wire)
1 Arduino Nano
1 DC to DC Converter (12V to 6V) (servo is rated for 6-8.4VDC)
1 Joystick Module

The servo motor is connected as follows:
Red +6VDC
Black Ground
White Pin D3 on Nano

The joystick is connected as follows:
GND Ground on DC to DC Converter and Nano
+5V 5V Pin Nano
VRX Pin A1 Nano
VRY Pin A0 Nano
SW Pin D4 Nano

The sketch I have now currently works fine for turning servo motor left or right.
What I would like to accomplish is that when I click down on the joystick, the motor goes back to center.
This will allow me to go in a straight line instantly whenever I click the button!
Currently, once I move the joystick Left or Right, the servo stays in that position until I change it.

Here's my code:

#include <Servo.h>

//const int ledPin = 13;
const int xPin = A1;                                               
const int yPin = A0;
const int switchPin = 4;
const int servoxPin = 3;
const int servoyPin = 11; 

int xValue;
int yValue;
int X_pos = 90;
int Y_pos = 90;

volatile int switchState = 0;
 
Servo servox;
Servo servoy;

void setup() 
{
  pinMode (xPin, INPUT) ;                     
  pinMode (yPin, INPUT) ;
//  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
  servox.attach(servoxPin ); 
  servoy.attach(servoyPin); 
  servox.write(X_pos);
  servoy.write(Y_pos);
  attachInterrupt(digitalPinToInterrupt(switchPin), switchISR, CHANGE);
}

void loop() 
{
  xValue = analogRead(xPin);  
  yValue = analogRead(yPin);

    
// For X-Axis Servo
  if (xValue < 300)
  {
    if (X_pos < 10) 
    {
      // Do Nothing 
    } 
    else
    {
      X_pos = X_pos - 5;
      servox.write(X_pos);
      delay(100); 
    } 
  } 
  
  if (xValue > 700)
  {
    if (X_pos > 160)
    {
      // Do Nothing  
    }
    else
    {
      X_pos = X_pos + 5;
      servox.write(X_pos);
      delay(100);
    }
  }
// For Y-Axis Servo
if (yValue < 300)
  {
    if (Y_pos < 10) 
    {
      // Do Nothing 
    } 
    else
    {
      Y_pos = Y_pos - 5;
      servoy.write(Y_pos);
      delay(100); 
    } 
  } 
  
  if (yValue > 700)
  {
    if (Y_pos > 160)
    {
      // Do Nothing  
    }
    else
    {
      Y_pos = Y_pos + 5;
      servoy.write(Y_pos);
      delay(100);
    }
   }
  }


void switchISR()
{
  switchState = digitalRead(switchPin);
  digitalWrite(HIGH, switchState);
}

Thanks in advance for the direction I am sure you guys can provide me!!
P.S. I did try searching around the internet for a few hours and tried a few things, but nothing seemed to work. I realized I was in over my head and here I am!!

What is the purpose of switchISR()? You don't need an ISR to detect a human pressing a button. Just check the button state every time through loop(). Something like this

  xValue = analogRead(xPin);  
  yValue = analogRead(yPin);
  buttonState = digitalRead(buttonPin);

  if (buttonState == LOW) {
     servoXPos = 90;
     servoYPos = 90;
  }

And you should only have a single delay(100); as the last thing in loop(). That allows all the inputs to be sampled 10 times per second which is probably sufficient.

If you are thinking of extending the program further you will probably want to get rid of the delay() altogether and use millis() for non-blocking timing as illustrated in Several Things at a Time

See Using millis() for timing, a beginners guide if you need more explanation.

...R

When you've clicked the button how long do you expect it to steer straight? Because as it is now if you centre the steering it will immediately go back round loop() and if the joystick isn't centred it will instantly move the steering again to wherever the joystick points.

Steve

So the code is something I found on the internet. I also am not actually using the Y axis either, but just left it in there because it is doing no harm. Same with the switchISR. I am not using it (that I know of :slight_smile: )

I will try messing with the millis vs delay. If I am not mistaken, the delay is there to allow the servo motor time to get into position, correct?

As for the steering straight part, this is a self-centering joystick. I would like to be able to click the joystick button down and it would command the servo to the middle (straight) position until I push the joystick either left or right.

As it is now, the servo motor stays in the last position I left it via the joystick.

JayBirde:
So the code is something I found on the internet. I also am not actually using the Y axis either, but just left it in there because it is doing no harm. Same with the switchISR. I am not using it (that I know of :slight_smile: )

Take out the irrelevant code - it just makes it harder to figure out what the relevant stuff is doing.

I will try messing with the millis vs delay. If I am not mistaken, the delay is there to allow the servo motor time to get into position, correct?

Partly, but note that I did not say the replacing delay() with millis() is immediately essential. I would get the code working with delay() first.

As it is now, the servo motor stays in the last position I left it via the joystick.

Have you tried the changes I suggested? What happened? If it did not do what you want what do you think the problem might be? (Note that I did not test what I suggested so it may well need some tweaking)

For your next Reply please post the latest version of the program.

...R

Robin, First off, thank you for your help!

The code you provided did need a little tweaking. When I click the joystick, it does return to center now. The only anomaly I am seeing is after I click the joystick to center it, the next time I press the joystick left or right, the servo seems to jump position quickly, opposite of the direction it should be going, then reverses and starts going the direction it should. Code below:

#include <Servo.h>

//const int ledPin = 13;
const int xPin = A1;
const int yPin = A0;
const int switchPin = 4;
const int servoxPin = 3;
const int servoyPin = 11;

int xValue;
int yValue;
int X_pos = 90;
int Y_pos = 90;
int buttonState;

volatile int switchState = 0;

Servo servox;
Servo servoy;

void setup()
{
  pinMode (xPin, INPUT) ;
  pinMode (yPin, INPUT) ;
  //  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
  servox.attach(servoxPin );
  servoy.attach(servoyPin);
  servox.write(X_pos);
  servoy.write(Y_pos);
}

void loop()
{
  xValue = analogRead(xPin);
  yValue = analogRead(yPin);
  buttonState = digitalRead(switchPin);

  if (buttonState == LOW) {
    servox.write(90);
    servoy.write(90);
  }
  // For X-Axis Servo
  if (xValue < 300)
  {
    if (X_pos < 10)
    {
      // Do Nothing
    }
    else
    {
      X_pos = X_pos - 5;
      servox.write(X_pos);
    }
  }

  if (xValue > 700)
  {
    if (X_pos > 160)
    {
      // Do Nothing
    }
    else
    {
      X_pos = X_pos + 5;
      servox.write(X_pos);
    }
  }

  {
    delay(100);
  }
}

Put the line servox.write(X_pos); immediately above the line delay(100); and delete it from everywhere else.

Also delete the lines

    servox.write(90);
    servoy.write(90);

and replace them with

X_pos = 90;

In other words the switch and the joystick set the value of X_pos but they don't directly move the joystick. That should only happen in one place.

...R

PS ... you don't need { and } around the line delay(100);

Robin2:
Put the line servox.write(X_pos); immediately above the line delay(100); and delete it from everywhere else.

Also delete the lines

    servox.write(90);

servoy.write(90);



and replace them with


X_pos = 90;




In other words the switch and the joystick set the value of X_pos but they don't directly move the joystick. That should only happen in one place.

...R

PS ... you don't need { and } around the line delay(100);

Robin, I made those changes you suggested and everything is working perfectly now!! Thanks so much! Posting final code below, in case anyone else is interested in this. Thanks again, you're an Arduino Genius!!

#include <Servo.h>

//const int ledPin = 13;
const int xPin = A1;
const int yPin = A0;
const int switchPin = 4;
const int servoxPin = 3;
const int servoyPin = 11;

int xValue;
int yValue;
int X_pos = 90;
int Y_pos = 90;
int buttonState;

volatile int switchState = 0;

Servo servox;
Servo servoy;

void setup()
{
  pinMode (xPin, INPUT) ;
  pinMode (yPin, INPUT) ;
  //  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
  servox.attach(servoxPin );
  servoy.attach(servoyPin);
  servox.write(X_pos);
  servoy.write(Y_pos);
}

void loop()
{
  xValue = analogRead(xPin);
  yValue = analogRead(yPin);
  buttonState = digitalRead(switchPin);

  if (buttonState == LOW) {
    X_pos = 90;
  }
  // For X-Axis Servo
  if (xValue < 300)
  {
    if (X_pos < 10)
    {
      // Do Nothing
    }
    else
    {
      X_pos = X_pos - 5;
      servox.write(X_pos);
    }
  }

  if (xValue > 700)
  {
    if (X_pos > 160)
    {
      // Do Nothing
    }
    else
    {
      X_pos = X_pos + 5;
      servox.write(X_pos);
    }
  }
  servox.write(X_pos);
  delay(100);
}

Thanks for the update. You still have servox.write(X_pos); on lines 53 and 66.

...R