I'm having trouble getting a servo to respond

If you wire the pot as in this tutorial http://www.arduino.cc/en/Tutorial/AnalogInput the readings should be 0 to 1023. If you are not getting readings between those values then the pot is faulty or not wired correctly.

Run the pot tutorial code and see if the delay changes smoothly as the pot is rotated. You may want to add some serial print statements to display the actual values to verify the values.

Once you get the expected pot readings it will be easier to debug the servo side. I find its always faster doing projects incrementally when learning something new. Trying too many new things at once usually wastes lots of unnecessary debugging time trying to guess which part of the project isn't working.

I took out a new pot and wired it exactly like the picture, but I got the same readings. I figured that since an entirely closed pot would spit out 5v, i decided to test that going back into the pin, Nothing. Could my Arduino be faulty? What other explanation is there?

I'm just going to go ahead and send angular commands to the servo through the serial link. Now I just have to find the right tut in the playground.(side note, is Zack Hoeken's Sanguino not officially an arduino board?)

My current problem is that when I send out an impulse, it's verifies the wrong integer, and sends the same wrong integer to the servo. Here's my serial code

int servoPin = 8; //Naming the pin for the servo
int pos = 0; //Declaring an initial value for "pos",
//"pos" will be rewritten before 600 can be used
void setup() //Declaring the usage of each pin
{
pinMode(servoPin, OUTPUT); //Set the Servo's pin as an output
Serial.begin(9600); //Set the data rate for serial communications at 9600

}

void loop() //The actual running loop
{
if (Serial.available() > 0) { //Only functions when I send something
pos = Serial.read(); //Takes what I sent and stores it as pos
//Serial.println(pos); //Tell me where the servo is
//pos = map(pos, 0, 180, 600, 2400); //Changing the pot's data into the impulse length
//Serial.println(pos); //Tell me where the servo is
digitalWrite(servoPin, HIGH); //Start the servo's impulse
delayMicroseconds(pos); //The impulse length as determined by the value of "pos"
digitalWrite(servoPin, LOW); //End the servo's impulse
delay(20); //Allow the servo to get to it's desired position
}

}

Can anybody tell me why my code changes my numbers all around?

You do not want digital servos. They take several bits
and use them to create a number to position the arm.

I use HS55s in RC all the time.

For centering, remove the servo arm and center it while
powered and at the center position.

Almost all servos have endpoints that are less than the maximum
pulse width and greater than 180 degrees.

For details from hitec on the HS5 look here:
http://www.hitecrcd.com/product_file/file/24/hs55.pdf

All the newer programmable RC transmitters allow you to adjust
the endpoints for each servo as well as a 'subtrim' that finely
adjusts the center position.

My transmitter instructions (loosely) say:

  1. power on the transmitter, then the receiver
  2. zero out the trim and the subtrim settings.
  3. Install the servo arm on as close to center as possible.
  4. use the subtrim to move the arm to as near center as possible.
  5. for each end of the servo movement, increase or decrease
    the endpoint adjustment until the servo stops 'chattering'
    then go one click further.

The sanguino is not officially an arduino and it is not 100% compatible

http://sanguino.cc/

http://sanguino.cc/differencesfromarduino

"# compatible with Arduino 0012 with minimal hacking"

You need to make some changes to some libraries also

:slight_smile:

Yeah I own one, and the hacking was a pain and I ended up reinstalling the arduino files and folders to get it right. They need to work on that...

FlickerShow wrote:

My current problem is that when I send out an impulse, it's verifies the wrong integer, and sends the same wrong integer to the servo. Here's my serial code

What do you mean by "wrong integer"? What do you send to the Arduino, and how? Your code just reads one byte/character, which means that your pulse can only be between 0 and 255 microseconds. Doesn't sound right to me. If you want to enter a number in the Arduino serial console and set the pulse width to this number, you need to read a string and then convert it to an int. Something like this:

#define SERVOPIN 8

