Society of Robots - Robot Forum

Electronics => Electronics => Topic started by: AKnickolai on February 11, 2012, 03:54:30 AM

Title: Controlling multiple motors with an Atmega16
Post by: AKnickolai on February 11, 2012, 03:54:30 AM
I'm trying to move to the next level with my robotics.  To this point I have been using a design similar to what is seen in the $50 code to perform line following and autonomous maze navigation using IR sensors.  Consider basic servo control code:

Code: [Select]
servo_left(){
PORT_ON(PORTD,4);
delay_cycles(50);
PORT_OFF(PORT,4);
delay_cycles(200);

servo_right(){
PORT_ON(PORTD,5);
delay_cycles(50);
PORT_OFF(PORT,5);
delay_cycles(200);

Now calling either of these commands will result in continuous rotation, but let's suppose I want better speed control out of my servos?  How to I do it?  Changing the delay times is only marginally effective since the variation in speed is pretty small and soon enough you are sending a wave form that is out of the range the servo will do anything with.

I can get great speed control on a single servo by running it and a known speed, then adding a delay:

Code: [Select]
servo_left(){
PORT_ON(PORTD,4);
delay_cycles(50);
PORT_OFF(PORT,4);
delay_cycles(200);

delay(X)

Where adjusting X sets the speed, gives me a much wider range of speeds and doesn't get too jerky until I reach larger values.  The problem is, this won't work with two servos as the delay(X) line stops the other servo dead in its tracks too (of course it does, the program is just waiting).

So, my question is what can I do code wise to improve the speed control on my servos and run two at a time?  For what it is worth, I have hooked my Atmega16 outputs to an Oscope to ensure I am sending correct wave forms to the servo (they are GWS continuous rotation servos) and everything is good there, I'm just not getting the speed resolution I want.  I've considered stepper motors, but I think I'd hit the same problem since they are still pulse driven and I don' think microstepping would give me what I want.  My ultimate goal is to implement a PID controller that doesn't have to control around a ton of error variables.  Any thoughts would be greatly appreciated.
Title: Re: Controlling multiple motors with an Atmega16
Post by: Soeren on February 11, 2012, 07:32:22 AM
Hi,

Continuous rotation servos are controlled with pulses between 1ms and 2ms with 1.5ms being off (the exact ends of the ranges can be a bit wider).

If 2ms is full speed forward (direction depends on how the servo is mounted) and 1.5ms is off, 1.6ms will be fairly slow, 1.7ms still not very fast and so on up to the 2ms. going under 1.5ms  works the same way, only in reverse, with the slowest speeds nearest 1.5ms and the fastest at 1.0ms The resolution of the range will depend on the exact servos electronics and may have a smaller range (i.e. be at full speed before the timing extremes are reached.

It won't help to just introduce delays between the pulses, you have to keep the pulses coming at roughly the same interval (~20ms) and then change the timing of the pulse.
Title: Re: Controlling multiple motors with an Atmega16
Post by: AKnickolai on February 11, 2012, 11:43:30 AM
That clears things up a bit with the pulses and timing that need to be sent to the servo.  I guess my next question would be around the internal clock speed of the Atmega16.  The data sheet indicates that it comes from the factory with the internal oscillator running a 1mhz, a2d conversion takes place at 16mhz, but when I code and LED to blink with a delay cycles line of code I get ~25 cycles per ms.  I can't find the relation in those clock speeds, I've struggled with this in the past and got by so far.  This probably explains the lack of speed control I'm seeing in the servos.  Maybe someone could provide a little more insight into how the clock speeds affect things in the Atmega?  Are there pieces of code that are run in the background that make the 1mhz clock appear as ~25 cycles per ms in my code?  I'm only loading aver/io.h and avr.interrupt.h for libraries, I can't imagine these would take significant processor time once I enter the main portion of my code.
Title: Re: Controlling multiple motors with an Atmega16
Post by: Soeren on February 11, 2012, 05:38:44 PM
Hi,

For the specifics on AVR timing, I'm not the one to consult, but you should take a look at "webbotlib" which I think may be just the solution for you. It has got all the low level stuff for driving servos (I think, I mostly use PICs myself) - perhaps put the question in the software section of the site, where all this is more appropriate.
Title: Re: Controlling multiple motors with an Atmega16
Post by: joe61 on February 11, 2012, 06:51:05 PM
That clears things up a bit with the pulses and timing that need to be sent to the servo.  I guess my next question would be around the internal clock speed of the Atmega16.  The data sheet indicates that it comes from the factory with the internal oscillator running a 1mhz, a2d conversion takes place at 16mhz, but when I code and LED to blink with a delay cycles line of code I get ~25 cycles per ms.
I don't know where you're getting the 16MHz number for the ADC. The ADC is clocked using a prescaler on the CPU clock, so it can't be faster than the CPU clock. The idiotic factory default clock speed can be increased to 8MHz (or more with an external crystal), but that won't really help you here as the machinery has some absolute time requirements, which limit the speed you should run it at.

Quote
I can't find the relation in those clock speeds, I've struggled with this in the past and got by so far.  This probably explains the lack of speed control I'm seeing in the servos.  Maybe someone could provide a little more insight into how the clock speeds affect things in the Atmega?  Are there pieces of code that are run in the background that make the 1mhz clock appear as ~25 cycles per ms in my code?  I'm only loading aver/io.h and avr.interrupt.h for libraries, I can't imagine these would take significant processor time once I enter the main portion of my code.

I'm not clear on what you're asking (I've been fighting a cold and my head isn't fully functional right now). In general, it takes 13 clock cycles to perform an AD conversion (I think it's 25 cycles for the first reading because of setup cost). You should set the prescaler such that the ADC clock is between 50 - 200KHz (you can go higher if you only need 8-bit resolution). Take a look at the "Analog to Digital" section of the data sheet, this is all there, only explained better.

I'd agree with Soren though, take a look at Webbotlib, until you get to know the chips pretty well this stuff can make you crazy.

Joe
Title: Re: Controlling multiple motors with an Atmega16
Post by: joe61 on February 11, 2012, 06:58:16 PM
That clears things up a bit with the pulses and timing that need to be sent to the servo.  I guess my next question would be around the internal clock speed of the Atmega16.  The data sheet indicates that it comes from the factory with the internal oscillator running a 1mhz, a2d conversion takes place at 16mhz, but when I code and LED to blink with a delay cycles line of code I get ~25 cycles per ms.
I just looked at this again and realized that I'm feeling worse than I realized. I thought you were asking about A to D conversions. Sorry. What was the "a2d conversion" comment about?

Can you post the code you're talking about? It would be easier to answer that way.

Joe
Title: Re: Controlling multiple motors with an Atmega16
Post by: AKnickolai on February 12, 2012, 12:37:07 PM
Thanks for the replies guys.  I learned a lot in the past few days, clock speeds are totally clear in my mind now.  Fcpu, timer clocks, and A to D clock speed.  The atmega16 can run up to 8MHz, timer clocks and A to D speed are different.  not sure where I got 16MHz from.  The cool thing about timers is that you can use them to generate PWM signals and the timers run in parallel with the code you have written.  The parallel execution part was the cause for more first post.  It may not have been clear, but I was having issues generating the PWM signals using the body of my code as the delay_cycles() line would cause delay in the entire program - affecting both servos, when I only wanted to change the speed of a single servo. 

For the benefit of anyone who might search this in the future, this link was quite helpful in understanding the timer functions of the chip:

http://tom-itx.dyndns.org:81/~webpage/abcminiuser/articles/avr_timers_index.php (http://tom-itx.dyndns.org:81/~webpage/abcminiuser/articles/avr_timers_index.php)
Title: Re: Controlling multiple motors with an Atmega16
Post by: Soeren on February 12, 2012, 12:44:17 PM
Hi,

For the benefit of anyone who might search this in the future, this link was quite helpful in understanding the timer functions of the chip:

http://tom-itx.dyndns.org:81/~webpage/abcminiuser/articles/avr_timers_index.php (http://tom-itx.dyndns.org:81/~webpage/abcminiuser/articles/avr_timers_index.php)
On behalf of anyone with a similar problem, thanks for posting your results and the link :)
(If only more people would do that).