<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    Howdy,<br>
    <br>
    Not to be overly pedantic...<br>
    <br>
    But another solution to these timing problems is to use a micro
    controller that is not running Linux to do your real time stuff. 
    The STM32 Nucleo board I'm using with an RTOS has a context switch
    time which is reliably less than 10 us (which is actually the least
    I can measure).   <br>
    <br>
    I understand the arguments for using Linux.  I've been using it both
    at work and home since the early 1990s.  But not on robots.  If the
    argument is that it makes robotly things easier, I'm not sure
    anyone's experience bears that out.<br>
    <br>
    Right tool for the job, as the old guys use to say.<br>
    <br>
    cheers!<br>
    dpa<br>
    <br>
    <br>
    <div class="moz-cite-prefix">On 2/18/21 11:03 AM, John Swindle via
      DPRGlist wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:1830267517.2943411.1613667783411@mail.yahoo.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <p style="background-color: #f4eaa5;color: #000000
        ;margin:5px;padding: 2px;text-align: left !important;
        align-content: center; display: block; border: 1px solid
        #000000; font-size: large; font-family: sans-serif;"><strong><em
            style="font-size: 11px;"> [EXTERNAL SENDER]</em></strong></p>
      <div style="color:black;font: 10pt Arial, Helvetica, sans-serif;">Going
        back to a previous topic regarding jitter in timing intervals.
        <div><br>
        </div>
        <div>Why can't parameters used in calculations be scaled by the
          actual sample interval? I understand 50ms is chosen because it
          gives optimum control without undue overhead. When the actual
          interval is, say, 47ms, why not scale the time-related
          parameters to 47/50 of what they nominally are, just for that
          interval? If the next interval is 74ms, scale the parameters
          to 74/50. Is this impractical? Is the uncertainty of measuring
          the time interval too large? This is, if Python says the time
          interval is 47ms, is the error, say, +/- 10ms?</div>
        <div><br>
        </div>
        <div>Related to this: If the sample-to-sample timing error is
          large or jittery, but if you have confidence that the
          long-term timing is 50ms per interval, then why can't the
          current calculations be smoothed, assuming that each
          calculation is jittery due to timing inaccuracy? Does the
          robot really make snap decisions based on a single interval?</div>
        <div><br>
        </div>
        <div>Most CPU datasheets require the clock to have 50 to 100ppm
          accuracy. That sounds good, but for audio processing, it means
          streams coming from different sources will beat with one
          another. I have to resample the streams to match the actual
          sample rate of one of the streams. I use a metronome signal
          that each gadget processes. That doesn't mean any of the
          timings are correct (including the timing of the metronome).
          It just means they are all forced to look like they are the
          same. I say this because resampling is like what I'm
          suggesting: Scale the calculations to the actual interval.</div>
        <div><br>
        </div>
        <div>Am I missing something here?</div>
        <div><br>
        </div>
        <div>John Swindle</div>
        <div><br>
        </div>
        <div>
          <div
            style="font-family:arial,helvetica;font-size:10pt;color:black"><font
              size="2">-----Original Message-----<br>
              From: Murray Altheim via DPRGlist
              <a class="moz-txt-link-rfc2396E" href="mailto:dprglist@lists.dprg.org"><dprglist@lists.dprg.org></a><br>
              To: Chris N <a class="moz-txt-link-rfc2396E" href="mailto:netterchris@gmail.com"><netterchris@gmail.com></a>;
              <a class="moz-txt-link-abbreviated" href="mailto:dprglist@lists.dprg.org">dprglist@lists.dprg.org</a> <a class="moz-txt-link-rfc2396E" href="mailto:dprglist@lists.dprg.org"><dprglist@lists.dprg.org></a><br>
              Sent: Thu, Feb 11, 2021 4:06 am<br>
              Subject: Re: [Dprglist] PID-tuned Clock in Python?<br>
              <br>
              <div dir="ltr">On 11/02/21 3:13 pm, Chris N wrote:> I
                don’t think you have a “clock accuracy” issue.  I’m
                pretty sure<br clear="none">
                > the hardware clocks, as in crystal + PLL etc., in
                things like the<br clear="none">
                > Pi, are plenty accurate for our needs.<br
                  clear="none">
                <br clear="none">
                Hi Chris,<br clear="none">
                <br clear="none">
                First, thanks very much, I appreciate your thoughtful
                reply.<br clear="none">
                <br clear="none">
                Yes, I understand that it's not the accuracy of the
                Raspberry Pi's<br clear="none">
                system clock that is in question, but the accuracy of
                time loops<br clear="none">
                when implemented in a Python application using a single
                or multiple<br clear="none">
                threads, executing within a time-sharing operating
                system like Linux.<br clear="none">
                <br clear="none">
                This is clearly where a microcontroller (like an
                Arduino, STM32,<br clear="none">
                ESP32, Pico RP2040, etc.) has its advantages. As I
                noted, my<br clear="none">
                MacBook was actually worse than my Raspberry Pi, which
                in this<br clear="none">
                light is perhaps not so surprising, i.e., the MacBook's
                processor<br clear="none">
                is a lot busier.<br clear="none">
                <br clear="none">
                My 3.5GHz multi-core i7 workstation is clearly giving at
                least a<br clear="none">
                whole core to the Python application and not struggling,
                so its<br clear="none">
                performance is very close to expected norms. But that's
                not the<br clear="none">
                case on the Pi, where I'll actually be using this timing
                loop.<br clear="none">
                <br clear="none">
                [...]<br clear="none">
                > Now regarding the PID idea:<br clear="none">
                > <br clear="none">
                > Say we have a loop that we want to run at a fixed
                rate. Say 20Hz / 50.0ms.<br clear="none">
                > <br clear="none">
                > Using PID to improve the timing accuracy of such
                loops is certainly<br clear="none">
                > an interesting idea, but I believe PID makes things
                worse in this case.<br clear="none">
                <br clear="none">
                I'm not clear that this is the case yet. My observation
                was the the PID<br clear="none">
                loop was improving things somewhat significantly, but
                more on that below.<br clear="none">
                <br clear="none">
                > See output from your clock_test.py below.   I ran
                this on my Pi 3.<br clear="none">
                > I deliberately used a tough background load to
                amplify the effect <br clear="none">
                > (stress –vm 4 –vm-bytes 128M) , but even with
                normal loads the <br clear="none">
                > negative effect of the PID can be observed, just
                the errors would<br clear="none">
                > be much smaller.<br clear="none">
                <br clear="none">
                Agreed, understood.<br clear="none">
                <br clear="none">
                > In line 6 you can see the 27ms error. <br
                  clear="none">
                > [...]<br clear="none">
                > The reason I think PID is a bad idea here is
                because the nature of<br clear="none">
                > the disturbance is simply too random and its very
                intermittent. <br clear="none">
                > The best you can do really is to use basic loop
                timing logic to <br clear="none">
                > ensure that the next iteration starts at the right
                time, despite<br clear="none">
                > the fact that this iteration took an unusual amount
                of time or <br clear="none">
                > sleep() took an unusual amount of time. With PID
                you end up  > over-compensating and you are
                effectively hurting the timing of<br clear="none">
                > subsequent iterations.<br clear="none">
                <br clear="none">
                I certainly agree based on both logic and my
                observations that the<br clear="none">
                disturbances are intermittent, and from the perspective
                of the<br clear="none">
                Python program (i.e., it not knowing what else is
                running), would<br clear="none">
                appear entirely randomly.<br clear="none">
                <br clear="none">
                But I'm not clear the PID loop is over-compensating in
                those cases.<br clear="none">
                When a disturbance is within one 20Hz clock cycle, there
                is no real<br clear="none">
                fix for that in software. I entirely agree with you in
                those cases.<br clear="none">
                But when the CPU is really busy with some longer-term
                process and<br clear="none">
                that activity extends say over several seconds, the PID
                (I believe)<br clear="none">
                would tend to compensate better than with no PID.<br
                  clear="none">
                <br clear="none">
                > There are straight forward ways to deal with the
                fact that  <br clear="none">
                > time.sleep(x) doesn’t sleep for exactly x amount of
                time, and the<br clear="none">
                > fact that the amount of work which needs to be done
                every iteration<br clear="none">
                > is not 100% constant.  A python version of such a
                fixed-rate loop > is here: <a shape="rect"
                  href="https://github.com/nettercm/timing%C2%A0%C2%A0"
                  target="_blank" moz-do-not-send="true">https://github.com/nettercm/timing  
                </a>I typically use<br clear="none">
                > similar loop timing logic in other languages and
                sometimes even <br clear="none">
                > on a microcontroller.<br clear="none">
                > <br clear="none">
                > In pseudo python it looks as follows. [...]<br
                  clear="none">
                If I'm reading your code correctly, this is kinda what I
                was doing<br clear="none">
                before I adopted the PID into the mix. I had a fixed
                trim value on<br clear="none">
                the Rate, and when the 50ms loop was consistently a bit
                slow or a<br clear="none">
                bit fast I'd just modify the trim value. It was trying
                to auto-correct<br clear="none">
                that trim value that led me to using a PID loop. Now, a
                fixed trim<br clear="none">
                would obviously not take into account those nasty
                intermittent surges<br clear="none">
                or lags, but is certainly simpler to implement and a lot
                less<br clear="none">
                mysterious in use than a PID loop.<br clear="none">
                <br clear="none">
                So if the PID turns out to be causing actual problems as
                you suggest,<br clear="none">
                I can set the flag to disable it, and maybe re-implement
                the fixed<br clear="none">
                trim. I've been setting the PID's kp constant from an
                RGB LED<br clear="none">
                potentiometer like:<br clear="none">
                <br clear="none">
                  <a shape="rect"
                  href="https://shop.pimoroni.com/products/rgb-potentiometer-breakout"
                  target="_blank" moz-do-not-send="true">https://shop.pimoroni.com/products/rgb-potentiometer-breakout</a><br
                  clear="none">
                <br clear="none">
                so if I end up disabling the PID I could manually set
                the trim from<br clear="none">
                the potentiometer, then just fix it in my YAML
                configuration. This<br clear="none">
                would be a "best guess" on a fixed, constant trim value.<br
                  clear="none">
                <br clear="none">
                I think we both agree that there's nothing anyone can do
                to get a<br clear="none">
                truly consistent loop using Python on Linux, but if I'm
                willing to<br clear="none">
                accept that those intermittent <50ms disturbances are
                also unfixable,<br clear="none">
                then the PID does still at least (IMO) manage the longer
                lags and<br clear="none">
                surges of the clock. This *seems* to be what I'm seeing
                in the<br clear="none">
                console outputs.<br clear="none">
                <br clear="none">
                The whole subject of PID is all a bit dream-catcher,
                Voynich Manuscript,<br clear="none">
                ouija board, patchouli incense kind of thing...
                verra-mysterious.
                <div class="yqt4755843592" id="yqtfd77735"><br
                    clear="none">
                  <br clear="none">
                  Cheers,<br clear="none">
                  <br clear="none">
                  Murray<br clear="none">
                  <br clear="none">
                  <br clear="none">