void setup()
{                                          
  pinMode(SERVOPIN, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  int pos;

  // Read the pulsewidth from the serial port
  pos = read_pulsewidth();
  Serial.println(pos); // For debugging purposes

  // Pulse the servo
  digitalWrite(SERVOPIN, HIGH);
  delayMicroseconds(pos);
  digitalWrite(SERVOPIN, LOW);
  delay(20);
}

// Wait until four numeric characters has been received
// on the serial port. Return the integer value of the
// string.
int read_pulsewidth(void)
{
  char buffer[] = "0000", *p = buffer;
  
  while(*p != '\0')
  {
    char c = Serial.read();
    if (c >= '0' and c <= '9')
      *p++ = c;
  }
  
  return atoi(buffer);
}

This (untested! Don't have an Arduino available at work...) code waits until you've entered a four digit number (so 795 must be entered as 0795) on the Arduino serial console. Then it pulses the servo once, before waiting for a new command. This is what your code did, except it only read one byte.

I don't know if you can get away with just sending one pulse though, or if the servo requires a steady train of pulses. If it does, then loop() should look something like this instead:

void loop()
{
  static int pos = 600;

  // Read the pulsewidth from the serial port
  if (Serial.available())
  {
    pos = read_pulsewidth();
    Serial.println(pos); // For debugging purposes
  }

  // Pulse the servo
  digitalWrite(SERVOPIN, HIGH);
  delayMicroseconds(pos);
  digitalWrite(SERVOPIN, LOW);
  delay(20);
}

Still a bit fragile (if you enter anything else than four numeric characters before pressing Enter on the console, this code will loop in read_pulsewidth()) but good enough for testing I think.

Btw I think there's too much comments in your code, every line was commented. This is unnecessary if you use descriptive names for all variables/constants/functions. Ideally each function should do just one really focused task, and a brief comment that describes the purpose of the function is enough. The code should speak for itself.

Skumlerod, the code needs to check that all four characters are available.

void loop() {
   static int pos = 1500; // default value should be within the normal range of a servo
 // Read the pulsewidth from the serial port 
  [glow]if (Serial.available() > =4)[/glow] { // wait for at least four characters
    pos = read_pulsewidth();
    Serial.println(pos); // For debugging purposes
   } 
   // Pulse the servo
   digitalWrite(SERVOPIN, HIGH);
   delayMicroseconds(pos);
   digitalWrite(SERVOPIN, LOW);
   delay(20); 
}

Make sure the serial sending side does not send a carriage return (and/or line feed). If so, the code would need to wait for 5 (or 6 ) characters to be available and read but otherwise ignore them.

Try it without the servo connected to make sure you are displaying the expected values

also, I shudder (on behalf of your servo) when I see 600 microseconds. Unless you know your servo can handle that very low value, it will be happier if you use a default value somewhere in the middle of its normal range. When you have everthing working, you can test with low and high values to see what you can get away with.

Btw I think there's too much comments in your code, every line was commented

This is a matter of personal preference and IMO the comments in FlickerShow's code would be helpful for people still learning Arduino progamming

Skumlerod, the code needs to check that all four characters are available.

It doesn't need to, but it makes it a bit more robust :slight_smile:

also, I shudder (on behalf of your servo) when I see 600 microseconds. Unless you know your servo can handle that very low value, it will be happier if you use a default value somewhere in the middle of its normal range.

I took the default of 600 from FlickerShow's code. I don't think you can damage a modern servo by feeding it pulses outside it's operating range. I'm into R/C and all servos I've bought the last years has microcontrollers in them that takes care of such thing.

Skumlerod, the code needs to check that all four characters are available.

It doesn't need to, but it makes it a bit more robust

Hi Skumlerud, are you sure?

The code you posted will attempt to read four characters, but only one may be available.

My comment about using a valid default value was directed at the OP. IMO, its good practice to provide default values known to be within the acceptable range of the target device.

Hi Skumlerud, are you sure?

The code you posted will attempt to read four characters, but only one may be available.

Yes, that's correct. I also wrote that below the code. The while-loop in read_pulsewidth() will loop until it has read four numeric characters. Any non-numeric (including -1 which Serial.read() returns if the receive buffer is empty (well, not in this case as c is a char and not an int, but it doesn't matter here)) character will not advance the buffer pointer, and the while loop will just loop until the buffer pointer points to a string terminator ('\0').

