Page 1 of 2

Background servo driver in hardware, no loop() code, no interrupts

Posted: 17 Feb 2018, 18:26
by Phil_G
For anyone who wants to make an ultra simple servo tester project, I've done a framework that continuously runs all the pulsing and timing in the background - the whole servo timing and pulse generation is completely isolated from any code you write in your loop() section.
All you need to do in loop(); is to plug in your values for the desired servo position. In fact it runs fine with a completely empty loop(), perfectly streaming neutral pulses at 20ms intervals - not so useful !

Using the timer in Fast-PWM mode means that however busy the code in your loop() is, it has has no effect at all on the timing, the pulse stream continuing regardless of any long delays, display updates or whatever other distractions. Your loop() code can go for a picnic and all the while the pulses will be accurately generated in the background until your next servo position update.

The Arduino is running at 16mhz and the selected prescaler is "divide by 8" so the timer is running continuously at 2mhz. The basic time element therefore is half a microsecond, so the required servo position in uS is doubled and then loaded into OCR1B. For example, servo neutral is 1500uS so the corresponding value in OCR1B is 3000. Changing OCR1B to 2000 will give a 1000uS pulse
and the servo will drive to one end, and changing OCR1B to 4000 will give a 2000uS pulse and the servo will drive to the other end.

The value in OCR1B can be slowly incremented or decremented within the 2000-4000 range to give servo sweep, etc. Purely as an example I've shown it set by a pot on A2, but you can set it however you like, maybe have an array of positions to copy the movement of the old PIC servo exercser from many years ago!

It only drives one servo but its extremely accurate and the resolution is 0.5uS which is very tight :D
Cheers
Phil

Code: Select all

// Using the 16-bit timer in "Fast PWM mode"  to drive a single servo on D10
// Runs in hardware, independently of any loop() code or interrupts
// Servo position in OCR1B=2000 to 4000  (1000 to 2000 doubled for .5uS clock)
// Framelength is in OCR1A=40000         (20ms doubled for .5uS clock)

void setup() {
  TCCR1A = 0;
  TCCR1B = 0;
  TIFR1  |= (1 << OCF1A);  // clear any pending interrupts;
  TCCR1A |= (1 << COM1B1); // Toggle on B compare
  TCCR1A |= (1 << WGM10) | (1 << WGM11);   // Fast PWM mode, TOP = OCR1A
  TCCR1B |= (1 << WGM12) | (1 << WGM13);   // Fast PWM mode, TOP = OCR1A
  TCCR1B |= (1 << CS11);   // 8 prescaler
  DDRB   |= (1 << DDB2); //turn on output pin 10 = OC1B
  OCR1A = 40000; // Frame rate 20ms - doubled for /8 prescaler
  OCR1B = 3000; // initial servo pulse of 1500us - doubled for /8 prescaler
}

void loop(){
   // in loop, all you need to do is to set OCR1B to double the required servo position, 
   // ie neutral=3000 for 1500uS.  For example:
   OCR1B=map(analogRead(2),0,1023,2000,4000);
  }   


Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 08 Mar 2018, 20:08
by Carl
Thanks Phil, this looks a very useful basis for something I'd like to do.

I'd like an onboard electric motor timer. I assume this will drive an esc in place of a servo.

You already mention a pot to set the servo position, so with an esc this would set the throttle position.

Another pot to set a time period - maybe maximum of 60 seconds - so the pot set half way would give 30 seconds.

I guess it would be a good idea to have a delay after switch on before the motor starts - maybe with a flashing LED or blip to countdown.

It will be used with a simple esc, so on switch on it could tell the esc the min/max settings before the count down begins.

Before I embark on this, does what I'm after doing possible? It maybe someone on this forum has already something that does what I'd like?

Carl

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 08 Mar 2018, 20:29
by Phil_G
Control-line timers for electric flight are readily available but its still a good homebrew project Carl.
In loop() you would start with OCR1B=2000 (ie 1000uS as its a 0.5uS tick)
Then wait for a 'start' condition such as a button press, or a switch, maybe do a 'beep' warning and a delay,
Then you would ramp up OCR1B to 4000 (ie 2000uS as its a 0.5uS tick) over a period of say 5 seconds, all the while polling the button or switch as an 'abort'. The timer can be done using millis() or whatever.
Or ramp it up to a value derived from a 'throttle' pot.
Just before the end of the timed run, say 30 seconds before, you could briefly chop the motor, just a dip, enough to signal to the pilot to prepare for landing. All perfectly doable and an interesting project.

Testing of course could be done with a servo rather than an ESC. Sounds like a plan?

So the simplest bare bones just to show the principle would be:

setup() { other stuff plus... pinMode(thr_switch, INPUT_PULLUP); }

loop() {
OCR1B=2000; 1000uS is throttle low/off
while(thr_switch==1); // wait for throttle switch to be thrown
OCR1B=4000; // 2000uS is throttle full

(wait for one minute or whatever...)

OCR1B=2000; // 1000uS is throttle low/off
}

Into this you would add your safety stuff, beeps, abort, ramp up, speed selection, time delay etc.
This is how most projects develop, start with something very simple & work up from there.
Remember to poll the switch in any loop, so the thing never gets 'stuck on' :D
Cheers
Phil

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 08 Mar 2018, 21:19
by Carl
Thanks Phil, getting me started on this and helpful direction, and yes "sounds like a plan"

I'll post in a separate thread what I come up with.

Carl

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 24 Mar 2018, 11:41
by DaveL
I built something similar last year for an indoor model, might be of interest to you:
https://www.youtube.com/watch?v=Fz9ai16gz-k


Based on the Attiny85, it has a single button which when pressed for (say) 5 seconds will give a motor run (ramped up/down) of 20 seconds. The button also allows you to select 1-5 power levels and calibrate the esc. I was trying to do it with the minimum of components as it was destined for a small model which you can see flying at:
https://www.youtube.com/watch?v=wG9xbIG5zEU

I'd be happy to post the code if you wish, hth

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 31 Jan 2019, 18:33
by MaxZ
I did have a discussion with an Arduino-savvy aeromodelling friend the other day, who is in the process of writing a sketch to emulate the SC emulator ;) that you designed Phil. His setup used delays for timing the pulses, but he was not happy with that.
My question, is there any way that the code you showed in this thread can be modified to generate a full PPM stream?

Max.

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 31 Jan 2019, 20:20
by Phil_G
Here you go Max:
viewtopic.php?f=41&t=144

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 31 Jan 2019, 20:27
by MaxZ
Thanks Phil, I will pass the info on. Maybe he is interested in joining this forum too......

Max.

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 31 Jan 2019, 20:59
by F2B
MaxZ wrote: 31 Jan 2019, 20:27Maybe he is interested in joining this forum too......
Who? Me? ;)

Savvy? :lol: No way... I'm getting there, but nowhere near yet...

By the way, I was not thinking of generating ppm that way, but the SC encoder.
I'm playing now with Frank's mod that has the throttle rotor on the single button too.
To my feel the throttle needs such a short pulse that my poor, aging thumb not always keeps up with.... :lol:
I've been thinking of using timing to decode the button duration first, then setting the 'right', 'left', 'up' and 'advance throttle' registers, finally setting the rotors for one cycle.

Re: Background servo driver in hardware, no loop() code, no interrupts

Posted: 31 Jan 2019, 22:10
by Martin
I do the short blips for throttle by flicking the edge of the button with my thumbnail - the same sort of action you use in tiddlywinks.