Servo PWM using 8 Bit timer

Hi,

I have done a lot of research and reading the last 2 days about 8bit timers and controlling hobby servos. I understand that a 16Bit timer gives you much better resolution, but my intent is to use an attiny85 to simply reverse 1 servo signal. So in essence, 1ms in comes from the rc receiver, and 2ms comes out of the attiny. This is specifically for controlling a rock crawler with rear wheel steering. The rear servo must operate opposite of the front servo. I have already designed and built a 555 circuit that accomplishes this but it is susceptible to temperature fluctuations that cause servo center instability. IE jitter or drift from center. Many people have eluded to the way that it would be done, but no one has DIRECTLY spelled out the exact math or mental process for implementing a better resolution 8bit PWM signal. From what i can glean from all my reading is this:

1: use a combination of F_CPU and Prescaler to get a clock frequency of 125K-Start with a F_CPU of either 1MHZ with a prescaler of 8 or a F_CPU of 8Mhz and a prescaler of 64. So, this gives you 8uS per clock instruction. Multiplied by 250 cycles gives you a 2mS pulse.

2: Take this 2ms pulse (now of which there are 128 steps between 1mS and 2mS) and every time this timer overflows (just thought that it might need to be 249 cycles to account for the overflow because it resets on zero.) increment a variable to count 10. This will give you a 20mS pulse, which is the 50hz pulse necessary for the servo.

3: Once the counter gets to 10, now you need to generate the required control pulse-so, i need to implement a timer loop to give me the required 1-2mS pulse.

at this point i need to figure out how to invert the incoming signal. I am planning on using the pulsein() to grab the control pulse from the receiver, store that value, but from here i need some help. The way i am accomplishing this in my other circuit is i am generating a 3ms reference pulse with one 555 and then subtracting the incoming pulse from the receiver. this gives me exactly what i need. 3mS reference - 1ms = 2mS and 3mS - 2 mS = 1mS.

What i am looking for is for someone to confirm my solution to the 8bit timer to control a servo so that others like me can benefit from the knowledge (I considered asking the guys over at AVR Freaks but they would flame me for sure, i read a ton of posts over there and they are pretty hash on people. that is why i am coming prepared with some knowledge and a plan). Also, any solutions on handing (inverting) the incoming servo pulse.

Thank you in advance to anyone who can help or verify my theories. My programming skills are not bad, but i really hate timers and banging registers.

Jason

Bump…

No one has any ideas or comments? I find this hard to believe. Come on fellow programmers help me out!

Jason

I did a quick Google search for “arduino decoding servo” and “arduino decoding radio control” and there are a lot of hits.

/mike

WOW…I really hate it when people reply with " i did a google search". I researched this EXACT issue for 2 days on google, avr freaks, and anywhere else that mentioned anything remotely close to this topic. If you don’t have anything to constructively add then maybe you should not even bother posting. This is something that i’m sure others would benefit from. i guess i could just use an atmega 328 and get “Dumb”, but why? The real trick is to be creative and figure out how to do it another way. That is what i was taught in school. It’s sad if this comment is the best this community can come up with… :evil: I expected more out of my fellow hacker/programmers.

icemanfiveoh:
at this point i need to figure out how to invert the incoming signal. I am planning on using the pulsein() to grab the control pulse from the receiver, store that value, but from here i need some help. The way i am accomplishing this in my other circuit is i am generating a 3ms reference pulse with one 555 and then subtracting the incoming pulse from the receiver. this gives me exactly what i need. 3mS reference - 1ms = 2mS and 3mS - 2 mS = 1mS.

I’m one of the 4 people left who don’t use Arduinos so I hesitate to respond but …

Does the Arduino have an “interrupt on change” input pin ? If so why not have the servo signal routed to the IOC pin to trigger a service routine the starts a counter. Then the ISR sets a flag = “counting” and returns. When the pulse trailing edge happens the ISR runs and checks the flag and if “counting” is true, it stops and reads the counter. You’ve now measured the incoming pulsewidth. Then the Tiny can do the math and figure out the desired output pulsewidth. Setup the PWM output to run one cycle* with the duty cycle set to yield the desired PW and output that to the servo (perhaps needing an appropriate driver). Not sure if Arduino Sketch speak allows all this low level stuff but that’s how I’d do it.