Your extension will improve on this if you enter less than four characters. But it doesn't know if you enter three digits and a letter, in which case "read_pulsewidth()" will loop until you enter enough numeric characters to fill the buffer.

I didn't bother checking this in my code, as it looks like FlickerShow only needs this for testing his servo code. As long as you know the limitation of the test-code it doesn't matter if it doesn't handle unexpected situations.

Btw FlickerShow: I think your servo-problems are related to your pulse-generating code. I'm not 100% sure about this, but I think that the servo needs a steady train of pulses. It's not trivial to implement this using delay() and delayMicroseconds() if you need to control several servos which it looks like you need. You should study one of the existing servo-libs instead of attempting to write your own code for this, that will allow you to concentrate on the fun bits :slight_smile:

Skumlerud, I see what you mean, but that was not obvious from a quick read of the code.
Perhaps a good example of why comments within a function are helpful :wink:

I had to reinstall my arduino software again, because It didn't like any of my libraries, be they lcd, servo, or serial and the environment it seems it was coming apart at seams. Luckily I keep the original .zip files handy. Anyway after redoing everything, My servo library finally works (it not doing so was why I wrote this fancy, albeit backwards, code). I've now got sweep running in front of me and I'll update this post when I get serial commands to work.

And I was just going to tell you that I tested the last version of my code and it works :wink: Well, atleast I've gained a bit more understanding of how to interface with servos. Btw my TowerPro servo has a range from 800 to 2200 microseconds. Pulses outside this range doesn't affect the servo at all, it just doesn't move.

I also discovered the reason for the "jerky" behavior of the servo in the YouTube-video you uploaded. The servo needs a steady train of pulses every 20ms, or it will stop. It did the same thing when I tried the first version of my code which only pulsed the servo once for every received pulsewidth.

Good to hear that you solved the servo problem. Now you only need to figure out why your potmeter gives you strange readings :slight_smile:

mem wrote:

Skumlerud, I see what you mean, but that was not obvious from a quick read of the code.
Perhaps a good example of why comments within a function are helpful Wink

Well, this is more of a philosophical question, but IMO the comment at the top of the function says exactly what it should do (and does). If you need comments to make five lines of code readable, something is wrong with the code. Code that needs explaining is not good, maintainable code if you ask me. Perhaps I could rephrase the code a bit to make it more clear:

// Wait until four numeric characters has been received
// on the serial port. Return the integer value of the
// string.
int read_pulsewidth(void)
{
  char buffer[] = "0000";
  int received = 0;
  
  while(received < 4)
  {
    int c = Serial.read();
    if (c >= '0' and c <= '9')
      buffer[received++] = (char) c;
  }
  
  return atoi(buffer);
}

Using a counter for received characters and only incrementing it when receiving a valid character should make this easier to read.

I agree we are discussing matters of style, and this is as much about personal preference as correctness. Would you agree that what may be an appropriate style for C experts may not be for C newcomers.

IMO, most code that uses pointers and any code that relies on functionality not explicit from the source code benefits from comments if the audience includes people new to programming. Experts like you and me can ignore the comments, but I think that a little extra effort explaining not only what the function is doing, but how it is doing it, helps people to learn. Yes, this would be out of place in a forum of experts such as avrfreaks, but this forum is a place more frequented with people new to coding, and I think we owe it to them to bend over backwards to explain what we are doing so they can learn to do it themselves.

I spent a couple of semesters teaching Pascal to newcomers at university. Overcommenting code is a typical beginner's mistake. When students got stuck with a piece of code, we often stripped the code from unnecessary comments which forced them to look at the actual statements. The comments often just stated what the student wanted the code to do and not what the code actually did.

So while careful commenting is helpful to other people that need to understand what your code does (or indeed yourself when you need to fix or change something a few months down the road), to much commenting can prevent a beginner from figuring out what his/hers code actually does.

People learning programming at university generally have an interest in the finer points of software engineering. Or at least, they are motivated to get comfortable enough with the language to pass the exams. Having hung out here for a while, I have seen a surprisingly large number of people build some impressive projects with little desire to spend time reading through technical documentation. You may be surprised to hear how many times problems have been posted by people trying to do a serial read without any check to see if the data is available or valid.

Anyway, perhaps this discussion is getting a little off topic.