My servo is ackting wird!

hey

I connected a servo to my baby O and all I wanted to do was to set him in the mid position. but there is a problem, when I set the servo on mid, he sets himself completely to the end of his motion location, and when I try to set him to the actual end of his motion location I hear the gears in side crunching. I tried several motors and it was the same with all of them.
why is this happening?
thanks
Arbel

Eep! Gears crunching are never good!

Most servos are a little off center, i.e. a 1.5ms pulse won’t put them dead center, but it should be somewhere in its reachable range!

Can you post two things, the code you’re using to try to set the servo to mid position, and how exactly you’re connecting everything up?

-Adam

If you are using the servo.h code in the orangutan_lib file I found when setting the controls on the Scorpion HX that I needed to set it to 1510 to get the “center” position. What method are you using?

The problem is not to set the servo in the center, the problem is that it got the directions all wrong! I’ll explain:
say that the servo can move from 0 to 180 degrees. when I try to set it to 90 deg’ it sets itself to 0 deg’. When I try to set it to 180 deg’, it sets it self to about 30 deg’. When I try to set it to 0 deg’ the gears start crunching.
the code I’m using is taken from the Orangutan-lib and it worked just fine until recently so I’m guessing it’s not the code. I think there is some thing wrong with my baby O.
Arbel

I doubt the servo is at fault, although you could test it on another servo controller to be sure (you probably don’t want to risk crunching another good servo just to test the Baby Orangutan). If code that used to work is now having this problem with no changes, it sounds like you may have a clock speed mismatch.

You say that two commands that used to be 90 degrees apart are now 30 degrees apart, which makes me think that the microcontroller is physically operating faster than the code thinks it is. The Baby O has a 20MHz external clock, and the Orangutan-lib servo program was designed so that it could work either at 20MHz, or at 8MHz running on a big Orangutan with no external clock (by default).

Make sure that at the top of your copy of device.h, the default Orangutan definition is commented out, and the Baby Orangutan definition is uncommented, like so:

//#define ORANGUTAN
 #define BABY_ORANGUTAN
// #define ORANGUTAN_X2

You could also be double sure by adding the line “#define F_CPU 20000000UL” to the top of your main servo program file, which will overwrite the setting from device.h.

Was that it?

-Adam

thanks! like allways you know the answer! I will check it out and let you know…
by the way, I love what you did with the site… (I don’t know if you ear part of the pololu team)

any how, I checked the defentions in the device.h file and they are as they should be, the second thing I can define is the pwm timer. now it’s on timer0, should I try pwm_timer2?
Arbel

all is good!!! you where wright! thanks!!! Arbel
by the way, do you have a video of that snake robot you made?

Glad everything is working now, I hope your servo survived!

On the ATMega168 Timer0 and Timer2 are both 8-bit timers, so it doesn’t make much of a difference which one you use to generate your servo signals, unless you want to use the other one for some other purpose in your code.

And since you asked…

As for the snake robots, I’ve actually worked on two different projects, both with university robotics labs, so I can’t take all the credit. Well, actually one is a snake robot project and one is a serpentine robot project. As we define it, a snake robot moves only by changing it’s shape (i.e. slithering, undulating, etc…) while a serpentine robot has some other means of locomotion, like wheels, legs, or in this case, tracks. Both types have advantages and disadvantages, but they’re both totally cool.

So, the website for my old snake robot project (still going on though) is here:
Modular Snake Robots (ModSnakes), Biorobotics Lab, Carnegie Mellon University
These robots are actuated entirely with hobby servos, but don’t let that fool you, they have some huge achievements. ModSnakes were the first snake robots to climb vertically inside a pipe, then later the first to climb vertically wrapped around the outside of a pipe. They have other neat tricks like climbing stairs, striking across wide gaps, and even swimming!

The video website for my current serpentine robot project is here:
OmniTread Serpentine Robot OT4, Mobile Robotics Lab, University of Michigan
This guy is really sweet. It has pneumatic joints (rigid when you need to cross gaps, compliant when you need to go over uneven terrain), and it’s covered in moving tracks, all driven by one central motor through a flexible drive-shaft spine. It can do neat things like climb up stairs/pipes too, and it can get through crazy obstacles, across wide gaps or over objects many times it’s own height. One of the OT4’s even has hobby servos in it, controlling the flipper tracks.

It’s really interesting to have worked on both projects, since they’re somewhat opposite approaches to robots with similar applications (industrial inspection, search & rescue, etc…). Also, it shows you can do some amazing things with hobby servos!

