Society of Robots - Robot Forum
Software => Software => Topic started by: kevinisnekkid on November 04, 2008, 02:07:50 AM
-
Hi,
I have 2 questions about servos.
First, I have an issue with servo vibration. I have an atmega8 running at 8mhz. I'm using uart to send commands to the chip. It's the $50 board, and most of the $50 code.
#define PWM(port, pin, spd) { PORT_ON(port, pin); delay_cycles(spd); PORT_OFF(port, pin); delay_cycles(1600); }
...
int x=240, y=0, z=0;
...
if (x != 0) PWM(PORTD, 2, x);
if (y != 0) PWM(PORTD, 3, y);
if (z != 0) PWM(PORTD, 4, z);
Many times it vibrates in that position for abit before it settles down. What causes this vibration?
Second, how fine of positioning can I get with servos? And can I send a single pulse to get a servo to move into a position, or must I keep sending pulses until it's in position?
Ok, that was 3... :)
-Kevin
PS. I don't have the code space to add the timer unless I rip out rprintf. I don't use much rprintf, so maybe I can strip that down to just sending chars over the uart.
-
So, it goes to the correct position, but it vibrates? Is there any force being applied to the servo? Which servo are you using? Are you extending the servo wire length at all?
Second, how fine of positioning can I get with servos?
Depends on the servo and applied external force, but typically somewhere between 2 and 5 degrees.
And can I send a single pulse to get a servo to move into a position, or must I keep sending pulses until it's in position?
You must keep sending pulses, although digital servos require fewer pulses than analog servos.
-
One of possible causes for vibartion tends to be controlling servo from 3.3V mcu... Some servos work with 3V signals nice, some don't work at all, some have increased settling time.
Are you using atmega8 or atmega8L?
-
It's the 8, not the 8l. I'm running an 8.6 batt pack (freshly charged). This is one of my boards from the $50 project.
Yea, it goes to about the right position, and vibrates. No force, these are just sitting on my table, not hooked up to anything. Hi-tec, futuba, and I forget what the 3rd brand is that I have, they all do the same. No wire extensions.
I'm not sure if it has an effect, but I'm using the uart to get positions of where they should move to.
My guess is that this is a timing issue.
I have an idea that I'd see what people think
/************************************
* Semi - PsuedoCode
* I don't know all the nessecary code yet,
* but I can figure it out if this idea might work.
************************************/
volatile int cnt;
Timer_Interupt_Handler(...) { cnt++; }
int main(void) {
int sx=500, sy=400, sz=600;
int bx=0, by=0, bz=0;
cnt=0;
Initialize_16bit_Timer(Trigger Fast);
while(1) {
Handle_Uart_IO(...);
//Turn on when it is time.
if ((cnt < sx) && (bx == 0)) { port_on(portd, 2); bx = 1; }
if ((cnt < sy) && (by == 0)) { port_on(portd, 3); by = 1; }
if ((cnt < sz) && (bz == 0)) { port_on(portd, 4); bz = 1; }
//Turn off when it is time.
if ((cnt > sx) && (bx == 1)) { port_off(portd, 2); bx = 0; }
if ((cnt > sy) && (by == 1)) { port_off(portd, 3); by = 0; }
if ((cnt > sy) && (by == 1)) { port_off(portd, 4); bz = 0; }
//Reset Counter (when one cycle is done)
if (cnt > 32000) cnt -= 32000;
}
return 0;
}
Would that work smooth enough to get a nice steady servo movement, and clean uart io?
-
I'm running an 8.6 batt pack (freshly charged).
8.6V freshly charged?! :o
You do realize most servos max out at around 6V, and your battery is probably around 9.5V fully charged :P
I've never run a servo at that voltage . . . but its a possibility that's causing your problem.
Also I noticed you have an interrupt running. Does the interrupt trigger while servos are being commanded? If so, it will mess up your servo timing. Always turn off your interrupts before commanding servos.
-
I'm running an 8.6 batt pack (freshly charged).
8.6V freshly charged?!
You do realize most servos max out at around 6V, and your battery is probably around 9.5V fully charged
No, I did not realize it... think it might damage the servo?
I'm using these batteries because they came with my RC airplane. I figured it would be the proper voltage...
I've never run a servo at that voltage . . . but its a possibility that's causing your problem.
That by itself isn't causing the problem. The $50 project code works fine with that voltage, even running at 8mhz.
Also I noticed you have an interrupt running.
No, I said I'm thinking of using a timer to get (hopefully) better servo response. I'm currently experimenting with timers.
I will be using uart (both input & output), 3 servos, 1 motor, 3+ sensors, and a partridge & a pear tree... (heh)
The chip will be mostly dumb, taking servo positions & motor speed from a computer. The sensors will be there to help calibrate it & make sure it isn't overloaded. With this much going on (yes, I will have the chip run at 8mhz) isn't timers the only way to get decent servo response?
-
isn't timers the only way to get decent servo response?
The best way to control servo's is to use de CCP peripherals, (use the compare functionality)
there are a few code examples on teh net somewhere, but they're not easy to find.
using this method will allow you to set one register with a certain value, only once, and this will result in the servo moving to the corresponding position. And the pulses will continue to be sent to the servo so it will do everything it can to stay there...
-
I am pretty sure using a high voltage on a servo causes jitters (it is equivalent to raising the P gain in the internal control circuit). If that isn't the problem (though I'm 99% certain it is), it could be your servo pot is dirty. If that is the case you can try to clean it or just get a new servo.
Use CCP for the servo if you can, you just set up the module and it will continuously send PWM pulses. Very easy to use. The datasheet (if it is any good, the microchip ones usually are, don't know about Atmel's) usually have a section on PWM function of the CCP module. It goes something like this
(this is dspic code, but it should be very similar for avrs)
void pwm_init(unsigned long freq)
{
timer2_init(freq); //initialize the timer to overflow at a given frequency
// Initialize Output Compare Module
OC1CONbits.OCM = 0b000; // Disable Output Compare Module
OC1R = 0; // Write the duty cycle for the first PWM pulse
OC1RS = 0; // Write the duty cycle for the second PWM pulse
OC1CONbits.OCTSEL = 0; // Select Timer 2 as output compare time base
OC1CONbits.OCM = 0b110; // Select the Output Compare mode
}
//Change the PWM duty cycle
void pwm_dutycycle(unsigned int percent)
{
//PRx+1 is the period in cycles
OC1RS=(PR2+1)/100*percent;
}