Society of Robots - Robot Forum

Software => Software => Topic started by: greywanderer012345 on July 26, 2012, 09:22:49 PM

Title: $50 robot servo programming
Post by: greywanderer012345 on July 26, 2012, 09:22:49 PM
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!
Title: Re: $50 robot servo programming
Post by: newInRobotics on July 27, 2012, 04:31:14 AM
PWM is always the best way to drive servos, so go for it. All You need to do is find correct pins on Your MCU, capable for PWM.

FIY, midpoint of a servo is 0°, NOT 90°. To set servo to 0° You have to output 50Hz PWM with 50% Duty-cycle.
Title: Re: $50 robot servo programming
Post by: greywanderer012345 on July 27, 2012, 12:20:57 PM
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.
Title: Re: $50 robot servo programming
Post by: newInRobotics on July 27, 2012, 03:22:25 PM
To find out what pins do what You have to refer to data-sheet --> ATmega48A/PA/88A/PA/168A/PA/328/P (http://www.atmel.com/Images/doc8271.pdf)

To learn Timers and PWM You can follow tutorials
--> Newbie's Guide to AVR Timers  (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106)
--> Part Nine - Pulse Width Modulation (PWM) (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=68302&start=all&postdays=0&postorder=asc)

Haven't tried it, but code underneath should set servo to 0° when servo is connected to pin 15 [PB1 (OC1A/PCINT1)] and microcontroller is running @ 1MHz:
Code: [Select]
int main(void)
{
TCCR1A |= 1 << COM1A1; // Set OC1A on Compare Match when up counting, clear - when down counting
TCCR1A |= 1 << WGM11; // PWM, phase and frequency correct

TCCR1B |= 1 << WGM13; // PWM, phase and frequency correct
TCCR1B |= 1 << CS10; // No prescaling

ICR1 = 19999; // PWM top value

OCR1A = 9999; // PWM compare value;

DDRB |= 1 << DDB1; // Set PB1 (OSC1A) as output

for(;;){}
}
Title: Re: $50 robot servo programming
Post by: waltr on July 27, 2012, 08:54:25 PM
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.
Title: Re: $50 robot servo programming
Post by: Webbot on July 28, 2012, 08:34:24 PM
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 (http://www.societyofrobots.com/member_tutorials/node/228) for an intro to PWM - or just use WebbotLib
Title: Re: $50 robot servo programming
Post by: Webbot on July 28, 2012, 08:43:01 PM
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 (http://www.societyofrobots.com/member_tutorials/node/233)
Title: Re: $50 robot servo programming
Post by: waltr on July 28, 2012, 09:39:38 PM
I stand corrected. Thanks for the link to ATMega PWM tutorial.
Title: Re: $50 robot servo programming
Post by: greywanderer012345 on August 06, 2012, 08:18:09 PM
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.
Title: Re: $50 robot servo programming
Post by: greywanderer012345 on August 09, 2012, 11:52:47 PM
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!
Code: [Select]
//Zero Servos Using Timer1 and Delay
//This is useful if you built a robot that uses servos or other square wave
//devices on pins that cannot use built in PWM.

#include <avr/io.h>
#include <avr/interrupt.h>

//Change the below value to your MCU Frequency.
//It is required for _delay_us()
#define F_CPU 1000000UL  // 1 MHz
#include <util/delay.h>

//This is used to count milliseconds by 2. I counted by 2 because of the compare value I ended up using
volatile unsigned int   clock_2millisecond=0;

int main() {
//Set PinD as Output
DDRD = 0xFF;

//Set up the timer1
//Set Prescaler to 8 and mode to CTC
       TCCR1B=(1<<WGM12)|(1<<CS10);

       //The below compare value was found empirically with the debugger
       //and will differ with other frequencies.
       OCR1A=2149;

       //Enable the Output Compare A interrupt
       TIMSK1|=(1<<OCIE1A); //For some MCUs this is TIMSK (there is not 1)

//Enable interrupts globally
       sei();

       //infinite loop
       while(1);

       return 0;
}

//ISR called every 2ms
ISR(TIMER1_COMPA_vect) {
   clock_2millisecond++;
   if(clock_2millisecond==10)
   {
      clock_2millisecond=0;

  //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;
   }
}
Title: Re: $50 robot servo programming
Post by: greywanderer012345 on August 16, 2012, 01:04:34 AM
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.
Title: Re: $50 robot servo programming
Post by: Webbot on August 16, 2012, 10:28:19 AM
Suggest getting rid of the
#include <util/delay.h>
and use the same function from WebbotLib see http://webbot.org.uk/WebbotLibDocs2/47113.html#obj_47642 (http://webbot.org.uk/WebbotLibDocs2/47113.html#obj_47642)
#include <core.h>
but the function is called "delay_us" ie no leading underscore

The value passed in is of type uint32_t so make sure that your variables are defined as that type and not something smaller like 'int' for example