I am trying to learn the basics of PID. I have made a contraption to try to implement a PID controller.

enter image description here

I am not using carbon fiber, but rather a chopstick.

So I am controlling the speed of the propeller with a PWM signal through a mosfet from an STM32. I think 14Khz...Dont recall what frequency I set it to. My counter control register which controls my duty cycle can vary from 0 to 1000.

I am reading the pot value through the an ADC channel.

In my attempt to implement one control method at a time. P then I then D I never got past P because I dont know what to do with the value I get.

For example, Let say my chopstick is level (parallel to floor) at an ADC value of 2000. and I currently read 1200 then my error is 800. According to PID literature this gets multiplied by a gain. lets say the gain is .5 So now my P value is 400. But what do i Do with that? I cant set the PWM CCR to 400 that is too low a duty cycle and it will drop even more.

So that is my issue how do I translate the value to something useful.

All I am doing right now is that if my error is grater than zero then PWM = PWM - 1; and vice versa for error less than zero Obviously it works really slow because I am using the value of 1 but this is NOT proportional control. At least i dont think it is.

EDit: I think has to do with my issue. enter image description here enter image description here SO Like I said in the comments I can get it to work (sort of) so long as when i disturb it I dont make it go above a certain point, otherwise It will fly all the way vertical have a huge error and then drop have another huge error and just keep going and going. And god forbid I try to make a target point that is above 0 deg that stays put for a few seconds and then oscillates again. I just think the complexity of this system requires more then the simple PID tutorials you see everywhere involving speed control of a motor. I would follow the edx course on this but I dont understand the math and their notations. No real number examples or anything. I do not learn well just seeing bunch of variables and no real world examples.

  • \$\begingroup\$ You do not say what CCR value gives you an ADC reading of 1200, or why you think that the proportional gain should be 0.5 and not something higher. \$\endgroup\$
    – TimWescott
    Commented Jan 6, 2019 at 4:27
  • \$\begingroup\$ The method you describe of incrementing or decrementing the PWM command is basically integrating the sign of the error. It will eventually result in something close to zero error, because of the integration, but it has a lot to dis-recommend it otherwise. \$\endgroup\$
    – TimWescott
    Commented Jan 6, 2019 at 4:28
  • \$\begingroup\$ Would this happen to be the real Tim Wescott? As in PID without a PHD and "Applied Control theory....." , The values stated were all just from the top of my head real values differ. But it seems to me that the value of CCR when ADC is 1200 is irrelevant because my CRR(Duty cycle) can be 100% and I can push the chopstick down and make the ADC read 1200. CCR can be at 50% and I can push the chopstick and make it read 1200... the 1200 adc reading is just the disturbance and not dependent on CCR \$\endgroup\$ Commented Jan 6, 2019 at 4:43
  • \$\begingroup\$ You have the saturation limits for PWM 0 to 2000. P Error =(Setpoint-Sensor ) . You have initial conditions for Angular position,velocity,acceleration. Fan torque works against gravity with a net sinusoidal torque with Y axis bias from gravity. You have to control RPM to get torque to get acceleration, then integrate velocity then integ. to position angle. So 2nd to 3rd order system but Kp,Ki,Kd is a product then summed to drive PWM. fly manual with PWM on manual pot first. record your best step response time and overshoot. Then design the loop to do it faster, better. \$\endgroup\$ Commented Jan 6, 2019 at 12:10
  • \$\begingroup\$ Or use a vbl DC supply voltage to control fan and record V for each angle then use excel to compute a function of the curve. COnvert to PWM vs ADC value. Then compute Kp,Ki,Kd to reduce the error in the shortest time to zero, from any initial angle and velocity =0 to any setpoint angle. \$\endgroup\$ Commented Jan 6, 2019 at 12:20

4 Answers 4


You need to make a distinction between the signals, the angle of the chopstick (range -90 to +90 degrees, assuming down = 0 degrees), the duty cycle of the motor (range 0-100% for zero to max speed), and the numbers in your system that represent those signals.

Do your PID mathematics in the signal domain. It doesn't matter whether you have a 11 bit ADC reading 2000 when the pendulum is at 90 to the floor, or an 8 bit ADC reading 200, they both represent 90 to the floor.

