Skip to content
Kevin Robert Keegan edited this page Oct 18, 2017 · 14 revisions

Table of contents

Intro

The firmware uses two PID controllers for each axis in an arrangement often called a Cascade Control Loop. The internet is full of articles describing what a PID controller is, Wikipedia - PID Controller, so we will not go into great detail here. Instead, the purpose of this page is to document the functions built into the Maslow that allow you to test different settings for the PID controllers and some general guidance about specific PID tuning on the Maslow.

Users of a stock MaslowCNC shouldn't need to tune their PID controllers, the default settings were selected using the stock machine. However, stock users may still want to tune their PID controllers to see if they can get better results than the stock version. If you do get better results, please share them in the forum. Finally, users with different motors or setups will likely benefit from some customization of the settings to their setup.

Controllers

As mentioned the firmware uses two PID controllers in series for each axis - a positional controller and a velocity controller. The positional controller attempts to move the router to the desired position by outputting a desired movement speed. The velocity controller attempts to achieve the speed demanded by the positional controller by outputting a motor voltage.

Velocity Controller - Tune First

Because the velocity controller is last in the stack, you want to tune it first if you are going to tune it. You can certainly accept the current values for the velocity controller and only tune the position controller. However, be aware, that if you change the tuning of the velocity controller, you may need to tune the position controller afterwards.

The B13 command will attempt to move an axis at a requested RPM for 2 seconds while dumping the velocity error to the log.

B13 R<1,0> L<1,0> Z<0,1> S<##> F<##> I<#>

R,L,Z - Select Right, Left, or zAxis using a 1. Only one axis can be enabled.
S - The starting RPM +,-
F - The finishing RPM +,-
I - The number of steps to take between the starting and finishing RPM 1 means only starting, 2 start and finish, and any higher number adds additional steps between the start and finish. Each step will run for 2 seconds.

Currently, the only way to directly input lines of code into the machine is to use wither Macro1 or Macro2. You will likely be running the same command over and over again for comparison, so the macros actually make it quite handy.

The log output will contain the something like the following (only much longer):

[PE:0.42,0.28,127]
Sent: B13 R1 S-10 F10 I21
[PE:0.42,0.28,127]
B13 R1 S-10 F10 I21
--PID Velocity Test Start--
Axis=R
Kp=20.00,Ki=1.00,Kd=0.00
7.79
2.27
-0.67
-2.51
-3.24
-2.86
-2.14
-1.40
-0.65
...
-3.75
-4.11
-3.75
--PID Velocity Test Stop--

[PEk:-13.59,62.13,0]

You can excerpt out the relevant data using the following sed command:

sed -n "/--PID Velocity Test Start--/,/--PID Velocity Test Stop--/p" log.txt > PID.csv

The data can then be pasted into a spreadsheet (I used google sheets) to visualize the error graph like this:

For this graph I used the command B13 R1 S-10 F10 I21 This was run on the default settings prior to September 25, 2017.

Your graphs may look very different.

Tuning Suggestions

I would recommend starting with the stock settings and running a test that has steps from 10RPM to -10RPM in 1RPM increments. I would graph this result and then make small changes and repeat this test comparing the graphed results. Because of the Minimum Velocity Resolution discussed below, I don't believe you can get rid of the +-.5RPM oscillations that you see in the graph.

The maximum speed of the motors is about 17RPM, it is worth running a few tests to confirm that these upper end speeds are working properly, but in my experience the slower speeds are the more difficult one. The Firmware currently limits the maximum speed request from the positional controller at 20RPM, this is to allow a little head room to actually hit the maximum RPM of the motors, so feel free to test speeds up to 20RPM to see how they react.

Also because of the Non-Linearity of the motors, also discussed below, you may not be able to get each RPM to average zero error. In my experience, it isn't essential to get an average of zero errors, instead the more important aspect is to have as few oscillations as possible in the velocity output. The positional controller is able to compensate for the non-zero error, but has a harder time compensating for random oscillations.

