Misbehaving servo

Hi Chaps
Last time i tried this it worked perfectly, though this time around i am using a high torque 40KG servo and its not behaving as expected.

Depending on the byte of info received, it should move the servo to a position, which it does - But then it returns to 0 degrees position instead of staying there until another byte is received.

Can you see the error of my ways?

void loop()
{
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
  if(inByte==1)
  {
    Serial.write("Q");
pvar=0;   
  }
    if(inByte==2)
  {
    Serial.write("W");
pvar=90;    
  }
    if(inByte==3)
  {
    Serial.write("E");
pvar=120;    
  }
    if(inByte==4)
  {
    Serial.print("Y");
digitalWrite(speaker, HIGH);
delay(10000);
digitalWrite(speaker, LOW);
  }
}

/*  while (Serial.available() <= 0) {
    Serial.print("B");   
    delay(300);
  }*/
  myservo.write(pvar); 
}

I can rule out the serial code byte recognition part of the code from being the issue. The byte sent back works as expected.

How is the servo powered ?
What data type is inByte ?
What values do you see if you print inByte when serial data is available and just before writing it to the servo ?

by a bench top power supply. The arduino is also connected to it so the ground is shared.

7.4V 3A

What is sending the data? The program is expecting binary data, which doesn't come from the Serial Monitor application.

Paul, its a C++ windows application which sends a capital letter over XBee wireless, to the receiving arduino.

Doesn't seem to be an issue sending one character in this manner, Ive used this method reliably for lots of projects.. just this servo doesn't seem to like staying where ive referenced it to go to.

Have you tried the exact same code with a small servo?

Have you tried the large servo with another sketch that works properly with a small servo?

...R

Paul, its a C++ windows application which sends a capital letter over XBee wireless, to the receiving arduino.

So, it's not binary data, and none of the if statements is affecting pvar.

Paul
yes the if conditions are firing. I know this because the C++ application is receiving the reply back. See line above setting pvar.

    if(inByte==2)
  {
[b]    Serial.write("W");[/b]
pvar=90;    
  }

Also, sending a char is fine over serial note that this is a byte, not a bit.. please see this book illustrating you can send a character over serial as reference:

Robin2:
Have you tried the exact same code with a small servo?

Have you tried the large servo with another sketch that works properly with a small servo?

...R

no ive not hooked up the smaller servo to this sketch. its a good thought... il give it a spin

Yes ive tried the large servo with another sketch which works fine with the smaller servo

Also, sending a char is fine over serial note that this is a byte, not a bit.. please see this book illustrating you can send a character over serial as reference:

I KNOW you can send ASCII data OR binary data. Your Arduino code is expecting binary data. The Serial Monitor can not send binary data. That's why I asked what was sending binary data.

Your reply was that you were sending characters TO the Arduino. Well, clearly you aren't. What you are sending FROM the Arduino is completely irrelevant.

0x01 and 0x02 and 0x03 are characters. They are not printable characters.

The other problem I can see, is that the obviously incomplete code fragment quoted doesn't include any declaration of the variable "pvar". On any of the millions of iterations through loop( ) in which no new incoming serial data is detected, you are still sending the value of pvar to the servo, and who knows what that might be.

PaulS:

Also, sending a char is fine over serial note that this is a byte, not a bit.. please see this book illustrating you can send a character over serial as reference:

I KNOW you can send ASCII data OR binary data. Your Arduino code is expecting binary data. The Serial Monitor can not send binary data. That's why I asked what was sending binary data.

Your reply was that you were sending characters TO the Arduino. Well, clearly you aren't. What you are sending FROM the Arduino is completely irrelevant.

Paul, thank you.. i see your meaning. il revisit it.

Michinyon I declare pvar at the top of the sketch, not within the setup block. quite simply int pvar;
I coded it this way hoping that with each if condition firing and altering the value of pvar, that this value wouldn't change until another if condition fired, therefore it wouldn't matter that its being constantly sent on each loop?

simplified, and full sketch. still behaves the same way. events are firing, just the servo keeps returning to the 90 degrees position.

#include <Servo.h> 
Servo myservo;
void setup()
{
  myservo.attach(9);
  Serial.begin(9600);
}

void loop()
{

  if(Serial.read()=='A')
  {
    Serial.write("Q");
  myservo.write(0);   
  }
    if(Serial.read()=='B')
  {
    Serial.write("W");
  myservo.write(90);     
  }

}

Also, i notice this servo is advertised as a steering servo.... is it possible that the servo is made to return to a preset location?

void loop()
{

  if(Serial.read()=='A')
  {
    Serial.write("Q");
  myservo.write(0);   
  }
    if(Serial.read()=='B')
  {
    Serial.write("W");
  myservo.write(90);     
  }

So did you notice that you read characters from the serial port even if nothing is pending?

And you read a value, check to see if it's an "A" and if not you throw it away and read another character (again without checking for pending input). So if the user types a 'B' I'd think they'd have to type two characters? (or type an "A" then "B"?)

EDIT: Ok I suspect that this would appear to work (since you don't wait for input) but it's not a very robust way to service the serial port.

I really think you want something more like

 void loop() {
   if (Serial.available()) {
      char inChar = Serial.read();
	  
      switch (inChar) {
        case 'A':
          Serial.write("Q");
          break;
        case 'B':
          Serial.write("W");
          break;
[...]
      }
    }
}

I hope this makes sense,

Brad
KF7FER

Hi Brad,
yes i agree the serial comm could be handled much better as you suggest, though its the servo not staying where i want it to be

When its powered up, it automatically goes to the 90 degree position which is fine.

When 'A' is received, it turns to 0 degrees as wanted, but 2 seconds later it turns back to 90 almost like the servo was designed to do that?

also, if i send B, BEFORE those two seconds have passed, it returns it to 90 as you would expect it would... just seems odd i cant get it to stay at 0

What happens if you use a simple program (no dependence on external input) that cycles the servo between 0, 90 and 180 with a delay between the movements ?

Bob
Oddly, it doesn’t do it.

#include <Servo.h> 
Servo myservo;
void setup()
{
  myservo.attach(9);
}

void loop()
{

  myservo.write(0);   
  delay(4000);
  myservo.write(90);
  delay(4000);
  myservo.write(180);   
  delay(4000);  


}

Same behaviour as before… turns 90 degrees, then goes back 90 degrees… and not with the 4000ms delay either.

Some servo test code you can try to see if the servo can be controlled.

// zoomkat 10-22-11 serial servo test
// type servo position 0 to 180 in serial monitor
// or for writeMicroseconds, use a value like 1500
// for IDE 0022 and later
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7, 500, 2500);  //the pin for the servo control, and range if desired
  Serial.println("servo-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string 
    int n = readString.toInt();  //convert readString into a number

    // auto select appropriate value, copied from someone elses code.
    if(n >= 500)
    {
      Serial.print("writing Microseconds: ");
      Serial.println(n);
      myservo.writeMicroseconds(n);
    }
    else
    {   
      Serial.print("writing Angle: ");
      Serial.println(n);
      myservo.write(n);
    }
    Serial.print("Last servo command position: ");    
    Serial.println(myservo.read());
    readString=""; //empty for next input
  } 
}

Can you provide a link to the servo that you are using ?