Author
Topic: $50 robot servo programming (Read 2156 times)

I've been away from robots for over a year and I just recently found the time to get back into it. I have the $50 robot built with a atmega328 MCU. I left this at the point where I need to superglue the pot head in place. WHERE IM HAVING TROUBLE IS, I cannot seem to program the servo to go to the '90*' midpoint. I remember having the impression that PWM was used to send the correct pulse length at the correct frequency, but I've been looking at documentation and tutorials for several hours now, and I'm not even sure if the output setup for the $50 robot MCU uses pins capable of PWM. I have a ridiculous attempt from when I was last trying to do this that uses waiting between bringing the signal high and low. It almost works, but seems completely impractical as interrupts and such can change the pulse width or frequency, and no other code is being executed during the waiting. Should I be persuing PWM, or is there a better way to control the servos? Thanks everyone!

Thanks for the quick reply. I understand that PWM is the best way to go. What I'm not sure of is whether or not the $50 robot output pins are capable of PWM. How do I know which pins are capable, and how do I set them as PWM output pins?

I just looked through the photovoreV1 project file. It appears that the program sends a pulse of length <speed1> to one servo, waits 20 ms, sends a pulse of length <speed2> to the other servo, then waits 500ms at the end of the program loop.

This, or a modified similar method would be acceptable for my final purpose, but should I use this method while modifying my servo? With this method, the servo jerks back and forth slightly rather than hold the angle. If I add a delay such as admin, the servo(modified in all ways except gluing the pot head) will be still for half a second with the pot in one position, and then start moving in one direction the next. Obviously this method has some variability to the angle it is outputting to the servos, at least the way I'm using it.

Would it be possible to use a timer and code my own PWM for the other output pins? I'm more experienced programming C++ for PC than microcontrollers still, so I don't know if it's possible to create some sort of timed callback function to interrupt the program and send the correct pulse. Thanks again for the help.

Most likely the hardware PWM module is not a good choice for producing pulses to control a servo. This is due to the very small duty cycle of a pulse width, 1 to 2 ms, to the pulse period, 20ms.It works much better to produce the servo pulses with software using either a software timing loops or hardware timers.Do some google searches on "RC servo controller", "atmega servo controller" to find code samples.

Most likely the hardware PWM module is not a good choice for producing pulses to control a servo. This is due to the very small duty cycle of a pulse width, 1 to 2 ms, to the pulse period, 20ms.It works much better to produce the servo pulses with software using either a software timing loops or hardware timers.Do some google searches on "RC servo controller", "atmega servo controller" to find code samples.

Eh? Think I must be getting old ...Hardware PWM is absolutely the most rock solid way to control servos, it is 100% rock-on, no nonsense, most accurate way to do it - software PWM will always be more flakey. Sorry waltr but I totally disagree with what you said ... prove me wrong and I'll eat my car.See my tutorial at http://www.societyofrobots.com/member_tutorials/node/228 for an intro to PWM - or just use WebbotLib

I've been away from robots for over a year and I just recently found the time to get back into it. I have the $50 robot built with a atmega328 MCU. I left this at the point where I need to superglue the pot head in place. WHERE IM HAVING TROUBLE IS, I cannot seem to program the servo to go to the '90*' midpoint. I remember having the impression that PWM was used to send the correct pulse length at the correct frequency, but I've been looking at documentation and tutorials for several hours now, and I'm not even sure if the output setup for the $50 robot MCU uses pins capable of PWM. I have a ridiculous attempt from when I was last trying to do this that uses waiting between bringing the signal high and low. It almost works, but seems completely impractical as interrupts and such can change the pulse width or frequency, and no other code is being executed during the waiting. Should I be persuing PWM, or is there a better way to control the servos? Thanks everyone!

The $50 robot CAN do hardware PWM. Each AVR has more, or less, PWM channels. Even the humble ATMega8 does it. Your are best using Timer1 (as its 16 bit) and if memory serves then these pins don't have pin headers, by default, on the $50 robot design. ie you may need to solder some more (at the bottom right of the chip if memory serves). See this page or more info http://www.societyofrobots.com/member_tutorials/node/233

Thanks everybody. Since I've got the bot all set up and screwed together, I'm going to try the software method. I need to learn more about timers. I understand that it overflows and then interrupts to update the counter. I don't know how to create my own interrupt for when the counter reaches some value, however.

I didn't want to go back to soldering on the board since I hadn't killed anything on it yet and I have no spare parts, So I wrote this program for centering the servos. It worked very well, although I found out that my MCU is running at 1MHz even though I thought it was 8MHz. I used a 1.5ms pulse, adjusted the pot until the servos stopped, then tested a few values between 1.0ms and 2.0ms. I plan to alter this code to control the servos on this bot without PWM. If anyone finds themselves looking for the same, feel free to use the code below, and anyone else feel free to suggest alternatives. Thanks again everyone!

//Toggle PORTD for 1.5 ms every 20ms //This could also be a series of individual pins being brought high //for different lengths of time PORTD=0xFF; _delay_us(1500); //Using a delay function within an interupt makes me irksome, but it works here. Also, nested interupts are turned off within the interupt by default, so the delay is accurate. PORTD=0x00; }}

I'm having some trouble when passing a variable into the delay functions. They work perfectly when passed a constant, but delay incorrectly when passed any type of number variable. I'm going to rewrite what I have using a delay function more like admin's, with a for loop, but will continue to use this within a timer interrupt.