The first thing to do therefore is to draw your block diagram, and express gains, signal ranges etc in sensible signal units. Then, the first thing you do when you read an angle, scale and offset it into a signal. The last thing you do when you have a PID controller output signal is to scale and offset it into a number that will control 0-100% duty cycle at your motor.

  • \$\begingroup\$ when you say I need to scale my angle into a range and then my PID output into a number to control my PWM duty .. what values and ranges do I use. For example, My pot (ADC VALUE) reads from 0 to 4095 but not all of that is relevant , because -90 is about 750 while +90 is 3300 and 0 degrees is about 2000. So if I am at something like 500 which is Below horizontal (0 deg) then my error is 1500 multiplying that by an integer gain would yield a larger number as output. Is that the number I need to scale? \$\endgroup\$ Commented Jan 8, 2019 at 7:30
  • \$\begingroup\$ and If I do scale that number.. and do i scale the entire pot range from 0 to 4095 or just what is relevant to me 750- to 3300--> 0 to1000....and then am I adding the output to my DUTY cycle.. as in Duty = Duty + output or am I simply setting duty = output? I have a feeling I have to add it but If my loop is running even as slow as 20Hz I can quickly get to my limit of 1000 for CCR and the propeller flies all the way up and there is no settling it. \$\endgroup\$ Commented Jan 8, 2019 at 7:35
  • 1
    \$\begingroup\$ I just feel like a lot of PID examples and tutorials I find involve the input being the same units as output. For example getting the speed of a motor with an encoder or hall sensor, and the using a PID controller to control the speed. so its speed input and speed output. while I have this ADC/Angle input to PWM output. Other than that the logic behind PID seems straight forward the code is simple enough but its the unit conversions thats bugging me. \$\endgroup\$ Commented Jan 8, 2019 at 7:38
  • \$\begingroup\$ @EdwinFairchild As things stand, you're not ready yet to build hardware. You are thinking too hardware-centric. Start instead with a software simulation, where the plant is, for instance, a capacitor, and you have to control it with a current source, to a particular voltage. A tame example perhaps, but it's what you need. Compare and contrast with hardware. Then model pots and ADCs that have excess range and odd scalings. Understand the importance of scale. Then increase the order. Then return to your pendulum fan. \$\endgroup\$
    – Neil_UK
    Commented Jan 8, 2019 at 7:40
  • \$\begingroup\$ unfortunately that sounds like I would have to go learn a piece of software, learn how to model something and learn how to implement PID in that software package etc... while I am all for learning I simply what this propeller arm to stay level and it feels like it should be easy, the PID math its all so simple, its just something tripping me up and I cant figure out that little thing that will make it all click. If find that if i set my target point below the horizontal plane the pid works but if i disturb it past horizontal (over 0 degrees) the propeller slows down a lot and its weight sends \$\endgroup\$ Commented Jan 8, 2019 at 20:53

You have implemented an I controller with a very low gain.

You haven't told us what the PWM CCR value is set to in order to reach your initial state (ADC = 1200). But no matter - as you said in a comment, you can apply external influence and modify the ADC reading , and the controller should react to oppose that influence.

What you HAVE told us is,

my error is 800. According to PID literature this gets multiplied by a gain. lets say the gain is .5 So now my P value is 400. But what do i Do with that? I cant set the PWM CCR to 400 that is too low a duty cycle and it will drop even more.

That is a way of saying that your gain is too low.

Having created a controller, you have to tune it for best response - that is, whatever best meets your goals (which you haven't told us either). Stating those would be a good start. They might be:

  • Keeping the arm horizontal with acceptably small error (5 degrees) and acceptable step response (fast settling with < 5 degree overshoot) or
  • Keeping the arm to any specified setpoint (angle) from 0 to 180 within similar limits.

Now you can let the controller do all the work, or you can give it some help.

Letting it do all the work:

Your first ADC reading is 1200 giving an Error term E = 800. You haven't told us what PWM setting gave that reading but you imply it is over 400 because "that is too low a duty cycle". So set the gain (Kp) high enough that E * Kp > current CCR value. The CCR (PWM duty cycle) will increase, reducing the next error. It will settle out at some error inversely proportional to the gain.

To reduce the error further : increase the gain further. At some point the gain will be high enough that the controller overshoots, the position bounces, the system becomes unstable.

Giving it some help:
You can use a-priori knowledge as an initial "guess" at the correct PWM ratio, and use the P controller to correct that guess.
For example, as the horizontal position is 50% of the potentiometer range, you might use 50% = 500 as a very crude guess at the "set point" for the CCR. If that gives you ADC=1200, Error = 800, then add (Error * Kp) to the set point. Now Kp = 0.5 gives you 500+400 = 900 for a considerable increase in power. This allows the control loop to work with considerably lower gain (Kp) which may help loop stability. Indeed, Kp = 0.5 may be too high already.

In either scenario there will be some remaining error : that's where the I term comes in.

  • \$\begingroup\$ "You have implemented an I controller with a very low gain." Actually he's implemented a nonlinear I controller that has very low (or, arguably, zero) incremental gain for large error, and an incremental for small errors that would be infinite but for measurement noise. \$\endgroup\$
    – TimWescott
    Commented Jan 6, 2019 at 23:39

You are overcomplicating things. The short answer is that you take your error, you run it through a PID (or other controller), and you apply that to your CCR register.

You can decorate that with other things (as when you realize that your fan thrust is roughly proportional to the CCR value squared), but that's what you do.

For error \$e_k\$ and output \$u_k\$ at time \$k\$, \$u_k = k_p e_k + k_i \sum_{t=0}^k e_t + k_d (e_k - e_{k-1})\$, unless you need a bandlimited derivative term, which gets a bit more complicated.


I think I understand your problem Edwin. You want to translate the value from the PID controller to PWM. My advice is to experimentally determine a mathematical function that maps the process variable (propellor speed) to the controller output variable (PWM value): try different equidistant PWM values and note the speed of the propellor (in ADC value). Then plot a curve for this in say Excel.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.