Wash, rinse, repeat for each pulse from the controller. Now this scheme puts a variable transport lag into the pulsetrain but that could be fixed to a constant transport lag (~3 ms) if needed.

  • I guess you could set the PWM frequency to be 50 Hz (or whatever) and then just change the duty cyle (PW) to be whatever was last measured (and subsequently “inverted”) on the fly but you’d be back to having some variable transport lag in the system for that servo given the incoming and outgoing pulsetrains won’t be exactly the same frequency (or exactly 50 Hz). Perhaps that’s not an issue.

Hmm,

That is an interesting approach. One i def. did not think of. :smiley: I thought that was the idea behind the pulsein() function… I could be wrong. I will research this aspect a little more and see if it can be used in this way. Thank you so much for your thoughts…

Jason

I’m one of the other 4 people left who don’t use Arduinos so I hesitate to respond but …

I’ve done this on PICs with the code written in assembler.

The input pulse is measured with an IOC as Mee_n_Mac suggests. The servo output pulse is timed using two of the PIC’s hardware timer modules, one for the period and the second one for the pulse width.

I could code this in C for the PIC but would not use any library functions. I would write all the needed functions so that I know exactly what they do.

Yo, check out the attached ServoDecode library for the Arduino. With this I think you can decode the incoming servo signal easily and get the pulse width, and using the ServoWrite library send out the manipulated pulse width.

You can even invert the input signal in software, see “#define PULSE_START_ON_RISING_EDGE 0” in the CPP file and change it to “#define PULSE_START_ON_RISING_EDGE 1”. Although I don’t know why you want to invert the signal yet but it’s there.

Get it working with the Arduino first and then work on porting it to something smaller like the ATTiny85 or even the ATTiny10 or ATTiny4. FYI the 85 is pretty expensive, vs. the 4.

Since the lower level code is all in the library, it should be easy to port over to another processor if it has comparable timers. The ATTiny4 even has a 16 bit timer, just 512 bytes of flash. The ATTiny10 has 1024 of flash. :wink:

-Brett (FightCube.com)

Yeah. I was all gung ho about using the 85, but if I can use the 10 then maybe I will do that, that way I can use the 16 bit timer. Don’t forget, I only want to reverse the input PWM signal not invert the levels. This is necessary to have the servo operate the opposite direction of the original signal. There may even be a port to the attiny10. We need to investigate.

Now that I see a few more replies since I last refreshed…

ServoDecode implements two interrupt service routines, an input capture and overflow interrupt.

pulseIn is polled but would probably work just fine based on what the class comments say:

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH

  • or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds

  • to 3 minutes in length, but must be called at least a few dozen microseconds

  • before the start of the pulse. */

Hmm, I’m starting to dig a little deeper and I see that ServoDeocde is actually used more for decoding the pulse train coming from a radio trainer plug. So it can decode up to 8 channels in a serial stream, but it looks like you could just set the channels to “1” and it should work for decoding one servo input. I’ll keep looking.

-Brett (FightCube.com)

Here is an interesting link that shows how Trainer Port PPM encoding is done.

http://www.mftech.de/ppm_en.htm

I’m guessing the ServoDecode won’t work unless we take out the sync pulse check and only look at one channel, but then it would probably be much easier to just code something up from scratch like Mee_n_Mac suggests.

I wrote a 2 channel radio receiver emulator program on one Arduino tonight, controlled by two potentiometers… and then wrote the servo reverser program on another Arduino… hooked them together and it works perfectly with zero noticeable lag!

Code sent to your email :wink:

FightCube:
I wrote a 2 channel radio receiver emulator program on one Arduino tonight, controlled by two potentiometers… and then wrote the servo reverser program on another Arduino… hooked them together and it works perfectly with zero noticeable lag!

Code sent to your email :wink:

In general terms, what was your solution ?

Mee_n_Mac:

