Remote control servo playback - help

Ok I’ve got a keyfob remote, when i push (and hold) the button on it i want the arduino to play back a series of movements on a servo and keep looping through that sequence as long as the button is pressed. when i release the button the sequence needs to stop and the servo return to the home position.

Here is my sketch

#include <Servo.h>

Servo servo;
int angle = 1;

void setup(){
  servo.attach(9);
  servo.write(angle);
  }

 
void loop(){
 

  while (digitalRead(4) == LOW) {
       // now scan back to home position and stay there
  for(angle = 180; angle > 0; angle--)    
 {                                
  servo.write(angle);           
  delay(25);    
  }  
  
  
  while (digitalRead(4) == HIGH) {  // Button 1 pressed

    //  scan from 10 to 40 degrees
  for(angle = 10; angle < 40; angle++)  
  {                                  
    servo.write(angle);               
    delay(15);                   
  } 
  // now scan back from 40 to 10 degrees
  for(angle = 40; angle > 10; angle--)    
 {                                
  servo.write(angle);           
  delay(25);       
 } 
   //  scan from 10 to 30 degrees
  for(angle = 10; angle < 30; angle++)  
  {                                  
    servo.write(angle);               
    delay(15);                   
  } 
  // now scan back from 30 to 20 degrees
  for(angle = 30; angle > 20; angle--)    
 {                                
  servo.write(angle);           
  delay(35);       
 }  
   

  }  

  }
  }

but the servo doesn’t do anything whether i press the button or not.

I’ve tested the RF (using the hi/low to light an LED) and that seems to work fine. If i just put the servo commands in to a sketch and loop it from boot up then it works; can anyone point out where i’m going wrong?

Hi tommoore,

Rather than using quotes for your code, you should use code tags. Makes it easier for us to put the code into a local copy of the IDE.

You have 2 basic tasks - reading the state of the remote and making servos move.
Test them independently.

Put in the servo sweep tutorial and see if you can make your servo move without the remote.
Put Serial.println() in your existing code commands to identify if the arduino is able to read the state of your remote.

Adjusted - thankyou

It does say in my final sentence that i have tested both elements separately and they worked just fine.

Switch out your whiles for ifs.

Also, take the code that does the work when pin four is high out from inside the code that operates when pin four is low - the one is suppressing the other.

More advice for you, and it is relevant to @wildbill's advice.
Autoformat.
Hit CTRL-T and let the IDE format the text for you.
This is very handy for finding problems with curly brackets (like when you have a test for HIGH inside of a chunk that only gets executed when it is LOW)

Thankyou for those pointers - I implemented and it still wasn’t working but i noticed that the “stationary” servo was getting very hot so i’ve tried to tidy the code up but that doesn’t seem to have improved the heat issue and the sketch as a whole still isn’t working; I’m moving backwards not forwards

#include <Servo.h>

Servo servo;
int angle = 1;

void setup() {
  servo.attach(9);
  servo.write(angle);
}


void loop() {


  if (digitalRead(4) == LOW) {
    // now scan back to home position and stay there
    servo.write (1);

  }


else if (digitalRead(4) == HIGH) {  // Button 1 pressed

  //  scan from 10 to 40 degrees
  for (angle = 10; angle < 40; angle++)
  {
    servo.write(angle);
    delay(5);
  }
  // now scan back from 40 to 10 degrees
  for (angle = 40; angle > 10; angle--)
  {
    servo.write(angle);
    delay(25);
  }
  //  scan from 10 to 30 degrees
  for (angle = 10; angle < 30; angle++)
  {
    servo.write(angle);
    delay(15);
  }
  // now scan back from 30 to 20 degrees
  for (angle = 30; angle > 20; angle--)
  {
    servo.write(angle);
    delay(35);
  }


}

}

Not all servos can manage a 180 degree range. Sending yours to the 1 position may be further than it can go and if so it will be straining against the stop and pulling a lot of current which would heat it up.

Try somewhere closer to 90.

You could use the sweep example in the IDE to verify the range your particular servo can manage.

