<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <div class="moz-cite-prefix">Kipton,<br>
      <br>
      Bingo!   That is so cool.<br>
      <br>
      thanks for the link.<br>
      <br>
      David<br>
      <br>
      <br>
      On 2/18/21 8:42 PM, Kipton Moravec via DPRGlist wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:5e86870e-1ac7-89d3-1a8e-facc406637ac@kdream.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <p>An option we are looking at for a work project is the
        STM32MP1XX family of processors. <br>
        <br>
        It has a Arm A7 and Arm M4 in the same chip. The A7 runs Linux,
        and the M4 is for the real-time stuff. They have a bus between
        the two processors so they can look at the other's peripherals
        and memory. <br>
        <br>
        They have a development board that is under $69 you could base a
        Robot around. <br>
        <a class="moz-txt-link-freetext"
href="https://www.mouser.com/ProductDetail/STMicroelectronics/STM32MP157A-DK1/?qs=9r4v7xj2LnkgRwGGD4%252BIjQ%3D%3D"
          moz-do-not-send="true">https://www.mouser.com/ProductDetail/STMicroelectronics/STM32MP157A-DK1/?qs=9r4v7xj2LnkgRwGGD4%252BIjQ%3D%3D</a><br>
      </p>
      <p>It is relatively new, and not for the faint of heart. I would
        recommend getting to understand the M4, the ST CubeIDE
        development tools, and how ST does things with the HAL before
        you jump into this beast. To program the M4, the IDE connects to
        Linux with Ethernet copies it over, and the A7 writes to the M4
        memory. <br>
        <br>
        <br>
        When I was doing a resonant power supply we had a PID loop that
        was executed every clock, between 25 and 100 kHz.  Our goal was
        to adjust the input voltage (on a slower loop) so the frequency
        was 50 kHz (resonance most efficient) and the clock by clock
        loop would deal with abrupt current changes by changing the
        frequency higher to shed power and make the frequency lower to
        provide more power. We had to compensate for the sample time in
        the PID equation.  It is possible to do. But Python would not do
        it. <br>
        <br>
        We were dealing with a power supply for a laptop PC. Where to
        save power they would shut parts of the processor and
        peripherals completely off when not needed, lowering the
        current, and turning things on quickly when needed causing the
        current to increase. These events would happen randomly
        sometimes multiple times a second. <br>
        <br>
        Kip<br>
      </p>
      <div class="moz-cite-prefix">On 2/18/21 3:58 PM, David Anderson
        via DPRGlist wrote:<br>
      </div>
      <blockquote type="cite"
        cite="mid:7a13d84e-177d-d38c-8b79-cfe709b45677@smu.edu"> 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">
          <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"
                    moz-do-not-send="true"><dprglist@lists.dprg.org></a><br>
                  To: Chris N <a class="moz-txt-link-rfc2396E"
                    href="mailto:netterchris@gmail.com"
                    moz-do-not-send="true"><netterchris@gmail.com></a>;
                  <a class="moz-txt-link-abbreviated"
                    href="mailto:dprglist@lists.dprg.org"
                    moz-do-not-send="true">dprglist@lists.dprg.org</a> <a
                    class="moz-txt-link-rfc2396E"
                    href="mailto:dprglist@lists.dprg.org"
                    moz-do-not-send="true"><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" moz-do-not-send="true">DPRGlist@lists.dprg.org</a>
<a class="moz-txt-link-freetext" href="http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org" moz-do-not-send="true">http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org</a>
</pre>
        </blockquote>
        <br>
        <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" moz-do-not-send="true">DPRGlist@lists.dprg.org</a>
<a class="moz-txt-link-freetext" href="http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org" moz-do-not-send="true">http://lists.dprg.org/listinfo.cgi/dprglist-dprg.org</a>
</pre>
      </blockquote>
      <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>