]> pere.pagekite.me Git - homepage.git/blobdiff - blog/Automatic_LinuxCNC_servo_PID_tuning_.html
Generated.
[homepage.git] / blog / Automatic_LinuxCNC_servo_PID_tuning_.html
index b1a2a81affdf63d2e4870b922cd6e44723dac30c..77e6cbcae4e4c2af33abee24f92f10fc12adcf48 100644 (file)
       <div class="body"><p>While working on a CNC with servo motors controlled by the
 <a href="https://en.wikipedia.org/wiki/LinuxCNC">LinuxCNC</a>
 <a href="https://en.wikipedia.org/wiki/PID_controller">PID
-controller</a>, I had to learn how to tune the collection of values
-that control this mathematical machinery.  It proved to be a lot
-harder than I hoped, and I still have not succeeded in getting the Z
-PID controller to successfully defy gravity.  But while climbing up
-this rather steep learning curve, I discovered that some motor control
+controller</a>, I recently had to learn how to tune the collection of values
+that control such mathematical machinery that a PID controller is.  It
+proved to be a lot harder than I hoped, and I still have not succeeded
+in getting the Z PID controller to successfully defy gravity, nor X
+and Y to move accurately and reliably.  But while climbing up this
+rather steep learning curve, I discovered that some motor control
 systems are able to tune their PID controllers.  I got the impression
 from the documentation that LinuxCNC were not.  This proved to be not
-true</p>
+true.</p>
 
 <p>The LinuxCNC
 <a href="http://linuxcnc.org/docs/html/man/man9/pid.9.html">pid
 component</a> is the recommended PID controller to use.  It uses eight
-values Pgain, Igain, Dgain, bias, FF0, FF1, FF2 and FF3 to calculate
-the output value, and all of these need to have a sensible value for
-the controller to behave properly.  Note, there are even more values
-involved in more edge cases.  In my case I need the X, Y and Z axes to
-follow the requested path with little error.  This has proved quite a
-challenge for someone who have never tuned a PID controller before,
-but there is some help to be found.
+constants <tt>Pgain</tt>, <tt>Igain</tt>, <tt>Dgain</tt>,
+<tt>bias</tt>, <tt>FF0</tt>, <tt>FF1</tt>, <tt>FF2</tt> and
+<tt>FF3</tt> to calculate the output value based on current and wanted
+state, and all of these need to have a sensible value for the
+controller to behave properly.  Note, there are even more values
+involved, theser are just the most important ones.  In my case I need
+the X, Y and Z axes to follow the requested path with little error.
+This has proved quite a challenge for someone who have never tuned a
+PID controller before, but there is at least some help to be found.
 
 <p>I discovered that included in LinuxCNC was this old PID component
 at_pid claiming to have auto tuning capabilities.  Sadly it had been
@@ -53,18 +56,22 @@ LinuxCNC HAL setup to test at_pid.  This was rather sad, when I wanted
 to quickly test auto tuning to see if it did a better job than me at
 figuring out good P, I and D values to use.</p>
 
-<p>So I decided to have a look if the situation could be improved.
-This involved trying to understand the code and history of the pid and
+<p>I decided to have a look if the situation could be improved.  This
+involved trying to understand the code and history of the pid and
 at_pid components.  Apparently they had a common ancestor, as code
 structure, comments and variable names were quite close to each other.
-But this was not reflected in the git history.  My guess is that the
-author of at_pid took a version of pid.c, rewrote it to follow the
-structure he wished pid.c to have, then added support for auto tuning
-and then committed it into the LinuxCNC repository.  This made it
+Sadly this was not reflected in the git history, making it hard to
+figure out what really happened.  My guess is that the author of
+<a href="https://github.com/LinuxCNC/linuxcnc/blob/master/src/hal/components/at_pid.c">at_pid.c</a>
+took a version of
+<a href="https://github.com/LinuxCNC/linuxcnc/blob/master/src/hal/components/pid.c">pid.c</a>,
+rewrote it to follow the structure he wished pid.c to have, then added
+support for auto tuning and finally got it included into the LinuxCNC
+repository.  The restructuring and lack of early history made it
 harder to figure out which part of the code were relevant to the auto
 tuning, and which part of the code needed to be updated to work the
 same way as the current pid.c implementation.  I started by trying to