What sort of servo is it and how is it powered? Put some Serial.prints in so you can tell when the servo is actually getting written to.

Servo getting hot sounds like you are possibly writing to it so fast that it can't follow the commands...though the delays in your loops would suggest it isn't that. But I'd still be interested to see what is being written to the servo and when.

Steve

I’m using an SG 90 servo which /should/ be able to go to 180 but by changing the start angle from 1 the project is now “working” in its rough form.

Put some Serial.prints in to you can tell when the servo is actually getting written to.

you’ve completely lost me there and googling the official guide for that has just confused things even more

So my only problem now is that when the button is pressed the “animation” only completely the 4 step cycle and only then stops. Why isn’t the If/else/whilst command constantly being checked and the sequence stopped sooner - i’ve tried all three terms and it doesn’t make any difference; it always works through the rest of the sequence and only then stops.

current sketch

#include <Servo.h>

Servo servo;
int angle = 5;

void setup() {
  servo.attach(9);
  servo.write(angle);
}


void loop() {


  if (digitalRead(4) == LOW) {
    // now scan back to home position and stay there
    servo.write (5);


  }


while (digitalRead(4) == HIGH) {  // Button 1 pressed

  //  scan from 10 to 40 degrees
  for (angle = 10; angle < 40; angle++)
  {
    servo.write(angle);
    delay(5);
  }
  // now scan back from 40 to 10 degrees
  for (angle = 40; angle > 10; angle--)
  {
    servo.write(angle);
    delay(5);
  }
  //  scan from 10 to 30 degrees
  for (angle = 10; angle < 30; angle++)
  {
    servo.write(angle);
    delay(7);
  }
  // now scan back from 30 to 20 degrees
  for (angle = 30; angle > 20; angle--)
  {
    servo.write(angle);
    delay(15);
  }


}

}

tommoore:
Why isn't the If/else/whilst command constantly being checked and the sequence stopped sooner - i've tried all three terms and it doesn't make any difference; it always works through the rest of the sequence and only then stops.

That's what you told it to do. The check for the button press occurs at the top of the animation sequence. You then run the three for loops to move the servo. There's nothing in there that ever checks whether the button is still pressed, so it proceeds blindly until complete. Next time the loop function is called, if the button is still pressed it will do it again.

As a step towards what you want, you could check for the button being pressed before each for loop.

Ok so firstly i realised my code was far too complcated - all that calculating of angles wasn’t actually achieving anything meaningful when i could just had code values so the sketch now looks like this

#include <Servo.h>

Servo servo;
int angle = 5;

void setup() {
  servo.attach(10);
  servo.write(angle);
}


void loop() {


  if (digitalRead(4) == LOW) {
    // now scan back to home position and stay there
    servo.write (5);


  }


  if (digitalRead(4) == HIGH) {  // Button 1 pressed

    servo.write(30);
    delay(200);
    servo.write(40);
    delay(100);
    servo.write(20);
    delay(100);
    servo.write(40);
    delay(100);

  }

}

but i just can’t find a way to get it to check during the “animation” that the button is still pressed. If i copy the “if digitalRead 4=high” code in to the middle of the animation then all that happens is it only plays/loops the animation up to that point and never progresses to the later steps. What’s the term i should be using to make it check the input and progress if it’s still high?

Maybe go back to your for loops and do this:

  for (angle = 10; angle < 40  && digitalRead(4) == LOW; angle++)
  {
    servo.write(angle);
    delay(5);
  }

"but i just can't find a way to get it to check during the "animation" that the button is still pressed."

Using "delays" in your code will probably prevent you from checking for switch position changes. You probably need to look at using "millis()" functions to allow your code to continue looping checking for a button state change.

wildbill:
Maybe go back to your for loops and do this:

  for (angle = 10; angle < 40  && digitalRead(4) == LOW; angle++)

{
    servo.write(angle);
    delay(5);
  }

It has to move when digital read is HIGH (the button pressed) so i modified your code to reflect that but I’m not getting any movement at all

