can't make my servo controlled camera arm move correctly

Hey everyone,

For a project I am making a servo controlled security camera arm. the arm and camera serve as a prop, so the camera is not real.

I have made a arm with two servo’s in it. One to move horizontally (180*) and the other to move vertical (135*), controlled with a arduino uno.

  • The idea is that the camera is looking down to a person sitting on a chair.

  • when a input is given to the arduino (for now I am doing this with a switch), the camera will quickly look away, and will begin to look around facing up. As if it was not spying on the person.

  • when the input from the switch is removed, the camera will slowly go back to spying on the person in the chair. so facing down.

My problem is that i can’t get the camera to move correctly. it shoots down, in between tasks, and i don’t know why

my servo’s are connected to pin 10 and 9, and the switch is connected to pin 8.
and this is the code I am using:

If you know anything that could help I would be really greatfull, thanks!

const int buttonPin = 8; // the number of the pushbutton pin

#include <Servo.h>
Servo servotop; // create servo object to control a servo
Servo servobelow; // a maximum of eight servo objects can be created

int pos = 0; // variable to store the servo position
int buttonState = 0; // variable for reading the pushbutton status

void setup()
{
pinMode(buttonPin, INPUT);
servotop.attach(9);
servobelow.attach(10);
// attaches the servotop on pin 9 and servobelow on pin 10 to the servo object
}

void loop(){

// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH)
{
// turn servotop on (look away):
for(pos = 30; pos < 150; pos += 1) // goes from 30 degrees to 150 degrees
{ // in steps of 1 degree
servotop.write(pos); // tell servo to go to position in variable ‘pos’
delay(50); // waits 50ms for the servo to reach the position
}
for(pos = 150; pos < 30; pos += 1) // goes from 150 degrees to 30 degrees
{ // in steps of 1 degree
servotop.write(pos); // tell servo to go to position in variable ‘pos’
delay(50); // waits 50ms for the servo to reach the position
}

// turn servobelow on (look away):
for(pos = 111; pos < 180; pos += 1) // goes from 111 degrees to 180 degrees
{ // in steps of 1 degree
servobelow.write(pos); // tell servo to go to position in variable ‘pos’
delay(50); // waits 50ms for the servo to reach the position
}
}

// return to start position (he will never know):
else {
{ // in steps of 1 degree
servotop.write(100); // tell servo to go to position in variable ‘pos’
delay(50); // waits …ms for the servo to reach the position
}

{ // in steps of 1 degree
servobelow.write(111); // tell servo to go to position in variable ‘pos’
delay(50); // waits …ms for the servo to reach the position
}
}
}

Can you go back and edit your previous post to use code tags? Good practice. Makes it easier to read. Makes it more likely that forum members will be willing to help you. :slight_smile:
Oh, and format your code.
Autoformat from the IDE menu or CTRL-T

I think you have some bad for loops.

(pos = 150; pos < 30; pos += 1)

If you start at 150 and go up, how long does it take to get less than 30?

Another thing: do fix the indentation of your code (CTRL-T in the IDE does this for you).

Missed that loop issue - good one. That's going to take a while indeed... 1630.9 seconds to be precise.

That may also explain some odd behaviour. The documentation of servo.write() is lacking, but I guess servo.write() expects to receive a byte (rather than an int, which is the type of pos). So the value goes to 180, then over 180 (presumably ignored by the servo.write() function), then when reaching 256 the byte overflows to 0 and the servo turns the other way.

wvmarle:
So the value goes to 180, then over 180 (presumably ignored by the servo.write() function)

Unfortunately not. When the (int) value gets over 180 it is treated as though you were trying to pass a number of microseconds to a writeMicroseconds() command rather than the plain write() you actually used.

This little trick of the servo library can cause all sorts of confusion.

Steve

Doesn't seem to be documented, either.
Admittedly I didn't study the servo documentation in detail but it's not obvious if it's there.

wvmarle:
Doesn't seem to be documented, either.
Admittedly I didn't study the servo documentation in detail but it's not obvious if it's there.

But it is in the library code. I very much dislike this feature.

slipstick:
Unfortunately not. When the (int) value gets over 180 it is treated as though you were trying to pass a number of microseconds to a writeMicroseconds() command rather than the plain write() you actually used.

This little trick of the servo library can cause all sorts of confusion.

Steve

I thought this didn't happen until much higher values, like around 540 degrees.

I'd rather call it a bug. A function has to do one thing and one thing only, and not when an input is out of range something totally different. That's the hallmark of a bug. It not being documented makes it even more of a bug.

It's open-source.
You have the code, you have, therefore, the documentation.

Source code != documentation. This kind of mindset is why so much open source software suffers from terrible documentation.

A mismatch between what the documentation says it does, and what the source actually does, doesn't make it less of a bug.

wvmarle:
Source code != documentation. This kind of mindset is why so much open source software suffers from terrible documentation.

Source code == documentation is the only mindset that ensures documentation is up-to-date, 'cos in this world of hobbyists, who is going to keep the documentation updated?
If you can't trust the source, you're on very shaky ground.

There's documentation? :wink:

Edit: For kicks I read through the servo reference.

You are right, no mention of the degrees/microseconds overload. But then I also read this:

Circuit
Servo motors have three wires: power, ground, and signal. The power wire is typically red, and should be connected to the 5V pin on the Arduino board.

So That should be an indication of the quality of the documentation.

Yes, it is often pretty terrible. It almost makes your average Instructable look good.
Another part that's lacking is that it does not mention the expected variable type for Servo.write(). That's a common thing in the Arduino documentation, though. Probably in name of "dumbing it down".

wvmarle:
It almost makes your average Instructable look good.

I'm sorry, I'm not having that :smiley:

You mean there are people who rely on finding documentation and don’t look at the code? It never occurs to me to do that for things at this open-source non-professional level.

But really you only have to go as far as the header file to find

    void write(int value);             // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds

Seems clear enough to me (even if misguided). The parameter is an int and 200 is limit for an angle, over that counts as microseconds.

OTOH TolpuddleSartre is also correct that, if you are using default timings then 544 microseconds is the shortest pulse it will actually deliver. But of course you can change those timings in the attach().

    uint8_t attach(int pin, uint16_t min, uint16_t max); // as above but also sets min and max values for writes.

Fun isn’t it!

Steve

slipstick:
You mean there are people who rely on finding documentation and don’t look at the code? It never occurs to me to do that for things at this open-source non-professional level.

But really you only have to go as far as the header file to find

    void write(int value);             // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds

I don’t even trust the comments, and very rarely even read them.

Your choice. To me it seems daft to ignore the hints that the coders put in to try to explain things...but maybe you're so much cleverer than me that you don't need the help.

Steve