-isolate relevant changes in pid.c, and applying them to at_pid.  My
+isolate relevant changes in pid.c, and applying them to at_pid.c.  My
 aim was to make sure the at_pid component could replace the pid
 component with a simple change in the HAL setup loadrt line, without
 having to "rewire" the rest of the HAL configuration.  After a few
@@ -80,39 +87,44 @@ This ensured compatibility with the current pid component, while
 adding auto tuning as a run time option.  To make it easier to identify
 the relevant parts in the future, I wrapped all the auto tuning code
 with '#ifdef AUTO_TUNER'.  The end result behave just like the current
-pid component by default, as the code is identical.  The
+pid component by default, as that part of the code is identical.  The
 <a href="https://github.com/LinuxCNC/linuxcnc/pull/1820">end result
-entered the LinuxCNC master branch</a> a few days ago.  To enable auto
-tuning, one need to set a few HAL pins in the PID component.  The most
-important ones are tune-effort, tune-mode and tune-start.  But lets
-take a step back, and see what the auto tuning code will do.</p>
-
-<p>I do not know the mathematical foundation of the at_pid algorithm,
-but from observation I can tell that the algorithm will, when enabled,
-produce a square wave pattern centered around the bias value on the
-output pin of the PID controller.  This can be seen using the HAL
-Scope provided by LinuxCNC.  In my case, this is translated into
-voltage (+-10V) sent to the motor controller, which in turn is
-translated into motor speed.  So it will ask the motor to move the
-axis back and forth.  The number of cycles in the pattern is
-controlled by the tune-cycles, and the extremes of the wave pattern is
-controlled by the tune-effort pin.  Of course, trying to change the
-direction of a physical object instantly (as in going directly from a
-positive voltage to the equivalent negative voltage) do not work, and
-it take some time for the object to slow down and move in the opposite
-direction.  This result in more smooth movement wave form, as the axis
-in question were vibrating back and forth.  When the axis reached the
-target speed in the opposing direction, the auto tuner change
-direction again.  After several of these, the average time delay
-between the 'peaks' and 'valleys' of this movement graph is then used
-to calculate proposed values for Pgain, Igain and Dgain, and insert
-them into the HAL model to use by the pid controller.  The end result
-is not great, but it work a lot better than the values I had been able
-to cook up on my own, at least for the horizontal X and Y axis.  I've
-been less lucky with the Z axis, which is moving a heavy object up and
-down, and seem to confuse the algorithm.  It became a lot better when
-I introduced a bias value to counter the gravitational drag, but I
-will have to work a lot more on the Z axis PID values.</p>
+entered the LinuxCNC master branch</a> a few days ago.</p>
+
+<p>To enable auto tuning, one need to set a few HAL pins in the PID
+component.  The most important ones are <tt>tune-effort</tt>,
+<tt>tune-mode</tt> and <tt>tune-start</tt>.  But lets take a step
+back, and see what the auto tuning code will do.  I do not know the
+mathematical foundation of the at_pid algorithm, but from observation
+I can tell that the algorithm will, when enabled, produce a square
+wave pattern centered around the <tt>bias</tt> value on the output pin
+of the PID controller.  This can be seen using the HAL Scope provided
+by LinuxCNC.  In my case, this is translated into voltage (+-10V) sent
+to the motor controller, which in turn is translated into motor speed.
+So at_pid will ask the motor to move the axis back and forth.  The
+number of cycles in the pattern is controlled by the
+<tt>tune-cycles</tt> pin, and the extremes of the wave pattern is
+controlled by the <tt>tune-effort</tt> pin.  Of course, trying to
+change the direction of a physical object instantly (as in going
+directly from a positive voltage to the equivalent negative voltage)
+do not change velocity instantly, and it take some time for the object
+to slow down and move in the opposite direction.  This result in a
+more smooth movement wave form, as the axis in question were vibrating
+back and forth.  When the axis reached the target speed in the
+opposing direction, the auto tuner change direction again.  After
+several of these changes, the average time delay between the 'peaks'
+and 'valleys' of this movement graph is then used to calculate
+proposed values for Pgain, Igain and Dgain, and insert them into the
+HAL model to use by the pid controller.  The auto tuned settings are
+not great, but htye work a lot better than the values I had been able
+to cook up on my own, at least for the horizontal X and Y axis.  But I
+had to use very small <tt>tune-effort<tt> values, as my motor
+controllers error out if the voltage change too quickly.  I've been
+less lucky with the Z axis, which is moving a heavy object up and
+down, and seem to confuse the algorithm.  The Z axis movement became a
+lot better when I introduced a <tt>bias</tt> value to counter the
+gravitational drag, but I will have to work a lot more on the Z axis
+PID values.</p>
 
 <p>Armed with this knowledge, it is time to look at how to do the
 tuning.  Lets say the HAL configuration in question load the PID