My belief is that you shouldn't try and chase perfection in the velocity controller. I spent a lot of time on this and it is elusive and maybe unobtainable. Plus, I am not sure that improvements in the velocity controller achieve much in the way of accuracy. It seems like the positional controller is able to compensate for much of the error in velocity just fine.

But, if you have the desire, the following are some of my thoughts on the issue.

Tuning Problems

Minimum Velocity Resolution

The encoders on the Maslow have 8148 steps per revolution and the PID compute process runs every 10 milliseconds (or 100 times per second). This means at 1RPM each computation of the PID expects to see 1.358 steps (8148/6000). As a result, the best velocity resolution you can achieve is between .25 RPM and .5 RPM. This obviously makes hitting the low RPMs accurately very difficult.

To hide this problem the code doesn't even try and turn the motors at extremely low RPMs ~1RPM. So you may see very flat error lines around 0RPM. This decreases the likelihood of integrator windup, discussed at the end, occurring at low RPMs. But it does mean that the positional controller may settle out not exactly at zero, but in my testing this seems to be less than .1mm, well below our desired error.

The old code used to use a running average of 10 readings as the input to the velocity controller. This caused the controller to react very slowly at low RPMs and often times introduced oscillations. I don't think that averaging is a good idea.

I tried decreasing the frequency at which the controller operates with little success, it didn't seem to harm anything, but I also didn't see any benefits.

Non-Linear Response Problem

Bar did a good job characterizing the motor's velocity response profile, this profile is not constant and changes under tension:

Using a velocity PID controller simplifies this somewhat, but is not a complete solution. In my experience, you can't get all RPM ranges to hover around zero error. The best you can achieve is to get low oscillations. This is largely because using a PID to control a non-linear process is not ideal. To solve this issue, articles and comments online suggest solutions which include Gain Scheduling and Linearizing the Output.

I will caution that both of these solutions add a lot of complexity to the system. Plus, the non-linearity of the response changes based on tension, so it is difficult or impossible to linearize the response without knowledge of the tension on the motors.

Gain Scheduling

Best I can understand, Gain Scheduling is comprised of breaking up the operating range into a series of discrete segments and applying different tuning values to each segment. In our case, we could break up the tunings based on the input RPM, different settings for low RPM and high RPM. I briefly tried this, and was generally unimpressed with the results, plus it clearly adds a layer of complexity.

http://www.controleng.com/search/search-single-display/back-to-basics-how-gain-scheduling-works/52cd5aac6a456dfb6b1352494e4dd169.html

Linearizing the Output

Alternatively, it sounds like some people attempt to linearize the output. This sounds like it would work well for systems where the non-linearity can be easily quantified. Although, I see a number of mentions that such linearity systems don't have to be perfect they just have to nudge things in the right direction. I also briefly tried this, I applied a formula to the voltage output before it was written to the motor. For example, increasing the voltage at the higher ends. This was inconsistent and had issues dealing with high tension vs low tension situations and it added complexity as well.

https://electronics.stackexchange.com/questions/198101/how-to-tune-a-pid-controller-to-a-nonlinear-process

Position Controller - Tune Second

Again, you don't have to tune the velocity controller, but if you want to do it, do it first. Changes to the velocity controller may require changes to the position controller.

The position controller is in many ways a lot easier to work with.

The B14 command will attempt to move an axis a requested distance while dumping the positional error to the log.

B14 R<1,0> L<1,0> Z<0,1> S<##> F<##> I<#> T<####>

R,L,Z - Select Right, Left, or zAxis using a 1. Only one axis can be enabled.
S - The starting distance to move in mm +,-
F - The final distance to end up at in mm +,-
I - The number of steps to take between the starting and finishing distance 1 means only starting, 2 start and finish, and any higher number adds additional steps between the start and finish.
T - The number of milliseconds to wait between each step.

Again, you can store you test command in a Macro to enable easy repeatability.

The log output will contain the something like the following (only much longer):

