So, using my newly scavenged motor, I set to work doing some firmware coding this weekend. Previously, my code simply took speed setting commands over serial and implemented them on the motor driver. Now, it's a little more intelligent.
Feedback is important when your environment is uncontrolled (or uncontrollable). A familiar example of a feedback system is the cruise control in your car. You set the desired speed, and it adjusts the gas pedal to account for changing conditions. When you go up hill, it revs the engine higher; when you go down hill, it lets off the gas.
That's exactly what I need for my wiper driver. Depending on atmospheric conditions, the same speed setting might produce different wiper speeds. For example, I found earlier that just wetting the windshield or turning the car off or on can have a drastic impact on the reported speed of the wipers.
With my new code, I only need to send a desired BPM to the driver board and it will attempt to match that BPM by trial and error. If it detects it's going too fast, it will "let off the gas" and so on.
My wiper system is what you would call a "first-order system". Basically, it has little to no inertia. When I change the speed setting of the wipers, they change speed immediately. Fortunately, first-order systems are pretty easy to control.
In my code, I implemented a very simple feedback loop. Here is a block diagram:
This might be a little funny to look at, so let's break it down:
This block represents environmental conditions that will change how the motor reacts to its input speed setting (wet windshield, etc)
Previous speed setting
This part is a little confusing. My system is a discrete system which means that rather than making continuous adjustments, it only makes them at certain points--specifically, once per cycle. The "Delay" block takes the speed setting from the previous cycle and brings it into the current cycle. This is the only type of "memory" that the feedback loop has.
With this delay, it is able to base the next cycle's speed setting on the previous cycle's.
This signal is the result of subtracting the actual speed from the desired speed and applying a gain. If the actual speed is lower than the desired speed, positive acceleration is needed and vice versa.
The gain stage is very important. Applying gain is basically multiplying the incoming signal by a constant. If the gain is too low, it will take too long for the system to react to change as the desired acceleration will be very small. If the gain is too high, the system could accelerate way too fast and overshoot its target speed. Feedback system designers are always playing with gain levels to try to get optimal performance of their system.
in code form
Rather than dealing with speeds, my code deals with time measurements per cycle, so things are a little switched around: higher time -> lower speed.
int32_t diff = targettime-currenttime; //subtract measured speed from current speed. diff = diff/3; //Apply gain (gain=.333) nextspeed = diff+OCR0A; //OCR0A is the speed setting currently implemented.
Note that nextspeed and OCR0A are inverted; a higher value means a slower speed. That's why diff is added instead of subtracted. Also note that the time measurements are not in the same scale as the speed settings. Time is measured as time elapsed during the cycle while speed is the duty cycle set from 0-255 where 0 is full duty cycle.
So the idea is that the farther the actual speed is from the target speed, the more abruptly the speed changes. If actual and target speed are equal, no change is required, and the motor setting from the previous cycle is copied over to the current cycle.
I'm very pleased with the performance of my motor under this code. I put together a little demo video showing it off.
In the video, you will see a live plot of the motor speed as it updates. Note that the plotted data is the speed of the previous rotation, so there will appear to be some time lag. You will also see a live output from the Python terminal showing the values that the micro-controller is measuring. Note that the "diff" value is inverted and not on the same scale as the other two.
You'll also catch a glimpse of my new metal motor driver enclosure. It's a work in progress at the moment, but I'll post about it when it's finished.
So, I've got code on my micro controller that will match the BPM sent to it. The next step will be getting it to match the BPM and the phase sent to it. As is, the wipers might be going the right speed, but they probably won't be reaching the ends of their cycle quite on beat.
Continue this story here.