@@ -125,28 +137,30 @@ loadrt pid names=pid.x,pid.y,pid.z
 <p>Armed with the new and improved at_pid component, the new line will
 look like this:</p>
 
-
 <blockquote><pre>
 loadrt at_pid names=pid.x,pid.y,pid.z
 </pre></blockquote>
 
-<p>The rest of the HAL setup can stay the same.</p>
+<p>The rest of the HAL setup can stay the same.  This work because the
+components are referenced by name.  If the component had used count=3
+instead, all use of pid.# had to be changed to at_pid.#.</p>
 
-<p>So, to start tuning the X axis, move the axis to the middle of its
+<p>To start tuning the X axis, move the axis to the middle of its
 range, to make sure it do not hit anything when it start moving back
-and forth.  Next, set the pid.x.tune-effort to a low number in the
+and forth.  Next, set the <tt>tune-effort</tt> to a low number in the
 output range.  I used 0.1 as my initial value.  Next, assign 1 to the
-tune-mode value. Note, this will disable the pid controlling part and
-feed 0 to the output pin, which in my case initially caused a lot of
-drift.  In my case it proved to be a good idea with X and Y to tune
-the motor driver to make sure 0 voltage stopped the motor rotation.
-On the other hand, for the Z axis this proved to be a bad idea, so it
-will depend on your setup.  It might help to set the bias value to a
-output value that reduce or eliminate the axis drift.  Finally, after
-setting tune-mode, set tune-start to 1 to activate the auto tuning.
-If all go well, your axis will vibrate for a few seconds and when it
-is done, new values for Pgain, Igain and Dgain will be active.  To
-test them, change tune-mode back to 0.  Note that this might cause the
+<tt>tune-mode</tt> value. Note, this will disable the pid controlling
+part and feed 0 to the output pin, which in my case initially caused a
+lot of drift.  In my case it proved to be a good idea with X and Y to
+tune the motor driver to make sure 0 voltage stopped the motor
+rotation.  On the other hand, for the Z axis this proved to be a bad
+idea, so it will depend on your setup.  It might help to set the
+<tt>bias</tt> value to a output value that reduce or eliminate the
+axis drift.  Finally, after setting <tt>tune-mode</tt>, set
+<tt>tune-start</tt> to 1 to activate the auto tuning.  If all go well,
+your axis will vibrate for a few seconds and when it is done, new
+values for Pgain, Igain and Dgain will be active.  To test them,
+change <tt>tune-mode</tt> back to 0.  Note that this might cause the
 machine to suddenly jerk as it bring the axis back to its commanded
 position, which it might have drifted away from during tuning.  To
 summarize with some halcmd lines:</p>
@@ -182,7 +196,7 @@ activities, please send Bitcoin donations to my address
 <b><a href="bitcoin:15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b">15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b</a></b>.</p>
 </div>
       
