EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: bsodmike on August 12, 2020, 03:25:12 pm

Title: Modelling a PID controller in C++/17 (or more recent) (or Rust, Python)
Post by: bsodmike on August 12, 2020, 03:25:12 pm
Hi all,

I have worked with PID in MATLAB etc., but I've had trouble getting a simple step-response working in code (think of it a toy simulation), as I have trouble coming with simulating a valid "error input".  This looks really interesting https://github.com/Heych88/udacity-sdcnd-extended-kalman-filter/tree/master/src (https://github.com/Heych88/udacity-sdcnd-extended-kalman-filter/tree/master/src) but I thought I'd first ask here if anyone has experience coding up a really basic PID controller.

There are other forms of PID control, i.e. there's velocity control, as well as position control.
I'm interested in getting a discretised version of the controller running in code, and ultimately build a test rig with a brushless DC motor and taco feedback.

I think my stumbling block is that I am not playing with actual tachymeter feedback, and therefore having trouble implementing the simple equation and control parameters.

Some of my notes are online too at: https://www.scribd.com/doc/19070283/Discrete-PI-and-PID-Controller-Design-and-Analysis-for-Digital-Implementation (https://www.scribd.com/doc/19070283/Discrete-PI-and-PID-Controller-Design-and-Analysis-for-Digital-Implementation)

Looking forward to feedback, cheers!
Title: Re: Modelling a PID controller in C++/17 (or more recent) (or Rust, Python)
Post by: Doctorandus_P on August 19, 2020, 12:24:19 am
For starters, forget Kalman filters.

Writing the code for a simple PID controller yourself in C / C++ or any other programming language is pretty simple. The difficult part is really understanding what a PID controller actually does.

First rule is that you need to do the controller funcion at regular intervals. So do not use the arduinoesque delay(), but use a real timer to get steady intervals, or else the I and D part will get faulty input.


The P part is the simplest.
Just multiply the input with a constant, and you're done.

The Integrator has a memory function. so you will need a (static) variable for this.
Then take the same input as for the P calculation, Multiply it with a constant (your Integrator constant) and add the result to the static variable.

The D action also needs a static variable for a memory, but it needs the previous input.
To calculate the D action, subtract the previous input from the latest input, and multiply this difference with a constant for your D-action.

The result of the PID regulator is the sum of these 3 results.

Real live PID controllers are a bit more complicated. The first complication usually is an anti windup feature for the Integrator, then adding limits for saturation, over exertion of the controller. For DC (and other) motors there may be modifiers to overcome static friction. D controllers may filter out noise, and many more.

If you want to experiment with this in real life, then I advise to start with a simple potentiometer, a DC motor with built in encoder, a mosFet (or motor driver IC) to to control the motor and some uC with built in ADC.

Then use the potentiometer as setpoint for the PID algorithm, and measure the motor speed with the (usually HALL sensors) on the motor quadrature inputs. Output to the motor is via an PWM pin of your uC and the mosFet or motor driver.

Also beware that motors have a limited range in which they can be controlled well. Once the speed of the motor gets below 5% of it's maximum speed it gets more difficult to control it, and of course, the maximum speed of the motor (for your power supply voltage) is also a limit.

As a learning experience I advise to write code for this from scratch.
You can use some library functions for reading the ADC and outputting PWM, so you do not have to interact with your uC peripherals directly, but building up the PID algorithm in steps will help in growing understnding of how it works.

The first step  will be the "P" action.
First program is to read the ADC, and directly output it to the PWM output.
This will likely get you into real world scaling issues. You may have a 10 bit adc (0 to 1023) and a 8 or 16 bit PWM.

So the next step is to use the "P" action to compensate for this scaling difference.

Once you've figured out the details like this and understand how real world stuff interacts with software algoritms you can go back to your Kalman filter. But first make sure you have a solid foundation to build upon.
Title: Re: Modelling a PID controller in C++/17 (or more recent) (or Rust, Python)
Post by: Doctorandus_P on August 19, 2020, 12:59:18 am
About the tachometer...
Nobody uses those anymore.
(Except maybe in school classes and explaining theory).

BLDC motors often have hall sensors, motors with encoders also generate easy to use pulses.

The simple way is to have a few small ISR functions, which trigger on each flank of (one of) the Hall sensors. You can combine that with a free running timer, and the time diffence between two pulses is then a measurement of your speed.

You can also have another ISR, (in practice 20Hz is a nice compromise) and then count the number of flanks in those 50ms, which is also a measurement for your speed and position feedback.

Brushed DC motors are much easier to control then BLDC motors. For a Brushed DC motor you can simply directly use a PWM output (at almost any frequency, really, anything between 30Hz and 100kHz will work) For a BLDC motor you have to know the motor position, and control the 3 half bridges separately and accurately.

for more of BLDC, have a look into "FOC" which stands for Field Oriented Control. There is lots of source code for this "out there". Texas Instuments has made a video series which is a nice introduction into FOC.
There are also plenty of examples on github and elsewhere. BLDC motors are often used in those drones, and there are plenty of open source versions of an "ESC" (Electronic Speed Controller) for these things.

A pretty much polished project in this direction is https://odriverobotics.com/ (https://odriverobotics.com/)
For a DIY solution, you could for example build something around a L6234.

Another way to get speed and position feedback is with a diametrically magnetized magnet and an angle position measurement IC. The AS5047 is an example of such an IC. This chip (or similar) is used in projects such as "mechaduino" and "ananas stepper".
Both have been mentioned on Hackaday.com, which also has collected lots of other motor related posts over the last 15+ years, and it has a search / browse funktion. I.E:

https://hackaday.com/?s=motor+controller (https://hackaday.com/?s=motor+controller)

The advantage on searching on hackaday (or instructables or similar) is that each article has some photographs and is meant to give some (hopefully decent) documentation, instead of just dumping some source code somewhere.


Title: Re: Modelling a PID controller in C++/17 (or more recent) (or Rust, Python)
Post by: Mattjd on August 22, 2020, 02:41:35 pm
Hi all,

I have worked with PID in MATLAB etc., but I've had trouble getting a simple step-response working in code (think of it a toy simulation), as I have trouble coming with simulating a valid "error input".  This looks really interesting https://github.com/Heych88/udacity-sdcnd-extended-kalman-filter/tree/master/src (https://github.com/Heych88/udacity-sdcnd-extended-kalman-filter/tree/master/src) but I thought I'd first ask here if anyone has experience coding up a really basic PID controller.

There are other forms of PID control, i.e. there's velocity control, as well as position control.
I'm interested in getting a discretised version of the controller running in code, and ultimately build a test rig with a brushless DC motor and taco feedback.

I think my stumbling block is that I am not playing with actual tachymeter feedback, and therefore having trouble implementing the simple equation and control parameters.

Some of my notes are online too at: https://www.scribd.com/doc/19070283/Discrete-PI-and-PID-Controller-Design-and-Analysis-for-Digital-Implementation (https://www.scribd.com/doc/19070283/Discrete-PI-and-PID-Controller-Design-and-Analysis-for-Digital-Implementation)

Looking forward to feedback, cheers!


A Kalman filter is not a PID controller. PID controllers are used for LTI systems where the mathematical principle of superposition can be applied. Kalman filters (actually a controller) are statistical based controllers were you are narrowing in to some envelop around the target value.

First reply gave a great response on how to do this naively in C. Like the poster suggests, a real PID requires the descretization of the S filter to Z to implement for real time on a micro.

Would you mind sharing what you've done in Matlab? I believe I could help. Considering how popular Matlab/Simulink is for controls, and my experience with using them for controls, I'm struggling to understand how a different language would be better.