-Adam

hay!
I got the same problem all over again. I know it is the clock, this is my code. every time the sensor is pressed, the servo should move a little. but again like in the beginning of this thread, the servo is acting up side down. any thoughts?
Arbel

the code:

#define F_CPU 20000000UL

#include "device.h" 
#include <avr/io.h> 
#include <util/delay.h> 
 
 #include "pwm.h" 
 
 
 #include "servo.h" 
 
// Past here the library has been loaded, and the rest is up to you. 
// Delay for N seconds 
void delay_sec(uint8_t sec) 
{ 
	unsigned int cycles; 
 
	// Delay 25ms at a time (38.4ms is the most we can delay with a 
	// 20MHz processor, unfortunately.  See the delay.h include file 
	// for more info.) 
 
	for(cycles = 0; cycles < (sec * 40); cycles ++) 
	{ 
		_delay_ms(25); 
	} 
} 
 
int main(void) 
{
pwm_init();
servo_init();
unsigned char finger11;
unsigned int pos;
pos = 920;
finger11 = servo_define(_SFR_IO_ADDR(DDRD), _SFR_IO_ADDR(PORTD), 0);


DDRB &=~(1<<PB4);

PORTB |=(1<<PB4);

servo_active(finger11);
servo_set(finger11,920);
for(;;){


if ((PINB & (1<<PB4)) == 0){
	servo_set(finger11, pos);
	pos = (pos + 10);

}

}
}

Hello.

What do you mean by “acting up side down”?

- Ben

I see one potential problem with your code’s main loop. You have no delays or other timing restrictions on how often you update the servo position. I would suggest making two changes:

  1. Insert a delay in the loop so that you can only update the servo position every x ms (where you choose x so that the servo motion is the speed you want).
  2. Add a check to make sure that the servo position is within the allowed range. If the position is outside the allowed range, don’t call the servo_set function.

Right now, your code will keep increasing the servo position if your sensor input is held low. If the behavior you want is for the servo to increase its position by 10 and only by 10 each time the sensor input goes low, you can add the following line to your code:

for(;;){


if ((PINB & (1<<PB4)) == 0){
	servo_set(finger11, pos);
	pos = (pos + 10);
while ((PINB & (1<<PB4)) == 0)
    ;
}

}

This will cause the servo position to increase by 10 when the sensor input goes low, and then wait until the sensor input goes high again. Now each time the sensor input goes low, the servo position will increase by 10 and no more.

- Ben

I bet Ben’s suggestions will clear up your problems.

I see you based your code on servo-test.c from Orangutan-Lib. The function servo_set takes the servo pulse width in microseconds (us) as the position variable, so you’ll want to limit your “pos” variable to between 1000 and 2000 (1500 should be right around centered for your servo). The servo-test.c example doesn’t explicitly do this, but the for loop that changes the “time” variable only goes from 1000 to 2000.

Also, this has nothing to do with your servo issues, but there is a slight problem with the delay_sec function in servo-test.c. It turns out that the _delay_ms function can only be used to delay for 13ms at a time on an AVR running at 20MHz (not 38.4 ms, as in the comment). If you want delay_sec to work on your baby Orangutan you can copy the version from lcd-test.c:

// Delay for N seconds
void delay_sec(unsigned char sec)
{
	unsigned int cycles;

	// Delay 25ms at a time (38.4ms is the most we can delay with a
	// 20MHz processor, unfortunately.  See the delay.h include file
	// for more info.)

	for(cycles = 0; cycles < (sec * 40); cycles ++)
	{
		_delay_ms(12);
		_delay_ms(13);
	}
}

The comment is still wrong, but the code produces actual second-long delays. Many of the Orangutan-Lib sample programs have this same bug, I’ve already talked to Tom Benedict about it, it should be fixed in the next version.

-Adam

I’m glad you said something about this. I thought I remembered calculating 13 ms as the limit for _delay_ms, but this code made me wonder if I was remembering correctly.

- Ben

When I said “up side down” I meant that when I set the servo to 920, It opens to the other end very fast. I think there is something wrong with my frequencies. I will try to set the servo to 1 position and see what happens.
I want the servo position to increase by 10 as long as the sensor is pressed. until it’s max position. That is the reason I didn’t add any delays.
Arbel

You should still add some delays so that the rate of servo movement is reasonable. Otherwise your observed behavior is likely to be that the servo will just shoot to its max position when the sensor is pressed. And you should definitely add code to prevent the servo from going past its max position.

- Ben