two servos (for wings) opposite direction

Hey guys,

My son and I are new to arduino and of course he new to coding. We are making a costume and got through wiring our board (just from looking at other diagrams and adding on to it, and have successfully gotten the wings to go up and down - even with LED's on the wings.

The challenge we are having is the following

  1. when the wings go down, they are going all the way down to 0, 180 rather than to the value we have set...

We are not sure if this is a problem with our code or with how we have wired our servos...

Any suggestions would be great.

Here is the code.

//zoomkat servo button toggle test 4-28-2012

#include <Servo.h>
int button = 5; //button pin, connect to ground to move servo
int press = 0;
Servo myservo; // initializing servos
Servo myservo1;
int i; // used for - for loop 20 times
int RedLed = 2; // red led
int GreenLed = 3;// green led
int ledState1 = LOW;             // ledState used to set the LED
unsigned long previousMillis1 = 0;        // will store last time LED was updated
long OnTime1 = 250;           // milliseconds of on-time
long OffTime1 = 750;          // milliseconds of off-time
int ledState2 = LOW;             // ledState used to set the LED
unsigned long previousMillis2 = 0;        // will store last time LED was updated
long OnTime2 = 330;           // milliseconds of on-time
long OffTime2 = 400;          // milliseconds of off-time

boolean toggle = true;

void setup()
{
  pinMode(button, INPUT); //arduino monitor pin state
  pinMode(RedLed, OUTPUT);
  pinMode(GreenLed, OUTPUT);
  myservo.attach(9); //pin for servo control signal
  myservo1.attach(10); //pin for servo control signal
  digitalWrite(5, HIGH); //enable pullups to make pin high
}

void loop()
{
  press = digitalRead(button);
  if (press == LOW)
  {
    if(toggle)
    {

/*
      myservo.write(90);
      myservo1.write(90);
      delay(2000);
      
 */
      /*
      myservo.write(170);
      myservo1.write(80);
      delay(50); 
      */

   // for servo one sweeping 
   int servpos=170;
   int servpos1=80;
   int pos =80; //variable to store the servo position
   int pos1 =170; // variable to store the servo position
   
   while(pos <= servpos && pos1 >= servpos1)
     {         // in steps of 1 degree

        pos++;
        pos1--;
        myservo.write(pos);    // tell servo to go to position in
          // variable 'pos'
        myservo1.write(pos1);    // tell servo to go to position in
        delay(15);      // waits 15ms for the servo to reach
          // the position
          
     }   
     
      
      for(i=0; i <=10; i++) {
        digitalWrite(RedLed, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(100); 
        digitalWrite(RedLed, LOW);    // turn the LED off by making the voltage LOW
        delay(100);              // wait for a second
      }
      
      toggle = !toggle;
      
    
    }
    else
    {

// to go down more slowly put in for loop'

     /*
      myservo.write(90);
      myservo1.write(90);
      delay(2000);
   */
      
     myservo.write(100);
     myservo1.write(170);
     delay(15);

     for(i=0; i <=10; i++) {
        digitalWrite(GreenLed, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(100); 
        digitalWrite(GreenLed, LOW);    // turn the LED off by making the voltage LOW
        delay(100);              // wait for a second
      }

      toggle = !toggle;
      
    }
  }
  delay(500);  //delay for debounce

  unsigned long currentMillis = millis();
 
  if((ledState1 == HIGH) && (currentMillis - previousMillis1 >= OnTime1))
  {
    ledState1 = LOW;  // Turn it off
    previousMillis1 = currentMillis;  // Remember the time
    digitalWrite(RedLed, ledState1);  // Update the actual LED
  }
  else if ((ledState1 == LOW) && (currentMillis - previousMillis1 >= OffTime1))
  {
    ledState1 = HIGH;  // turn it on
    previousMillis1 = currentMillis;   // Remember the time
    digitalWrite(RedLed, ledState1);   // Update the actual LED
  }
  
  if((ledState2 == HIGH) && (currentMillis - previousMillis2 >= OnTime2))
  {
    ledState2 = LOW;  // Turn it off
    previousMillis2 = currentMillis;  // Remember the time
    digitalWrite(GreenLed, ledState2);  // Update the actual LED
  }
  else if ((ledState2 == LOW) && (currentMillis - previousMillis2 >= OffTime2))
  {
    ledState2 = HIGH;  // turn it on
    previousMillis2 = currentMillis;   // Remember the time
    digitalWrite(GreenLed, ledState2);   // Update the actual LED
  } 

 
}

Here are the wings in motion - we made the changes to the wings on the way down - so they go slower...

Any advice? Should I shoot a photo on how we have the breadboard set up?

Servo myservo; // initializing servos
Servo myservo1;

Do you count this way? Number ALL the variables in the set, if you have to number anything.

Use Serial.begin() in setup() and Serial.print() in the while loop to see where you are sending the servos.

Using millis() and delay() in the same sketch is rather pointless.

You have a section of code that moves the servos step by step through a range. Then, later on, at line 95 you have code that makes the servos go to specific positions. Perhaps the code at line 95 should not be there?

I would strongly suggest that you organise your code into small single-purpose functions to make it more manageable - as illustrated in Planning and Implementing a Program

...R

Thanks for your input.

We had another version where we kept the delay for the blinking light - and the button would not toggle. So, we grabbed some other script to work from that used milliseconds instead of delay and the button would behave normally.

Also, in regards to while loop - we had the while loop for going up and down but, noticed that the wings would go up incrementally and it would just shoot straight down. Not sure why.

In regards to variable declaration, we will be sure to number correctly and plan better - this is our first project and just getting familiar with coding again and getting my 11 year old son to do most of it.

the program is read top to bottom. when its reach's the last line it goes back to the top

so lets look at some of the code

minor point. don't use red words as variable names so

int press = 0; should be changed

to save having to write the pin high its better to use

pinMode(button, INPUT_PULLUP);

then you don't need

digitalWrite(5, HIGH); //enable pullups to make pin high

  int servpos = 170;
      int servpos1 = 80;
      int pos = 80; //variable to store the servo position
      int pos1 = 170; // variable to store the servo position

      while (pos <= servpos && pos1 >= servpos1)
      { // in steps of 1 degree

        pos++;
        pos1--;
        myservo.write(pos);    // tell servo to go to position in
        // variable 'pos'
        myservo1.write(pos1);    // tell servo to go to position in
        delay(15);      // waits 15ms for the servo to reach
        // the position

      }

when you leave this piece of code

168pos 82pos1
169pos 81pos1
170pos 80pos1 these are the last numbers written to the servos

2 seconds later (time it takes to flash redled 10 times) you tell the servos to move directly to

myservo.write(100);
myservo1.write(170);

so pos1 has to move from 80 to 170 and pos has to move from 170 to 100

that's going to be shown as a large fast movement

about 2 seconds after that

int pos = 80
int pos1 = 170

pos was 100 now it will be 80
pos1 was 170 and will stay 170
so only one wing will move

another problem is this code

 if ((ledState1 == HIGH) && (currentMillis - previousMillis1 >= OnTime1))
  {
    ledState1 = LOW;  // Turn it off
    previousMillis1 = currentMillis;  // Remember the time
    digitalWrite(RedLed, ledState1);  // Update the actual LED
  }
  else if ((ledState1 == LOW) && (currentMillis - previousMillis1 >= OffTime1))
  {
    ledState1 = HIGH;  // turn it on
    previousMillis1 = currentMillis;   // Remember the time
    digitalWrite(RedLed, ledState1);   // Update the actual LED
  }

  if ((ledState2 == HIGH) && (currentMillis - previousMillis2 >= OnTime2))
  {
    ledState2 = LOW;  // Turn it off
    previousMillis2 = currentMillis;  // Remember the time
    digitalWrite(GreenLed, ledState2);  // Update the actual LED
  }
  else if ((ledState2 == LOW) && (currentMillis - previousMillis2 >= OffTime2))
  {
    ledState2 = HIGH;  // turn it on
    previousMillis2 = currentMillis;   // Remember the time
    digitalWrite(GreenLed, ledState2);   // Update the actual LED
  }

this is in the open loop so it requires the program to leave this section and get back with in 250ms. With all the delays its not really doing anything. unless the button is high (not pushed) then all the delays are removed which will allow it to run correctly. Correction: you will still have this delay in there
delay(500); //delay for debounce
to be honest delay for debounce is not really needed unless the program is super fast and even then 40ms is about all that is required (fast to us but slow to a arduino)

(you might be seeing the red or green led being turned on and staying on which may seem random because of this section of code)

think about and test small programs to control your servos. You have the right idea to make small changes but you do that using a while where a if would be better that way the arduino can go check out the rest of the program and come back to make the next small change
(you will have to think about how you enter the number you want the servo to move to so its not rewritten every loop)

I tried to write a lot of text to explain state machines but im not good at writing so I made a example.

this code has errors based on the servo positions (where it ends and where it should finnish) but ive written notes so you can see the idea behind the code

This is not designed as a answer more of a option to think about (to late to add serial prints to test tonight but I think the basic idea works as I copyed parts of your code)

//zoomkat servo button toggle test 4-28-2012

#include <Servo.h>
int button = 5; //button pin, connect to ground to move servo
int pressed = 0;//...........changed so its not a red name
Servo myservo; // initializing servos
Servo myservo1;
int i; // used for - for loop 20 times
int RedLed = 2; // red led
int GreenLed = 3;// green led
int ledState1 = LOW;             // ledState used to set the LED
unsigned long previousMillis1 = 0;        // will store last time LED was updated
long OnTime1 = 250;           // milliseconds of on-time
long OffTime1 = 750;          // milliseconds of off-time
int ledState2 = LOW;             // ledState used to set the LED
unsigned long previousMillis2 = 0;        // will store last time LED was updated
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;
unsigned long OnTime2 = 330;           // milliseconds of on-time
unsigned long OffTime2 = 400;          // milliseconds of off-time

boolean toggle = true;
int servpos = 170;
int servpos1 = 80;
int pos = 80; //variable to store the servo position
int pos1 = 170; // variable to store the servo position
byte state = 0;





void setup()
{
  pinMode(button, INPUT_PULLUP); //arduino monitor pin state..note changed to pullup
  pinMode(RedLed, OUTPUT);
  pinMode(GreenLed, OUTPUT);
  myservo.attach(9); //pin for servo control signal
  myservo1.attach(10); //pin for servo control signal

}

void loop()
{
  unsigned long currentMillis = millis();
  pressed = digitalRead(button);
  if ((pressed == LOW) && (state == 0)) {
    state = 1;//onced pressed it will run one cycle
  }
  if (pressed == LOW) {//will pause if button released removed if not required
    switch (state) {
      case 0://allows arduino to quickly exit
        break;

      case 1:
        servpos = 170;
        servpos1 = 80;
        pos = 80;
        pos1 = 170;
        state = 2;
        break;

      case 2:
        if (pos <= servpos && pos1 >= servpos1)
        { // in steps of 1 degree
          pos++;
          pos1--;
          myservo.write(pos);    // tell servo to go to position in
          // variable 'pos'
          myservo1.write(pos1);    // tell servo to go to position in
          delay(15);      // waits 15ms for the servo to reach
          // the position
        } else { //servos in position move to next state
          state = 3;//move to next state
          previousMillis4 = currentMillis;//take a time stamp for next state
        }
        break;

      case 3:
        if (currentMillis - previousMillis4 <= 2000) {//for 2 seconds do this
          if (currentMillis - previousMillis3 >= 100) {//every 100ms do this
            ledState1 = ! ledState1;//toggle led
            previousMillis3 = currentMillis;
            digitalWrite(RedLed, ledState1);
          }
        } else {//2 second time is up 
          digitalWrite(RedLed, LOW);//when finnished turn led off
          state = 4;
          //move to next state
          //load next movement to be
          //carryed out by
          //state 4
          servpos = 170;
          servpos1 = 80;
          pos = 100;
          pos1 = 150;
        }

        break;

      case 4:
        if (pos <= servpos && pos1 >= servpos1)
        { // in steps of 1 degree
          pos++;
          pos1--;
          myservo.write(pos);    // tell servo to go to position in
          // variable 'pos'
          myservo1.write(pos1);    // tell servo to go to position in
          delay(15);      // waits 15ms for the servo to reach
          // the position
        } else { //servos in position move to next state
          state = 5;
          previousMillis4 = currentMillis;
        }
        break;

      case 5:
        if (currentMillis - previousMillis4 <= 2000) {//for 2 seconds do this
          if (currentMillis - previousMillis3 >= 100) {//every 100ms do this
            ledState1 = ! ledState1;//toggle led
            previousMillis3 = currentMillis;
            digitalWrite(GreenLed, ledState1);
          }
        } else {
          digitalWrite(GreenLed, LOW);//when finnished turn led off
          state = 6;//move to next state
          servpos = 170;//leave wings in a finnished state so
          servpos1 = 80;//theres no large movement
          pos = 100;//between state 6 and state 1
          pos1 = 150;
        }

        break;

      case 6:
        if (pos <= servpos && pos1 >= servpos1)
        { // in steps of 1 degree
          pos++;
          pos1--;
          myservo.write(pos);    // tell servo to go to position in
          // variable 'pos'
          myservo1.write(pos1);    // tell servo to go to position in
          delay(15);      // waits 15ms for the servo to reach
          // the position
        } else { //servos in position move to next state
          state = 0;
        }

        break;
    }//close switch
  }//close  if (pressed == LOW)


  if ((pressed == HIGH) && (state == 0)) {
    if ((ledState1 == HIGH) && (currentMillis - previousMillis1 >= OnTime1))
    {
      ledState1 = LOW;  // Turn it off
      previousMillis1 = currentMillis;  // Remember the time
      digitalWrite(RedLed, ledState1);  // Update the actual LED
    }
    else if ((ledState1 == LOW) && (currentMillis - previousMillis1 >= OffTime1))
    {
      ledState1 = HIGH;  // turn it on
      previousMillis1 = currentMillis;   // Remember the time
      digitalWrite(RedLed, ledState1);   // Update the actual LED
    }

    if ((ledState2 == HIGH) && (currentMillis - previousMillis2 >= OnTime2))
    {
      ledState2 = LOW;  // Turn it off
      previousMillis2 = currentMillis;  // Remember the time
      digitalWrite(GreenLed, ledState2);  // Update the actual LED
    }
    else if ((ledState2 == LOW) && (currentMillis - previousMillis2 >= OffTime2))
    {
      ledState2 = HIGH;  // turn it on
      previousMillis2 = currentMillis;   // Remember the time
      digitalWrite(GreenLed, ledState2);   // Update the actual LED
    }
  }
}

Hi,

when the wings go down, they are going all the way down to 0, 180 rather than to the value we have set...

In your video I see the wings moving only 90Degrees, where is your zero degrees reference?

Have you written a simple servo only sketch to see how they work and where 0 and 90 and 180 is.

How are you powering the arduino and the servos?

Tom... :slight_smile:

TomGeorge:
Hi,

In your video I see the wings moving only 90Degrees, where is your zero degrees reference?

Have you written a simple servo only sketch to see how they work and where 0 and 90 and 180 is.

How are you powering the arduino and the servos?

Tom... :slight_smile:

Before we mounted the servos onto the wings, my son and I powered up the servos and just wrote a quick script to put the servos at 0 and 180... I am thinking, maybe we have it wrong and this morning we will take a look- read the servo position. If it's wrong, we are going to have to figure a work around.

With the simple script - servo only - up and down - this is the script for that:

 #include <Servo.h>

Servo myservo0;
Servo myservo1;



void setup() {
  // put your setup code here, to run once:

myservo0.attach(9);
myservo1.attach(10);
}

void loop() {
  // put your main code here, to run repeatedly:

myservo0.write(90);
myservo1.write(10);
delay(1000);

myservo1.write(90);
myservo0.write(10);
delay(1000);

myservo0.write(90);
myservo1.write(10);
delay(1000);

}

For powering the servos, we are running a separate power supply, a 6 volt AA battery pack. We bought a second one yesterday from Tinkersphere and plan to run the 2nd in parallel doubling the power time without changing volts.

If you want the servos to move in complementary directions you can do it with a for loop

for (int pos = 0; pos <= 180; pos++)
{
  servo1.write(pos);
  servo2.write(180 - pos);
  delay(whatever);  //if you need it
}

Adjust the limits of the for loop to suit your requirements.

Thank you gpop1..

We are going to break the code into smaller functions today and put them in the void loop to be called and too comment them out while we are testing each part of the code. It looks like we have to figure out if our servo positions are indeed at 0 (which they might not be).

A couple of questions -

*int press = 0; should be changed * When you say change, we are not sure to what? Chang it to 1? or leave it declared.

For the led blink state, that is open, we had it as a function before we sent this - void blinker(); but - that didn't seem to work right - how does one close that loop? We are going to figure that out now.

For the bounce delay - you are saying we can just remove it right? We are using an arcade button - not sure if that changes the bounce requirement if at all..

  • Thank you all for your help on this by the way. My son is very excited with this project and a few of his friends too... a group of his 11 yr old friends went yesterday and got arduino boards and my son picked up a mega board and some sensors to do some cool projects with.

UKHeliBob:
If you want the servos to move in complementary directions you can do it with a for loop

for (int pos = 0; pos <= 180; pos++)

{
  servo1.write(pos);
  servo2.write(180 - pos);
  delay(whatever);  //if you need it
}



Adjust the limits of the for loop to suit your requirements.

Thank you UKHeliBob...

Before we put in the while loop we actually did put in a FOR loop.. It worked but, we were still experiencing the wings go past their initial set position.... and also whipping instead of going slow...
Here was that bit of code:

for(pos = 60; pos < 150; pos +=1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in
// variable 'pos'
delay(15); // waits 15ms for the servo to reach
// the position

//Serial.println(pos);
}

//for servo two

for(pos1 = 150; pos1>=60; pos1 -=1) // goes from 180 degrees to 0 degrees
{
myservo1.write(pos1); // tell servo to go to position in
// variable 'pos'
delay(15); // waits 15ms for the servo to reach
// the position
//Serial.println(pos1);
}

When we did the FOR loop this way, one wing would go first, then the other after. The way you have it makes way more sense.

Right now, we are first going to get a read out of the servo position when it goes all the way down. Then break this code into smaller pieces as you have all suggested. We will post a photo of the board later today once we have added the second power source in parallel...

Question: we were reading something about saving power for the servos use you can "detach" and "reattach"? So, when the servos reach their up position, we can detach and the servo will lock in position... Same with servos being down. Are we making any sense?

Right now, we are first going to get a read out of the servo position when it goes all the way down.

All that you will learn is the last position you told the servo to go to. And, you already know that.

we can detach and the servo will lock in position.

They won't lock into position, rather they will be free to move and the control surfaces may blow back. As you have been talking about ailerons I assume that they will not stay in one position for any significant length of time anyway.

As to saving power, probably not much, if any. The servo motor will not actually be turning although it will resist movement of the servo arm to maintain its position and the servo electronics will remain powered anyway. If you are worried about the ability of your power train to supply the required current for the required period of time then I suggest that you are using an inadequate power source.

PaulS:

Servo myservo; // initializing servos

Servo myservo1;



Do you count this way? Number ALL the variables in the set, if you have to number anything.

Use Serial.begin() in setup() and Serial.print() in the while loop to see where you are sending the servos.

Using millis() and delay() in the same sketch is rather pointless.

Do you count this way? Ha.. we see your point..

Using millis() and delay() in the same sketch is rather pointless. When we used delay(1000) for blink high/low - we ran into the issue with the button... We would press and press -and nothing would happen. We then noticed that if we timed the press between light stated(high/low) it would work. We then figured it had to do with the delay. We found that code ala the milliseconds - first created a separate function (void blinker() ) and it didn't work as we had to pass the values of the Led1/Led2 - which we couldn't figure out how to do. So, we put that millisecond code into the "void loop()" and things began to work - as you have seen in the video.

What is your suggestion? Remove the delays? Thank you again for your help...

I have lost track of what is your current code. Is it as in a previous post or have you changed it since ?

albaadventures:
Thank you gpop1..

We are going to break the code into smaller functions today and put them in the void loop to be called and too comment them out while we are testing each part of the code. It looks like we have to figure out if our servo positions are indeed at 0 (which they might not be).

A couple of questions -

*int press = 0; should be changed * When you say change, we are not sure to what? Chang it to 1? or leave it declared.

For the led blink state, that is open, we had it as a function before we sent this - void blinker(); but - that didn't seem to work right - how does one close that loop? We are going to figure that out now.

For the bounce delay - you are saying we can just remove it right? We are using an arcade button - not sure if that changes the bounce requirement if at all..

  • Thank you all for your help on this by the way. My son is very excited with this project and a few of his friends too... a group of his 11 yr old friends went yesterday and got arduino boards and my son picked up a mega board and some sensors to do some cool projects with.

certain words have different uses with in the program. These words turn red to indicate that. Press is one of them which means you shouldn't use it as a name.

As for debounce. I wish I could find you the link that shows a button bounce measured on a oscilloscope I know theres a great example that has been posted on here before. The bounce is a spike a few milliseconds after the button changes state. Even worse case 40ms should be able to cover that.

I do not think there is a way to use that style of led flashing. If you take a time stamp then compare to see if 250ms has passed the program needs to be able to get back with in 250 ms. (even a fast for loop may be longer than that) what you are really doing is toggling the led when ever the program gets free and gets a chance to processes that code

I think its great that you are teaching your son. I bought the first arduino kit for my daughter and we had a lot of fun making small projects together.

All,

We want to thank you for your help on this. We tried the switch case statement but, that for some reason lead to servos not responding correctly. In the end, my son and I got the code to work that we originally hacked together and we will post a video on how the wings are now responding later today.

What we noticed was that the servos were not perfectly set at 0.. Ironically a screw came loose on the one wing that was giving us issues, which meant we had to cut open the wing and get it screwed, glued and painted - we did that in 30 minutes. But, that helped us in getting the wing in the right location.

Our intent is to clean up this code today into smaller functions that can be managed. We find that using the Milliseconds over delay helped with the button - the delay just took up all the processing (we need to figure out how to code for multithreads on this thing).

We will get an updated version of the code posted on this thread also later.

we need to figure out how to code for multithreads on this thing

Have a look at Several things at the same time

Hey guys,

Here is the finished produce on the wings - you can fast forward to about 5 minutes - but, if you are curious too see how we made the Baymax 2.0 outfit, please watch it.

Thank you for your help.

R