...........................................................................<br
                    clear="none">
                  Murray Altheim <murray18 at altheim dot com>   
                                    = =  ===<br clear="none">
                  <a shape="rect" href="http://www.altheim.com/murray/"
                    target="_blank" moz-do-not-send="true">http://www.altheim.com/murray/
                  </a>                                    ===  ===<br
                    clear="none">
                                                                       
                                = =  ===<br clear="none">
                      In the evening<br clear="none">
                      The rice leaves in the garden<br clear="none">
                      Rustle in the autumn wind<br clear="none">
                      That blows through my reed hut.<br clear="none">
                              -- Minamoto no Tsunenobu<br clear="none">
                  <br clear="none">
                  _______________________________________________<br
                    clear="none">
                  DPRGlist mailing list<br clear="none">
                  <a shape="rect"
                    ymailto="mailto:DPRGlist@lists.dprg.org"
                    href="mailto:DPRGlist@lists.dprg.org"
                    moz-do-not-send="true">DPRGlist@lists.dprg.org</a><br
                    clear="none">
                  <a shape="rect"
                    href="http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org"
                    target="_blank" moz-do-not-send="true">http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org</a><br
                    clear="none">
                </div>
              </div>
            </font></div>
        </div>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <pre class="moz-quote-pre" wrap="">_______________________________________________
DPRGlist mailing list
<a class="moz-txt-link-abbreviated" href="mailto:DPRGlist@lists.dprg.org">DPRGlist@lists.dprg.org</a>
<a class="moz-txt-link-freetext" href="http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org">http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>