#include <Servo.h>

Servo servo;
int angle = 5;


void setup() {
  servo.attach(10);
  servo.write(angle);
}


void loop() {


  if (digitalRead(4) == LOW) {
    // now scan back to home position and stay there
    servo.write (5);
  }
  for (angle = 10; angle < 40  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 40; angle > 20  && digitalRead(4) == HIGH; angle--)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 20; angle < 30  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 30; angle > 10  && digitalRead(4) == HIGH; angle--)
  {
    servo.write(angle);
    delay(50);
  } for (angle = 10; angle < 20  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 20; angle < 40  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }

}/[code]

Can we all agree it's an odd oversight that they've invented a programming language that doesn't include basic input monitoring / comparing without huge chunks of code? :-p

zoomkat:
“but i just can’t find a way to get it to check during the “animation” that the button is still pressed.”

Using “delays” in your code will probably prevent you from checking for switch position changes. You probably need to look at using “millis()” functions to allow your code to continue looping checking for a button state change.

One step forward, 10 steps back - i’ve been through a couple of tutorials on it and still can’t even get a basic code to work

#include <Servo.h>

Servo servo;
int angle = 5;
int step = 0;   // a variable to keep track of what step you're on.
unsigned long currentMillis = 1;
unsigned long previousMillis = 0;
unsigned long interval = 1000;  // set to length of first interval.


void setup() {
  servo.attach(10);
  servo.write(angle);
}


void loop() {


  if (digitalRead(4) == LOW) {
    // now scan back to home position and stay there
    servo.write (5);
  }
  if(currentMillis - previousMillis >= interval && digitalRead(4) == HIGH){
   servo.write(40);
  }
}

You never set currentMillis or previousMillis to any useful values. At some point you need to use the millis() function.

Steve

You may have a floating input - do you have a pulldown resistor on your switch?

If not, set the pinMode on pin 4 to INPUT_PULLUP. Note that a button press will then show as LOW.

If the version with for loops is failing, I think you have some other issue: wiring or power perhaps. I ran this on an Uno:

#include <Servo.h>

Servo servo;
int angle = 5;


void setup()
{
  Serial.begin(115200);
  servo.attach(10);
  servo.write(angle);
}


void loop()
{
  if (digitalRead(4) == LOW)
  {
    // now scan back to home position and stay there
    Serial.println(F("Go home"));
    servo.write (5);
  }
  for (angle = 10; angle < 40  && digitalRead(4) == HIGH; angle++)
  {
    Serial.print(F("Go to: "));
    Serial.println(angle);
    servo.write(angle);
    delay(50);
  }
  for (angle = 40; angle > 20  && digitalRead(4) == HIGH; angle--)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 20; angle < 30  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 30; angle > 10  && digitalRead(4) == HIGH; angle--)
  {
    servo.write(angle);
    delay(50);
  } for (angle = 10; angle < 20  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }
  for (angle = 20; angle < 40  && digitalRead(4) == HIGH; angle++)
  {
    servo.write(angle);
    delay(50);
  }
}

I didn’t hook a servo up but the Serial output is as expected. If I ground pin 4, it says “Go home”. If I tie it to 5V, it shows angles from 10 to 39. What does it do for you?

serial output is as follows…

⸮C⸮⸮ B⸮⸮⸮5
Go home
Go home
Go home
Go home
Go home
⸮⸮⸮Tr⸮[z⸮Ґ⸮⸮[z⸮>⸮z⸮⸮⸮{z⸮Ґ⸮⸮[z⸮Ґ⸮⸮[zz⸮Ґ⸮⸮[z⸮Ґ⸮⸮[z⸮>⸮z⸮⸮[⸮⸮0zҐ⸮⸮[z⸮Ґ⸮⸮[z⸮>

and that gibberish just carries on indefinitely whether the button is pressed or not

With regard the possibiliy of a floating input - i’m taking a lead straight from the RX receiver to the board (there’s a picture of the assembly in my first posting) so didn’t think i would need one?