View Full Version : Discussion Pic jittering servo mixer
CombatWombat
Mar 22, 2009, 01:41 PM
I am working on an anti-lock brake module for an R/C car and am having some problems with my PIC code. I am wondering if the overall program structure I am using is simply the wrong approach.
The basics of my contraption goes like this:
I have some magnets and a hall effect switch on the axle of my car.
I have a circuit between the speed control (brushed right now) and the receiver.
What I do is read the incoming pulse width from the receiver from the throttle channel. If it is below neutral value I know the driver is braking.
When this happens I start to look at the hall effect sensor. If the sensor stops toggling for a set period of time, I know that the axle has stopped rotating, and I would like the PIC to over-ride the incoming PWM and output a different signal (to release the brakes momentarily). Under other conditions I wish to output a PWM that is equal to the one input from the receiver.
Problems I am encountering: If I tell the PWM portion of the code to output a fixed value the servo will be solid. If I read the duty cycle of the incoming Rx signal and use that to set the length of the outgoing PWM, I get a servo jitter. The servo DOES follow the input, but it twitches enough that an ESC hooked up will not arm. I am using a FM Direct Servo Lab to generate my Rx signal, and I have verified that the servo is solid when driven directly from it. The so Rx signal itself is solid.
the pwm modules built into pics (I am trying to use the 12F series because they are available in small surface mount packages, but have 16F's available as well) are not capable of such a low frequency (50hz) to drive servos/esc with a good resolution. I am running my PIC at 8mhz to try and get resolution, but there is no workable prescaler value to get the 50hz pwm. Is this true? As a result I am doing the PWM through software.
Currently I use an interrupt generated every 50uS and start/stop the outputting PWM as well as poll the hall effect sensor for changes and update its counter. I am doing all of this in the interrupt, as I have had better luck that way than through setting flags and doing it in main. I have verified my timings and they look ok in the simulator.
So then... is there a way I can make use of the PIC hardware modules (pwm, capture, etc) to make this easier? Is generating an interrupt at a fixed interval and updating my stuff a workable solution to this? I am having a hard time getting resolution since the 1-2ms period is so short.
I apologize for writing a book, but I figure more information is better than leaving everyone guessing, no? Appreciate suggestions...
AndyKunz
Mar 22, 2009, 03:20 PM
Use the PIC's capture mode to measure the incoming signal. You do not need an interrupt to do this, just read the CCP section of the manual.
Next, use the IOC on RB4-7 or INT on RB0 to handle the Hall's. Again, this does not require interrupts.
Finally, create the output pulse using interrupts off TMR1. Set TMR1 to (65536 - intended output pulse with in us - fixed overhead) and when it rolls over you can process the time correctly. If you don't need failsafe, you can use the ending signal from the rx (CCP 1->0 transition) to set TMR1 to the new value.
It sounds like your gain might be a little high, though. You are generating too much output for the given delta of the Hall measurement. Also, watch what the halls are doing - you will see there is quite a bit of jitter. An optical measurement and appropriate filtering might be a better approach for ABS.
Andy
CombatWombat
Mar 22, 2009, 04:13 PM
Use the PIC's capture mode to measure the incoming signal. You do not need an interrupt to do this, just read the CCP section of the manual.
Next, use the IOC on RB4-7 or INT on RB0 to handle the Hall's. Again, this does not require interrupts.
I assume IOC is interrupt on change? So I can reset a counter of some kind in this interrupt to say "yeah, the sensor is seeing rotation"?
Finally, create the output pulse using interrupts off TMR1. Set TMR1 to (65536 - intended output pulse with in us - fixed overhead) and when it rolls over you can process the time correctly. If you don't need failsafe, you can use the ending signal from the rx (CCP 1->0 transition) to set TMR1 to the new value.
I'm fuzzy on this bit. Wont this just give me a square wave kinda thing with a period of "pulse with". The servo pwm has a lot of "low" space since it is 20ms long with only a 1-2ms high time.
Won't having two seperate interrupts interfere with each others timing? For instance if TMR1 rolls over right about the same time as the IOC occurs?
It sounds like your gain might be a little high, though. You are generating too much output for the given delta of the Hall measurement. Also, watch what the halls are doing - you will see there is quite a bit of jitter. An optical measurement and appropriate filtering might be a better approach for ABS.
Andy
I assume you mean since there are many cycles of process going on between each toggle of the hall sensor? Is there a way I can filter the halls with some simple resistor/capacitor filters to help? I dont really have a realistic way to fit an optical encoder setup on the vehicle.
I'm not trying to be obtuse. This is my first PIC project more advanced than "blink some lights".
JimDrew
Mar 22, 2009, 04:46 PM
Definitely use the CCP1 register to time the PPM input. You DO want to make this entire thing interrupt driven. The great thing about the capture is that the PPM pulse length is stored in the two capture registers so you get an accurate time. You can process the HALL interrupts along with the capture without worrying about being inaccurate. Use TMR2 to generate your PPM output pulse. You can't use TMR1 since that is tied to the capture register (it measures the length of the incoming pulse). Set TMR2 to the length of your high pulse and when that expires, set the length to your frame rate - the length of the high pulse (ie. Frame rate = 14ms .. high pulse 1.5ms and low pulse 12.5ms). If you use a 18F series part (much better choice) you could use TMR3 as a 16 bit counter or you could use any part that has two capture/compare registers. This would give you a 100% accurate input count and output pulse, all driven via hardware. Your mainloop at that point would be just a routine that alters the output pulse length based on the input and hall sensors.
JimDrew
Mar 22, 2009, 04:49 PM
BTW, if you make the halls interrupt driven with the IOC, you can filter them in your ISR by using simple debounce counters.
AndyKunz
Mar 23, 2009, 09:00 AM
I assume IOC is interrupt on change? So I can reset a counter of some kind in this interrupt to say "yeah, the sensor is seeing rotation"?
Yes. You don't actually use the interrupt to enter the ISR, though. It sets a flag which is easy to test than than multiple bits (assuming multiple Halls). If you only use one sensor, it doesn't matter because you can just test the pin directly.
I'm fuzzy on this bit. Wont this just give me a square wave kinda thing with a period of "pulse with". The servo pwm has a lot of "low" space since it is 20ms long with only a 1-2ms high time.
It would, but if you have the pin already low and you leave it low, then it's not a problem. E-mail me and I'll send you the ISR you want (in C).
Another easy way to approach this is to disable the TMR1 interrupt (TMR1IE = 0) until the CCP finishes a pulse measurement (NOT using interrupts), then this sequence:
TMR1 = 65536 - newServoPulse - overhead;
TMR1IF = 0; // Clear the interrupt flag so we don't end up there immediately
TMR1IE = 1; // Enable the interrupt to occur
PORTC6 = 1; // Start the pulse
// Go back to watching the Halls. The CCP won't need to be serviced for a long time because it just finished a pulse.
Whichever concept fits your understanding better would be the one to use.
Won't having two seperate interrupts interfere with each others timing? For instance if TMR1 rolls over right about the same time as the IOC occurs?
The ONLY interrupt you are using is for TMR1 rollover. The PIC hardware sets the xxxIF flag for each active peripheral. If you have xxxIE clear, then the interrupt will not cause the micro to jump to the ISR.
Using an interrupt for each device will do exactly as you say, making things worse.
I assume you mean since there are many cycles of process going on between each toggle of the hall sensor? Is there a way I can filter the halls with some simple resistor/capacitor filters to help? I dont really have a realistic way to fit an optical encoder setup on the vehicle.
Optical is easy - you put a bunch of stripes on a wheel so it looks sort of like a UPC code. You can use 50/50 black if you have a high-RPM device. Your pickup is just a 2-pin IR LED or photo transistor.
You can't filter the Hall's like that - they're digital. You need to filter in code.
This is my first PIC project more advanced than "blink some lights".
Ah. What language are you working with?
Andy
CombatWombat
Mar 23, 2009, 12:55 PM
Thank you. I will try some of these suggestions when I get some free time.
Ah. What language are you working with?
I am using hitech C.
JimDrew
Mar 23, 2009, 01:01 PM
Ugh... I have no suggestions for you then. We do everything in hand optimized (cycle counted) assembly. This allows us to account for interrupt overhead, giving us 100% accurate timing.
AndyKunz
Mar 23, 2009, 01:51 PM
I am using hitech C.
Excellent! This will allow you to develop good code quickly w/o wasting a lot of time for little or no gain. Are you using STD or PRO?
Hitech's compiler has a fantastic optimizer and will often produce faster, smaller code than doing it by hand in assembly (I did PIC assembly for years before changing over to Hitech back when they were still beta testing it). It is easily the best PIC C compiler available.
You made the right choice on your tools.
Drew apparently doesn't realize that you can have 100% accurate timing using C (within the same constraints of instruction latencies as he has to deal with manually). The C compiler generates clean interrupt entry/exit code and I use it all the time to have 1us resolution on an 8-channel receiver servo output pulse with a standard 4MHz osc in a PIC16.
Drop me an e-mail and I'll go over your schematic with you too.
Andy
JimDrew
Mar 23, 2009, 11:09 PM
I have disassembled a lot of Hitec C and other C compiler code for the PIC for other companies... C doesn't produce code anywhere near what can be achieved by hand optimizing assembly code. I have been a programmer for 34 years, working with dozens of different CPUs, and I have yet to see ANY compiled language match what an experienced assembly programmer can do.
AndyKunz
Mar 24, 2009, 08:34 AM
Yes, dear. You and I have been thru this before, Jim, on threads where you tell us how you rate your receivers for watts passing thru the pads, and where you tell us about your unethical hiring and salary practices.
I've been programming as long as you have, with scores of processors, in a huge variety of languages, tested out of my hardware classes in college, double-majored in computers with a minor in math, graduated early, and have dozens of products in production. We can one-up each other all day long.
Fact of the matter is, if you can't change the code easily as requirements change, it's worthless. I have products with 100K+ lines of code in C, written years ago, which I can tell people what module to look in when they want to update it. And THEY can modify it without having to ask what tons of questions. It doesn't matter if YOU can (usually with a little time spent figuring out stuff), it matters what OTHERS can do with your code. Being a one-man shop doesn't change that - I'm sure you have put all your development tools into escrow so that should you become incapacitated, your customers will not have any trouble updating the product.
You cannot write an assembly function as well as a modern C compiler can which can be adapted very easily as optimizations change, AND change it just as efficiently.
Now since you've already admitted you can't help the man, why don't you find somewhere else to not contribute?
Andy
vBulletin® Copyright ©2000-2009, Jelsoft Enterprises Ltd.