Since our previous post last Thursday, Sibille and I have kept working on speed control. It has taken us much longer than we originally thought, but we’re happy with the result. Now that we have a working product, we’ll go back over what all went into making it work:
As mentioned previously we use a Proportional, Integral, Derivative (PID) control scheme to regulate the throttle command given to our ESC so that the motor speed matches the desired speed.
If you’ll recall, Vlaya had previously written code to capture the edges of a once-a-rotation interruption (the “period interruption”) from a Hall sensor or an optical sensor and deduce the elapsed time during the rotation, and from there the speed.
There’s a twist however: since the timer counter only has 16 bits, if the speed is zero or simply too slow, the timer can overrun before a new edge is detected. Thankfully, we can trigger an interrupt when an overrun occurs. In that case the speed recorded is simply zero (even though it might simply be very slow), and the time elapsed is the maximum time the timer can count. That way if the motor stops, the speed is still updated regularly and we notice quickly that the new speed is zero.
In order to maximize the precision available, we’ve decided to use all the range of a 32 bit unsigned integer to store the speed : the maximum speed in rotations per second we wish to consider (40 RPS in order to have a margin above our top speed of 30 RPS) is encoded as the highest value on 32 bits.
In the same previous article we said that after considering computing the PID during the speed feedback interrupt, we decided to instead compute it much more frequently in a constant loop.
Well, we subsequently concluded that our first idea was in fact better, so after a bit of back and forth, we did end up updating the PID in the speed feedback interruption. We added a faster constant loop that handles the actual sending of the throttle value to the ESC via DShot. The actual throttle value sent to the ESC is not in fact the PID computed throttle: in that loop we merely increment or decrement the throttle in the direction of the PID throttle to ramp it up or down over several loop iterations. That way the sudden changes in throttle from the PID computation are smoothed out (since the PID is infrequent, the throttle corrections are bigger).
Compared to the official version of the PID controller implementation, we add a few details to make it more suitable for our utilization.
First, we use a normalizing coefficient for our PID correction in order to have the opportunity to adjust the PID coefficients (KI, KP and KD) more accurately: as everything is stored on integers, we can’t have values with decimal point precision. So everything is stored on really big integers and we only divide by the normalizing coefficient at the very end.
Then, instead of starting the motor with an initial throttle value of 48 (equivalent speed of 0 RPS), we choose to start the motor with a throttle of 260, equivalent to a speed of approximately 10 RPS in our voltage range. This is to ease the motor start-up sequence from a still position. Otherwise, the PID computation takes a while to reach a throttle value able to provide a sufficient start-up torque, which makes the motor kind of hiccup and creak at the beginning.
Then, about the integral error, we compute it only when the speed is non-zero, and we reset the accumulated value every time there is a new speed command.
Yesterday, our software had at last a consistent behavior: we were ready to start working on the coefficients. To do so, we dropped the motor setup with which we were working and set up a Hall sensor feedback on the Phyllo by affixing magnets to the PVC plate with duct tape. We continue to use the same speed feedback code and it worked like a charm 🙂
We finally were able to take care of the PID coefficient choice that Sibille will present in the next article.
We will read more on the subject in parallel of progressing in the other parts of the software architecture to determine if it is useful to use a H-infinity control for our motor speed.