-      <div class="tags">Tags: <a href="https://people.skolelinux.org/pere/blog/tags/3d-printer">3d-printer</a>, <a href="https://people.skolelinux.org/pere/blog/tags/debian">debian</a>, <a href="https://people.skolelinux.org/pere/blog/tags/english">english</a>, <a href="https://people.skolelinux.org/pere/blog/tags/robot">robot</a>.</div>
+      <div class="tags">Tags: <a href="https://people.skolelinux.org/pere/blog/tags/3d-printer">3d-printer</a>, <a href="https://people.skolelinux.org/pere/blog/tags/debian">debian</a>, <a href="https://people.skolelinux.org/pere/blog/tags/english">english</a>, <a href="https://people.skolelinux.org/pere/blog/tags/linuxcnc">linuxcnc</a>, <a href="https://people.skolelinux.org/pere/blog/tags/robot">robot</a>.</div>
       
       
     </div>
@@ -197,6 +211,27 @@ activities, please send Bitcoin donations to my address
 <h2>Archive</h2>
 <ul>
 
+<li>2023
+<ul>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/01/">January (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/02/">February (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/04/">April (2)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/05/">May (3)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/06/">June (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/08/">August (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2023/10/">October (1)</a></li>
+
+</ul></li>
+
 <li>2022
 <ul>
 
@@ -210,6 +245,12 @@ activities, please send Bitcoin donations to my address
 
 <li><a href="https://people.skolelinux.org/pere/blog/archive/2022/07/">July (1)</a></li>
 
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/09/">September (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/10/">October (1)</a></li>
+
+<li><a href="https://people.skolelinux.org/pere/blog/archive/2022/12/">December (1)</a></li>
+
 </ul></li>
 
 <li>2021
@@ -603,21 +644,21 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/chrpath">chrpath (2)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/debian">debian (181)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/debian">debian (194)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/debian edu">debian edu (159)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/debian-handbook">debian-handbook (8)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/debian-handbook">debian-handbook (9)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/digistan">digistan (11)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/dld">dld (18)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/docbook">docbook (30)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/docbook">docbook (31)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/drivstoffpriser">drivstoffpriser (4)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/english">english (437)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/english">english (451)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/fiksgatami">fiksgatami (23)</a></li>
 
@@ -637,7 +678,7 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/kart">kart (23)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/kodi">kodi (4)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/kodi">kodi (6)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/ldap">ldap (9)</a></li>
 
@@ -645,6 +686,8 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/lenker">lenker (8)</a></li>
 
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/linuxcnc">linuxcnc (5)</a></li>
+
  <li><a href="https://people.skolelinux.org/pere/blog/tags/lsdvd">lsdvd (2)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/ltsp">ltsp (1)</a></li>
@@ -653,13 +696,13 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/mesh network">mesh network (8)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/multimedia">multimedia (42)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/multimedia">multimedia (46)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/nice free software">nice free software (13)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/nice free software">nice free software (15)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/noark5">noark5 (23)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/norsk">norsk (320)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/norsk">norsk (322)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/nuug">nuug (198)</a></li>
 
@@ -667,6 +710,8 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/open311">open311 (2)</a></li>
 
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/opensnitch">opensnitch (4)</a></li>
+
  <li><a href="https://people.skolelinux.org/pere/blog/tags/opphavsrett">opphavsrett (75)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/personvern">personvern (114)</a></li>
@@ -679,7 +724,7 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/rfid">rfid (3)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/robot">robot (16)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/robot">robot (17)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/rss">rss (1)</a></li>
 
@@ -693,13 +738,13 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/skepsis">skepsis (5)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/standard">standard (72)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/standard">standard (74)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/stavekontroll">stavekontroll (7)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/stortinget">stortinget (14)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/surveillance">surveillance (62)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/surveillance">surveillance (64)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/sysadmin">sysadmin (5)</a></li>
 
@@ -709,7 +754,7 @@ activities, please send Bitcoin donations to my address
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/verkidetfri">verkidetfri (20)</a></li>
 
- <li><a href="https://people.skolelinux.org/pere/blog/tags/video">video (77)</a></li>
+ <li><a href="https://people.skolelinux.org/pere/blog/tags/video">video (79)</a></li>
 
  <li><a href="https://people.skolelinux.org/pere/blog/tags/vitenskap">vitenskap (4)</a></li>