FightCube:
I wrote a 2 channel radio receiver emulator program on one Arduino tonight, controlled by two potentiometers… and then wrote the servo reverser program on another Arduino… hooked them together and it works perfectly with zero noticeable lag!

Code sent to your email :wink:

In general terms, what was your solution ?

Hi Mee_n_Mac!

So I basically started creating the RxEmulator as a way to quickly debug the ServoReverser. I created a two channel system that would generate the 1.0 to 2.0ms pulse, and also be able to completely shut off the pulse so that I could test the ServoReverser for a lost signal.

The RxEmulator was pretty easy. A main loop reads two ADC inputs and main loop calculates onTime values for the servo output based on the percentage of ADC value vs. the max value. Once these values are known, both servo outputs are set HIGH and a while loop is started that counts down 20ms worth of time. Within that loop the onTime for each output is monitored and terminated (i.e. set LOW) at the correct time. If the ADC value is 0 the outputs are never set HIGH but the 20ms loop runs anyway.

The ServoReverser is pretty cool. I used the attachInterrupt() function in the Arduino which is capable of interrupting on a pin change. Fortunately there are two of these available in the Arduino library because I needed two. The Mega supports an additional 4 more. Obviously there are more available for the ATmega328 but they are not all implemented in the default libraries, so it’s not a limitation really if you need more… you just have to figure it out yourself… not too hard. Anyhoo, using the attachInterrupt() function, it was easy to set up ISR’s that were called for every change on the inputs, one for each Rx channel. I decided to just interrupt on both rising and falling states, and do a simple test to see which pulse width value I wanted to store. This is easy to do because the period is 20ms, and the pulses I care about are always less than 3ms :wink:

I used the micros() function to keep track of a few different counters for measuring pulse widths of the two Rx channels, and to generate the output pulse with the same type of while loop used in the RxEmulator. Reversing the pulse width was dead simple, so I added another couple neat features to make things a bit more interesting. Jason had the idea to use the other channel to do something for the system, so I worked that in. Also, I decided if any signal was lost for more than 100ms, the reversed output would return to the default center position of 1.5ms. As of right now it works as designed. All of this was done in basically one evening, and the ServoReverser code is only 1.8K. The output is obviously delayed due to measurement and calculation, but it’s absolutely transparent to the user operating the servos. In fact, if you look at the channels of a multi-channel receiver on a scope, you’ll see they are all done the same way and are not sync’d on the leading edge. At least they are on my Spektrum DX7 7 channel system.

If I were you, I would take a look at the Arduino. It’s a fantastic rapid prototyping development tool that I use all of the time. With so many variations that plug right into a breadboard, all of the shields available with just about every sensor you can think of, and super simple compiling and programming they are a snap to use. The power of the system is really only as good as the operator though… so if you don’t know C code and don’t have room in your brain for some more code library knowledge, it won’t be for you. However, they even have Arduino compatible boards that use the PIC32 as the main uC now, and they are still compatible with the Arduino IDE as well. They work for me and that’s what counts when I need to get something done quickly. I can be out in the lab running some new test or testing some new sensors while the rest of the engineering staff are still sitting around trying to configure the files for a PIC uC.

-Brett (FightCube.com)

FightCube:
Also, I decided if any signal was lost for more than 100ms, the reversed output would return to the default center position of 1.5ms.

That’s were I was headed using the PWM output. Since the servo is now really controlled from the “reverser”, some more smarts can be added to have the system degrade gracefully in the event something goes wrong. And conceivably one could work in in-phase vs opposite-phase rear wheel steering (? as a function of speed ?) as has been done in some autos. Not sure if that’s an advantage in an RC rock crawler but there you go. :mrgreen:

I like the “degrading gracefully” idea. I might have to implement that. It would basically be a filtered response if the signal was lost, but if there was signal then there would be an immediate response.

As for the steering vs. function of speed… it would be automatic actually. Most radios these days have a simple function to limit the steering as a function of the throttle. And since the rear servo is tied to the steering servo, it would respond the same way. However I think with rock crawlers you’d want full range all of the time.

It’s a fun little application to code for, but can be as complex as your wildest imagination.