[PE:0.42,0.28,127]
Sent: B14 R1 S.15 F150 I1000 T10
[PE:0.42,0.28,127]
B14 R1 S.15 F150 I1000 T10
--PID Position Test Start--
Axis=R
Kp=1100.00,Ki=0.00,Kd=0.00
-1.51
-1.24
-1.86
-1.14
-1.40
-1.65
...
-1.75
-1.11
-1.75
--PID Position Test Stop--

[PEk:-13.59,62.13,0]

You can excerpt out the relevant data using the following sed command:

sed -n "/--PID Position Test Start--/,/--PID Position Test Stop--/p" log.txt > PID.csv

The data can then be pasted into a spreadsheet (I used google sheets) to visualize the error graph like this:

In the above case the command I used was something like:

B14 R1 S.15 F150 I1000 T10

Which roughly simulated moving the axis at full speed for ten seconds. The blue line demonstrates the default settings prior to September 25, 2017 and the red line is my new version.

You can also focus more closely on a few moves such as the following:

In the case above the command I used was something like:

B14 R1 S10 F50 I5 T2000

I use this type of graph to look for subtle oscillations or other issues that get buried in the 1000 step chart.

You graphs may look very different.

Tuning Suggestions

When tuning the positional controller you are trying to balance the following:

  1. Move to the set point as fast as possible. Low rise time.
  2. Don't overshoot the set point too much. Limited overshoot.
  3. Don't create oscillations/vibrations.

Items 1&2 are fairly easy to achieve using the graphs and testing. The first graph shows you the average position error of a single axis and helps resolve Item 1. You can vary the steps to simulate the various cutting speeds. It is usually helpful to graph the existing tunings first and then compare your new settings. The second graph makes it easier to resolve Item 2. Some overshoot is ok and will help decrease your rise time, the goal isn't strictly 0 overshoot.

Item 3 is a bit elusive and subjective. I normally have to at least manually move the sled around the work surface listening and looking for chain or motor support arm vibrations. If that seems fine then I usually run some test cut routines (you don't need to be cutting). I know that the top of the work surface at the center is hard for the motor to traverse left to right, so I often load a file of a square and put an edge right at the top. Sometimes it takes a few rotations of the cut for the oscillations to appear. If you have a file or part that was a problem in the past, try it now.

Decreasing Item 3 may mean sacrificing Items 1 & 2.

Tuning Problems

Interactions with Rise Time

The motors are very capable of accelerating to full speed in less than 10ms. If you get your rise time too fast, this can cause vibrations particularly at lower speeds.

Inconsistent Timing

The movement command frequency and the controller frequency are not tied to each other. The controller operates using interrupts and happens consistently every 10ms. The movement command is handled either by a while loop or a delay function that attempts to issue movement commands every 10ms. A drift of even 1ms can result in a 10hz vibration because 10 times a second the controller is commanded to move double the distance or no distance at all.

I can confirm that issuing movement commands every 14ms while the controller operated at a 10ms frequency did cause vibration issues. However, we now have the movement command frequency much closer to 10ms. I have been debating whether any remaining jitter is sufficient enough to warrant a reworking of the code so that movement commands are issued at the same time the controller processing happens.

General Tuning Comments

Integrator Term

It very well may be the case that the Ki term should always remain zero. There are a number of problems with using an integrator in our setup:

  • Integrator Windup - Discussed below
  • Required Overshoot - If using the standard Proportional on Error system, the integrator term can only be decreased by overshooting the setpoint. A problem for the positional controller.
  • Inverted Term - The position and velocity controllers run in both the positive and negative direction. When the direction inverts, the integrator has the wrong direction. You can't simply flip the integrator, because then the integrator never decreases because it never sees overshoot.

Integrator Windup is a common problem in PID controllers. In the maslow, it seems like this issue crops up when the zaxis is operating for a period of time. This is likely because when this happens the L & R axes try and hold a specific position, but likely accumulate a small error over time. This small error accumulates significantly when the z-axis is running and as a result, when the machine then starts an XY movement after this point, the machine may jump because of the large integrator.