<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title> – Limiters and shaping</title>
    <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/</link>
    <description>Recent content in Limiters and shaping on </description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="/docs/developing-control-applications/control-blocks/limiters-and-shaping/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: Limiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter-3.30/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter-3.30/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version c3-version--archived&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/&#34;&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter-3.30/&#34; selected&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;
    Superseded. The current release is
    &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/&#34;&gt;3.34&lt;/a&gt;.
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Limiter&lt;/code&gt; clamps a signal between a lower and an upper bound. It is the block
that sits between a controller and an actuator that cannot take more than a
certain torque, and it is the simplest protection in the library.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;adaptive&lt;/strong&gt; variant is also available. It starts from wherever the signal
already is and closes in on the configured bounds only as the signal allows —
so switching it on around a signal that is already outside its band does not
produce a step. A plain limiter in the same situation clamps at once.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — signal to clamp&amp;quot;]) --&amp;gt; B[&amp;quot;Limiter&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — clamped signal&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting — per channel&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The adaptive variant adds two outputs:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input&amp;quot;]) --&amp;gt; B[&amp;quot;AdaptiveLimiter&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
    B --&amp;gt; o4([&amp;quot;activeLowerLimit — the bound in use now&amp;quot;])
    B --&amp;gt; o5([&amp;quot;activeUpperLimit&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;output&lt;/code&gt; = &lt;code&gt;input&lt;/code&gt; clamped to [&lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt;], per channel.
There is no time constant, no lag and no filtering — the clamp is exact and
instant. Nothing here depends on the task rate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The limiter ships switched off.&lt;/strong&gt; &lt;code&gt;enable&lt;/code&gt; defaults to false, so a fresh
limiter passes everything through. This matters most when a limiter is one
block inside a larger one: its bound is not protecting anything until it is
enabled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you write the limits the wrong way round, the block swaps them for you&lt;/strong&gt;
and you will read back the swapped pair.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to clamp. One element per channel; the channel count is fixed by the machine configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the limiter: &lt;code&gt;input&lt;/code&gt; passes straight to &lt;code&gt;output&lt;/code&gt; and every flag clears. Use it for a runtime override from a supervisor; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The clamped signal, one element per channel. Equals &lt;code&gt;input&lt;/code&gt; exactly while bypassed, and exactly whenever the input is inside the bounds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True per channel while &lt;code&gt;input&lt;/code&gt; is outside the configured bounds. On the adaptive variant this means &amp;ldquo;the signal wants more than you allowed&amp;rdquo;, which is &lt;strong&gt;not&lt;/strong&gt; the same as &amp;ldquo;the output was changed&amp;rdquo; — see below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false. A single value for the whole block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeLowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Adaptive variant only.&lt;/strong&gt; The bound actually in use this cycle, per channel. It is never tighter than &lt;code&gt;lowerLimit&lt;/code&gt; and may be looser while the signal is outside.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Adaptive variant only.&lt;/strong&gt; The upper equivalent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False bypasses the limiter entirely. &lt;strong&gt;Set this, or the block does nothing.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;−1&lt;/td&gt;
&lt;td&gt;below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The lower bound, per channel. Set it to what the consumer can actually accept. If it ends up above &lt;code&gt;upperLimit&lt;/code&gt; the two are swapped silently.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;td&gt;above &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The upper bound, per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adaptive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Adaptive variant only.&lt;/strong&gt; False makes it behave as a plain limiter. A plain limiter cannot be made adaptive at runtime.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All parameters are persistent and survive a controller restart. &lt;strong&gt;No parameters
exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt; to what the consumer can accept. The
defaults of ±1 are placeholders, not machine values.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;enable&lt;/code&gt; false and confirm &lt;code&gt;output&lt;/code&gt; follows &lt;code&gt;input&lt;/code&gt; exactly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drive the input past a bound and confirm &lt;code&gt;isLimiting&lt;/code&gt; goes true for that
channel while &lt;code&gt;output&lt;/code&gt; still follows — the flag works while bypassed only in
the sense that it stays false; here it will read false, which confirms the
bypass.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true and repeat. &lt;code&gt;output&lt;/code&gt; should now stop at the bound and
&lt;code&gt;isLimiting&lt;/code&gt; should read true.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 changes what reaches the consumer.&lt;/strong&gt; If the signal is already
outside the band when you enable a plain limiter, the output &lt;strong&gt;steps&lt;/strong&gt; to
the bound. Enable it with the signal inside the band, or use the adaptive
variant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element of &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;isLimiting&lt;/code&gt;. Limits are per
channel, so an element with the wrong bound is easy to miss.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the adaptive variant, watch &lt;code&gt;activeLowerLimit&lt;/code&gt; and &lt;code&gt;activeUpperLimit&lt;/code&gt;.
They should converge onto the configured bounds as the signal moves inside
them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;There is nothing to tune. The bounds are a machine property, and the only real
decision is which variant to use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set the bounds from the consumer&amp;rsquo;s datasheet, not by watching the signal.
A limiter tuned to what the signal happens to do is not protecting anything.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;plain&lt;/strong&gt; limiter wherever the bound is a hard safety limit. It
clamps immediately and always, which is what a protection limit must do.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;adaptive&lt;/strong&gt; variant wherever the bound shapes a signal rather than
protecting the machine, and a step on engagement would be felt. It never
introduces a discontinuity, and it tightens toward the configured bounds
only as the signal allows.&lt;/li&gt;
&lt;li&gt;Do not use the adaptive variant as a safety limit. If the signal never
returns inside the band, the active bounds never tighten and nothing is
ever clipped.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;isLimiting&lt;/code&gt; during commissioning. Persistent limiting means either
the bound is too tight or something upstream is commanding more than the
machine can deliver — and the second is usually the real problem.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/limiter-transfer-634b0e6e.svg&#34; alt=&#34;Output against input at three limit pairs: with no limit the line runsstraight through, plus-or-minus 1 flattens at both ends, and a lower limit of-0.5 with an upper of 1.5 flattens asymmetrically.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read each bound off the height at which its line goes flat.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is limited and &lt;code&gt;isLimiting&lt;/code&gt; stays false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt; defaults to false&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;enable&lt;/code&gt; true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; reads true but &lt;code&gt;output&lt;/code&gt; equals &lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;You are on the adaptive variant, and the active band still admits the signal&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;activeLowerLimit&lt;/code&gt; and &lt;code&gt;activeUpperLimit&lt;/code&gt;; use the plain limiter if you need a hard bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stepped when the limiter was enabled&lt;/td&gt;
&lt;td&gt;Expected on the plain limiter: it clamps at once&lt;/td&gt;
&lt;td&gt;Enable with the signal inside the band, or use the adaptive variant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The adaptive limiter never clips anything&lt;/td&gt;
&lt;td&gt;Expected: the active bounds only tighten when the signal comes back inside them&lt;/td&gt;
&lt;td&gt;Use the plain limiter for a hard bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The limits read back swapped&lt;/td&gt;
&lt;td&gt;Expected: they were written the wrong way round and the block corrected them&lt;/td&gt;
&lt;td&gt;Write the lower bound to &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is pinned at one value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt; are equal&lt;/td&gt;
&lt;td&gt;Separate them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One channel limits and the others do not&lt;/td&gt;
&lt;td&gt;Expected: the bounds are per channel&lt;/td&gt;
&lt;td&gt;Check every element of both limit arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is unbounded inside a larger block&lt;/td&gt;
&lt;td&gt;That block&amp;rsquo;s internal limiter has not been enabled&lt;/td&gt;
&lt;td&gt;Enable it in its own sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value passed straight through&lt;/td&gt;
&lt;td&gt;Expected: the clamp does not reject non-numeric values&lt;/td&gt;
&lt;td&gt;Fix the source; on the adaptive variant, bypass the block for a cycle to clear its active bounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The signal is clipped harshly and the machine bumps&lt;/td&gt;
&lt;td&gt;A hard clamp is what this block does&lt;/td&gt;
&lt;td&gt;Use a soft limiter if you need a rounded approach to the bound&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for bounding an actuator command at ±10 in its own units:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable     = true
lowerLimit = -10.0
upperLimit = 10.0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt; below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;If they are inverted the two are &lt;strong&gt;swapped in place&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Silently; read both back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt; while enabled&lt;/td&gt;
&lt;td&gt;Clamped exactly, with no lag. Unbounded while &lt;code&gt;enable&lt;/code&gt; is false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;, per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit values&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. Any finite pair is accepted, and equal limits pin the output to that value&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; meaning&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Reports the input against the &lt;strong&gt;configured&lt;/strong&gt; bounds. On the adaptive variant the output may not have been changed at all&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptive band&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The active bounds can only ever be &lt;strong&gt;wider&lt;/strong&gt; than the configured ones, never tighter. They are not reset at start&lt;/td&gt;
&lt;td&gt;Published as &lt;code&gt;activeLowerLimit&lt;/code&gt; / &lt;code&gt;activeUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Passes through unchanged. On the adaptive variant it also poisons the active bounds until a bypassed cycle re-derives them&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Limiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/&#34; selected&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter-3.30/&#34;&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;Current release&lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Limiter&lt;/code&gt; clamps a signal between a lower and an upper bound. It is the block
that sits between a controller and an actuator that cannot take more than a
certain torque, and it is the simplest protection in the library.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;adaptive&lt;/strong&gt; variant is also available. It starts from wherever the signal
already is and closes in on the configured bounds only as the signal allows —
so switching it on around a signal that is already outside its band does not
produce a step. A plain limiter in the same situation clamps at once.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — signal to clamp&amp;quot;]) --&amp;gt; B[&amp;quot;Limiter&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — clamped signal&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting — per channel&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The adaptive variant adds two outputs:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input&amp;quot;]) --&amp;gt; B[&amp;quot;AdaptiveLimiter&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
    B --&amp;gt; o4([&amp;quot;activeLowerLimit — the bound in use now&amp;quot;])
    B --&amp;gt; o5([&amp;quot;activeUpperLimit&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;output&lt;/code&gt; = &lt;code&gt;input&lt;/code&gt; clamped to [&lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt;], per channel.
There is no time constant, no lag and no filtering — the clamp is exact and
instant. Nothing here depends on the task rate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The limiter ships switched off.&lt;/strong&gt; &lt;code&gt;enable&lt;/code&gt; defaults to false, so a fresh
limiter passes everything through. This matters most when a limiter is one
block inside a larger one: its bound is not protecting anything until it is
enabled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you write the limits the wrong way round, the block swaps them for you&lt;/strong&gt;
and you will read back the swapped pair.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to clamp. One element per channel; the channel count is fixed by the machine configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the limiter: &lt;code&gt;input&lt;/code&gt; passes straight to &lt;code&gt;output&lt;/code&gt; and every flag clears. Use it for a runtime override from a supervisor; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The clamped signal, one element per channel. Equals &lt;code&gt;input&lt;/code&gt; exactly while bypassed, and exactly whenever the input is inside the bounds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True per channel while &lt;code&gt;input&lt;/code&gt; is outside the configured bounds. On the adaptive variant this means &amp;ldquo;the signal wants more than you allowed&amp;rdquo;, which is &lt;strong&gt;not&lt;/strong&gt; the same as &amp;ldquo;the output was changed&amp;rdquo; — see below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false. A single value for the whole block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeLowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Adaptive variant only.&lt;/strong&gt; The bound actually in use this cycle, per channel. It is never tighter than &lt;code&gt;lowerLimit&lt;/code&gt; and may be looser while the signal is outside.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Adaptive variant only.&lt;/strong&gt; The upper equivalent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False bypasses the limiter entirely. &lt;strong&gt;Set this, or the block does nothing.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;−1&lt;/td&gt;
&lt;td&gt;below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The lower bound, per channel. Set it to what the consumer can actually accept. If it ends up above &lt;code&gt;upperLimit&lt;/code&gt; the two are swapped silently.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;td&gt;above &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The upper bound, per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adaptive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Adaptive variant only.&lt;/strong&gt; False makes it behave as a plain limiter. A plain limiter cannot be made adaptive at runtime.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All parameters are persistent and survive a controller restart. &lt;strong&gt;No parameters
exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt; to what the consumer can accept. The
defaults of ±1 are placeholders, not machine values.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;enable&lt;/code&gt; false and confirm &lt;code&gt;output&lt;/code&gt; follows &lt;code&gt;input&lt;/code&gt; exactly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drive the input past a bound and confirm &lt;code&gt;isLimiting&lt;/code&gt; goes true for that
channel while &lt;code&gt;output&lt;/code&gt; still follows — the flag works while bypassed only in
the sense that it stays false; here it will read false, which confirms the
bypass.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true and repeat. &lt;code&gt;output&lt;/code&gt; should now stop at the bound and
&lt;code&gt;isLimiting&lt;/code&gt; should read true.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 changes what reaches the consumer.&lt;/strong&gt; If the signal is already
outside the band when you enable a plain limiter, the output &lt;strong&gt;steps&lt;/strong&gt; to
the bound. Enable it with the signal inside the band, or use the adaptive
variant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element of &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;isLimiting&lt;/code&gt;. Limits are per
channel, so an element with the wrong bound is easy to miss.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the adaptive variant, watch &lt;code&gt;activeLowerLimit&lt;/code&gt; and &lt;code&gt;activeUpperLimit&lt;/code&gt;.
They should converge onto the configured bounds as the signal moves inside
them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;There is nothing to tune. The bounds are a machine property, and the only real
decision is which variant to use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set the bounds from the consumer&amp;rsquo;s datasheet, not by watching the signal.
A limiter tuned to what the signal happens to do is not protecting anything.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;plain&lt;/strong&gt; limiter wherever the bound is a hard safety limit. It
clamps immediately and always, which is what a protection limit must do.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;adaptive&lt;/strong&gt; variant wherever the bound shapes a signal rather than
protecting the machine, and a step on engagement would be felt. It never
introduces a discontinuity, and it tightens toward the configured bounds
only as the signal allows.&lt;/li&gt;
&lt;li&gt;Do not use the adaptive variant as a safety limit. If the signal never
returns inside the band, the active bounds never tighten and nothing is
ever clipped.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;isLimiting&lt;/code&gt; during commissioning. Persistent limiting means either
the bound is too tight or something upstream is commanding more than the
machine can deliver — and the second is usually the real problem.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/limiter-transfer-634b0e6e.svg&#34; alt=&#34;Output against input at three limit pairs: with no limit the line runsstraight through, plus-or-minus 1 flattens at both ends, and a lower limit of-0.5 with an upper of 1.5 flattens asymmetrically.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read each bound off the height at which its line goes flat.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is limited and &lt;code&gt;isLimiting&lt;/code&gt; stays false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt; defaults to false&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;enable&lt;/code&gt; true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; reads true but &lt;code&gt;output&lt;/code&gt; equals &lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;You are on the adaptive variant, and the active band still admits the signal&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;activeLowerLimit&lt;/code&gt; and &lt;code&gt;activeUpperLimit&lt;/code&gt;; use the plain limiter if you need a hard bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stepped when the limiter was enabled&lt;/td&gt;
&lt;td&gt;Expected on the plain limiter: it clamps at once&lt;/td&gt;
&lt;td&gt;Enable with the signal inside the band, or use the adaptive variant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The adaptive limiter never clips anything&lt;/td&gt;
&lt;td&gt;Expected: the active bounds only tighten when the signal comes back inside them&lt;/td&gt;
&lt;td&gt;Use the plain limiter for a hard bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The limits read back swapped&lt;/td&gt;
&lt;td&gt;Expected: they were written the wrong way round and the block corrected them&lt;/td&gt;
&lt;td&gt;Write the lower bound to &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is pinned at one value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt; are equal&lt;/td&gt;
&lt;td&gt;Separate them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One channel limits and the others do not&lt;/td&gt;
&lt;td&gt;Expected: the bounds are per channel&lt;/td&gt;
&lt;td&gt;Check every element of both limit arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is unbounded inside a larger block&lt;/td&gt;
&lt;td&gt;That block&amp;rsquo;s internal limiter has not been enabled&lt;/td&gt;
&lt;td&gt;Enable it in its own sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value passed straight through&lt;/td&gt;
&lt;td&gt;Expected: the clamp does not reject non-numeric values&lt;/td&gt;
&lt;td&gt;Fix the source; on the adaptive variant, bypass the block for a cycle to clear its active bounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The signal is clipped harshly and the machine bumps&lt;/td&gt;
&lt;td&gt;A hard clamp is what this block does&lt;/td&gt;
&lt;td&gt;Use a soft limiter if you need a rounded approach to the bound&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for bounding an actuator command at ±10 in its own units:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable     = true
lowerLimit = -10.0
upperLimit = 10.0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt; below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;If they are inverted the two are &lt;strong&gt;swapped in place&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Silently; read both back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt; while enabled&lt;/td&gt;
&lt;td&gt;Clamped exactly, with no lag. Unbounded while &lt;code&gt;enable&lt;/code&gt; is false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;, per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit values&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. Any finite pair is accepted, and equal limits pin the output to that value&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; meaning&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Reports the input against the &lt;strong&gt;configured&lt;/strong&gt; bounds. On the adaptive variant the output may not have been changed at all&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptive band&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The active bounds can only ever be &lt;strong&gt;wider&lt;/strong&gt; than the configured ones, never tighter. They are not reset at start&lt;/td&gt;
&lt;td&gt;Published as &lt;code&gt;activeLowerLimit&lt;/code&gt; / &lt;code&gt;activeUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Passes through unchanged. On the adaptive variant it also poisons the active bounds until a bypassed cycle re-derives them&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.32.1 (340db23).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: SoftLimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/soft-limiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/soft-limiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SoftLimiter&lt;/code&gt; bounds a signal the way a hard limiter does, but rounds the
approach instead of cutting it off. Between the break points the output equals
the input exactly; beyond them it curves over and approaches the limit
gradually.&lt;/p&gt;
&lt;p&gt;It &lt;strong&gt;adds no lag and no dynamics&lt;/strong&gt; — the curve depends only on the current
input, so unlike a rate limiter or a filter it costs nothing in responsiveness.
The trade is that &lt;strong&gt;the limit is never actually reached&lt;/strong&gt;, only approached.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — signal to limit&amp;quot;]) --&amp;gt; B[&amp;quot;SoftLimiter&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — softly limited signal&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting — per channel&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Between &lt;code&gt;lowerBreakPoint&lt;/code&gt; and &lt;code&gt;upperBreakPoint&lt;/code&gt; the output is the input,
exactly. Beyond a break point it curves toward the matching limit and gets
there only at infinity. The &lt;strong&gt;fade distance&lt;/strong&gt; — limit minus break point — is
the whole tuning: a wide gap gives a long gentle curve, a narrow one a sharp
bend. Set the break point equal to the limit and you get a hard clamp.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;This limit is not a guarantee.&lt;/strong&gt; If the bound must be respected exactly, put
a &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/&#34;&gt;&lt;code&gt;Limiter&lt;/code&gt;&lt;/a&gt; after this one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disabling this block freezes its output&lt;/strong&gt; rather than passing the input
through — see Limits and errors. Unlike most limiters here, it ships
&lt;strong&gt;enabled&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to limit. One element per channel; the channel count is fixed by the machine configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True stops the block updating. &lt;strong&gt;It does not bypass it&lt;/strong&gt; — &lt;code&gt;output&lt;/code&gt; freezes at its last value. Use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The softly limited signal, one element per channel. Equals &lt;code&gt;input&lt;/code&gt; exactly between the break points. &lt;strong&gt;Frozen at its last value while the block is disabled.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True per channel while the input is beyond either break point, so the taper is active. It also freezes while disabled.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false. A single value for the whole block.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;true&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Ships on. False freezes the output rather than bypassing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;−1.0&lt;/td&gt;
&lt;td&gt;below &lt;code&gt;lowerBreakPoint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The lower asymptote. The output approaches it and never reaches it. Swapped with &lt;code&gt;upperLimit&lt;/code&gt; if the two are inverted.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerBreakPoint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;−0.9&lt;/td&gt;
&lt;td&gt;between &lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperBreakPoint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where the lower taper begins. Corrected up to &lt;code&gt;lowerLimit&lt;/code&gt; if set below it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperBreakPoint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;+0.9&lt;/td&gt;
&lt;td&gt;between &lt;code&gt;lowerBreakPoint&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where the upper taper begins. Corrected down to &lt;code&gt;upperLimit&lt;/code&gt; if set above it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;+1.0&lt;/td&gt;
&lt;td&gt;above &lt;code&gt;upperBreakPoint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The upper asymptote.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All five are persistent and survive a restart. Every limit and break point is
&lt;strong&gt;per channel&lt;/strong&gt;. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;upperLimit&lt;/code&gt; and &lt;code&gt;lowerLimit&lt;/code&gt; to the values the signal must stay inside.
Remember the output only approaches them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the two break points inside those limits. The gap between a break point
and its limit is the fade distance — start with about 10% of the range, as
the defaults do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;output&lt;/code&gt; equals &lt;code&gt;input&lt;/code&gt; exactly while the signal stays between the
break points, and that &lt;code&gt;isLimiting&lt;/code&gt; reads false.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3 is the check that matters.&lt;/strong&gt; If the output differs from the input
in the middle of the range, a break point is inside your working range and
the block is tapering signals you meant to pass untouched.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drive the signal past a break point and confirm &lt;code&gt;output&lt;/code&gt; curves over and
&lt;code&gt;isLimiting&lt;/code&gt; goes true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drive it far past the limit and confirm &lt;code&gt;output&lt;/code&gt; gets close to, but never
equals, the limit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element. All four bounds are per channel.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Choose the limits from the consumer, as you would for a hard limiter.&lt;/li&gt;
&lt;li&gt;Choose the break points from how much of the range you are willing to
distort. Everything between them is untouched; everything outside is
compressed.&lt;/li&gt;
&lt;li&gt;Widen the fade distance if the bend is harsh, and narrow it if too much of
your working range is being compressed. Those two pull against each other,
and the gap between them is the whole tuning.&lt;/li&gt;
&lt;li&gt;If the machine needs the bound respected exactly, follow this block with a
hard limiter set to the same value. The soft taper does the shaping and the
hard clamp does the guaranteeing.&lt;/li&gt;
&lt;li&gt;To turn a channel into a hard clamp, set its break point equal to its limit.
The block handles that case explicitly.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/soft-limiter-taper-3afc0cba.svg&#34; alt=&#34;Output against input with a limit of 1.0 at three break points: a break pointof 0.9 gives a short taper, 0.5 gives a long gentle curve, and 1.0 gives a hardclip with no taper.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the fade distance off the gap between where a curve bends and where it
flattens.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The output never quite reaches the limit&lt;/td&gt;
&lt;td&gt;Expected: the limit is an asymptote, not a bound&lt;/td&gt;
&lt;td&gt;Add a hard limiter after this block if the bound must be exact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is distorted in the middle of the working range&lt;/td&gt;
&lt;td&gt;A break point is inside the range you meant to leave alone&lt;/td&gt;
&lt;td&gt;Move the break points outward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The bend at the break point feels harsh&lt;/td&gt;
&lt;td&gt;The fade distance is too small&lt;/td&gt;
&lt;td&gt;Move the break point further from the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Too much of the range is compressed&lt;/td&gt;
&lt;td&gt;The fade distance is too large&lt;/td&gt;
&lt;td&gt;Move the break point closer to the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output froze and will not follow the input&lt;/td&gt;
&lt;td&gt;Expected: disabling this block freezes it rather than bypassing&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;enable&lt;/code&gt; true and &lt;code&gt;disable&lt;/code&gt; false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; is stuck true&lt;/td&gt;
&lt;td&gt;Same cause — the flag freezes with the output&lt;/td&gt;
&lt;td&gt;Re-enable the block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A break point reads back different from what was written&lt;/td&gt;
&lt;td&gt;Expected: break points are corrected inside their own limits&lt;/td&gt;
&lt;td&gt;Write it inside the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The limits read back swapped&lt;/td&gt;
&lt;td&gt;Expected: inverted limits are corrected&lt;/td&gt;
&lt;td&gt;Write the lower value to &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only the upper taper seems to work&lt;/td&gt;
&lt;td&gt;The two break points are crossed, and the upper taper is applied last&lt;/td&gt;
&lt;td&gt;Keep &lt;code&gt;lowerBreakPoint&lt;/code&gt; below &lt;code&gt;upperBreakPoint&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A channel clips hard instead of tapering&lt;/td&gt;
&lt;td&gt;Its break point equals its limit&lt;/td&gt;
&lt;td&gt;Separate them, or keep it if a hard clamp is what you wanted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limits were corrected only after the block was enabled&lt;/td&gt;
&lt;td&gt;Expected: the correction runs only while the block is running&lt;/td&gt;
&lt;td&gt;Enable it, then read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One channel behaves differently from the others&lt;/td&gt;
&lt;td&gt;Expected: all four bounds are per channel&lt;/td&gt;
&lt;td&gt;Check every element of all four arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value passed straight through untapered&lt;/td&gt;
&lt;td&gt;Expected: the comparisons that trigger the taper fail for it&lt;/td&gt;
&lt;td&gt;Fix the source; the block holds no state and recovers at once&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for shaping a command that must stay inside ±10, tapering over
the last 20% of the range:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable          = true
lowerLimit      = -10.0
lowerBreakPoint = -8.0
upperBreakPoint = 8.0
upperLimit      = 10.0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; against the limits&lt;/td&gt;
&lt;td&gt;The taper&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Approached, never reached.&lt;/strong&gt; This block cannot guarantee a bound — follow it with a hard limiter if you need one&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;, per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt; below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Inverted limits are swapped in place&lt;/td&gt;
&lt;td&gt;Silently; read both back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Break points inside their limits&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A break point outside its own limit is corrected onto it. &lt;strong&gt;The two break points are not ordered against each other&lt;/strong&gt; — if they cross, only the upper taper applies&lt;/td&gt;
&lt;td&gt;Silently; read them back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameter correction&lt;/td&gt;
&lt;td&gt;While enabled only&lt;/td&gt;
&lt;td&gt;The corrections above run only while the block is enabled&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disabled behaviour&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The output freezes at its last value&lt;/strong&gt; rather than passing the input through, unlike every other limiter here&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fade distance zero&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A break point equal to its limit gives a hard clamp at that value&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit values&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked beyond the ordering above&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Passes through untapered. The block is stateless and recovers immediately&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: HardLimitVector</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/vector-limiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/vector-limiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;HardLimitVector&lt;/code&gt; limits the &lt;strong&gt;length&lt;/strong&gt; of a vector rather than each of its
components. When the vector is too long every component is scaled down by the
same factor, so &lt;strong&gt;the direction is preserved exactly&lt;/strong&gt; and only the size
changes.&lt;/p&gt;
&lt;p&gt;That is why it exists. Clamping a Cartesian velocity component by component
turns a diagonal move into a different diagonal — the axis that reaches its
bound first stops growing while the others carry on, and the commanded
direction rotates. Scaling the whole vector keeps the direction and just slows
the move down.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — the vector&#39;s components&amp;quot;]) --&amp;gt; B[&amp;quot;HardLimitVector&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — scaled or unchanged vector&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;upperLimit&lt;/code&gt; is the maximum &lt;strong&gt;length&lt;/strong&gt; of the whole vector, as a single
number — not a bound on any one component. While the length is inside the
limit the output is the input exactly. Beyond it, every component is
multiplied by &lt;code&gt;upperLimit&lt;/code&gt; ÷ the actual length.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every component must share the same unit.&lt;/strong&gt; The block computes one length
across all of them, so a mixed vector — a pose with metres in some elements and
radians in others — has a length with no physical meaning. Use one instance per
unit group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no lower limit&lt;/strong&gt;, and there cannot usefully be one: a zero-length
vector has no direction to grow in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The block ships switched off.&lt;/strong&gt; &lt;code&gt;enable&lt;/code&gt; defaults to false.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The vector&amp;rsquo;s components, one element per channel. All of them must share a unit. The channel count is fixed by the machine configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the limiter: every component passes straight through. Use it for a runtime override from a supervisor; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The vector, scaled down uniformly if it was too long and unchanged otherwise. Its direction always matches &lt;code&gt;input&lt;/code&gt;. Equals &lt;code&gt;input&lt;/code&gt; exactly while bypassed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the vector is being scaled. &lt;strong&gt;A single value for the whole vector&lt;/strong&gt;, not one per channel — the vector is limited as a whole.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False bypasses the limiter. &lt;strong&gt;Set this, or the block does nothing.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;The maximum vector length, as a &lt;strong&gt;single number for the whole vector&lt;/strong&gt;. 0 collapses the vector to zero. &lt;strong&gt;Not checked — a negative value points the output the opposite way.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both are persistent and survive a controller restart. &lt;strong&gt;No parameters exist
below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Confirm every element of &lt;code&gt;input&lt;/code&gt; carries the same unit. If they do not, this
block cannot limit them together — split them into separate instances.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;upperLimit&lt;/code&gt; to the largest vector length the consumer can accept — for
a Cartesian velocity, the maximum tool speed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;enable&lt;/code&gt; false and confirm &lt;code&gt;output&lt;/code&gt; matches &lt;code&gt;input&lt;/code&gt; element for
element.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true. Command a vector well inside the limit and confirm
&lt;code&gt;output&lt;/code&gt; still matches &lt;code&gt;input&lt;/code&gt; exactly and &lt;code&gt;isLimiting&lt;/code&gt; reads false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a vector longer than the limit. Confirm &lt;code&gt;isLimiting&lt;/code&gt; goes true, and
check the &lt;strong&gt;ratios&lt;/strong&gt; between the output components are unchanged from the
input&amp;rsquo;s.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 is the check that direction is preserved.&lt;/strong&gt; If the ratios change,
something else in the chain is clamping components individually — that is
exactly the behaviour this block exists to replace.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm the output&amp;rsquo;s length equals &lt;code&gt;upperLimit&lt;/code&gt; while limiting.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;There is nothing to tune beyond the one bound.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;upperLimit&lt;/code&gt; from the consumer, not from the signal. For a tool velocity
it is the machine&amp;rsquo;s rated speed; for a force it is what the structure can
take.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;isLimiting&lt;/code&gt; during normal operation. Persistent limiting means
something upstream is commanding more than the machine can deliver, and that
is usually the real problem.&lt;/li&gt;
&lt;li&gt;If individual components also need bounds — a per-axis speed limit as well
as a tool speed limit — add a &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/limiter/&#34;&gt;&lt;code&gt;Limiter&lt;/code&gt;&lt;/a&gt; after this one. Order
matters: this block first keeps the direction, and the per-component clamp
afterwards catches anything still out of range.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/vector-limiter-norm-6b3d78d3.svg&#34; alt=&#34;Length of the output against length of the input at three limits: each linefollows the input until it reaches its limit and is flatbeyond.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read each limit off the height at which its line goes flat.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is limited and &lt;code&gt;isLimiting&lt;/code&gt; stays false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt; defaults to false&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;enable&lt;/code&gt; true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output points the opposite way from the input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt; is negative&lt;/td&gt;
&lt;td&gt;Set it positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output collapses to zero whenever the input moves&lt;/td&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set a positive limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The direction changes when the limit bites&lt;/td&gt;
&lt;td&gt;Not possible in this block — something downstream is clamping components individually&lt;/td&gt;
&lt;td&gt;Check what follows this block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The limit bites at a length that makes no sense&lt;/td&gt;
&lt;td&gt;The vector mixes units, so its computed length is not physical&lt;/td&gt;
&lt;td&gt;Use one instance per unit group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stepped when the block was enabled&lt;/td&gt;
&lt;td&gt;Expected: the block is memoryless and clamps at once&lt;/td&gt;
&lt;td&gt;Enable while the vector is inside the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One component is still too large&lt;/td&gt;
&lt;td&gt;Expected: this block bounds the whole vector&amp;rsquo;s length, not any one component&lt;/td&gt;
&lt;td&gt;Add a per-component limiter after it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; is a single value, not one per channel&lt;/td&gt;
&lt;td&gt;Expected: the vector is limited as a whole&lt;/td&gt;
&lt;td&gt;Use a per-component limiter if you need per-channel flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limiting is persistent during ordinary motion&lt;/td&gt;
&lt;td&gt;The limit is too low, or something upstream is over-commanding&lt;/td&gt;
&lt;td&gt;Check the command before raising the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric component passed straight through&lt;/td&gt;
&lt;td&gt;Expected: the length comparison fails and the block copies through&lt;/td&gt;
&lt;td&gt;Fix the source; the block holds no state and recovers at once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need a minimum length as well&lt;/td&gt;
&lt;td&gt;Not available — a zero-length vector has no direction to grow in&lt;/td&gt;
&lt;td&gt;Handle it upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for bounding a three-axis Cartesian velocity to 0.25 m/s:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable     = true
upperLimit = 0.25
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt; non-negative&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked. A negative value scales every component by a negative factor, so the output points the opposite way&lt;/strong&gt; at the limit&amp;rsquo;s magnitude&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt; = 0&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Any non-zero vector is collapsed to zero&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; reads true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; length&lt;/td&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt; while enabled&lt;/td&gt;
&lt;td&gt;Bounded exactly. Unbounded while &lt;code&gt;enable&lt;/code&gt; is false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;, one flag for the vector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Individual components&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded.&lt;/strong&gt; A long vector along one axis is scaled, but nothing caps any single component on its own&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unit consistency&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked, and cannot be. A vector mixing units has a length with no physical meaning&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lower limit&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;There is none, by design: a zero-length vector has no direction to scale toward&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enabling&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The block is memoryless, so a vector already too long is scaled on the first enabled cycle — a step&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Passes through unchanged. The block is stateless and recovers immediately&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: RateLimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/rate-limiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/rate-limiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RateLimiter&lt;/code&gt; caps how fast a signal may change. Where a limiter bounds a
signal&amp;rsquo;s &lt;strong&gt;value&lt;/strong&gt;, this bounds its &lt;strong&gt;slope&lt;/strong&gt;: the output follows the input
wherever it can, and ramps toward it at no more than &lt;code&gt;rateLimit&lt;/code&gt; per second
wherever it cannot.&lt;/p&gt;
&lt;p&gt;Use it to take a step out of a command — a mode switch, a new setpoint typed in
by an operator, a discontinuous reference — &lt;strong&gt;without a filter&amp;rsquo;s lag&lt;/strong&gt;. Below
the rate limit the output is the input exactly. Only when the limit binds does
the block do anything at all.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — signal to slew&amp;quot;]) --&amp;gt; B[&amp;quot;RateLimiter&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — rate-limited signal&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isLimiting — per channel&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;rateLimit&lt;/code&gt; is in &lt;strong&gt;units per second&lt;/strong&gt;, so a step of height $H$ takes
$H/$&lt;code&gt;rateLimit&lt;/code&gt; seconds to follow. The setting keeps its meaning across task
rates — unlike the sample-counted blocks, nothing needs rescaling if the task
period changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disabling this block lets the signal jump.&lt;/strong&gt; The output snaps to the input on
the same cycle. That is the one thing not to do while the machine is moving —
raise &lt;code&gt;rateLimit&lt;/code&gt; instead until it no longer binds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After a controller start the output ramps up from zero&lt;/strong&gt;, taking
input ÷ &lt;code&gt;rateLimit&lt;/code&gt; seconds to catch up.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to slew. One element per channel; the channel count is fixed by the machine configuration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the block: &lt;code&gt;input&lt;/code&gt; passes straight to &lt;code&gt;output&lt;/code&gt;, &lt;strong&gt;as a step&lt;/strong&gt;. Use it for a runtime override from a supervisor; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The rate-limited signal, one element per channel. Equals &lt;code&gt;input&lt;/code&gt; exactly whenever the input&amp;rsquo;s slope is inside the limit, and while bypassed. &lt;strong&gt;Starts from zero after every controller start&lt;/strong&gt; and is not cleared by a stop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True per channel on cycles where the output was actually clamped. It is exact — no false positives.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false. A single value for the whole block.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;true&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Ships on. False bypasses the block, letting the signal step.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;0 upward, per channel&lt;/td&gt;
&lt;td&gt;The fastest the output may change. Lower is gentler and slower to follow. &lt;strong&gt;0 freezes the output&lt;/strong&gt; where it is. &lt;strong&gt;Not checked — a negative value makes the output run away.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both are persistent and survive a controller restart. &lt;code&gt;rateLimit&lt;/code&gt; is &lt;strong&gt;per
channel&lt;/strong&gt;. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Work out the fastest change the consumer can accept, in units per second.
That is your &lt;code&gt;rateLimit&lt;/code&gt; — it is a property of the machine, not of the
signal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;rateLimit&lt;/code&gt; for every channel. The default of 1.0 is a placeholder.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true and confirm &lt;code&gt;isEnabled&lt;/code&gt; reads true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step the input and time how long &lt;code&gt;output&lt;/code&gt; takes to catch up. It should be
the step height divided by &lt;code&gt;rateLimit&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move the input at a normal working speed and confirm &lt;code&gt;output&lt;/code&gt; tracks it
&lt;strong&gt;exactly&lt;/strong&gt;, with &lt;code&gt;isLimiting&lt;/code&gt; reading false.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 is the check that the limit is not in your way.&lt;/strong&gt; If
&lt;code&gt;isLimiting&lt;/code&gt; is true during normal motion, the limit is shaping every move
and not just the steps — raise it until it only bites on the
discontinuities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element of &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;isLimiting&lt;/code&gt;. Rates are per
channel.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the rate from the machine, not from the signal. It is the slope the
consumer downstream can absorb.&lt;/li&gt;
&lt;li&gt;Confirm it does not bind during normal motion, per Setup step 5. A rate
limiter that is always active has become a slow ramp generator.&lt;/li&gt;
&lt;li&gt;Lower it only until steps are absorbed comfortably. Every reduction also
delays genuine fast movements.&lt;/li&gt;
&lt;li&gt;If you need smoothing as well as slope limiting, add a filter — this block
only bounds the slope, and leaves corners at the start and end of every
ramp.&lt;/li&gt;
&lt;li&gt;If the corners themselves are a problem, you need acceleration limiting, not
rate limiting. A PVA limiter bounds the rate of the rate.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change. The rate is in
units per second and keeps its meaning.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/rate-limiter-step-49347c8d.svg&#34; alt=&#34;Response to a unit step at three rate limits: a rate of 10 reaches 1 in0.1 s, a rate of 2 in 0.5 s, and the default rate of 1 takes a fullsecond.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the rate off the slope of any ramp.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The output ramps up from zero for a while after every start&lt;/td&gt;
&lt;td&gt;Expected: the output starts at zero and slews to the input&lt;/td&gt;
&lt;td&gt;Gate the consumer for input ÷ &lt;code&gt;rateLimit&lt;/code&gt; seconds, or bypass for one cycle to seed it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output jumped when the block was bypassed&lt;/td&gt;
&lt;td&gt;Expected: bypassing assigns the input directly&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;rateLimit&lt;/code&gt; until it no longer binds, then bypass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output froze and will not move&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; is 0 for that channel&lt;/td&gt;
&lt;td&gt;Set a positive rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output runs away in one direction&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; is negative&lt;/td&gt;
&lt;td&gt;Set it positive, then bypass for one cycle to re-seed the output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; is true during ordinary motion&lt;/td&gt;
&lt;td&gt;The rate is too low for normal moves&lt;/td&gt;
&lt;td&gt;Raise it, per Tuning step 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is slower than commanded everywhere&lt;/td&gt;
&lt;td&gt;Same cause&lt;/td&gt;
&lt;td&gt;Raise the rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Steps still reach the consumer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt; is false, &lt;code&gt;disable&lt;/code&gt; is true, or the rate is far above the step&amp;rsquo;s slope&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;isEnabled&lt;/code&gt;; lower &lt;code&gt;rateLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output has sharp corners at the start and end of each ramp&lt;/td&gt;
&lt;td&gt;Expected: this block bounds slope only, not acceleration&lt;/td&gt;
&lt;td&gt;Use a PVA limiter if the corners matter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A sine wave came out as a triangle&lt;/td&gt;
&lt;td&gt;Expected: the rate limit is below the sine&amp;rsquo;s peak slope&lt;/td&gt;
&lt;td&gt;Raise the rate above 2π × frequency × amplitude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One channel slews differently from the others&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;rateLimit&lt;/code&gt; is per channel&lt;/td&gt;
&lt;td&gt;Check every element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The behaviour changed after a task-rate change&lt;/td&gt;
&lt;td&gt;Not possible — the rate is in units per second&lt;/td&gt;
&lt;td&gt;Look elsewhere in the loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stuck at a non-numeric value&lt;/td&gt;
&lt;td&gt;A non-numeric input latched into the output, which then poisons every bound&lt;/td&gt;
&lt;td&gt;Bypass the block for one cycle to clear it, then fix the source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block resumed from an old value after a restart&lt;/td&gt;
&lt;td&gt;Expected: the output is not cleared by a stop&lt;/td&gt;
&lt;td&gt;Bypass for one cycle at start&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for slewing a position command that may move at 0.5 units per
second:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable    = true
rateLimit = 0.5
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; non-negative&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked. A negative value makes the output decrease every cycle without bound.&lt;/strong&gt; Only bypassing the block or a restart clears it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; = 0&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Freezes the output at its current value. This is legitimate and is the way to hold a signal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt; reads true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; slope&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; while enabled&lt;/td&gt;
&lt;td&gt;Bounded exactly, with no overshoot and no lag inside the bound&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;, per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; value&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded — this block limits slope, not magnitude. Follow it with a limiter if the value needs a bound&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disabled behaviour&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Exact pass-through, so the output &lt;strong&gt;steps&lt;/strong&gt; to the input&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output state&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Not cleared at start or stop. There is no reset input — bypassing for one cycle is the only way to re-seed it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Latches permanently: once the output is non-numeric every bound derived from it is too. Bypass for one cycle to clear&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task rate&lt;/td&gt;
&lt;td&gt;Independent&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; is in units per second and keeps its meaning at any task period&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: RateLimiter3D</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/rate-limiter-3d/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/rate-limiter-3d/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;RateLimiter3D&lt;/code&gt; caps how fast a &lt;strong&gt;point in three dimensions&lt;/strong&gt; may move. Each
cycle it moves the output along a straight line toward the target, by no more
than &lt;code&gt;rateLimit&lt;/code&gt; per second.&lt;/p&gt;
&lt;p&gt;It is the vector form of &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/rate-limiter/&#34;&gt;&lt;code&gt;RateLimiter&lt;/code&gt;&lt;/a&gt;, and the difference
matters. Limiting each axis&amp;rsquo;s rate separately makes a diagonal move &lt;strong&gt;bend&lt;/strong&gt; —
the axis that saturates first falls behind while the others carry on, so the
path through space changes and not just its speed. Scaling the whole step keeps
the point travelling in a straight line toward where it was told to go.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;inputs — target point, three values&amp;quot;]) --&amp;gt; B[&amp;quot;RateLimiter3D&amp;quot;]
    B --&amp;gt; o1([&amp;quot;outputs — rate-limited point, three values&amp;quot;])
    B --&amp;gt; o2([&amp;quot;active — true while limiting&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;rateLimit&lt;/code&gt; is the maximum &lt;strong&gt;speed through space&lt;/strong&gt;, in units per second, and
it applies to the whole vector — a diagonal move is limited to the same speed
as a move along one axis. The setting keeps its meaning across task rates.
While the target is close enough to reach in one cycle, the output arrives
exactly and &lt;code&gt;active&lt;/code&gt; reads false.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Both defaults leave the block transparent.&lt;/strong&gt; &lt;code&gt;enable&lt;/code&gt; is false, and
&lt;code&gt;rateLimit&lt;/code&gt; starts at the largest number a double can hold. You must set both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block has no &lt;code&gt;disable&lt;/code&gt; input and no &lt;code&gt;isEnabled&lt;/code&gt; output&lt;/strong&gt;, unlike every
other limiter here. &lt;code&gt;enable&lt;/code&gt; is the only switch, and &lt;code&gt;active&lt;/code&gt; tells you it is
limiting — not that it is switched on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After a controller start the output begins at the origin&lt;/strong&gt; and travels to
wherever &lt;code&gt;inputs&lt;/code&gt; points. On a position command that is a commanded move from
zero — see Limits and errors.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m, or any shared unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The target point, as three values. All three must share a unit for the speed limit to mean anything. Note the path name is plural.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m, or the input unit&lt;/td&gt;
&lt;td&gt;The rate-limited point, three values. It travels toward &lt;code&gt;inputs&lt;/code&gt; in a straight line at no more than &lt;code&gt;rateLimit&lt;/code&gt;, and arrives exactly once the remaining distance fits in one cycle. &lt;strong&gt;Starts at the origin after every controller start&lt;/strong&gt; and is not cleared by a stop. Note the plural path name.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;active&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the step is being scaled — the equivalent of &lt;code&gt;isLimiting&lt;/code&gt; on the other limiters, under a different name. False while the output is keeping up.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False passes &lt;code&gt;inputs&lt;/code&gt; straight to &lt;code&gt;outputs&lt;/code&gt;, as a step. &lt;strong&gt;Set this, or the block does nothing.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unit per second&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;effectively unlimited&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;The maximum speed through space. &lt;strong&gt;The default is so large that the block is transparent even when enabled&lt;/strong&gt; — set a real value. 0 freezes the point. &lt;strong&gt;Not checked — a negative value drives the output away from the target.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both are persistent and survive a controller restart. &lt;strong&gt;No parameters exist
below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Confirm all three elements of &lt;code&gt;inputs&lt;/code&gt; share a unit — three positions in
metres, or three velocities in metres per second. A mixed vector has no
meaningful speed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;rateLimit&lt;/code&gt; to the maximum speed the machine may travel at. The default
is not a limit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a target close to the current point and confirm &lt;code&gt;outputs&lt;/code&gt; reaches it
in one cycle with &lt;code&gt;active&lt;/code&gt; reading false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a distant target and confirm &lt;code&gt;active&lt;/code&gt; goes true, &lt;code&gt;outputs&lt;/code&gt; moves
toward it, and the &lt;strong&gt;ratios between the three components of the remaining
distance stay constant&lt;/strong&gt; — that is what a straight path looks like.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 is the check that the path is straight.&lt;/strong&gt; If the ratios drift,
something downstream is limiting the axes separately, which is exactly
what this block exists to replace.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Time the move and divide the distance travelled by it. That should equal
&lt;code&gt;rateLimit&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Plan for the first cycle after a start.&lt;/strong&gt; The output begins at the origin,
so with a real rate configured the block will command a straight-line move
from zero to the current target. Gate the consumer, or command the machine&amp;rsquo;s
actual position first.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the rate from the machine, not from the signal — it is the fastest the
point may travel.&lt;/li&gt;
&lt;li&gt;Confirm it does not bind during ordinary moves. &lt;code&gt;active&lt;/code&gt; true all the time
means the limit has become the speed governor rather than a safety net.&lt;/li&gt;
&lt;li&gt;If you need the corners of the ramp smoothed as well, this block cannot do
it: it bounds speed, not acceleration. A PVA limiter bounds the rate of the
rate.&lt;/li&gt;
&lt;li&gt;If individual axes also need a bound, add a per-axis limiter &lt;strong&gt;after&lt;/strong&gt; this
one — this block keeps the direction, and the per-axis clamp catches
anything still out of range.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change. The rate is in
units per second.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/rate-limiter-3d-step-fb03fd06.svg&#34; alt=&#34;Vector length approaching a unit-length target at three rate limits: a rateof 10 arrives in 0.1 s, 2 in 0.5 s and 1 in a fullsecond.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the speed off the slope of any ramp.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is limited and &lt;code&gt;active&lt;/code&gt; stays false&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt; is false, or &lt;code&gt;rateLimit&lt;/code&gt; is still at its enormous default&lt;/td&gt;
&lt;td&gt;Set both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine made a long move immediately after a restart&lt;/td&gt;
&lt;td&gt;Expected: the output starts at the origin and travels to the target&lt;/td&gt;
&lt;td&gt;Command the machine&amp;rsquo;s actual position first, or gate the consumer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output moves away from the target&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; is negative&lt;/td&gt;
&lt;td&gt;Set it positive, then disable for one cycle to re-seed the output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output froze&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set a positive rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The path bends instead of running straight&lt;/td&gt;
&lt;td&gt;Not possible in this block — something downstream is limiting the axes separately&lt;/td&gt;
&lt;td&gt;Check what follows this block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The point jumped when the block was disabled&lt;/td&gt;
&lt;td&gt;Expected: disabling assigns the target directly&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;rateLimit&lt;/code&gt; until it no longer binds, then disable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;active&lt;/code&gt; is true during ordinary moves&lt;/td&gt;
&lt;td&gt;The rate is too low for normal motion&lt;/td&gt;
&lt;td&gt;Raise it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The speed limit bites at a value that makes no sense&lt;/td&gt;
&lt;td&gt;The three inputs do not share a unit&lt;/td&gt;
&lt;td&gt;Use this block only on a vector with one unit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;There is no way to override the block at runtime&lt;/td&gt;
&lt;td&gt;Expected: there is no &lt;code&gt;disable&lt;/code&gt; input&lt;/td&gt;
&lt;td&gt;Write &lt;code&gt;enable&lt;/code&gt; false, or raise &lt;code&gt;rateLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot tell whether the block is switched on&lt;/td&gt;
&lt;td&gt;Expected: there is no &lt;code&gt;isEnabled&lt;/code&gt; output. &lt;code&gt;active&lt;/code&gt; means limiting, not enabled&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;enable&lt;/code&gt; back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The path has sharp corners at the start and end&lt;/td&gt;
&lt;td&gt;Expected: this block bounds speed only&lt;/td&gt;
&lt;td&gt;Use a PVA limiter if the corners matter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The outputs stuck at a non-numeric value&lt;/td&gt;
&lt;td&gt;A non-numeric input latched into the output, which then poisons every step&lt;/td&gt;
&lt;td&gt;Disable for one cycle to clear it, then fix the source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for limiting a Cartesian position command to 0.25 m/s:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable    = true
rateLimit = 0.25
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; non-negative&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked. A negative value drives the output away from the target, without bound.&lt;/strong&gt; Only disabling the block or a restart clears it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; = 0&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Freezes the point where it is&lt;/td&gt;
&lt;td&gt;&lt;code&gt;active&lt;/code&gt; reads true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; default&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Effectively unlimited, so an enabled but unconfigured block is transparent&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed through space&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rateLimit&lt;/code&gt; while enabled&lt;/td&gt;
&lt;td&gt;Bounded exactly, with the direction preserved&lt;/td&gt;
&lt;td&gt;&lt;code&gt;active&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Individual axes&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded.&lt;/strong&gt; This block limits the vector&amp;rsquo;s speed, not any one axis&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Position&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded — this block limits speed, not travel. Follow it with a limiter if the value needs a bound&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup position&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The output starts at the &lt;strong&gt;origin&lt;/strong&gt;, not at the current target. There is no reset input&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disabled behaviour&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Exact pass-through, so the point &lt;strong&gt;steps&lt;/strong&gt; to the target&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime override&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;There is no &lt;code&gt;disable&lt;/code&gt; input and no &lt;code&gt;isEnabled&lt;/code&gt; output&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Latches permanently — once an output is non-numeric every step derived from it is too. Disable for one cycle to clear&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dimensions&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Always three channels. It cannot be resized&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PVALimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter-3.30/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter-3.30/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version c3-version--archived&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter-3.30/&#34; selected&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;
    Superseded. The current release is
    &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;3.34&lt;/a&gt;.
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PVALimiter&lt;/code&gt; shapes a position command so the motion it produces respects a
position range, a velocity limit and an acceleration limit &lt;strong&gt;all at once&lt;/strong&gt;. It
outputs a matching position, velocity and acceleration, so whatever follows it
gets a consistent set.&lt;/p&gt;
&lt;p&gt;Its most useful behaviour is at the position limits. Instead of clamping the
position — which arrives as a wall and demands an impossible deceleration — it
works out, every cycle, the fastest it could be going and still stop in time,
and holds the velocity below that. The axis &lt;strong&gt;decelerates into the limit and
arrives at zero speed&lt;/strong&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — position reference&amp;quot;]) --&amp;gt; B[&amp;quot;PVALimiter&amp;quot;]
    i2([&amp;quot;inputDot — velocity reference&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — acceleration reference&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — limited position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — limited velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — limited acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;currentMaxVel — allowed velocity now&amp;quot;])
    B --&amp;gt; o5([&amp;quot;currentMinVel&amp;quot;])
    B --&amp;gt; o6([&amp;quot;pLimActive&amp;quot;])
    B --&amp;gt; o7([&amp;quot;vLimActive&amp;quot;])
    B --&amp;gt; o8([&amp;quot;aLimActive&amp;quot;])
    B --&amp;gt; o9([&amp;quot;state&amp;quot;])
    B --&amp;gt; o10([&amp;quot;inputFilt, inputFiltDot, inputFiltDDot&amp;quot;])
    B --&amp;gt; o11([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Approaching a limit, the allowed velocity is
$\sqrt{2 \times \text{distance} \times \texttt{maxBrakingAcceleration}}$ —
so at 0.1 m from the limit with a braking limit of 10, the axis may travel at
1.4 m/s. &lt;code&gt;omega&lt;/code&gt; and &lt;code&gt;beta&lt;/code&gt; set how hard the block chases the input:
higher &lt;code&gt;omega&lt;/code&gt; tracks more tightly, and &lt;code&gt;beta&lt;/code&gt; 4 is heavily damped so it does
not overshoot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; at or below &lt;code&gt;maxAcceleration&lt;/code&gt;.&lt;/strong&gt; The block sizes
its approach speed on the braking figure but can only ever deliver the
acceleration figure. Setting braking higher promises a stop the block cannot
perform, and the axis overshoots the limit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every instance logs a warning at startup with default settings.&lt;/strong&gt; &lt;code&gt;omega&lt;/code&gt;
ships at infinity, meaning &amp;ldquo;as fast as possible&amp;rdquo;, and the block corrects it to
what the task rate allows — and says so in the log. It is expected.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The position reference to shape.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The velocity reference. &lt;strong&gt;Only used when &lt;code&gt;enablePVAInputs&lt;/code&gt; is set&lt;/strong&gt;; ignored otherwise.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The acceleration reference. Same condition.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the block: &lt;code&gt;input&lt;/code&gt; passes straight to &lt;code&gt;output&lt;/code&gt;. Use it for a runtime override; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The limited position. &lt;strong&gt;Starts from zero after every controller start&lt;/strong&gt; and moves to the input under its own limits — a real commanded move if the input is not near zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The limited velocity. It is &lt;strong&gt;not&lt;/strong&gt; updated while the block is bypassed, so it holds a stale value from before.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The limited acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currentMaxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The fastest the block will currently allow, given how close the axis is to the upper limit. &lt;strong&gt;The single most useful output for understanding why the axis slowed down.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currentMinVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The same toward the lower limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the position envelope is holding the velocity down.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the velocity limit is binding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the acceleration limit is binding — &lt;strong&gt;but it is forced false whenever either of the other two is true&lt;/strong&gt;, so it under-reports.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The same three flags again, grouped.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputFilt&lt;/code&gt;, &lt;code&gt;inputFiltDot&lt;/code&gt;, &lt;code&gt;inputFiltDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m, m/s, m/s²&lt;/td&gt;
&lt;td&gt;The block&amp;rsquo;s internal smoothed copy of the input. Only meaningful while &lt;code&gt;enablePVAInputs&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False bypasses the block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;−1.0&lt;/td&gt;
&lt;td&gt;below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The lowest position the output may reach.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;+1.0&lt;/td&gt;
&lt;td&gt;above &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The highest.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Speed limit. Negative values are used as their magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;10.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How hard the block may accelerate &lt;strong&gt;or&lt;/strong&gt; decelerate in practice. Used as its magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;10.0&lt;/td&gt;
&lt;td&gt;at most &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How hard the block &lt;strong&gt;assumes&lt;/strong&gt; it can brake, when sizing the approach to a position limit. &lt;strong&gt;Set it at or below &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rad/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;infinity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 up to a task-rate ceiling&lt;/td&gt;
&lt;td&gt;Tracking bandwidth. Higher follows the input more tightly. The infinite default means &amp;ldquo;as fast as the task rate allows&amp;rdquo; and is corrected at startup with a logged warning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;beta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Tracking damping. 4 is heavily damped and does not overshoot. Lowering it makes the output chase harder and eventually ring.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePLim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Switches the position envelope &lt;strong&gt;and&lt;/strong&gt; the hard position clamp on. False leaves only the velocity and acceleration limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePVAInputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False: the block derives velocity and acceleration internally from &lt;code&gt;input&lt;/code&gt; alone. True: it uses &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt;. &lt;strong&gt;This changes how the block tracks, not just what it reads&lt;/strong&gt; — decide once and leave it.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All ten are persistent and survive a restart. &lt;strong&gt;No parameters exist below this
block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt; to the axis&amp;rsquo;s real travel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxVelocity&lt;/code&gt; and &lt;code&gt;maxAcceleration&lt;/code&gt; from the machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; &lt;strong&gt;equal to or below&lt;/strong&gt; &lt;code&gt;maxAcceleration&lt;/code&gt;. Equal
is the normal choice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;omega&lt;/code&gt; alone. It corrects itself at startup and logs that it did.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;beta&lt;/code&gt; at 4 and &lt;code&gt;enablePVAInputs&lt;/code&gt; false for a first pass.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true. Command a small move well inside the limits and confirm
&lt;code&gt;output&lt;/code&gt; follows &lt;code&gt;input&lt;/code&gt; closely with all three flags false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a fast move and watch &lt;code&gt;vLimActive&lt;/code&gt; and &lt;code&gt;aLimActive&lt;/code&gt; go true in turn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit. Watch &lt;code&gt;currentMaxVel&lt;/code&gt; fall
as the axis approaches, and confirm the axis &lt;strong&gt;arrives at the limit with
&lt;code&gt;outputDot&lt;/code&gt; at zero&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 8 drives the axis into its travel limit deliberately.&lt;/strong&gt; Do it at
low speed first, and confirm the deceleration is inside what the machine
can take before repeating it at full speed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the three machine limits first — position, velocity, acceleration. They
are properties of the hardware.&lt;/li&gt;
&lt;li&gt;Keep braking at or below acceleration, per Setup step 3. This is the one
parameter relationship the block does not check and it is the one that
causes overshoot.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;omega&lt;/code&gt; at its default unless the output visibly lags the input during
ordinary moves. It is already as fast as the task rate allows.&lt;/li&gt;
&lt;li&gt;Lower &lt;code&gt;beta&lt;/code&gt; only if the block is too slow to catch a fast input. Below
about 1 it starts to overshoot, which for a limiter is the wrong direction.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;enablePVAInputs&lt;/code&gt; when your source already produces a consistent
position, velocity and acceleration — a setpoint generator, say. It lets the
block follow without having to infer the derivatives, so it tracks much more
closely. Do not switch it at runtime.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;currentMaxVel&lt;/code&gt; during a limit approach. It is the envelope, and it
tells you directly whether &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is set sensibly: a
larger value gives a steeper, later deceleration.&lt;/li&gt;
&lt;li&gt;If you need jerk limited as well, this block does not do it — use a PVAJ
limiter.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/pva-limiter-envelope-94256123.svg&#34; alt=&#34;Highest allowed velocity against distance to the position limit, at threebraking accelerations: each curve is a square root rising from zero at thelimit, and all three flatten at the velocitylimit.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the allowed speed at any distance off the curve for your braking setting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A warning about &lt;code&gt;omega&lt;/code&gt; at every startup&lt;/td&gt;
&lt;td&gt;Expected: the default is infinity and the block corrects it&lt;/td&gt;
&lt;td&gt;Ignore it, or set a finite &lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis overshoots its position limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is higher than &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set it at or below the acceleration limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis stops well short of the limit and creeps in&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is very low, so the envelope is conservative&lt;/td&gt;
&lt;td&gt;Raise it, up to &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis slows down and nothing seems to be limiting&lt;/td&gt;
&lt;td&gt;The position envelope is active — check &lt;code&gt;pLimActive&lt;/code&gt; and &lt;code&gt;currentMaxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is the block working as designed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt; never goes true&lt;/td&gt;
&lt;td&gt;Expected: it is suppressed whenever the position or velocity limit is also active&lt;/td&gt;
&lt;td&gt;Watch all three flags together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output lags the input during ordinary moves&lt;/td&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt; too low, or &lt;code&gt;beta&lt;/code&gt; too high&lt;/td&gt;
&lt;td&gt;Leave &lt;code&gt;omega&lt;/code&gt; alone and try &lt;code&gt;enablePVAInputs&lt;/code&gt; if your source provides derivatives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output overshoots the input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;beta&lt;/code&gt; too low&lt;/td&gt;
&lt;td&gt;Raise it back toward 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking changed when &lt;code&gt;enablePVAInputs&lt;/code&gt; was switched&lt;/td&gt;
&lt;td&gt;Expected: it changes how the block tracks, not just what it reads&lt;/td&gt;
&lt;td&gt;Choose one mode and keep it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; seem to be ignored&lt;/td&gt;
&lt;td&gt;Expected: they are only read when &lt;code&gt;enablePVAInputs&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;Set that parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis made a move immediately after a restart&lt;/td&gt;
&lt;td&gt;Expected: the output starts at zero and travels to the input under its limits&lt;/td&gt;
&lt;td&gt;Command the machine&amp;rsquo;s actual position first, or gate the consumer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The velocity output is wrong just after re-enabling&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;outputDot&lt;/code&gt; is not updated while bypassed and resumes from a stale value&lt;/td&gt;
&lt;td&gt;Re-enable at rest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The position stopped at the limit but the velocity output is not zero&lt;/td&gt;
&lt;td&gt;The hard backstop clamped the position without zeroing the velocity — the envelope did not do its job&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; against &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is jerky at the start and end of moves&lt;/td&gt;
&lt;td&gt;Expected: this block bounds acceleration, not jerk&lt;/td&gt;
&lt;td&gt;Use a PVAJ limiter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value latched into the outputs&lt;/td&gt;
&lt;td&gt;The block holds state and there is no reset&lt;/td&gt;
&lt;td&gt;Bypass the block for one cycle to recover the position; restart to clear the velocity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for an axis with 1 m of travel, 1 m/s and 10 m/s² on a 1 ms
task:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable                 = true
lowerLimit             = -0.5
upperLimit             = 0.5
maxVelocity            = 1.0
maxAcceleration        = 10.0
maxBrakingAcceleration = 10.0
beta                   = 4.0
enablePLim             = true
enablePVAInputs        = false
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt; at most &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked.&lt;/strong&gt; A higher braking figure makes the block approach the limit faster than it can stop, and the axis &lt;strong&gt;overshoots&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt; while &lt;code&gt;enablePLim&lt;/code&gt; is set&lt;/td&gt;
&lt;td&gt;Bounded two ways: the velocity envelope decelerates the axis in, and a hard clamp catches anything the envelope missed. The clamp does &lt;strong&gt;not&lt;/strong&gt; zero the velocity, so the two outputs can disagree on that cycle&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxVelocity&lt;/code&gt;, and the position envelope&lt;/td&gt;
&lt;td&gt;Bounded by whichever is lower&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vLimActive&lt;/code&gt;, &lt;code&gt;currentMaxVel&lt;/code&gt;, &lt;code&gt;currentMinVel&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clamped&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt;, &lt;strong&gt;but it is suppressed whenever the position or velocity limit is also active&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jerk&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not limited.&lt;/strong&gt; Acceleration can step&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Task rate and &lt;code&gt;beta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Corrected to a stable value at startup and on every cycle. The infinite default always triggers this&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged as a warning&lt;/strong&gt; each time it corrects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;beta&lt;/code&gt;, &lt;code&gt;maxVelocity&lt;/code&gt;, &lt;code&gt;maxAcceleration&lt;/code&gt;, &lt;code&gt;maxBrakingAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sign forced&lt;/td&gt;
&lt;td&gt;Negative values are used as their magnitude&lt;/td&gt;
&lt;td&gt;Not reported; read them back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero acceleration limits&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Either at exactly zero forces the allowed velocity to zero, stopping the axis where it stands&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;The output position and velocity are &lt;strong&gt;not cleared at start&lt;/strong&gt; and there is no reset input. Bypassing recovers the position but not the velocity&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;One axis per instance. Use the plural block for several&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block logs a warning whenever it corrects &lt;code&gt;omega&lt;/code&gt; or &lt;code&gt;beta&lt;/code&gt; — which with
the default settings happens once at startup for every instance. Every other
failure above shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PVALimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34; selected&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter-3.30/&#34;&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;Current release&lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PVALimiter&lt;/code&gt; shapes a position command so the motion it produces respects a
position range, a velocity limit and an acceleration limit &lt;strong&gt;all at once&lt;/strong&gt;. It
outputs a matching position, velocity and acceleration, so whatever follows it
gets a consistent set.&lt;/p&gt;
&lt;p&gt;Its most useful behaviour is at the position limits. Instead of clamping the
position — which arrives as a wall and demands an impossible deceleration — it
works out, every cycle, the fastest it could be going and still stop in time,
and holds the velocity below that. The axis &lt;strong&gt;decelerates into the limit and
arrives at zero speed&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Deprecated — scheduled for removal.&lt;/strong&gt; &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt; is
the only setpoint limiter that may be used for new work. It bounds the
setpoint in jerk as well as position, velocity and acceleration, and its
position guarantee holds &lt;strong&gt;with no tolerance&lt;/strong&gt; where this block&amp;rsquo;s holds to
about 1e-9. This block is kept only until the last machine is off it, and
will then be deleted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;It is not a drop-in swap.&lt;/strong&gt; The replacement has no input filter, so &lt;code&gt;omega&lt;/code&gt;,
&lt;code&gt;beta&lt;/code&gt; and &lt;code&gt;enablePVAInputs&lt;/code&gt; have no counterpart. Feed it the position setpoint
directly and supply the derivatives on its own &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt;
leaves, each behind its own switch. See
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt; for the parameter reference.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — position reference&amp;quot;]) --&amp;gt; B[&amp;quot;PVALimiter&amp;quot;]
    i2([&amp;quot;inputDot — velocity reference&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — acceleration reference&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — limited position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — limited velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — limited acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;currentMaxVel — allowed velocity now&amp;quot;])
    B --&amp;gt; o5([&amp;quot;currentMinVel&amp;quot;])
    B --&amp;gt; o6([&amp;quot;pLimActive&amp;quot;])
    B --&amp;gt; o7([&amp;quot;vLimActive&amp;quot;])
    B --&amp;gt; o8([&amp;quot;aLimActive&amp;quot;])
    B --&amp;gt; o9([&amp;quot;state&amp;quot;])
    B --&amp;gt; o10([&amp;quot;inputFilt, inputFiltDot, inputFiltDDot&amp;quot;])
    B --&amp;gt; o11([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Approaching a limit, the allowed velocity is
$\sqrt{2 \times \text{distance} \times \texttt{maxBrakingAcceleration}}$ —
so at 0.1 m from the limit with a braking limit of 10, the axis may travel at
1.4 m/s. &lt;code&gt;omega&lt;/code&gt; and &lt;code&gt;beta&lt;/code&gt; set how hard the block chases the input:
higher &lt;code&gt;omega&lt;/code&gt; tracks more tightly, and &lt;code&gt;beta&lt;/code&gt; 4 is heavily damped so it does
not overshoot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; at or below &lt;code&gt;maxAcceleration&lt;/code&gt;.&lt;/strong&gt; The block sizes
its approach speed on the braking figure but can only ever deliver the
acceleration figure. Setting braking higher promises a stop the block cannot
perform, and the axis overshoots the limit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every instance logs a warning at startup with default settings.&lt;/strong&gt; &lt;code&gt;omega&lt;/code&gt;
ships at infinity, meaning &amp;ldquo;as fast as possible&amp;rdquo;, and the block corrects it to
what the task rate allows — and says so in the log. It is expected.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The position reference to shape.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The velocity reference. &lt;strong&gt;Only used when &lt;code&gt;enablePVAInputs&lt;/code&gt; is set&lt;/strong&gt;; ignored otherwise.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The acceleration reference. Same condition.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the block: &lt;code&gt;input&lt;/code&gt; passes straight to &lt;code&gt;output&lt;/code&gt;. Use it for a runtime override; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The limited position. &lt;strong&gt;Starts from zero after every controller start&lt;/strong&gt; and moves to the input under its own limits — a real commanded move if the input is not near zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The limited velocity. It is &lt;strong&gt;not&lt;/strong&gt; updated while the block is bypassed, so it holds a stale value from before.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The limited acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currentMaxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The fastest the block will currently allow, given how close the axis is to the upper limit. &lt;strong&gt;The single most useful output for understanding why the axis slowed down.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currentMinVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The same toward the lower limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the position envelope is holding the velocity down.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the velocity limit is binding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while the acceleration limit is binding — &lt;strong&gt;but it is forced false whenever either of the other two is true&lt;/strong&gt;, so it under-reports.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The same three flags again, grouped.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputFilt&lt;/code&gt;, &lt;code&gt;inputFiltDot&lt;/code&gt;, &lt;code&gt;inputFiltDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m, m/s, m/s²&lt;/td&gt;
&lt;td&gt;The block&amp;rsquo;s internal smoothed copy of the input. Only meaningful while &lt;code&gt;enablePVAInputs&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False bypasses the block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;−1.0&lt;/td&gt;
&lt;td&gt;below &lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The lowest position the output may reach.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;+1.0&lt;/td&gt;
&lt;td&gt;above &lt;code&gt;lowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The highest.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Speed limit. Negative values are used as their magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;10.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How hard the block may accelerate &lt;strong&gt;or&lt;/strong&gt; decelerate in practice. Used as its magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;10.0&lt;/td&gt;
&lt;td&gt;at most &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How hard the block &lt;strong&gt;assumes&lt;/strong&gt; it can brake, when sizing the approach to a position limit. &lt;strong&gt;Set it at or below &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rad/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;infinity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 up to a task-rate ceiling&lt;/td&gt;
&lt;td&gt;Tracking bandwidth. Higher follows the input more tightly. The infinite default means &amp;ldquo;as fast as the task rate allows&amp;rdquo; and is corrected at startup with a logged warning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;beta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Tracking damping. 4 is heavily damped and does not overshoot. Lowering it makes the output chase harder and eventually ring.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePLim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Switches the position envelope &lt;strong&gt;and&lt;/strong&gt; the hard position clamp on. False leaves only the velocity and acceleration limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePVAInputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False: the block derives velocity and acceleration internally from &lt;code&gt;input&lt;/code&gt; alone. True: it uses &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt;. &lt;strong&gt;This changes how the block tracks, not just what it reads&lt;/strong&gt; — decide once and leave it.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All ten are persistent and survive a restart. &lt;strong&gt;No parameters exist below this
block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;lowerLimit&lt;/code&gt; and &lt;code&gt;upperLimit&lt;/code&gt; to the axis&amp;rsquo;s real travel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxVelocity&lt;/code&gt; and &lt;code&gt;maxAcceleration&lt;/code&gt; from the machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; &lt;strong&gt;equal to or below&lt;/strong&gt; &lt;code&gt;maxAcceleration&lt;/code&gt;. Equal
is the normal choice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;omega&lt;/code&gt; alone. It corrects itself at startup and logs that it did.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;beta&lt;/code&gt; at 4 and &lt;code&gt;enablePVAInputs&lt;/code&gt; false for a first pass.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true. Command a small move well inside the limits and confirm
&lt;code&gt;output&lt;/code&gt; follows &lt;code&gt;input&lt;/code&gt; closely with all three flags false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a fast move and watch &lt;code&gt;vLimActive&lt;/code&gt; and &lt;code&gt;aLimActive&lt;/code&gt; go true in turn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit. Watch &lt;code&gt;currentMaxVel&lt;/code&gt; fall
as the axis approaches, and confirm the axis &lt;strong&gt;arrives at the limit with
&lt;code&gt;outputDot&lt;/code&gt; at zero&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 8 drives the axis into its travel limit deliberately.&lt;/strong&gt; Do it at
low speed first, and confirm the deceleration is inside what the machine
can take before repeating it at full speed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the three machine limits first — position, velocity, acceleration. They
are properties of the hardware.&lt;/li&gt;
&lt;li&gt;Keep braking at or below acceleration, per Setup step 3. This is the one
parameter relationship the block does not check and it is the one that
causes overshoot.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;omega&lt;/code&gt; at its default unless the output visibly lags the input during
ordinary moves. It is already as fast as the task rate allows.&lt;/li&gt;
&lt;li&gt;Lower &lt;code&gt;beta&lt;/code&gt; only if the block is too slow to catch a fast input. Below
about 1 it starts to overshoot, which for a limiter is the wrong direction.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;enablePVAInputs&lt;/code&gt; when your source already produces a consistent
position, velocity and acceleration — a setpoint generator, say. It lets the
block follow without having to infer the derivatives, so it tracks much more
closely. Do not switch it at runtime.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;currentMaxVel&lt;/code&gt; during a limit approach. It is the envelope, and it
tells you directly whether &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is set sensibly: a
larger value gives a steeper, later deceleration.&lt;/li&gt;
&lt;li&gt;If you need jerk limited as well, this block does not do it — use a PVAJ
limiter.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/pva-limiter-envelope-94256123.svg&#34; alt=&#34;Highest allowed velocity against distance to the position limit, at threebraking accelerations: each curve is a square root rising from zero at thelimit, and all three flatten at the velocitylimit.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the allowed speed at any distance off the curve for your braking setting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A warning about &lt;code&gt;omega&lt;/code&gt; at every startup&lt;/td&gt;
&lt;td&gt;Expected: the default is infinity and the block corrects it&lt;/td&gt;
&lt;td&gt;Ignore it, or set a finite &lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis overshoots its position limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is higher than &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set it at or below the acceleration limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis stops well short of the limit and creeps in&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is very low, so the envelope is conservative&lt;/td&gt;
&lt;td&gt;Raise it, up to &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis slows down and nothing seems to be limiting&lt;/td&gt;
&lt;td&gt;The position envelope is active — check &lt;code&gt;pLimActive&lt;/code&gt; and &lt;code&gt;currentMaxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is the block working as designed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt; never goes true&lt;/td&gt;
&lt;td&gt;Expected: it is suppressed whenever the position or velocity limit is also active&lt;/td&gt;
&lt;td&gt;Watch all three flags together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output lags the input during ordinary moves&lt;/td&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt; too low, or &lt;code&gt;beta&lt;/code&gt; too high&lt;/td&gt;
&lt;td&gt;Leave &lt;code&gt;omega&lt;/code&gt; alone and try &lt;code&gt;enablePVAInputs&lt;/code&gt; if your source provides derivatives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output overshoots the input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;beta&lt;/code&gt; too low&lt;/td&gt;
&lt;td&gt;Raise it back toward 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking changed when &lt;code&gt;enablePVAInputs&lt;/code&gt; was switched&lt;/td&gt;
&lt;td&gt;Expected: it changes how the block tracks, not just what it reads&lt;/td&gt;
&lt;td&gt;Choose one mode and keep it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; seem to be ignored&lt;/td&gt;
&lt;td&gt;Expected: they are only read when &lt;code&gt;enablePVAInputs&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;Set that parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis made a move immediately after a restart&lt;/td&gt;
&lt;td&gt;Expected: the output starts at zero and travels to the input under its limits&lt;/td&gt;
&lt;td&gt;Command the machine&amp;rsquo;s actual position first, or gate the consumer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The velocity output is wrong just after re-enabling&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;outputDot&lt;/code&gt; is not updated while bypassed and resumes from a stale value&lt;/td&gt;
&lt;td&gt;Re-enable at rest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The position stopped at the limit but the velocity output is not zero&lt;/td&gt;
&lt;td&gt;The hard backstop clamped the position without zeroing the velocity — the envelope did not do its job&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; against &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is jerky at the start and end of moves&lt;/td&gt;
&lt;td&gt;Expected: this block bounds acceleration, not jerk&lt;/td&gt;
&lt;td&gt;Use a PVAJ limiter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value latched into the outputs&lt;/td&gt;
&lt;td&gt;The block holds state and there is no reset&lt;/td&gt;
&lt;td&gt;Bypass the block for one cycle to recover the position; restart to clear the velocity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for an axis with 1 m of travel, 1 m/s and 10 m/s² on a 1 ms
task:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable                 = true
lowerLimit             = -0.5
upperLimit             = 0.5
maxVelocity            = 1.0
maxAcceleration        = 10.0
maxBrakingAcceleration = 10.0
beta                   = 4.0
enablePLim             = true
enablePVAInputs        = false
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxBrakingAcceleration&lt;/code&gt; at most &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked.&lt;/strong&gt; A higher braking figure makes the block approach the limit faster than it can stop, and the axis &lt;strong&gt;overshoots&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt; while &lt;code&gt;enablePLim&lt;/code&gt; is set&lt;/td&gt;
&lt;td&gt;Bounded two ways: the velocity envelope decelerates the axis in, and a hard clamp catches anything the envelope missed. The clamp does &lt;strong&gt;not&lt;/strong&gt; zero the velocity, so the two outputs can disagree on that cycle&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxVelocity&lt;/code&gt;, and the position envelope&lt;/td&gt;
&lt;td&gt;Bounded by whichever is lower&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vLimActive&lt;/code&gt;, &lt;code&gt;currentMaxVel&lt;/code&gt;, &lt;code&gt;currentMinVel&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clamped&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt;, &lt;strong&gt;but it is suppressed whenever the position or velocity limit is also active&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jerk&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not limited.&lt;/strong&gt; Acceleration can step&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Task rate and &lt;code&gt;beta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Corrected to a stable value at startup and on every cycle. The infinite default always triggers this&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged as a warning&lt;/strong&gt; each time it corrects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;beta&lt;/code&gt;, &lt;code&gt;maxVelocity&lt;/code&gt;, &lt;code&gt;maxAcceleration&lt;/code&gt;, &lt;code&gt;maxBrakingAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sign forced&lt;/td&gt;
&lt;td&gt;Negative values are used as their magnitude&lt;/td&gt;
&lt;td&gt;Not reported; read them back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero acceleration limits&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Either at exactly zero forces the allowed velocity to zero, stopping the axis where it stands&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;The output position and velocity are &lt;strong&gt;not cleared at start&lt;/strong&gt; and there is no reset input. Bypassing recovers the position but not the velocity&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;One axis per instance. Use the plural block for several&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block logs a warning whenever it corrects &lt;code&gt;omega&lt;/code&gt; or &lt;code&gt;beta&lt;/code&gt; — which with
the default settings happens once at startup for every instance. Every other
failure above shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.32.1 (340db23).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PVALimiters</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters-3.30/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters-3.30/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version c3-version--archived&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters/&#34;&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters-3.30/&#34; selected&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;
    Superseded. The current release is
    &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters/&#34;&gt;3.34&lt;/a&gt;.
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PVALimiters&lt;/code&gt; is the multi-axis form of &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt;. It
takes array inputs, runs one independent limiter per channel, and returns array
outputs — so a multi-axis machine presents one block instead of several.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each channel keeps its own limits.&lt;/strong&gt; Every axis has a complete parameter set
in its own sub-tree: its own travel range, speed, acceleration and tracking
settings. This block only fans the signals out and gathers them back.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;inputs — position references&amp;quot;]) --&amp;gt; B[&amp;quot;PVALimiters&amp;quot;]
    i2([&amp;quot;inputsDot — velocity references&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputsDDot — acceleration references&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;outputs — limited positions&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputsDot — limited velocities&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputsDDot — limited accelerations&amp;quot;])
    B --&amp;gt; o4([&amp;quot;pLimActive&amp;quot;])
    B --&amp;gt; o5([&amp;quot;vLimActive&amp;quot;])
    B --&amp;gt; o6([&amp;quot;aLimActive&amp;quot;])
    B --&amp;gt; o7([&amp;quot;state&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Each channel behaves exactly as &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt; describes,
including the square-root velocity envelope that decelerates an axis into its
position limit. &lt;strong&gt;Read that page for the tuning&lt;/strong&gt; — everything below is about
the wrapper.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The three limiting flags are combined across channels.&lt;/strong&gt; &lt;code&gt;pLimActive&lt;/code&gt; true
means &lt;em&gt;some&lt;/em&gt; axis is at its position envelope; it does not say which. To find
out, read the same flag inside each channel&amp;rsquo;s own sub-tree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;inputsDDot&lt;/code&gt; has no effect.&lt;/strong&gt; The acceleration array is accepted and ignored
— the sub-limiters never receive it. Leave it unlinked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable, no disable and no &lt;code&gt;isEnabled&lt;/code&gt;.&lt;/strong&gt; To bypass one
axis, use &lt;code&gt;disable&lt;/code&gt; inside that channel&amp;rsquo;s own sub-tree.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Position references, one element per channel. Note the plural path names throughout this block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Velocity references. They reach each channel&amp;rsquo;s limiter, and are used only where that channel has its own &lt;code&gt;enablePVAInputs&lt;/code&gt; set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Accepted and ignored.&lt;/strong&gt; The acceleration array does not reach the per-channel limiters. Leave it unlinked.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The limited positions, one element per channel. Each starts from zero after a controller start and moves to its input under that channel&amp;rsquo;s limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputsDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The limited velocities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputsDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The limited accelerations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while &lt;strong&gt;at least one&lt;/strong&gt; channel is being held back by its position envelope.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while at least one channel is at its speed limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while at least one channel is at its acceleration limit. Like the single-axis block, it is suppressed on any channel where a position or velocity limit is also active, so it under-reports.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The same three flags again, grouped.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;There are no parameters at this level.&lt;/strong&gt; Everything is configured per
channel, in the sub-trees &lt;code&gt;pvaLimiter01&lt;/code&gt;, &lt;code&gt;pvaLimiter02&lt;/code&gt; and so on — one per
channel, numbered from 1 and always two digits.&lt;/p&gt;
&lt;p&gt;Each of those carries the full set described in
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;: &lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt;, &lt;code&gt;maxVelocity&lt;/code&gt;,
&lt;code&gt;maxAcceleration&lt;/code&gt;, &lt;code&gt;maxBrakingAcceleration&lt;/code&gt;, &lt;code&gt;omega&lt;/code&gt;, &lt;code&gt;beta&lt;/code&gt;, &lt;code&gt;enable&lt;/code&gt;,
&lt;code&gt;disable&lt;/code&gt;, &lt;code&gt;enablePLim&lt;/code&gt; and &lt;code&gt;enablePVAInputs&lt;/code&gt;, along with that channel&amp;rsquo;s own
outputs and diagnostics.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read the length of &lt;code&gt;inputs&lt;/code&gt; from the parameter tree and confirm it matches
your axis count. It is fixed when the machine is built.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure &lt;strong&gt;each&lt;/strong&gt; channel&amp;rsquo;s sub-tree separately: travel limits, speed and
acceleration for that axis. There is no shared setting — an axis you forget
keeps the defaults of ±1, 1 m/s and 10 m/s².&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; at or below &lt;code&gt;maxAcceleration&lt;/code&gt; in every channel.
This is the one relationship that silently causes overshoot, per axis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link &lt;code&gt;inputs&lt;/code&gt; and, if your source produces them, &lt;code&gt;inputsDot&lt;/code&gt;. Leave
&lt;code&gt;inputsDDot&lt;/code&gt; unlinked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a small move on one axis and confirm only that channel&amp;rsquo;s &lt;code&gt;outputs&lt;/code&gt;
element responds.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 is the check that the channels are independent.&lt;/strong&gt; If moving one
axis changes another&amp;rsquo;s output, the arrays are wired in the wrong order —
and every limit you set afterwards will be applied to the wrong axis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit on one axis. Confirm
&lt;code&gt;pLimActive&lt;/code&gt; goes true here, and that the same flag is true in that
channel&amp;rsquo;s own sub-tree and false in the others.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Expect one startup warning per channel about &lt;code&gt;omega&lt;/code&gt;. It is normal — see
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;All the tuning is per channel and is described in
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;. What is specific to this block:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tune one axis at a time, in its own sub-tree, with the others held still.
The aggregate flags cannot tell you which axis is limiting.&lt;/li&gt;
&lt;li&gt;Keep a written record of which sub-tree is which axis. The numbering starts
at 1 and the array indices start at 0, so &lt;code&gt;pvaLimiter01&lt;/code&gt; is element 0.&lt;/li&gt;
&lt;li&gt;When the aggregate &lt;code&gt;pLimActive&lt;/code&gt; goes true unexpectedly, walk the sub-trees
and read each channel&amp;rsquo;s own &lt;code&gt;pLimActive&lt;/code&gt; to find the axis. There is no
faster route.&lt;/li&gt;
&lt;li&gt;Watch each channel&amp;rsquo;s &lt;code&gt;currentMaxVel&lt;/code&gt; during a limit approach — it is the
most informative signal in the block and there is one per axis.&lt;/li&gt;
&lt;li&gt;If several axes should move together and stop together, note that this block
does &lt;strong&gt;not&lt;/strong&gt; coordinate them: each is limited independently, so a limited
axis falls behind and the path through space changes. Coordinate upstream if
that matters.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/pva-limiters-step-b0a64c45.svg&#34; alt=&#34;One channel following a 0.9 step: the position rises and settles at 0.9, thevelocity ramps up, holds at the 1.0 limit and returns to zero, and theacceleration saturates at both ends of themove.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read each channel&amp;rsquo;s behaviour the same way; the axes do not interact.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One axis behaves nothing like the others&lt;/td&gt;
&lt;td&gt;That channel&amp;rsquo;s sub-tree was never configured, so it holds the defaults&lt;/td&gt;
&lt;td&gt;Configure every channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moving one axis changed another&amp;rsquo;s output&lt;/td&gt;
&lt;td&gt;The arrays are wired in the wrong order&lt;/td&gt;
&lt;td&gt;Check the link order against the sub-tree numbering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt; is true and no axis looks limited&lt;/td&gt;
&lt;td&gt;Some axis is — the flag is combined across all of them&lt;/td&gt;
&lt;td&gt;Read the same flag inside each channel&amp;rsquo;s sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDDot&lt;/code&gt; seems to have no effect&lt;/td&gt;
&lt;td&gt;Expected: it is not forwarded to the per-channel limiters&lt;/td&gt;
&lt;td&gt;Leave it unlinked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An axis overshoots its position limit&lt;/td&gt;
&lt;td&gt;That channel&amp;rsquo;s &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is above its &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fix it in that channel&amp;rsquo;s sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Several axes fall out of step during a coordinated move&lt;/td&gt;
&lt;td&gt;Expected: each axis is limited independently and a limited one falls behind&lt;/td&gt;
&lt;td&gt;Coordinate the motion upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One warning per axis at every startup&lt;/td&gt;
&lt;td&gt;Expected: each channel&amp;rsquo;s limiter corrects its own default &lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignore, or set a finite &lt;code&gt;omega&lt;/code&gt; in each sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot switch the whole block off&lt;/td&gt;
&lt;td&gt;Expected: there is no enable at this level&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;disable&lt;/code&gt; inside each channel&amp;rsquo;s sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axes all made a move after a restart&lt;/td&gt;
&lt;td&gt;Expected: each output starts at zero and travels to its input&lt;/td&gt;
&lt;td&gt;Command actual positions first, or gate the consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The sub-tree numbering does not match my axis numbering&lt;/td&gt;
&lt;td&gt;The sub-trees are numbered from 1; array elements from 0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pvaLimiter01&lt;/code&gt; is element 0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There is no block-level starting point to give — configure each channel from
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;&amp;rsquo;s starting point, with that axis&amp;rsquo;s own
travel, speed and acceleration.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Every per-channel limit&lt;/td&gt;
&lt;td&gt;Each channel&amp;rsquo;s own sub-tree&lt;/td&gt;
&lt;td&gt;Position, velocity and acceleration are bounded independently per axis, exactly as the single-axis block describes&lt;/td&gt;
&lt;td&gt;That channel&amp;rsquo;s own flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not forwarded&lt;/td&gt;
&lt;td&gt;Accepted, stored, and never used&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate flags&lt;/td&gt;
&lt;td&gt;Combined&lt;/td&gt;
&lt;td&gt;Each is true when &lt;strong&gt;any&lt;/strong&gt; channel&amp;rsquo;s is. The channel is not identified&lt;/td&gt;
&lt;td&gt;Not reported; read the per-channel flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block-level enable&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;There is no &lt;code&gt;enable&lt;/code&gt;, &lt;code&gt;disable&lt;/code&gt; or &lt;code&gt;isEnabled&lt;/code&gt; at this level&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coordination between axes&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Each axis is limited on its own. A limited axis falls behind and a multi-axis path is distorted&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts. Read the array lengths to discover it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything else&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;See &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;, which applies per channel&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block itself raises no errors or warnings. Each channel&amp;rsquo;s limiter logs a
warning when it corrects its own &lt;code&gt;omega&lt;/code&gt;, which with default settings happens
once per channel at startup.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PVALimiters</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters/&#34; selected&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiters-3.30/&#34;&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;Current release&lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PVALimiters&lt;/code&gt; is the multi-axis form of &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt;. It
takes array inputs, runs one independent limiter per channel, and returns array
outputs — so a multi-axis machine presents one block instead of several.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each channel keeps its own limits.&lt;/strong&gt; Every axis has a complete parameter set
in its own sub-tree: its own travel range, speed, acceleration and tracking
settings. This block only fans the signals out and gathers them back.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Deprecated — scheduled for removal.&lt;/strong&gt; &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt; is
the only setpoint limiter that may be used for new work, and it is natively
multi-channel: one instance limits N axes, with every limit, switch and
diagnostic per channel. &lt;strong&gt;This wrapper has no counterpart to port&lt;/strong&gt; — give
the replacement the channel count instead. This block is kept only until the
last machine is off it, and will then be deleted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The per-channel migration is the one described on
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt;: the replacement has no input filter, so feed it
the setpoint directly and supply the derivatives on its own leaves.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;inputs — position references&amp;quot;]) --&amp;gt; B[&amp;quot;PVALimiters&amp;quot;]
    i2([&amp;quot;inputsDot — velocity references&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputsDDot — acceleration references&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;outputs — limited positions&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputsDot — limited velocities&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputsDDot — limited accelerations&amp;quot;])
    B --&amp;gt; o4([&amp;quot;pLimActive&amp;quot;])
    B --&amp;gt; o5([&amp;quot;vLimActive&amp;quot;])
    B --&amp;gt; o6([&amp;quot;aLimActive&amp;quot;])
    B --&amp;gt; o7([&amp;quot;state&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Each channel behaves exactly as &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt; describes,
including the square-root velocity envelope that decelerates an axis into its
position limit. &lt;strong&gt;Read that page for the tuning&lt;/strong&gt; — everything below is about
the wrapper.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The three limiting flags are combined across channels.&lt;/strong&gt; &lt;code&gt;pLimActive&lt;/code&gt; true
means &lt;em&gt;some&lt;/em&gt; axis is at its position envelope; it does not say which. To find
out, read the same flag inside each channel&amp;rsquo;s own sub-tree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;inputsDDot&lt;/code&gt; has no effect.&lt;/strong&gt; The acceleration array is accepted and ignored
— the sub-limiters never receive it. Leave it unlinked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable, no disable and no &lt;code&gt;isEnabled&lt;/code&gt;.&lt;/strong&gt; To bypass one
axis, use &lt;code&gt;disable&lt;/code&gt; inside that channel&amp;rsquo;s own sub-tree.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Position references, one element per channel. Note the plural path names throughout this block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Velocity references. They reach each channel&amp;rsquo;s limiter, and are used only where that channel has its own &lt;code&gt;enablePVAInputs&lt;/code&gt; set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Accepted and ignored.&lt;/strong&gt; The acceleration array does not reach the per-channel limiters. Leave it unlinked.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The limited positions, one element per channel. Each starts from zero after a controller start and moves to its input under that channel&amp;rsquo;s limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputsDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The limited velocities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputsDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The limited accelerations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while &lt;strong&gt;at least one&lt;/strong&gt; channel is being held back by its position envelope.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while at least one channel is at its speed limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aLimActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True while at least one channel is at its acceleration limit. Like the single-axis block, it is suppressed on any channel where a position or velocity limit is also active, so it under-reports.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The same three flags again, grouped.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;There are no parameters at this level.&lt;/strong&gt; Everything is configured per
channel, in the sub-trees &lt;code&gt;pvaLimiter01&lt;/code&gt;, &lt;code&gt;pvaLimiter02&lt;/code&gt; and so on — one per
channel, numbered from 1 and always two digits.&lt;/p&gt;
&lt;p&gt;Each of those carries the full set described in
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;: &lt;code&gt;lowerLimit&lt;/code&gt;, &lt;code&gt;upperLimit&lt;/code&gt;, &lt;code&gt;maxVelocity&lt;/code&gt;,
&lt;code&gt;maxAcceleration&lt;/code&gt;, &lt;code&gt;maxBrakingAcceleration&lt;/code&gt;, &lt;code&gt;omega&lt;/code&gt;, &lt;code&gt;beta&lt;/code&gt;, &lt;code&gt;enable&lt;/code&gt;,
&lt;code&gt;disable&lt;/code&gt;, &lt;code&gt;enablePLim&lt;/code&gt; and &lt;code&gt;enablePVAInputs&lt;/code&gt;, along with that channel&amp;rsquo;s own
outputs and diagnostics.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read the length of &lt;code&gt;inputs&lt;/code&gt; from the parameter tree and confirm it matches
your axis count. It is fixed when the machine is built.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure &lt;strong&gt;each&lt;/strong&gt; channel&amp;rsquo;s sub-tree separately: travel limits, speed and
acceleration for that axis. There is no shared setting — an axis you forget
keeps the defaults of ±1, 1 m/s and 10 m/s².&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; at or below &lt;code&gt;maxAcceleration&lt;/code&gt; in every channel.
This is the one relationship that silently causes overshoot, per axis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link &lt;code&gt;inputs&lt;/code&gt; and, if your source produces them, &lt;code&gt;inputsDot&lt;/code&gt;. Leave
&lt;code&gt;inputsDDot&lt;/code&gt; unlinked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a small move on one axis and confirm only that channel&amp;rsquo;s &lt;code&gt;outputs&lt;/code&gt;
element responds.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 is the check that the channels are independent.&lt;/strong&gt; If moving one
axis changes another&amp;rsquo;s output, the arrays are wired in the wrong order —
and every limit you set afterwards will be applied to the wrong axis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit on one axis. Confirm
&lt;code&gt;pLimActive&lt;/code&gt; goes true here, and that the same flag is true in that
channel&amp;rsquo;s own sub-tree and false in the others.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Expect one startup warning per channel about &lt;code&gt;omega&lt;/code&gt;. It is normal — see
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;All the tuning is per channel and is described in
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;. What is specific to this block:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tune one axis at a time, in its own sub-tree, with the others held still.
The aggregate flags cannot tell you which axis is limiting.&lt;/li&gt;
&lt;li&gt;Keep a written record of which sub-tree is which axis. The numbering starts
at 1 and the array indices start at 0, so &lt;code&gt;pvaLimiter01&lt;/code&gt; is element 0.&lt;/li&gt;
&lt;li&gt;When the aggregate &lt;code&gt;pLimActive&lt;/code&gt; goes true unexpectedly, walk the sub-trees
and read each channel&amp;rsquo;s own &lt;code&gt;pLimActive&lt;/code&gt; to find the axis. There is no
faster route.&lt;/li&gt;
&lt;li&gt;Watch each channel&amp;rsquo;s &lt;code&gt;currentMaxVel&lt;/code&gt; during a limit approach — it is the
most informative signal in the block and there is one per axis.&lt;/li&gt;
&lt;li&gt;If several axes should move together and stop together, note that this block
does &lt;strong&gt;not&lt;/strong&gt; coordinate them: each is limited independently, so a limited
axis falls behind and the path through space changes. Coordinate upstream if
that matters.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/pva-limiters-step-b0a64c45.svg&#34; alt=&#34;One channel following a 0.9 step: the position rises and settles at 0.9, thevelocity ramps up, holds at the 1.0 limit and returns to zero, and theacceleration saturates at both ends of themove.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read each channel&amp;rsquo;s behaviour the same way; the axes do not interact.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One axis behaves nothing like the others&lt;/td&gt;
&lt;td&gt;That channel&amp;rsquo;s sub-tree was never configured, so it holds the defaults&lt;/td&gt;
&lt;td&gt;Configure every channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moving one axis changed another&amp;rsquo;s output&lt;/td&gt;
&lt;td&gt;The arrays are wired in the wrong order&lt;/td&gt;
&lt;td&gt;Check the link order against the sub-tree numbering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pLimActive&lt;/code&gt; is true and no axis looks limited&lt;/td&gt;
&lt;td&gt;Some axis is — the flag is combined across all of them&lt;/td&gt;
&lt;td&gt;Read the same flag inside each channel&amp;rsquo;s sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDDot&lt;/code&gt; seems to have no effect&lt;/td&gt;
&lt;td&gt;Expected: it is not forwarded to the per-channel limiters&lt;/td&gt;
&lt;td&gt;Leave it unlinked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An axis overshoots its position limit&lt;/td&gt;
&lt;td&gt;That channel&amp;rsquo;s &lt;code&gt;maxBrakingAcceleration&lt;/code&gt; is above its &lt;code&gt;maxAcceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fix it in that channel&amp;rsquo;s sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Several axes fall out of step during a coordinated move&lt;/td&gt;
&lt;td&gt;Expected: each axis is limited independently and a limited one falls behind&lt;/td&gt;
&lt;td&gt;Coordinate the motion upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One warning per axis at every startup&lt;/td&gt;
&lt;td&gt;Expected: each channel&amp;rsquo;s limiter corrects its own default &lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignore, or set a finite &lt;code&gt;omega&lt;/code&gt; in each sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot switch the whole block off&lt;/td&gt;
&lt;td&gt;Expected: there is no enable at this level&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;disable&lt;/code&gt; inside each channel&amp;rsquo;s sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axes all made a move after a restart&lt;/td&gt;
&lt;td&gt;Expected: each output starts at zero and travels to its input&lt;/td&gt;
&lt;td&gt;Command actual positions first, or gate the consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The sub-tree numbering does not match my axis numbering&lt;/td&gt;
&lt;td&gt;The sub-trees are numbered from 1; array elements from 0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pvaLimiter01&lt;/code&gt; is element 0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There is no block-level starting point to give — configure each channel from
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;&amp;rsquo;s starting point, with that axis&amp;rsquo;s own
travel, speed and acceleration.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Every per-channel limit&lt;/td&gt;
&lt;td&gt;Each channel&amp;rsquo;s own sub-tree&lt;/td&gt;
&lt;td&gt;Position, velocity and acceleration are bounded independently per axis, exactly as the single-axis block describes&lt;/td&gt;
&lt;td&gt;That channel&amp;rsquo;s own flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputsDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not forwarded&lt;/td&gt;
&lt;td&gt;Accepted, stored, and never used&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate flags&lt;/td&gt;
&lt;td&gt;Combined&lt;/td&gt;
&lt;td&gt;Each is true when &lt;strong&gt;any&lt;/strong&gt; channel&amp;rsquo;s is. The channel is not identified&lt;/td&gt;
&lt;td&gt;Not reported; read the per-channel flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block-level enable&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;There is no &lt;code&gt;enable&lt;/code&gt;, &lt;code&gt;disable&lt;/code&gt; or &lt;code&gt;isEnabled&lt;/code&gt; at this level&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coordination between axes&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Each axis is limited on its own. A limited axis falls behind and a multi-axis path is distorted&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts. Read the array lengths to discover it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything else&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;See &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;pva-limiter.md&lt;/code&gt;&lt;/a&gt;, which applies per channel&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block itself raises no errors or warnings. Each channel&amp;rsquo;s limiter logs a
warning when it corrects its own &lt;code&gt;omega&lt;/code&gt;, which with default settings happens
once per channel at startup.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.32.1 (340db23).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PvajLimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.30/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.30/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version c3-version--archived&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.34/&#34;&gt;3.32–3.34&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.30/&#34; selected&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;
    Superseded. The current release is
    &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;3.34&lt;/a&gt;.
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PvajLimiter&lt;/code&gt; bounds a position setpoint in &lt;strong&gt;jerk, acceleration, velocity and
position at the same time&lt;/strong&gt;, and guarantees the position limits are never
crossed. The output satisfies &lt;code&gt;positionLowerLimit&lt;/code&gt; ≤ output ≤
&lt;code&gt;positionUpperLimit&lt;/code&gt; exactly — not to within a margin.&lt;/p&gt;
&lt;p&gt;It replaces &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt; for new work. That block tracks with
a filter and clamps acceleration; this one plans a trajectory and bounds jerk
as well, so motion starts and stops without the corners that shake a machine.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — raw position setpoint&amp;quot;]) --&amp;gt; B[&amp;quot;PvajLimiter&amp;quot;]
    i2([&amp;quot;inputDot — setpoint velocity&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — setpoint acceleration&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — bounded position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;outputDDDot — jerk&amp;quot;])
    B --&amp;gt; o5([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each channel also publishes its own status group under &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;
and so on: &lt;code&gt;isLimiting&lt;/code&gt;, the four per-limit flags, &lt;code&gt;predictedStop&lt;/code&gt;, &lt;code&gt;viable&lt;/code&gt;,
&lt;code&gt;softEntryActive&lt;/code&gt;, &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, the two
active position limits, and a &lt;code&gt;debug/&lt;/code&gt; group.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A full stop from &lt;code&gt;velocityLimit&lt;/code&gt; needs
$V^2/2A_b + V A_b/2J_b$ of travel, with $A_b$ and $J_b$ the braking
authority. &lt;strong&gt;If twice that does not fit between your position limits&lt;/strong&gt;, some
states inside the box can no longer be stopped in time — the block tells you
so through &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt; rather than refusing the
settings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every parameter can be changed while the machine is running&lt;/strong&gt;, and the change
takes effect on the very next cycle. A setting that is nonsense on its own — a
non-positive limit, or an inverted box — is refused and reported in &lt;code&gt;status&lt;/code&gt;,
and the limiter keeps running on the last good set. &lt;strong&gt;A bad edit is ignored; it
never leaves the setpoint unbounded.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block bounds the setpoint, not the machine.&lt;/strong&gt; The axis follows through a
servo loop with a following error, so the mechanism will pass the limit by
roughly that error. Back your limits off by the certified worst case.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The raw position setpoint. A non-numeric value is treated as a fault upstream and the previous setpoint is held.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The setpoint&amp;rsquo;s own velocity. &lt;strong&gt;Only used where that channel&amp;rsquo;s &lt;code&gt;enableInputDot&lt;/code&gt; is set.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The setpoint&amp;rsquo;s own acceleration. &lt;strong&gt;Only used where &lt;code&gt;enableInputDDot&lt;/code&gt; is set&lt;/strong&gt;, and only supply it if it is exact — see Tuning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True passes &lt;code&gt;input&lt;/code&gt; straight to &lt;code&gt;output&lt;/code&gt; and slaves the internal state to it, so re-enabling is bumpless. Use it for a runtime override; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The bounded position setpoint. &lt;strong&gt;Never outside the position limits.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;Its velocity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;Its jerk. While the block is bypassed this is estimated by difference rather than left at zero, so a feedforward consumer does not see it vanish.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Per channel, under &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, …:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any clamp shaped the output this cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The setpoint is outside the box, or the stopping test clamped the motion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt;, &lt;code&gt;accelerationLimitActive&lt;/code&gt;, &lt;code&gt;jerkLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;That limit is binding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activePositionLowerLimit&lt;/code&gt;, &lt;code&gt;activePositionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The bounds actually in force, which differ from the configured ones while soft entry is ratcheting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;predictedStop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where a full brake from the current state would come to rest.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;False when the current state can no longer be stopped inside the box.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The limit set cannot be guaranteed with the authority in force. Describes the &lt;strong&gt;settings&lt;/strong&gt;, not the current state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;softEntryActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A limit is ratcheted to the state because the state is outside it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The result of the last settings check. Non-zero means an edit was refused.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;debug/error&lt;/code&gt;, &lt;code&gt;debug/errorDot&lt;/code&gt;, &lt;code&gt;debug/errorDDot&lt;/code&gt;, &lt;code&gt;debug/targetActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Indicative only.&lt;/strong&gt; These explain what the limiter did. &lt;strong&gt;Do not wire them into logic&lt;/strong&gt; — the signals a supervisor may act on are the ones above.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;p&gt;Block level: &lt;code&gt;enable&lt;/code&gt; (default true).&lt;/p&gt;
&lt;p&gt;Per channel, under &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, …:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;−1.0&lt;/td&gt;
&lt;td&gt;below the upper&lt;/td&gt;
&lt;td&gt;The box. Never crossed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;+1.0&lt;/td&gt;
&lt;td&gt;above the lower&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;20.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;400.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Symmetric. Lower rounds the corners of every move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAccelerationBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;at least &lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Elevated authority for defending the position limits. &lt;strong&gt;0 means &amp;ldquo;inherit &lt;code&gt;accelerationLimit&lt;/code&gt;&amp;quot;&lt;/strong&gt;, and stays 0 so it keeps following it. A value below the normal limit is raised, and the raise is written back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxJerkBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;at least &lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same rule.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;inputDot&lt;/code&gt; instead of differencing &lt;code&gt;input&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;inputDDot&lt;/code&gt;. &lt;strong&gt;Only set this if the value is exact&lt;/strong&gt; — see Tuning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePositionLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False leaves the box effectively unbounded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;0 – 1&lt;/td&gt;
&lt;td&gt;How far ahead the tracking target is placed. 1 is the full lead, 0 turns the feedforward off. Trades overshoot of the commanded amplitude against tracking lag. Corrected silently if out of range.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableSoftEntry&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;When the state is already outside a limit, ratchet that limit to the state so only motion that makes the violation worse is forbidden.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;defendLimitsHard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Spend the elevated braking authority in normal operation rather than keeping it as a backstop. Costs a step in commanded acceleration when the reference crosses a limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preventPositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Size the braking authority automatically so overshoot cannot happen. &lt;strong&gt;Read the braking values back afterwards&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a restart.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read how many channels this instance has, and note that the sub-trees are
numbered from 1 — &lt;code&gt;Limits01&lt;/code&gt; is array element 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set each channel&amp;rsquo;s box, &lt;code&gt;velocityLimit&lt;/code&gt;, &lt;code&gt;accelerationLimit&lt;/code&gt; and &lt;code&gt;jerkLimit&lt;/code&gt;
from the machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the stopping arithmetic: $V^2/2A + VA/2J$, doubled, against the width
of your box. If it does not fit, &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;
will be true — lower &lt;code&gt;velocityLimit&lt;/code&gt; until it clears.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave the braking values at 0 for now, so they follow the normal limits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave both input switches off and &lt;code&gt;feedforwardGain&lt;/code&gt; at 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link &lt;code&gt;input&lt;/code&gt; and set &lt;code&gt;enable&lt;/code&gt; true. Command a move and confirm &lt;code&gt;output&lt;/code&gt;
follows, &lt;code&gt;status&lt;/code&gt; reads zero, and &lt;code&gt;viable&lt;/code&gt; stays true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit. Confirm &lt;code&gt;output&lt;/code&gt; &lt;strong&gt;stops at
the limit exactly&lt;/strong&gt; and &lt;code&gt;positionLimitActive&lt;/code&gt; goes true.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 7 drives the axis into its travel limit.&lt;/strong&gt; The setpoint is
guaranteed; the machine is not — it will pass the limit by its following
error. Do this at low speed first and back the limits off by that error.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If your motion source publishes its own velocity, set &lt;code&gt;enableInputDot&lt;/code&gt; and
confirm tracking improves.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the four limits from the machine first. They are hardware properties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lower &lt;code&gt;jerkLimit&lt;/code&gt; to smooth the motion&lt;/strong&gt;, raise it to sharpen it. This is
the knob this block has and &lt;code&gt;PVALimiter&lt;/code&gt; does not, and it is what removes
the corners at the start and end of every move.&lt;/li&gt;
&lt;li&gt;Supply the setpoint&amp;rsquo;s own derivatives if you have them. The improvement is
large and measured: on a 0.2 m 1 Hz sine, differencing the input gives
1.9e-2 m of error, &lt;code&gt;inputDot&lt;/code&gt; alone gives 1.8e-2 m, and &lt;strong&gt;&lt;code&gt;inputDot&lt;/code&gt; plus
&lt;code&gt;inputDDot&lt;/code&gt; gives 8.0e-8 m&lt;/strong&gt; — five orders of magnitude.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only set &lt;code&gt;enableInputDDot&lt;/code&gt; if the acceleration is exact.&lt;/strong&gt; An acceleration
differenced from an input carrying a millimetre of noise measured
6.5e-2 m — three times &lt;em&gt;worse&lt;/em&gt; than leaving it off. If your generator does
not produce a true acceleration, leave the switch off.&lt;/li&gt;
&lt;li&gt;Lower &lt;code&gt;feedforwardGain&lt;/code&gt; toward 0 if the output overshoots the commanded
amplitude; raise it toward 1 if the output lags. That is the whole trade.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reserve the braking authority explicitly&lt;/strong&gt; — set &lt;code&gt;maxAccelerationBraking&lt;/code&gt;
and &lt;code&gt;maxJerkBraking&lt;/code&gt; above the normal limits — if you will ever retune
&lt;code&gt;accelerationLimit&lt;/code&gt; on a running axis. See Limits and errors for why.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;defendLimitsHard&lt;/code&gt; only if you want the extra authority spent in normal
operation. It costs a step in commanded acceleration at the limit.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt; after every limits edit. It
describes the settings, so it answers &amp;ldquo;can this configuration ever be
guaranteed&amp;rdquo; — &lt;code&gt;viable&lt;/code&gt; answers &amp;ldquo;can the axis be stopped from where it is
right now&amp;rdquo;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/pvajlimiter-jerk-6be2edfb.svg&#34; alt=&#34;Accelerating to 2 m/s at three jerk limits with an acceleration limit of 20:a jerk of 1000 reaches speed in 0.12 s with nearly square corners, 200 takes0.19 s, and 50 takes 0.38 s and never reaches the accelerationlimit.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the effect of the jerk limit off how rounded each curve&amp;rsquo;s corners are.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt; is non-zero and a limits edit did nothing&lt;/td&gt;
&lt;td&gt;The edit was nonsense on its own — a non-positive limit or an inverted box&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;status&lt;/code&gt;, fix the value; the limiter is still running on the last good set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;A full stop from &lt;code&gt;velocityLimit&lt;/code&gt; does not fit in the box twice over&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;velocityLimit&lt;/code&gt;, raise the braking authority, or set &lt;code&gt;preventPositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt; went false&lt;/td&gt;
&lt;td&gt;The axis cannot be stopped inside the box from where it is now&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;predictedStop&lt;/code&gt; to see how far past it will go; this usually follows a limits narrowing under a moving setpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The guarantee was lost after tightening &lt;code&gt;accelerationLimit&lt;/code&gt; mid-move&lt;/td&gt;
&lt;td&gt;A setpoint already moving fast near a limit cannot be stopped once the limits are lowered — arithmetic, not a fault&lt;/td&gt;
&lt;td&gt;Reserve &lt;code&gt;maxAccelerationBraking&lt;/code&gt; and &lt;code&gt;maxJerkBraking&lt;/code&gt; explicitly so they do not follow the normal limits down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is jerky at the start and end of moves&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt; too high&lt;/td&gt;
&lt;td&gt;Lower it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moves take too long&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt; or &lt;code&gt;accelerationLimit&lt;/code&gt; too low&lt;/td&gt;
&lt;td&gt;Raise them, then re-check step 3 of Setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking lags the input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt; too low, or the derivative switches are off&lt;/td&gt;
&lt;td&gt;Raise the gain toward 1; supply &lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output overshoots the commanded amplitude&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt; too high&lt;/td&gt;
&lt;td&gt;Lower it toward 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking got &lt;strong&gt;worse&lt;/strong&gt; after enabling &lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The acceleration being supplied is estimated, not exact&lt;/td&gt;
&lt;td&gt;Turn the switch off; a differenced acceleration is worse than none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine passed the position limit&lt;/td&gt;
&lt;td&gt;Expected: the &lt;strong&gt;setpoint&lt;/strong&gt; is guaranteed, not the mechanism&lt;/td&gt;
&lt;td&gt;Back the limits off by the servo&amp;rsquo;s worst-case following error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A step in commanded acceleration when crossing a limit&lt;/td&gt;
&lt;td&gt;Expected with &lt;code&gt;defendLimitsHard&lt;/code&gt; set&lt;/td&gt;
&lt;td&gt;Clear it to keep the extra authority as a backstop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;softEntryActive&lt;/code&gt; is true and the axis is moving oddly&lt;/td&gt;
&lt;td&gt;The state is outside a limit, so only motion reducing the violation is allowed&lt;/td&gt;
&lt;td&gt;Expected during recovery; it clears once the state is back inside&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The braking values read back higher than written&lt;/td&gt;
&lt;td&gt;Expected: a value below the normal limit is raised, and the raise is written back&lt;/td&gt;
&lt;td&gt;Write a value above the normal limit, or leave it at 0 to inherit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A braking value left at 0 stayed 0&lt;/td&gt;
&lt;td&gt;Expected and deliberate: 0 means &amp;ldquo;inherit&amp;rdquo;, and keeps following the normal limit&lt;/td&gt;
&lt;td&gt;Set a number if you want it fixed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The &lt;code&gt;debug/&lt;/code&gt; values look wrong&lt;/td&gt;
&lt;td&gt;They are indicative only and are not part of the contract&lt;/td&gt;
&lt;td&gt;Use the top-level status signals instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric setpoint did not disturb the output&lt;/td&gt;
&lt;td&gt;Expected: the previous setpoint is held&lt;/td&gt;
&lt;td&gt;Fix the source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a 1 m axis on a 1 ms task, with the braking authority
reserved so limits can be retuned safely:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable = true
Limits01/positionLowerLimit     = -0.5
Limits01/positionUpperLimit     =  0.5
Limits01/velocityLimit          =  1.0
Limits01/accelerationLimit      = 10.0
Limits01/jerkLimit              = 200.0
Limits01/maxAccelerationBraking = 20.0
Limits01/maxJerkBraking         = 400.0
Limits01/enableInputDot         = false
Limits01/enableInputDDot        = false
Limits01/feedforwardGain        = 1.0
Limits01/enableSoftEntry        = true
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position&lt;/td&gt;
&lt;td&gt;The box&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Guaranteed, with no tolerance.&lt;/strong&gt; The setpoint never leaves the limits&lt;/td&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;, &lt;code&gt;activePositionLowerLimit&lt;/code&gt;, &lt;code&gt;activePositionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; velocity, acceleration, jerk&lt;/td&gt;
&lt;td&gt;Their limits&lt;/td&gt;
&lt;td&gt;Bounded&lt;/td&gt;
&lt;td&gt;The three matching flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settings validity&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A non-positive velocity, acceleration or jerk limit, or an inverted box, is &lt;strong&gt;refused&lt;/strong&gt;; the limiter keeps running on the last valid set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Achievability&lt;/td&gt;
&lt;td&gt;Reported, not refused&lt;/td&gt;
&lt;td&gt;A limit set whose stop does not fit in the box is accepted and flagged&lt;/td&gt;
&lt;td&gt;&lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current state&lt;/td&gt;
&lt;td&gt;Reported&lt;/td&gt;
&lt;td&gt;Whether the axis can still be stopped inside the box from where it is&lt;/td&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt;, &lt;code&gt;predictedStop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Narrowing limits under a moving setpoint&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Arithmetic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A setpoint moving fast near a limit &lt;strong&gt;cannot&lt;/strong&gt; be stopped once the limits are lowered. The limiter brakes at everything it is allowed and reports &lt;code&gt;viable&lt;/code&gt; false throughout. &lt;strong&gt;Reserving the braking authority explicitly removes the hazard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt;, &lt;code&gt;predictedStop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preventPositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic sizing&lt;/td&gt;
&lt;td&gt;Commands whatever braking authority the arithmetic demands, &lt;strong&gt;which may exceed what the drive can deliver.&lt;/strong&gt; Authority the machine does not have is authority the guarantee does not have&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;maxAccelerationBraking&lt;/code&gt; and &lt;code&gt;maxJerkBraking&lt;/code&gt; back and check them against the axis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The mechanism&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;This block bounds the &lt;strong&gt;setpoint&lt;/strong&gt;. The machine passes the limit by its servo following error&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Braking authority&lt;/td&gt;
&lt;td&gt;Inheritance&lt;/td&gt;
&lt;td&gt;0 inherits the normal limit and stays 0; a value below it is raised and written back&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task period&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Recorded as part of the settings check. A task-rate change re-triggers validation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts. Sub-trees are numbered from 1&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every condition above
is published as a signal you can trace or wire into a supervisor.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PvajLimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.34/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.34/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version c3-version--archived&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.34/&#34; selected&gt;3.32–3.34&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.30/&#34;&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;
    Superseded. The current release is
    &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;3.34&lt;/a&gt;.
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PvajLimiter&lt;/code&gt; bounds a position setpoint in &lt;strong&gt;jerk, acceleration, velocity and
position at the same time&lt;/strong&gt;, and guarantees the position limits are never
crossed. The output satisfies &lt;code&gt;positionLowerLimit&lt;/code&gt; ≤ output ≤
&lt;code&gt;positionUpperLimit&lt;/code&gt; exactly — not to within a margin.&lt;/p&gt;
&lt;p&gt;It replaces &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt; for new work. That block tracks with
a filter and clamps acceleration; this one plans a trajectory and bounds jerk
as well, so motion starts and stops without the corners that shake a machine.
It also runs as a &lt;strong&gt;velocity limiter&lt;/strong&gt; driven by &lt;code&gt;inputDot&lt;/code&gt;. Even then it
brings the axis to rest on a position limit rather than through it.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — raw position setpoint&amp;quot;]) --&amp;gt; B[&amp;quot;PvajLimiter&amp;quot;]
    i2([&amp;quot;inputDot — setpoint velocity&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — setpoint acceleration&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — bounded position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;outputDDDot — jerk&amp;quot;])
    B --&amp;gt; o5([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each channel also publishes its own status group under &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;
and so on: &lt;code&gt;isLimiting&lt;/code&gt;, the four per-limit flags, &lt;code&gt;predictedStop&lt;/code&gt;, &lt;code&gt;viable&lt;/code&gt;,
&lt;code&gt;softEntryActive&lt;/code&gt;, &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, the two
active position limits, and a &lt;code&gt;debug/&lt;/code&gt; group.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A full stop from &lt;code&gt;velocityLimit&lt;/code&gt; needs
$V^2/2A_b + V A_b/2J_b$ of travel, with $A_b$ and $J_b$ the braking
authority. &lt;strong&gt;If twice that does not fit between your position limits&lt;/strong&gt;, some
states inside the box can no longer be stopped in time — the block tells you
so through &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt; rather than refusing the
settings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every parameter can be changed while the machine is running&lt;/strong&gt;, and the change
takes effect on the very next cycle. A setting that is nonsense on its own — a
non-positive limit, or an inverted box — is refused and reported in &lt;code&gt;status&lt;/code&gt;,
and the limiter keeps running on the last good set. &lt;strong&gt;A bad edit is ignored; it
never leaves the setpoint unbounded.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block bounds the setpoint, not the machine.&lt;/strong&gt; The axis follows through a
servo loop with a following error, so the mechanism will pass the limit by
roughly that error. Back your limits off by the certified worst case.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The raw position setpoint. A non-numeric value is treated as a fault upstream and the previous setpoint is held. &lt;strong&gt;Not read at all where that channel&amp;rsquo;s &lt;code&gt;enableInput&lt;/code&gt; is false.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The setpoint&amp;rsquo;s own velocity, used where that channel&amp;rsquo;s &lt;code&gt;enableInputDot&lt;/code&gt; is set. Where &lt;code&gt;enableInput&lt;/code&gt; is false this leaf is the &lt;strong&gt;velocity command&lt;/strong&gt; instead, and is read whatever &lt;code&gt;enableInputDot&lt;/code&gt; says. A non-numeric command is held, not followed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The setpoint&amp;rsquo;s own acceleration. &lt;strong&gt;Only used where &lt;code&gt;enableInputDDot&lt;/code&gt; is set&lt;/strong&gt;, and only supply it if it is exact — see Tuning. Unused where &lt;code&gt;enableInput&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True passes &lt;code&gt;input&lt;/code&gt; straight to &lt;code&gt;output&lt;/code&gt; and slaves the internal state to it, so re-enabling is bumpless. Use it for a runtime override; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The bounded position setpoint. &lt;strong&gt;Never outside the position limits.&lt;/strong&gt; Where &lt;code&gt;enableInput&lt;/code&gt; is false it is the integral of the velocity actually emitted, and it freezes where it stands while the block is bypassed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;Its velocity. While bypassed this is &lt;code&gt;inputDot&lt;/code&gt; where &lt;code&gt;enableInputDot&lt;/code&gt; is set, and a difference of &lt;code&gt;input&lt;/code&gt; where it is not.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;Its acceleration. While bypassed this is &lt;code&gt;inputDDot&lt;/code&gt; where &lt;code&gt;enableInputDDot&lt;/code&gt; is set, and a difference of &lt;code&gt;outputDot&lt;/code&gt; where it is not.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;Its jerk. While the block is bypassed this is estimated by difference rather than left at zero, so a feedforward consumer does not see it vanish.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Per channel, under &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, …:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any clamp shaped the output this cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The setpoint is outside the box, or the stopping test clamped the motion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt;, &lt;code&gt;accelerationLimitActive&lt;/code&gt;, &lt;code&gt;jerkLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;That limit is binding. Where &lt;code&gt;enableInput&lt;/code&gt; is false, &lt;code&gt;velocityLimitActive&lt;/code&gt; means &lt;code&gt;velocityLimit&lt;/code&gt; clipped the &lt;strong&gt;command&lt;/strong&gt; — not that the axis is converging on it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activePositionLowerLimit&lt;/code&gt;, &lt;code&gt;activePositionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The bounds actually in force, which differ from the configured ones while soft entry is ratcheting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;predictedStop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where a full brake from the current state would come to rest.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;False when the current state can no longer be stopped inside the box.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The limit set cannot be guaranteed with the authority in force. Describes the &lt;strong&gt;settings&lt;/strong&gt;, not the current state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;softEntryActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A limit is ratcheted to the state because the state is outside it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The result of the last settings check. Non-zero means an edit was refused.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;debug/error&lt;/code&gt;, &lt;code&gt;debug/errorDot&lt;/code&gt;, &lt;code&gt;debug/errorDDot&lt;/code&gt;, &lt;code&gt;debug/targetActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Indicative only.&lt;/strong&gt; These explain what the limiter did. &lt;strong&gt;Do not wire them into logic&lt;/strong&gt; — the signals a supervisor may act on are the ones above. Where &lt;code&gt;enableInput&lt;/code&gt; is false, &lt;code&gt;debug/error&lt;/code&gt; is always 0 — there is no position to be in error by — and &lt;code&gt;debug/errorDot&lt;/code&gt; is the tracking error that matters.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each channel also publishes &lt;code&gt;State01&lt;/code&gt;, &lt;code&gt;State02&lt;/code&gt;, … as a &lt;strong&gt;sibling&lt;/strong&gt; of its
&lt;code&gt;Limits&lt;/code&gt; group, not inside it:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;State{NN}/positionUpperLimitActive&lt;/code&gt;, &lt;code&gt;State{NN}/positionLowerLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Which position bound is binding, rather than only that one is.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;State{NN}/velocityUpperLimitActive&lt;/code&gt;, &lt;code&gt;State{NN}/velocityLowerLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same, one derivative up.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;State{NN}/accelerationUpperLimitActive&lt;/code&gt;, &lt;code&gt;State{NN}/accelerationLowerLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;And one more.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;State{NN}/active&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any of the six is set.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use this group where a dashboard needs the &lt;strong&gt;direction&lt;/strong&gt; of the limit. The
flags under &lt;code&gt;Limits{NN}&lt;/code&gt; say that a limit is binding; these say which side.&lt;/p&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;p&gt;Block level: &lt;code&gt;enable&lt;/code&gt; (default true).&lt;/p&gt;
&lt;p&gt;Per channel, under &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, …:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;−1.0&lt;/td&gt;
&lt;td&gt;below the upper&lt;/td&gt;
&lt;td&gt;The box. Never crossed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;+1.0&lt;/td&gt;
&lt;td&gt;above the lower&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;20.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;400.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Symmetric. Lower rounds the corners of every move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAccelerationBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;at least &lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Elevated authority for defending the position limits. &lt;strong&gt;0 means &amp;ldquo;inherit &lt;code&gt;accelerationLimit&lt;/code&gt;&amp;quot;&lt;/strong&gt;, and stays 0 so it keeps following it. A value below the normal limit is raised, and the raise is written back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxJerkBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;at least &lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same rule.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True tracks &lt;code&gt;input&lt;/code&gt; as a position setpoint. False ignores &lt;code&gt;input&lt;/code&gt; and reads &lt;code&gt;inputDot&lt;/code&gt; as a velocity command — see the mode table below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;inputDot&lt;/code&gt; instead of differencing &lt;code&gt;input&lt;/code&gt;. No effect where &lt;code&gt;enableInput&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;inputDDot&lt;/code&gt;. &lt;strong&gt;Only set this if the value is exact&lt;/strong&gt; — see Tuning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePositionLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False leaves the box effectively unbounded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;0 – 1&lt;/td&gt;
&lt;td&gt;How far ahead the tracking target is placed. 1 is the full lead, 0 turns the feedforward off. Trades overshoot of the commanded amplitude against tracking lag. Corrected silently if out of range.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableSoftEntry&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;When the state is already outside a limit, ratchet that limit to the state so only motion that makes the violation worse is forbidden.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;defendLimitsHard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Spend the elevated braking authority in normal operation rather than keeping it as a backstop. Costs a step in commanded acceleration when the reference crosses a limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preventPositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Size the braking authority automatically so overshoot cannot happen. &lt;strong&gt;Read the braking values back afterwards&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a restart. Each is per channel, so a six-axis
instance can run some axes as position limiters and others as velocity
limiters. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;enableInput&lt;/code&gt; selects which of the two modes a channel runs in:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;th&gt;Parameters that matter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;true (default)&lt;/td&gt;
&lt;td&gt;Tracks &lt;code&gt;input&lt;/code&gt; as a position setpoint, bounded in jerk, acceleration, velocity and position.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enableInputDot&lt;/code&gt;, &lt;code&gt;enableInputDDot&lt;/code&gt;, &lt;code&gt;feedforwardGain&lt;/code&gt;, and all four limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;Ignores &lt;code&gt;input&lt;/code&gt; and drives &lt;code&gt;outputDot&lt;/code&gt; onto the &lt;code&gt;inputDot&lt;/code&gt; command within the jerk, acceleration and velocity limits. &lt;code&gt;output&lt;/code&gt; is the integral of what was emitted, and the position limits still stop the axis &lt;strong&gt;on&lt;/strong&gt; the limit.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;, &lt;code&gt;accelerationLimit&lt;/code&gt;, &lt;code&gt;jerkLimit&lt;/code&gt;, &lt;code&gt;enablePositionLimit&lt;/code&gt;, and the box&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use the false setting for a velocity-driven axis — a vehicle drive, a spindle,
a conveyor — where there is no position setpoint. It also removes a hazard: an
unconnected &lt;code&gt;input&lt;/code&gt; sitting at 0 is otherwise tracked as &amp;ldquo;go to the origin&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read how many channels this instance has, and note that the sub-trees are
numbered from 1 — &lt;code&gt;Limits01&lt;/code&gt; is array element 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set each channel&amp;rsquo;s box, &lt;code&gt;velocityLimit&lt;/code&gt;, &lt;code&gt;accelerationLimit&lt;/code&gt; and &lt;code&gt;jerkLimit&lt;/code&gt;
from the machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the stopping arithmetic: $V^2/2A + VA/2J$, doubled, against the width
of your box. If it does not fit, &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;
will be true — lower &lt;code&gt;velocityLimit&lt;/code&gt; until it clears.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave the braking values at 0 for now, so they follow the normal limits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave both input switches off and &lt;code&gt;feedforwardGain&lt;/code&gt; at 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link &lt;code&gt;input&lt;/code&gt; and set &lt;code&gt;enable&lt;/code&gt; true. Command a move and confirm &lt;code&gt;output&lt;/code&gt;
follows, &lt;code&gt;status&lt;/code&gt; reads zero, and &lt;code&gt;viable&lt;/code&gt; stays true.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit. Confirm &lt;code&gt;output&lt;/code&gt; &lt;strong&gt;stops at
the limit exactly&lt;/strong&gt; and &lt;code&gt;positionLimitActive&lt;/code&gt; goes true.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 7 drives the axis into its travel limit.&lt;/strong&gt; The setpoint is
guaranteed; the machine is not — it will pass the limit by its following
error. Do this at low speed first and back the limits off by that error.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If your motion source publishes its own velocity, set &lt;code&gt;enableInputDot&lt;/code&gt; and
confirm tracking improves.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For a velocity-driven axis, clear &lt;code&gt;enableInput&lt;/code&gt; instead. Leave &lt;code&gt;input&lt;/code&gt;
unlinked, link your velocity command to &lt;code&gt;inputDot&lt;/code&gt;, and confirm &lt;code&gt;outputDot&lt;/code&gt;
follows it while &lt;code&gt;debug/error&lt;/code&gt; stays 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a velocity that runs the axis into a position limit. Confirm
&lt;code&gt;output&lt;/code&gt; comes to rest &lt;strong&gt;on&lt;/strong&gt; the limit and &lt;code&gt;positionLimitActive&lt;/code&gt; goes
true, with &lt;code&gt;outputDDot&lt;/code&gt; peaking at &lt;code&gt;accelerationLimit&lt;/code&gt; rather than at
&lt;code&gt;maxAccelerationBraking&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the four limits from the machine first. They are hardware properties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lower &lt;code&gt;jerkLimit&lt;/code&gt; to smooth the motion&lt;/strong&gt;, raise it to sharpen it. This is
the knob this block has and &lt;code&gt;PVALimiter&lt;/code&gt; does not, and it is what removes
the corners at the start and end of every move.&lt;/li&gt;
&lt;li&gt;Supply the setpoint&amp;rsquo;s own derivatives if you have them. The improvement is
large and measured: on a 0.2 m 1 Hz sine, differencing the input gives
1.9e-2 m of error, &lt;code&gt;inputDot&lt;/code&gt; alone gives 1.8e-2 m, and &lt;strong&gt;&lt;code&gt;inputDot&lt;/code&gt; plus
&lt;code&gt;inputDDot&lt;/code&gt; gives 8.0e-8 m&lt;/strong&gt; — five orders of magnitude.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Only set &lt;code&gt;enableInputDDot&lt;/code&gt; if the acceleration is exact.&lt;/strong&gt; An acceleration
differenced from an input carrying a millimetre of noise measured
6.5e-2 m — three times &lt;em&gt;worse&lt;/em&gt; than leaving it off. If your generator does
not produce a true acceleration, leave the switch off.&lt;/li&gt;
&lt;li&gt;Lower &lt;code&gt;feedforwardGain&lt;/code&gt; toward 0 if the output overshoots the commanded
amplitude; raise it toward 1 if the output lags. That is the whole trade.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reserve the braking authority explicitly&lt;/strong&gt; — set &lt;code&gt;maxAccelerationBraking&lt;/code&gt;
and &lt;code&gt;maxJerkBraking&lt;/code&gt; above the normal limits — if you will ever retune
&lt;code&gt;accelerationLimit&lt;/code&gt; on a running axis. See Limits and errors for why.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;defendLimitsHard&lt;/code&gt; only if you want the extra authority spent in normal
operation. It costs a step in commanded acceleration at the limit.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt; after every limits edit. It
describes the settings, so it answers &amp;ldquo;can this configuration ever be
guaranteed&amp;rdquo; — &lt;code&gt;viable&lt;/code&gt; answers &amp;ldquo;can the axis be stopped from where it is
right now&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;In the velocity-driven mode, tune &lt;code&gt;accelerationLimit&lt;/code&gt; and &lt;code&gt;jerkLimit&lt;/code&gt; only.
&lt;code&gt;feedforwardGain&lt;/code&gt; and both derivative switches do nothing there. The
approach to a position limit decelerates at &lt;code&gt;accelerationLimit&lt;/code&gt;, so that
number sets how far in front of the limit braking begins.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/pvajlimiter-jerk-6be2edfb.svg&#34; alt=&#34;Accelerating to 2 m/s at three jerk limits with an acceleration limit of 20:a jerk of 1000 reaches speed in 0.12 s with nearly square corners, 200 takes0.19 s, and 50 takes 0.38 s and never reaches the accelerationlimit.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the effect of the jerk limit off how rounded each curve&amp;rsquo;s corners are.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt; is non-zero and a limits edit did nothing&lt;/td&gt;
&lt;td&gt;The edit was nonsense on its own — a non-positive limit or an inverted box&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;status&lt;/code&gt;, fix the value; the limiter is still running on the last good set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;A full stop from &lt;code&gt;velocityLimit&lt;/code&gt; does not fit in the box twice over&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;velocityLimit&lt;/code&gt;, raise the braking authority, or set &lt;code&gt;preventPositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt; went false&lt;/td&gt;
&lt;td&gt;The axis cannot be stopped inside the box from where it is now&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;predictedStop&lt;/code&gt; to see how far past it will go; this usually follows a limits narrowing under a moving setpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The guarantee was lost after tightening &lt;code&gt;accelerationLimit&lt;/code&gt; mid-move&lt;/td&gt;
&lt;td&gt;A setpoint already moving fast near a limit cannot be stopped once the limits are lowered — arithmetic, not a fault&lt;/td&gt;
&lt;td&gt;Reserve &lt;code&gt;maxAccelerationBraking&lt;/code&gt; and &lt;code&gt;maxJerkBraking&lt;/code&gt; explicitly so they do not follow the normal limits down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is jerky at the start and end of moves&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt; too high&lt;/td&gt;
&lt;td&gt;Lower it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moves take too long&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt; or &lt;code&gt;accelerationLimit&lt;/code&gt; too low&lt;/td&gt;
&lt;td&gt;Raise them, then re-check step 3 of Setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking lags the input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt; too low, or the derivative switches are off&lt;/td&gt;
&lt;td&gt;Raise the gain toward 1; supply &lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output overshoots the commanded amplitude&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt; too high&lt;/td&gt;
&lt;td&gt;Lower it toward 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking got &lt;strong&gt;worse&lt;/strong&gt; after enabling &lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The acceleration being supplied is estimated, not exact&lt;/td&gt;
&lt;td&gt;Turn the switch off; a differenced acceleration is worse than none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine passed the position limit&lt;/td&gt;
&lt;td&gt;Expected: the &lt;strong&gt;setpoint&lt;/strong&gt; is guaranteed, not the mechanism&lt;/td&gt;
&lt;td&gt;Back the limits off by the servo&amp;rsquo;s worst-case following error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A step in commanded acceleration when crossing a limit&lt;/td&gt;
&lt;td&gt;Expected with &lt;code&gt;defendLimitsHard&lt;/code&gt; set&lt;/td&gt;
&lt;td&gt;Clear it to keep the extra authority as a backstop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;softEntryActive&lt;/code&gt; is true and the axis is moving oddly&lt;/td&gt;
&lt;td&gt;The state is outside a limit, so only motion reducing the violation is allowed&lt;/td&gt;
&lt;td&gt;Expected during recovery; it clears once the state is back inside&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The braking values read back higher than written&lt;/td&gt;
&lt;td&gt;Expected: a value below the normal limit is raised, and the raise is written back&lt;/td&gt;
&lt;td&gt;Write a value above the normal limit, or leave it at 0 to inherit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A braking value left at 0 stayed 0&lt;/td&gt;
&lt;td&gt;Expected and deliberate: 0 means &amp;ldquo;inherit&amp;rdquo;, and keeps following the normal limit&lt;/td&gt;
&lt;td&gt;Set a number if you want it fixed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The &lt;code&gt;debug/&lt;/code&gt; values look wrong&lt;/td&gt;
&lt;td&gt;They are indicative only and are not part of the contract&lt;/td&gt;
&lt;td&gt;Use the top-level status signals instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric setpoint did not disturb the output&lt;/td&gt;
&lt;td&gt;Expected: the previous setpoint is held&lt;/td&gt;
&lt;td&gt;Fix the source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis drives to the origin as soon as the limiter is enabled&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enableInput&lt;/code&gt; is true with &lt;code&gt;input&lt;/code&gt; unlinked, so the setpoint reads 0&lt;/td&gt;
&lt;td&gt;Clear &lt;code&gt;enableInput&lt;/code&gt; for a velocity-driven axis, or link &lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;debug/error&lt;/code&gt; reads 0 while the axis is clearly moving&lt;/td&gt;
&lt;td&gt;Expected where &lt;code&gt;enableInput&lt;/code&gt; is false: there is no position setpoint to be in error by&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;debug/errorDot&lt;/code&gt; instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt; is true at a velocity well below &lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected where &lt;code&gt;enableInput&lt;/code&gt; is false: the flag reports the &lt;strong&gt;command&lt;/strong&gt; being clipped&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;outputDot&lt;/code&gt; for what the axis is doing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; did not move while the block was bypassed, and jumped on re-enable&lt;/td&gt;
&lt;td&gt;Expected where &lt;code&gt;enableInput&lt;/code&gt; is false: &lt;code&gt;output&lt;/code&gt; freezes while bypassed, so it is not the integral of &lt;code&gt;outputDot&lt;/code&gt; in that state&lt;/td&gt;
&lt;td&gt;Re-enable from a zero command, or accept the step&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a 1 m axis on a 1 ms task, with the braking authority
reserved so limits can be retuned safely:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable = true
Limits01/positionLowerLimit     = -0.5
Limits01/positionUpperLimit     =  0.5
Limits01/velocityLimit          =  1.0
Limits01/accelerationLimit      = 10.0
Limits01/jerkLimit              = 200.0
Limits01/maxAccelerationBraking = 20.0
Limits01/maxJerkBraking         = 400.0
Limits01/enableInput            = true
Limits01/enableInputDot         = false
Limits01/enableInputDDot        = false
Limits01/feedforwardGain        = 1.0
Limits01/enableSoftEntry        = true
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position&lt;/td&gt;
&lt;td&gt;The box&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Guaranteed, with no tolerance.&lt;/strong&gt; The setpoint never leaves the limits&lt;/td&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;, &lt;code&gt;activePositionLowerLimit&lt;/code&gt;, &lt;code&gt;activePositionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; velocity, acceleration, jerk&lt;/td&gt;
&lt;td&gt;Their limits&lt;/td&gt;
&lt;td&gt;Bounded&lt;/td&gt;
&lt;td&gt;The three matching flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settings validity&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A non-positive velocity, acceleration or jerk limit, or an inverted box, is &lt;strong&gt;refused&lt;/strong&gt;; the limiter keeps running on the last valid set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Achievability&lt;/td&gt;
&lt;td&gt;Reported, not refused&lt;/td&gt;
&lt;td&gt;A limit set whose stop does not fit in the box is accepted and flagged&lt;/td&gt;
&lt;td&gt;&lt;code&gt;warningPositionLimitOvershootPossible&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current state&lt;/td&gt;
&lt;td&gt;Reported&lt;/td&gt;
&lt;td&gt;Whether the axis can still be stopped inside the box from where it is&lt;/td&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt;, &lt;code&gt;predictedStop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Narrowing limits under a moving setpoint&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Arithmetic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A setpoint moving fast near a limit &lt;strong&gt;cannot&lt;/strong&gt; be stopped once the limits are lowered. The limiter brakes at everything it is allowed and reports &lt;code&gt;viable&lt;/code&gt; false throughout. &lt;strong&gt;Reserving the braking authority explicitly removes the hazard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;viable&lt;/code&gt;, &lt;code&gt;predictedStop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preventPositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic sizing&lt;/td&gt;
&lt;td&gt;Commands whatever braking authority the arithmetic demands, &lt;strong&gt;which may exceed what the drive can deliver.&lt;/strong&gt; Authority the machine does not have is authority the guarantee does not have&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;maxAccelerationBraking&lt;/code&gt; and &lt;code&gt;maxJerkBraking&lt;/code&gt; back and check them against the axis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position, velocity-driven mode&lt;/td&gt;
&lt;td&gt;The box&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Still guaranteed.&lt;/strong&gt; A velocity command that would run the axis past a limit is refused in time and the axis comes to rest on the limit, at &lt;code&gt;accelerationLimit&lt;/code&gt; and &lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commanded velocity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt; and the soft-entry ratchets&lt;/td&gt;
&lt;td&gt;Clipped before it is tracked&lt;/td&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The mechanism&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;This block bounds the &lt;strong&gt;setpoint&lt;/strong&gt;. The machine passes the limit by its servo following error&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Braking authority&lt;/td&gt;
&lt;td&gt;Inheritance&lt;/td&gt;
&lt;td&gt;0 inherits the normal limit and stays 0; a value below it is raised and written back&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task period&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Recorded as part of the settings check. A task-rate change re-triggers validation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts. Sub-trees are numbered from 1&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every condition above
is published as a signal you can trace or wire into a supervisor.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.32.1 (340db23).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: PvajLimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.34/&#34;&gt;3.32–3.34&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34; selected&gt;3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter-3.30/&#34;&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;Current release&lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;PvajLimiter&lt;/code&gt; bounds a position setpoint in &lt;strong&gt;jerk, acceleration, velocity and
position at the same time&lt;/strong&gt;, and guarantees the position limits are never
crossed. The output satisfies &lt;code&gt;positionLowerLimit&lt;/code&gt; ≤ &lt;code&gt;output&lt;/code&gt; ≤
&lt;code&gt;positionUpperLimit&lt;/code&gt; exactly — not to within a margin, because every cycle the
block asks &amp;ldquo;if I apply this jerk, can the setpoint still be brought to rest
inside the box?&amp;rdquo; before it applies it.&lt;/p&gt;
&lt;p&gt;It replaces &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pva-limiter/&#34;&gt;&lt;code&gt;PVALimiter&lt;/code&gt;&lt;/a&gt; for new work. That block tracks with
a filter and clamps acceleration; this one plans a trajectory and bounds jerk
as well, so motion starts and stops without the corners that shake a machine.
It also runs as a &lt;strong&gt;velocity limiter&lt;/strong&gt; driven by &lt;code&gt;inputDot&lt;/code&gt;. Even then it
brings the axis to rest on a position limit rather than through it.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — position setpoint&amp;quot;]) --&amp;gt; B[&amp;quot;PvajLimiter&amp;quot;]
    i2([&amp;quot;inputDot — setpoint velocity, or the velocity command&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — setpoint acceleration&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;Limits0N/positionLowerLimit, positionUpperLimit&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;Limits0N/velocityLimit, accelerationLimit, jerkLimit&amp;quot;]) --&amp;gt; B
    p3([&amp;quot;Limits0N/maxAccelerationBraking, maxJerkBraking&amp;quot;]) --&amp;gt; B
    p4([&amp;quot;Limits0N/enableInput, enableInputDot, enableInputDDot&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — bounded position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;outputDDDot — jerk applied this cycle&amp;quot;])
    B --&amp;gt; o5([&amp;quot;isEnabled&amp;quot;])
    B --&amp;gt; o6([&amp;quot;Limits0N/isLimiting and the four limit flags&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It runs in one of two modes, chosen per channel by &lt;code&gt;enableInput&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;&lt;code&gt;enableInput&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;enableInputDot&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What is commanded&lt;/th&gt;
&lt;th&gt;What you read&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PVAJ&lt;/strong&gt; (default)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;optional — &lt;code&gt;1&lt;/code&gt; only if &lt;code&gt;inputDot&lt;/code&gt; really carries the setpoint velocity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt; is a position setpoint&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;, &lt;code&gt;outputDot&lt;/code&gt;, &lt;code&gt;outputDDot&lt;/code&gt;, &lt;code&gt;outputDDDot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VAJ&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;1&lt;/code&gt;&lt;/strong&gt; — it is the switch that says &lt;code&gt;inputDot&lt;/code&gt; carries a velocity; with it &lt;code&gt;0&lt;/code&gt; the leaf is not read and the command is zero&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt; is a velocity command; &lt;code&gt;input&lt;/code&gt; is not read at all&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;, &lt;code&gt;outputDDot&lt;/code&gt;, &lt;code&gt;outputDDDot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both modes shape the motion with the same J, A and V limits. §7 and §8 give a complete configuration for each.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;enableInputDot&lt;/code&gt; means one thing in both modes: &lt;strong&gt;the &lt;code&gt;inputDot&lt;/code&gt; leaf carries a real velocity, read it.&lt;/strong&gt; Off, the
leaf is never read. In PVAJ mode the block then estimates the setpoint velocity by differencing &lt;code&gt;input&lt;/code&gt;; in VAJ mode
there is no &lt;code&gt;input&lt;/code&gt; to difference, so the command is zero and the axis is brought to rest. The three switches that
shape the &lt;em&gt;position&lt;/em&gt; tracking lead — &lt;code&gt;enableInputDDot&lt;/code&gt;, &lt;code&gt;feedforwardGain&lt;/code&gt; and &lt;code&gt;suppressInputDDotEstimation&lt;/code&gt; — are
optional in PVAJ mode and inert in VAJ mode.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A full stop from &lt;code&gt;velocityLimit&lt;/code&gt; needs $V^2/2A_b + V A_b/2J_b$ of travel, with $A_b$ and $J_b$ the braking
authority. &lt;strong&gt;If twice that does not fit between your position limits&lt;/strong&gt;, states exist inside the box from which the
setpoint can no longer be stopped in time — the block tells you so through
&lt;code&gt;warningSettingsMayCausePositionLimitOvershoot&lt;/code&gt; rather than refusing the settings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every parameter can be changed while the machine is running&lt;/strong&gt;, and the change takes effect on the very next
cycle. &lt;strong&gt;Nothing is refused&lt;/strong&gt;: a value that is not usable as a limit is fixed into one and written back to the leaf,
so there is one thing to look at — the limit set — and no status code to cross-check it against (§3).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This block bounds the setpoint, not the machine.&lt;/strong&gt; The axis follows through a servo loop with a following error,
so the mechanism will pass the limit by roughly that error. Back your limits off by the certified worst case.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Everything is &lt;strong&gt;per channel&lt;/strong&gt;: an N-channel instance publishes &lt;code&gt;Limits01&lt;/code&gt;..&lt;code&gt;LimitsNN&lt;/code&gt;, and a six-axis stage can run
channel 1 in PVAJ mode and channel 2 in VAJ mode. Every parameter named below lives under the channel&amp;rsquo;s folder —
for channel 1 of an instance called &lt;code&gt;pvajLimiter&lt;/code&gt;, &lt;code&gt;positionUpperLimit&lt;/code&gt; is
&lt;code&gt;root/Control/pvajLimiter/Limits01/positionUpperLimit&lt;/code&gt;. The examples use channel 1.&lt;/p&gt;
&lt;h2 id=&#34;1-signals&#34;&gt;1. Signals&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;input&lt;/code&gt;, &lt;code&gt;inputDot&lt;/code&gt;, &lt;code&gt;inputDDot&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt;, &lt;code&gt;outputDot&lt;/code&gt;, &lt;code&gt;outputDDot&lt;/code&gt; and &lt;code&gt;outputDDDot&lt;/code&gt; are &lt;strong&gt;N-element arrays&lt;/strong&gt; at
the top of the module. &lt;code&gt;enable&lt;/code&gt;, &lt;code&gt;disable&lt;/code&gt; and &lt;code&gt;isEnabled&lt;/code&gt; are single leaves that apply to the whole stage.&lt;/p&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Position setpoint. Ignored entirely while &lt;code&gt;enableInput&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;. A non-finite value is held, not followed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read only while &lt;code&gt;enableInputDot&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt;. In PVAJ mode it is then the setpoint velocity, for the tracking lead; in VAJ mode it is &lt;strong&gt;the commanded velocity&lt;/strong&gt;. With &lt;code&gt;enableInputDot&lt;/code&gt; &lt;code&gt;0&lt;/code&gt; the leaf is ignored in both modes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The setpoint acceleration, used only if &lt;code&gt;enableInputDDot&lt;/code&gt; says it is real. Unused in VAJ mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stage-wide. While set, every channel passes its input through and limits nothing.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limited position. Never outside the box. Reads &lt;strong&gt;zero&lt;/strong&gt; in VAJ mode unless &lt;code&gt;suppressPositionOutput&lt;/code&gt; is cleared.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limited velocity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limited acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double[N]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The jerk applied this cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable &amp;amp;&amp;amp; !disable&lt;/code&gt;. Stage-wide; per-channel enables do not affect it.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;per-channel-status-limits0n&#34;&gt;Per-channel status, &lt;code&gt;Limits0N/&lt;/code&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One of the four limits clamped the output this cycle. Converging on the setpoint is &lt;strong&gt;not&lt;/strong&gt; limiting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The position limiter is shaping this cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The velocity limit is binding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The acceleration limit is binding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The jerk limit is binding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;softEntryActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The state is outside a limit and only motion that makes the violation worse is forbidden (§4). Always false while disabled.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningSettingsMayCausePositionLimitOvershoot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The limit set&lt;/strong&gt; cannot guarantee the box: a stop from &lt;code&gt;velocityLimit&lt;/code&gt; does not fit in half of it. Fix the settings (§3).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningNotAbleToStopBeforeLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The current state&lt;/strong&gt; can no longer be stopped inside the box — the guarantee is already lost. Only reachable by seeding a bad state or narrowing the limits under a moving setpoint.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;per-channel-diagnostics-limits0ndebug&#34;&gt;Per-channel diagnostics, &lt;code&gt;Limits0N/debug/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Indicative only; nothing here feeds the control law.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trackingError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;input - output&lt;/code&gt;. Zero while disabled and in VAJ mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trackingErrorDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The setpoint velocity in use minus &lt;code&gt;outputDot&lt;/code&gt;: &lt;code&gt;inputDot&lt;/code&gt; where &lt;code&gt;enableInputDot&lt;/code&gt; is set, the estimate differenced from &lt;code&gt;input&lt;/code&gt; otherwise (zero in VAJ mode without &lt;code&gt;enableInputDot&lt;/code&gt;). &lt;strong&gt;This&lt;/strong&gt; is the tracking error in VAJ mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trackingErrorDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The setpoint acceleration in use minus &lt;code&gt;outputDDot&lt;/code&gt;: &lt;code&gt;inputDDot&lt;/code&gt; where &lt;code&gt;enableInputDDot&lt;/code&gt; is set, the estimate otherwise.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;predictedStopPosition&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where a full brake from the current state would come to rest, as an absolute position. Plot it next to &lt;code&gt;output&lt;/code&gt; and the limits to see the braking margin.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;state0n&#34;&gt;&lt;code&gt;State0N/&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The same facts as the flags above, in the shape &lt;code&gt;GainSchedulingPVALimiter&lt;/code&gt; published them, so existing dashboards
keep resolving. Prefer the &lt;code&gt;Limits0N/&lt;/code&gt; flags in anything new.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Equals&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;active&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLimiting&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionUpperLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;, while the setpoint is in the upper half of the box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;positionLimitActive&lt;/code&gt;, while it is in the lower half&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityUpperLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt;, while &lt;code&gt;outputDot&lt;/code&gt; is positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLowerLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;velocityLimitActive&lt;/code&gt;, while &lt;code&gt;outputDot&lt;/code&gt; is negative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationUpperLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;accelerationLimitActive&lt;/code&gt;, while &lt;code&gt;outputDDot&lt;/code&gt; is positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLowerLimitActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;accelerationLimitActive&lt;/code&gt;, while &lt;code&gt;outputDDot&lt;/code&gt; is negative&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There is no jerk counterpart — &lt;code&gt;GainSchedulingPVALimiter&lt;/code&gt; had no jerk limit.&lt;/p&gt;
&lt;h2 id=&#34;2-parameters&#34;&gt;2. Parameters&lt;/h2&gt;
&lt;p&gt;All under &lt;code&gt;Limits0N/&lt;/code&gt;, all writable while the loop runs. The names are the same on the tree and in C++.&lt;/p&gt;
&lt;h3 id=&#34;the-limit-set&#34;&gt;The limit set&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lower travel limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upper travel limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Maximum speed, symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Maximum acceleration, symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Maximum jerk, symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAccelerationBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Elevated acceleration reserved for defending the travel limits. &lt;code&gt;0&lt;/code&gt; inherits &lt;code&gt;accelerationLimit&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxJerkBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Elevated jerk for the same purpose. &lt;code&gt;0&lt;/code&gt; inherits &lt;code&gt;jerkLimit&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block never assumes a unit: whatever &lt;code&gt;input&lt;/code&gt; is in, &lt;code&gt;velocityLimit&lt;/code&gt; is that per second, &lt;code&gt;accelerationLimit&lt;/code&gt;
per second squared and &lt;code&gt;jerkLimit&lt;/code&gt; per second cubed. Linear or rotary, the arithmetic is the same.&lt;/p&gt;
&lt;h3 id=&#34;mode-and-behaviour-switches&#34;&gt;Mode and behaviour switches&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This channel&amp;rsquo;s own enable, ANDed with the stage-wide &lt;code&gt;enable&lt;/code&gt;/&lt;code&gt;disable&lt;/code&gt;. Set &lt;code&gt;0&lt;/code&gt; to hold one axis out while the rest of the stage runs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt; = PVAJ mode, &lt;code&gt;0&lt;/code&gt; = VAJ mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suppressPositionOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;In VAJ mode, publish &lt;code&gt;output&lt;/code&gt; as zero instead of the position the block integrates along the way. No effect in PVAJ mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePositionLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enforce the travel limits. &lt;code&gt;0&lt;/code&gt; bypasses them outright — the bounds become infinite and no position action is taken.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt; carries a real velocity — read it. PVAJ mode: optional, with it off the block differences &lt;code&gt;input&lt;/code&gt; instead. VAJ mode: &lt;strong&gt;required&lt;/strong&gt; — with it off there is no velocity input and nothing to difference, so the command is zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt; carries the real setpoint acceleration. Optional, PVAJ mode only, and independent of &lt;code&gt;enableInputDot&lt;/code&gt;. &lt;strong&gt;Do not set it on an unconnected leaf&lt;/strong&gt; — that declares the acceleration to be exactly zero and the block believes it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suppressInputDDotEstimation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Take the setpoint acceleration as zero instead of estimating it from the input&amp;rsquo;s history. Set it for one reason only: a &lt;strong&gt;measured&lt;/strong&gt; input whose noise the estimate would amplify.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How much of the braking-distance lead the tracking target is shifted by, &lt;code&gt;0&lt;/code&gt;..&lt;code&gt;1&lt;/code&gt;. &lt;code&gt;1&lt;/code&gt; tracks accurately; &lt;code&gt;0&lt;/code&gt; keeps the setpoint inside the commanded amplitude. Values outside the range are clamped and written back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableSoftEntry&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;On enabling with the setpoint outside a limit, ratchet that limit to the state instead of driving the setpoint back inside at once (§4).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableMaxBrakingAtLimits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Plan &lt;strong&gt;every&lt;/strong&gt; limit approach with the braking authority, not just recovery: braking starts later and is harder. Does nothing while the braking values inherit the ordinary ones.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;autoAdjustBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;maxAccelerationBraking&lt;/code&gt; / &lt;code&gt;maxJerkBraking&lt;/code&gt; automatically until a stop from &lt;code&gt;velocityLimit&lt;/code&gt; fits inside the box, and write the result back. See the warning in §3.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;3-configuring-the-limits&#34;&gt;3. Configuring the limits&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Nothing is refused.&lt;/strong&gt; A value that is not usable as a limit is fixed into one, so there is one thing to look at —
the limit set — and no status leaf to cross-check it against:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You write&lt;/th&gt;
&lt;th&gt;In force&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt; or &lt;code&gt;accelerationLimit&lt;/code&gt; = &lt;code&gt;0&lt;/code&gt;, negative, or non-finite&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no limit&lt;/strong&gt; (infinite)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt; = &lt;code&gt;0&lt;/code&gt;, negative, or non-finite&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no jerk limit&lt;/strong&gt;: &lt;code&gt;1e9&lt;/code&gt; stands in, because the jerk is the block&amp;rsquo;s control input and an infinite value is not-a-number in its arithmetic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAccelerationBraking&lt;/code&gt; / &lt;code&gt;maxJerkBraking&lt;/code&gt; = &lt;code&gt;0&lt;/code&gt; or below the ordinary limit&lt;/td&gt;
&lt;td&gt;inherits or is raised to the ordinary limit, and written back to the leaf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit &amp;gt; positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;swapped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;the two position limits equal, or either non-finite&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no box&lt;/strong&gt; at all, even with &lt;code&gt;enablePositionLimit&lt;/code&gt; set&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A small but positive value is taken literally: &lt;code&gt;velocityLimit = 1e-9&lt;/code&gt; is a very slow axis, not a mistake the block
can recognise — it will freeze the setpoint. &lt;code&gt;0&lt;/code&gt; is what means &amp;ldquo;no limit&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Edits take effect on the &lt;strong&gt;next cycle&lt;/strong&gt;. Start-up fails only if the task period is unknown.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check &lt;code&gt;warningSettingsMayCausePositionLimitOvershoot&lt;/code&gt; after configuring.&lt;/strong&gt; It is true when a stop from
&lt;code&gt;velocityLimit&lt;/code&gt; does not fit in half the box, which means states exist inside the box from which the setpoint could
no longer be stopped in time. Three ways out: lower &lt;code&gt;velocityLimit&lt;/code&gt;, raise &lt;code&gt;accelerationLimit&lt;/code&gt; / &lt;code&gt;jerkLimit&lt;/code&gt;, or
reserve &lt;code&gt;maxAccelerationBraking&lt;/code&gt; / &lt;code&gt;maxJerkBraking&lt;/code&gt; explicitly. &lt;code&gt;autoAdjustBraking&lt;/code&gt; does the last one for you —
but it commands whatever authority the arithmetic demands, which may exceed what the drive can deliver, and
authority the machine does not have is authority the guarantee does not have either. Read the two braking leaves
back afterwards and check them against the worst-case &lt;em&gt;deliverable&lt;/em&gt; figures.&lt;/p&gt;
&lt;h2 id=&#34;4-enabling-with-the-setpoint-outside-a-limit-soft-entry&#34;&gt;4. Enabling with the setpoint outside a limit (soft entry)&lt;/h2&gt;
&lt;p&gt;This is about the moment you &lt;strong&gt;enable&lt;/strong&gt;. A disabled block passes &lt;code&gt;input&lt;/code&gt; straight through, so if the input sits
outside the travel limits when you enable, the limiter starts from a state that is already outside the box. Soft
entry, on by default (&lt;code&gt;enableSoftEntry&lt;/code&gt;), decides what happens next.&lt;/p&gt;
&lt;p&gt;Without it, the limiter treats the box as gospel and drives the setpoint back inside immediately, at the braking
authority — the setpoint snaps to the limit whether the input wants that or not.&lt;/p&gt;
&lt;p&gt;With it, the violated limit is &lt;strong&gt;ratcheted to the state&lt;/strong&gt;: the box in force is widened just enough to contain where
the setpoint already is, so the only motion that remains forbidden is motion that makes the violation &lt;em&gt;worse&lt;/em&gt;. Two
cases follow, measured on a &lt;code&gt;±1.0&lt;/code&gt; box with the input parked at &lt;code&gt;1.5&lt;/code&gt; at the moment of enabling:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The input then&lt;/th&gt;
&lt;th&gt;What &lt;code&gt;output&lt;/code&gt; does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;moves &lt;strong&gt;further from&lt;/strong&gt; the limit (&lt;code&gt;1.5&lt;/code&gt; → &lt;code&gt;3.5&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;held where it was&lt;/strong&gt;, at &lt;code&gt;1.500&lt;/code&gt; — the setpoint does not follow the input further out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;moves &lt;strong&gt;back toward&lt;/strong&gt; the limit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;follows the input inward&lt;/strong&gt;, and entered the box as the input did (at &lt;code&gt;0.944&lt;/code&gt; in the measurement)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The ratchet re-tightens every cycle against the new position, so the setpoint can approach the limit but never
retreat from it again. The moment the state is inside, &lt;code&gt;softEntryActive&lt;/code&gt; clears and the real box applies in full.&lt;/p&gt;
&lt;p&gt;While the state is outside, the velocity and acceleration limits are relaxed to whatever the state already carries,
for the same reason: an inherited over-speed is not required to vanish instantly, only not to grow. Nothing about
normal operation depends on any of this — every effective value equals the configured one whenever the state is
inside the box.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The consequence to plan for:&lt;/strong&gt; a setpoint outside the box &lt;strong&gt;stays&lt;/strong&gt; outside while the input asks it to. Getting
back inside is the caller&amp;rsquo;s business — command the input back — and the setpoint comes with it. &lt;code&gt;softEntryActive&lt;/code&gt;
tells you it is happening. Clear &lt;code&gt;enableSoftEntry&lt;/code&gt; if you would rather the limiter recover by itself, accepting that
the setpoint then moves against the input.&lt;/p&gt;
&lt;p&gt;Enabling is not the only way in: &lt;code&gt;resetState()&lt;/code&gt; can seed a state outside the box, and narrowing the travel limits
underneath a moving setpoint leaves it outside. Soft entry handles all three the same way.&lt;/p&gt;
&lt;h2 id=&#34;5-enabling-with-a-noisy-input&#34;&gt;5. Enabling with a noisy input&lt;/h2&gt;
&lt;p&gt;§4 covered enabling with the setpoint outside the box. This one is about the derivatives it inherits.&lt;/p&gt;
&lt;p&gt;While the limiter is disabled — the stage-wide &lt;code&gt;enable&lt;/code&gt; cleared, &lt;code&gt;disable&lt;/code&gt; set, or the channel&amp;rsquo;s own &lt;code&gt;enable&lt;/code&gt;
cleared — &lt;code&gt;input&lt;/code&gt; passes straight through to &lt;code&gt;output&lt;/code&gt; and the internal state is slaved to it, so enabling is
bumpless in position. The derivatives it hands over come from differencing that input: &lt;code&gt;outputDot&lt;/code&gt; is the first
difference of &lt;code&gt;input&lt;/code&gt; unless &lt;code&gt;enableInputDot&lt;/code&gt; supplies a real velocity, and the acceleration and jerk are further
differences.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On the first enabled cycle the block zeroes the inherited acceleration and jerk, and keeps the inherited
velocity.&lt;/strong&gt; Zeroing the acceleration is essential: differencing multiplies input noise by &lt;code&gt;1/dt²&lt;/code&gt;, so noise of
&lt;code&gt;1e-4&lt;/code&gt; on the input at a 1 ms cycle arrives as an acceleration of &lt;strong&gt;100&lt;/strong&gt; — ten times a typical
&lt;code&gt;accelerationLimit&lt;/code&gt; — and unwinding that takes &lt;code&gt;|a| / jerkLimit&lt;/code&gt; seconds with the velocity integrating the whole
way. Measured at &lt;code&gt;jerkLimit = 100&lt;/code&gt;, &lt;code&gt;accelerationLimit = 10&lt;/code&gt;, &lt;code&gt;velocityLimit = 1&lt;/code&gt; with that much noise, the output
flew &lt;strong&gt;625&lt;/strong&gt; away from the input before returning; with the acceleration zeroed the same case peaks at &lt;strong&gt;0.056&lt;/strong&gt;. The velocity is kept because it is mostly the
input&amp;rsquo;s real velocity, and zeroing it would be a sudden stop when the limiter is enabled under a moving input.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That is why a noisy input still costs you something at enable.&lt;/strong&gt; The velocity handed over is &lt;code&gt;noise / dt&lt;/code&gt; — &lt;code&gt;0.1&lt;/code&gt;
for noise of &lt;code&gt;1e-4&lt;/code&gt; at a 1 ms cycle — and it is real as far as the limiter is concerned: the setpoint sets off at
that speed and
then has to be brought back within &lt;code&gt;accelerationLimit&lt;/code&gt; and &lt;code&gt;jerkLimit&lt;/code&gt;, which moves the position by roughly
&lt;code&gt;v²/(2·accelerationLimit)&lt;/code&gt; before it settles. On a path, that is a deviation from the path.&lt;/p&gt;
&lt;p&gt;So, for a clean hand-over:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Give the limiter a smooth input.&lt;/strong&gt; Filter a measured setpoint upstream rather than feeding raw encoder or
network-quantised values into &lt;code&gt;input&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better still, supply the velocity.&lt;/strong&gt; Connect a filtered velocity to &lt;code&gt;inputDot&lt;/code&gt; and set &lt;code&gt;enableInputDot&lt;/code&gt;: no
differencing happens at all, so there is no noise to inherit. Do the same for &lt;code&gt;inputDDot&lt;/code&gt; with &lt;code&gt;enableInputDDot&lt;/code&gt;
if the filter provides it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enable while the input is settled&lt;/strong&gt; where the application allows it. With the input at rest there is no
velocity to inherit, noisy or not.&lt;/li&gt;
&lt;li&gt;If the input is measured and cannot be filtered, set &lt;code&gt;suppressInputDDotEstimation&lt;/code&gt; as well (§2), so the tracking
lead does not differentiate that noise a second time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Disabling is unconditional and immediate: the channel stops limiting that cycle and goes back to passing &lt;code&gt;input&lt;/code&gt;
through. Note that a disabled block bounds nothing, so a command beyond &lt;code&gt;velocityLimit&lt;/code&gt; reaches the limiter
unbounded and has to be braked back once it takes over — bring the command inside the envelope before re-enabling
if that matters.&lt;/p&gt;
&lt;h2 id=&#34;6-tuning-the-tracking-accuracy&#34;&gt;6. Tuning the tracking accuracy&lt;/h2&gt;
&lt;p&gt;The switches below change only how accurately the limited output follows an unconstrained input. &lt;strong&gt;None of them can affect the position guarantee&lt;/strong&gt; — they all live in the tracking &lt;em&gt;proposal&lt;/em&gt;, which is clamped into the box before it is applied.&lt;/p&gt;
&lt;h3 id=&#34;enableinputdot--enableinputddot&#34;&gt;&lt;code&gt;enableInputDot&lt;/code&gt; / &lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Measured settled error on a 0.2 amplitude, 1 Hz sine, with &lt;code&gt;suppressInputDDotEstimation&lt;/code&gt; &lt;strong&gt;set&lt;/strong&gt; so that each row shows what the two switches alone buy. Left at its default the estimate fills the acceleration in, and the first two rows collapse to the accuracy of the last two:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;enableInputDot&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;enableInputDDot&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Setpoint velocity&lt;/th&gt;
&lt;th&gt;Setpoint acceleration&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;first difference of &lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;zero when &lt;code&gt;suppressInputDDotEstimation&lt;/code&gt; is set, otherwise estimated&lt;/td&gt;
&lt;td&gt;1.92e-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;zero when suppressed, otherwise estimated&lt;/td&gt;
&lt;td&gt;1.81e-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;first difference of &lt;code&gt;input&lt;/code&gt;, advanced by &lt;code&gt;a·dt/2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;lt; 1e-6&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.0e-8&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last two rows are worth five orders of magnitude because the tracking lead is how far the input travels before it could come to rest — leaving its acceleration out pretends the input is coasting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The two switches are independent claims about two separate leaves.&lt;/strong&gt; Each says &amp;ldquo;this one carries the real value&amp;rdquo;, and each is honoured on its own: a source that publishes position and acceleration but no velocity is a usable combination (third row), where the differenced velocity is lined up with the supplied acceleration by half a step. &lt;code&gt;enableInputDDot&lt;/code&gt; also &lt;strong&gt;wins over &lt;code&gt;suppressInputDDotEstimation&lt;/code&gt;&lt;/strong&gt; — an explicit claim is not second-guessed — which is the trap to know about: set it on an unconnected leaf and you have declared the acceleration to be exactly zero. The limiter then believes you and locks the setpoint&amp;rsquo;s acceleration to zero, which tracks the &lt;em&gt;position&lt;/em&gt; perfectly on a moving input while publishing an &lt;code&gt;outputDDot&lt;/code&gt; of zero. Leave both off if you only have a position.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It needs an exact value.&lt;/strong&gt; An acceleration differenced from an input carrying 1e-3 of noise measured 6.53e-2, three times &lt;em&gt;worse&lt;/em&gt; than leaving it off. Nothing is estimated here unless the estimate is left on (below), and the switch defaults to off for that reason: turn it on if the value is real, leave it off if it is estimated, unconnected or unknown.&lt;/p&gt;
&lt;h3 id=&#34;feedforwardgain&#34;&gt;&lt;code&gt;feedforwardGain&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The feedforward shifts the tracking target ahead by the braking distance at the setpoint&amp;rsquo;s own speed, cancelling
the lag that &amp;ldquo;always be able to stop on the setpoint&amp;rdquo; would otherwise cost. &lt;code&gt;feedforwardGain&lt;/code&gt; is how much of that
lead is applied, and it is the feedforward&amp;rsquo;s only control: &lt;code&gt;0&lt;/code&gt; is off, &lt;code&gt;1&lt;/code&gt; is the full lead. The two ends are far
apart, which is what makes the value in between worth tuning. Measured on a 0.5 amplitude sine at &lt;code&gt;jerkLimit&lt;/code&gt; = 1745, &lt;code&gt;accelerationLimit&lt;/code&gt; = 30,
&lt;code&gt;velocityLimit&lt;/code&gt; = 3.14, position input only:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;gain&lt;/th&gt;
&lt;th&gt;0.5 Hz: envelope excess / error / lag&lt;/th&gt;
&lt;th&gt;1.0 Hz&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.00 (= off)&lt;/td&gt;
&lt;td&gt;−1.4e-5 / 5.4e-2 / 31 ms&lt;/td&gt;
&lt;td&gt;−3.7e-4 / 1.67e-1 / 51 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;+8.6e-7 / 2.7e-2 / 15 ms&lt;/td&gt;
&lt;td&gt;−1.5e-4 / 8.6e-2 / 26 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.75&lt;/td&gt;
&lt;td&gt;+1.6e-5 / 1.4e-2 / 8 ms&lt;/td&gt;
&lt;td&gt;+4.7e-4 / 4.8e-2 / 14 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.00 (= on)&lt;/td&gt;
&lt;td&gt;+4.6e-5 / 2.4e-3 / 0 ms&lt;/td&gt;
&lt;td&gt;+2.0e-3 / 2.1e-2 / 5 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Monotone and smooth throughout: roughly 7–12 ms of lag and a factor of 2–5 in overshoot per 0.25 of gain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The landmark worth tuning to is where the envelope excess changes sign&lt;/strong&gt; — around &lt;code&gt;0.5&lt;/code&gt; at 0.5 Hz and
&lt;code&gt;0.6&lt;/code&gt;–&lt;code&gt;0.7&lt;/code&gt; at 1 Hz here. Just below it the output never exceeds what was commanded while most of the lag
reduction is still there. It moves with frequency, so it is an application tune, not a constant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prefer the derivatives where you have them.&lt;/strong&gt; The overshoot exists because the lead is computed as how far the
input travels before it could come to rest, which assumes the input is &lt;em&gt;coasting&lt;/em&gt; when only &lt;code&gt;input&lt;/code&gt; is available.
A sine is decelerating into its peak, so the lead is overestimated exactly there. Supplying exact &lt;code&gt;inputDot&lt;/code&gt; and
&lt;code&gt;inputDDot&lt;/code&gt; removes the cause instead of trading against it, and beats any gain below 1: the same measurement
gives 1.3e-7 of tracking error, no lag, and zero envelope excess. Reach for the gain when only &lt;code&gt;input&lt;/code&gt; is real.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The gain is bounded to &lt;code&gt;[0, 1]&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;0&lt;/code&gt; is no lead, &lt;code&gt;1&lt;/code&gt; is the full lead, and there is nothing useful past it:
over-leading was measured — at gain 2, 5.0e-2 excess against 9.0e-2 error; by gain 5 the target is permanently
clamped to the position limit, so the setpoint just parks at the box edge and stops following at all. Out-of-range
values are &lt;strong&gt;clamped, not refused&lt;/strong&gt;, so a bad config value leaves the limiter running on the nearest usable gain
rather than on nothing. The clamp is applied by the setters and again at the top of every cycle — a &lt;code&gt;control.xml&lt;/code&gt;
or parameter-server write lands straight on the leaf without passing a setter — and the clamped value is &lt;strong&gt;written
back&lt;/strong&gt;, so &lt;code&gt;feedforwardGain&lt;/code&gt; reads what is in force rather than what was asked for. A non-finite value becomes &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No gain can touch the position guarantee&lt;/strong&gt; — the bound is a convenience, not the safety argument. Verified to
gain 100 before the bound existed: the position never left the box by any amount, and the emitted motion gained no
oscillation. The lead moves the tracking target only, and the target is clamped into the box before the
braking-set test runs.&lt;/p&gt;
&lt;h3 id=&#34;gain-0-the-feedforward-off&#34;&gt;Gain &lt;code&gt;0&lt;/code&gt;: the feedforward off&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;feedforwardGain = 0&lt;/code&gt; is the feedforward switched off outright — no lead is computed and the tracking target is the input itself. It costs a factor of 38 in tracking accuracy and buys exactly one thing: the output then stays inside the &lt;em&gt;commanded&lt;/em&gt; amplitude envelope instead of leading it by the lead distance. On a 0.5 amplitude, 0.2 Hz sine, tracking error is 2.5e-2 off against 6.5e-4 at the full lead; envelope excess is −1.2e-6 off against +4.3e-6. That is the only reason the off end exists — for machines where the setpoint must not exceed what was commanded, quite apart from the position limits.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;enableInputDot&lt;/code&gt; and &lt;code&gt;enableInputDDot&lt;/code&gt; both set the trade-off evaporates: 1.1e-8 of tracking error &lt;em&gt;and&lt;/em&gt; −1.1e-12 of envelope excess. Better on both counts, so leave the gain at &lt;code&gt;1.0&lt;/code&gt; there.&lt;/p&gt;
&lt;h3 id=&#34;suppressinputddotestimation-the-inputs-acceleration-and-the-reversal-transient-without-it&#34;&gt;&lt;code&gt;suppressInputDDotEstimation&lt;/code&gt;: the input&amp;rsquo;s acceleration, and the reversal transient without it&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Set it for one reason only: to suppress noise on the input.&lt;/strong&gt; By default the acceleration is estimated; setting
this takes it as zero instead. The estimate is a second difference, so input noise reaches the lead multiplied by
1/dt² — and above roughly 1e-7 of jitter at a 1 ms cycle, taking the acceleration as zero is the better guess. Everywhere
else — any computed input, and any input whose derivatives you supply — leave it clear. If the input is measured
&lt;em&gt;and&lt;/em&gt; you can filter it, do that and supply &lt;code&gt;inputDot&lt;/code&gt; / &lt;code&gt;inputDDot&lt;/code&gt; instead: that beats both settings at every noise
level.&lt;/p&gt;
&lt;p&gt;With only &lt;code&gt;input&lt;/code&gt; connected and the acceleration taken as zero, the lead is computed as if the input were
coasting. That is exact on a ramp, but it grows as the square root of the distance-to-stop, so its curvature is
unbounded where the input&amp;rsquo;s velocity passes through zero. The setpoint answers with full jerk both ways, and
&lt;code&gt;outputDDot&lt;/code&gt; shows a spike at &lt;strong&gt;every velocity reversal&lt;/strong&gt; — on a 0.0975 amplitude, 1 rad/s sine at
&lt;code&gt;jerkLimit&lt;/code&gt; = &lt;code&gt;accelerationLimit&lt;/code&gt; = 10 π, the target&amp;rsquo;s acceleration one millisecond before the reversal reaches
0.127, more than the sine&amp;rsquo;s own 0.0975. With the gain at &lt;code&gt;0&lt;/code&gt; the same
reversal shows a longer, lower bump instead: the output then has to arrive at every instantaneous input position
able to stop there, so it over-brakes into a reversal and re-accelerates only as the input opens a gap again.&lt;/p&gt;
&lt;p&gt;By default the limiter supplies the missing acceleration from the input&amp;rsquo;s own history: the acceleration is the
second backward difference of &lt;code&gt;input&lt;/code&gt;, and the velocity is the first difference &lt;strong&gt;advanced by half a step&lt;/strong&gt;
(&lt;code&gt;a · dt / 2&lt;/code&gt;), because a plain backward difference is the velocity at &lt;code&gt;k − ½&lt;/code&gt; and that half-step error is larger
than the velocity itself in the last millisecond before a reversal. When &lt;code&gt;enableInputDot&lt;/code&gt; is set and
&lt;code&gt;enableInputDDot&lt;/code&gt; is not, the acceleration is the difference of &lt;code&gt;inputDot&lt;/code&gt; instead. Measured on the sine above,
gain &lt;code&gt;1&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;derivative source&lt;/th&gt;
&lt;th&gt;peak |aOut − aIn|&lt;/th&gt;
&lt;th&gt;cycles at ±J per five periods&lt;/th&gt;
&lt;th&gt;peak error&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;0.179 (184 % of aIn)&lt;/td&gt;
&lt;td&gt;118&lt;/td&gt;
&lt;td&gt;1.6e-4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;backward differences, not aligned&lt;/td&gt;
&lt;td&gt;0.056 (58 %)&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;2.5e-6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;estimated (the default)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 (locked)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exact &lt;code&gt;inputDot&lt;/code&gt; + &lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.000&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 (locked)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The zero errors are the rest window locking onto the reference state once the derivatives are known; before it
did, the estimator measured 3.0e-7 and exact derivatives 1.6e-9.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is for computed inputs&lt;/strong&gt; — a trajectory generator, an interpolated path, a kinematics output — not for
measured ones. Differencing amplifies noise by &lt;code&gt;1/dt&lt;/code&gt; and &lt;code&gt;1/dt²&lt;/code&gt;: on a position carrying 1e-8 of noise at a 1 ms cycle
the acceleration estimate is already 10 of noise against 0.1 of signal and the jerk sits on its limit
most of the time. (From 1e-6 of noise upwards even exact derivatives no longer help at this jerk limit, because the
position target itself jitters by &lt;code&gt;e/dt³&lt;/code&gt; ≈ 1000 against &lt;code&gt;jerkLimit&lt;/code&gt; = 31 — the limiter is then smoothing a noisy
setpoint, and the reversal is not the problem.) For a sensor-driven input, filter first and hand over the filter&amp;rsquo;s
derivatives with &lt;code&gt;enableInputDot&lt;/code&gt; / &lt;code&gt;enableInputDDot&lt;/code&gt;. Off by default.&lt;/p&gt;
&lt;p&gt;It does not change what the limits do at a step or a corner. A block wave is shaped by J, A and V alone and tracks
identically with the estimator on or off; a triangle wave tracks identically to the exact-derivative case. Note
that the &lt;strong&gt;lead itself&lt;/strong&gt; overshoots a triangle&amp;rsquo;s corner by the braking distance at the ramp velocity — 0.058 at a
ramp velocity of 0.5 with &lt;code&gt;jerkLimit&lt;/code&gt; = &lt;code&gt;accelerationLimit&lt;/code&gt; = 10 π, on and off the estimator alike and with exact derivatives too — because a lead is a
prediction that the input keeps its velocity, and at a non-differentiable corner that prediction is wrong by exactly
that distance. Use gain &lt;code&gt;0&lt;/code&gt; where a setpoint may never exceed what was commanded.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;7-example-configuration--pvaj-mode-position&#34;&gt;7. Example configuration — PVAJ mode (position)&lt;/h2&gt;
&lt;p&gt;An axis driven by a trajectory generator that publishes a position only. Accurate tracking wanted, the
travel limits guaranteed at an authority the drive can actually deliver. The limit values here are the block&amp;rsquo;s
defaults, so on a fresh instance only the last three rows are edits:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Set to&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the travel, backed off by the worst-case servo following error &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot; &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;what the mechanism can deliver &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot; &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot; &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAccelerationBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;15.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;authority reserved for defending the travel, at worst-case &lt;em&gt;deliverable&lt;/em&gt; figures — &lt;code&gt;0.0&lt;/code&gt; by default, which inherits &lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxJerkBraking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1500.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot; — &lt;code&gt;0.0&lt;/code&gt; by default, which inherits &lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;accurate tracking — &lt;code&gt;0.0&lt;/code&gt; by default, which is the feedforward off&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;enableInput&lt;/code&gt; and &lt;code&gt;enablePositionLimit&lt;/code&gt; are already &lt;code&gt;1&lt;/code&gt;, which is PVAJ mode with the travel enforced, so they need
no edit. Everything else can stay at its default too.&lt;/p&gt;
&lt;p&gt;Connect &lt;code&gt;input&lt;/code&gt; to the generator&amp;rsquo;s position output. &lt;code&gt;enableInputDot&lt;/code&gt; and &lt;code&gt;enableInputDDot&lt;/code&gt; are &lt;strong&gt;optional&lt;/strong&gt;: leave them at &lt;code&gt;0&lt;/code&gt; unless
the generator really publishes a velocity and an acceleration on those leaves. With them off the block differences
the input for the velocity and estimates the acceleration from its history, which is what keeps the lead accurate
through a velocity reversal — so a position-only setpoint needs no extra configuration.&lt;/p&gt;
&lt;p&gt;What to expect: &lt;code&gt;output&lt;/code&gt; follows &lt;code&gt;input&lt;/code&gt; closely and never leaves &lt;code&gt;±1.0&lt;/code&gt;; &lt;code&gt;trackingError&lt;/code&gt; is the lag;
&lt;code&gt;isLimiting&lt;/code&gt; is false while merely converging on a new setpoint and true when J, A, V or the box actually binds;
&lt;code&gt;warningSettingsMayCausePositionLimitOvershoot&lt;/code&gt; reads false with these numbers — a stop from &lt;code&gt;1.0&lt;/code&gt; at &lt;code&gt;15.0&lt;/code&gt;
needs &lt;code&gt;0.038&lt;/code&gt; of travel, against the &lt;code&gt;1.0&lt;/code&gt; of half-box available.&lt;/p&gt;
&lt;p&gt;Two adjustments worth knowing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feedforwardGain&lt;/code&gt; &lt;code&gt;1&lt;/code&gt; lets the setpoint exceed the &lt;em&gt;commanded&lt;/em&gt; amplitude slightly on a curved input. Set it to
&lt;code&gt;0&lt;/code&gt; where that must never happen, at the cost of tracking lag.&lt;/li&gt;
&lt;li&gt;If the generator publishes exact derivatives, set &lt;code&gt;enableInputDot&lt;/code&gt; and &lt;code&gt;enableInputDDot&lt;/code&gt; — that is more accurate
still than any estimate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;8-example-configuration--vaj-mode-velocity&#34;&gt;8. Example configuration — VAJ mode (velocity)&lt;/h2&gt;
&lt;p&gt;A conveyor driven by a velocity command, with no end stops. Only J, A and V are to be enforced; the position is
meaningless and must not be published. The envelope is again left at the block&amp;rsquo;s defaults, so the three mode
switches are the only edits:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Set to&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VAJ mode: &lt;code&gt;input&lt;/code&gt; is not read at all, &lt;code&gt;inputDot&lt;/code&gt; is the commanded velocity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableInputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;1&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;says the &lt;code&gt;inputDot&lt;/code&gt; leaf carries that velocity — off, the leaf is not read and the command is zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enablePositionLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;no travel limits on this axis — and with the position output suppressed there is no published position for a limit to mean anything against&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suppressPositionOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; reads zero rather than a position nobody commanded &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the envelope the command is shaped into &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot; &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot; &lt;em&gt;(default)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Everything else can stay at its default.&lt;/p&gt;
&lt;p&gt;Connect the velocity command to &lt;code&gt;inputDot&lt;/code&gt;. Leave &lt;code&gt;input&lt;/code&gt; unconnected — it is not read, and it may hold anything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;enableInputDot&lt;/code&gt; must be &lt;code&gt;1&lt;/code&gt; here.&lt;/strong&gt; It is the one switch that says the &lt;code&gt;inputDot&lt;/code&gt; leaf carries a velocity; with it
&lt;code&gt;0&lt;/code&gt; the leaf is not read in either mode, and in this mode there is no &lt;code&gt;input&lt;/code&gt; to estimate a velocity from, so the
command is zero and the axis comes to rest. In PVAJ mode the same switch declares that the leaf carries a real
setpoint velocity for the tracking lead. &lt;code&gt;enableInputDDot&lt;/code&gt;, &lt;code&gt;feedforwardGain&lt;/code&gt; and &lt;code&gt;suppressInputDDotEstimation&lt;/code&gt;,
by contrast, change nothing here: they shape the &lt;em&gt;position&lt;/em&gt; tracking lead, which this mode does not have.&lt;/p&gt;
&lt;p&gt;What to expect: &lt;code&gt;outputDot&lt;/code&gt; is brought onto the command within &lt;code&gt;accelerationLimit&lt;/code&gt; and &lt;code&gt;jerkLimit&lt;/code&gt; without
overshooting it, and is clipped to &lt;code&gt;velocityLimit&lt;/code&gt;; &lt;code&gt;outputDot&lt;/code&gt;, &lt;code&gt;outputDDot&lt;/code&gt; and &lt;code&gt;outputDDDot&lt;/code&gt; are a consistent
triple; &lt;code&gt;output&lt;/code&gt; reads &lt;code&gt;0&lt;/code&gt;; &lt;code&gt;trackingErrorDot&lt;/code&gt; is the tracking error to watch. A command beyond &lt;code&gt;velocityLimit&lt;/code&gt; is
clipped, not refused, and a non-finite command is held rather than followed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;suppressPositionOutput&lt;/code&gt; is only about the published leaf — the block keeps integrating the position internally
either way, and the trajectory is identical. Clear it if you want to see how far the axis has travelled; with no
box in force that number is unbounded and drifts as far as the commanded motion takes it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With end stops instead&lt;/strong&gt;, set &lt;code&gt;enablePositionLimit&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; and give the travel: the box is then defended on the
integrated position while the command is still followed in velocity, which is the reason to use this block rather
than a rate limiter. Note that suppressing the output does &lt;strong&gt;not&lt;/strong&gt; switch the box off — the two are independent, so
with both set the box is enforced on a position &lt;code&gt;output&lt;/code&gt; does not show. Clear &lt;code&gt;suppressPositionOutput&lt;/code&gt; when you
need to see that position, or read it in C++ with &lt;code&gt;getIntegratedPosition()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;9-diagnosing&#34;&gt;9. Diagnosing&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Output frozen after a limit edit&lt;/td&gt;
&lt;td&gt;A tiny positive J, A or V taken literally (§3). &lt;code&gt;0&lt;/code&gt; would have meant &lt;em&gt;no&lt;/em&gt; limit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output ignores the travel limits&lt;/td&gt;
&lt;td&gt;The two position limits are equal, or one is non-finite, which is no box at all (§3).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningSettingsMayCausePositionLimitOvershoot&lt;/code&gt; true&lt;/td&gt;
&lt;td&gt;A stop from &lt;code&gt;velocityLimit&lt;/code&gt; does not fit in half the box. §3.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;warningNotAbleToStopBeforeLimit&lt;/code&gt; true&lt;/td&gt;
&lt;td&gt;The limits were narrowed under a moving setpoint, or a bad state was seeded. The guarantee is already lost; &lt;code&gt;debug/predictedStopPosition&lt;/code&gt; says how far past the limit the setpoint will go.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setpoint sits outside the box and stays there&lt;/td&gt;
&lt;td&gt;Soft entry doing its job — &lt;code&gt;softEntryActive&lt;/code&gt; is true, and the input is still asking for it. §4.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output lags badly&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feedforwardGain&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;, or &lt;code&gt;enableInputDot&lt;/code&gt; is off on a generator that publishes a real velocity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt; spikes at every velocity reversal of the input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;suppressInputDDotEstimation&lt;/code&gt; is set, so the lead assumes the input coasts. Clear it, or supply &lt;code&gt;inputDDot&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt; reads zero on a moving axis&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enableInputDDot&lt;/code&gt; is set on an unconnected &lt;code&gt;inputDDot&lt;/code&gt;, which declares the acceleration to be zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; reads zero in VAJ mode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;suppressPositionOutput&lt;/code&gt;, by design (§8).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stops at a limit harsher than &lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enableMaxBrakingAtLimits&lt;/code&gt; is set, so approaches are planned at the braking authority.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deviation from the path just after enabling&lt;/td&gt;
&lt;td&gt;A noisy &lt;code&gt;input&lt;/code&gt;: the velocity inherited from differencing it is real to the limiter, and removing it moves the setpoint. Filter the input, or supply &lt;code&gt;inputDot&lt;/code&gt;. §5.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Module refuses to start&lt;/td&gt;
&lt;td&gt;The task period is unknown at start-up.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: GainSchedulingPVALimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter-3.30/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter-3.30/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version c3-version--archived&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter/&#34;&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter-3.30/&#34; selected&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;
    Superseded. The current release is
    &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter/&#34;&gt;3.34&lt;/a&gt;.
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;GainSchedulingPVALimiter&lt;/code&gt; bounds a position reference in position, velocity,
acceleration and jerk. It uses a feedback loop whose gain is &lt;strong&gt;scheduled&lt;/strong&gt;:
when the trajectory runs into a limit the gain is reduced so the limited
setpoint parks smoothly against the limit rather than fighting it, and once
every signal is back inside its limits the gain returns to normal over
&lt;code&gt;gainReturnTime&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt; for new work.&lt;/strong&gt; It replaces this block,
and its parameter names were deliberately chosen to match these ones so an
existing configuration and dashboard keep working. The important difference is
the position limit:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Block&lt;/th&gt;
&lt;th&gt;How closely the position limit is held&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Exactly. No tolerance at all&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;This block&lt;/td&gt;
&lt;td&gt;To about 1e-6 — &lt;strong&gt;a soft limit&lt;/strong&gt;, not a guarantee&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Those figures come from a test that runs both against the same limit set. If
your position limit is a safety boundary rather than a shaping preference,
that difference is the reason to migrate.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — unlimited position reference&amp;quot;]) --&amp;gt; B[&amp;quot;GainSchedulingPVALimiter&amp;quot;]
    i2([&amp;quot;inputDot — unlimited velocity&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — unlimited acceleration&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — limited position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — limited velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — limited acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;gainOutput — the scheduled gain&amp;quot;])
    B --&amp;gt; o5([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each channel also publishes &lt;code&gt;State01&lt;/code&gt;, &lt;code&gt;State02&lt;/code&gt;, … with six limit flags and an
&lt;code&gt;active&lt;/code&gt; flag, plus &lt;code&gt;Limits01/activePositionLowerLimit&lt;/code&gt; and
&lt;code&gt;activePositionUpperLimit&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The scheduled gain falls toward zero while any limit is active and returns to
1 once everything is inside. &lt;code&gt;gainReturnTime&lt;/code&gt; sets that recovery, but the
gain is also smoothed, so &lt;strong&gt;the actual recovery takes about
&lt;code&gt;gainReturnTime&lt;/code&gt; ÷ 0.7&lt;/strong&gt; — roughly 2.9 s for a setting of 2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Supply exact derivatives or none.&lt;/strong&gt; This block&amp;rsquo;s gain schedule degrades when
&lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; are differenced from a noisy input. If your motion
source does not produce true derivatives, leave those inputs at zero.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block cannot be configured from an application in C++&lt;/strong&gt; — its limits are
reachable only through the parameter tree.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The unlimited position reference. One element per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The unlimited velocity reference, used in the modes that take it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The unlimited acceleration reference.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True passes &lt;code&gt;input&lt;/code&gt; straight to &lt;code&gt;output&lt;/code&gt;. Use it for a runtime override; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The limited position. &lt;strong&gt;It settles against the limit rather than being clamped to it&lt;/strong&gt;, so it may sit a fraction outside — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The limited velocity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The limited acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The scheduled gain, one element per channel. 1 while free, near zero while a limit is active, recovering in between. &lt;strong&gt;Watch this to see when the block is limiting and how long it takes to let go.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Per channel, &lt;code&gt;State01&lt;/code&gt;, &lt;code&gt;State02&lt;/code&gt;, …: &lt;code&gt;positionUpperLimitActive&lt;/code&gt;,
&lt;code&gt;positionLowerLimitActive&lt;/code&gt;, &lt;code&gt;velocityUpperLimitActive&lt;/code&gt;,
&lt;code&gt;velocityLowerLimitActive&lt;/code&gt;, &lt;code&gt;accelerationUpperLimitActive&lt;/code&gt;,
&lt;code&gt;accelerationLowerLimitActive&lt;/code&gt; and &lt;code&gt;active&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;p&gt;Block level: &lt;code&gt;enable&lt;/code&gt;, and &lt;code&gt;adaptive&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Settings&lt;/code&gt; holds the loop tuning:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s²&lt;/td&gt;
&lt;td&gt;Position gain of the feedback loop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s&lt;/td&gt;
&lt;td&gt;Velocity gain. The two together are really one bandwidth-and-damping choice.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;How long the gain takes to recover after the last limit clears. &lt;strong&gt;Accepted range 0.1 – 5.0&lt;/strong&gt;; outside that it is corrected and logged. The real recovery is about this divided by 0.7.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rad/s&lt;/td&gt;
&lt;td&gt;Cut-off of the input pre-filter.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, … hold each channel&amp;rsquo;s limits:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit&lt;/code&gt;, &lt;code&gt;positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The position band. &lt;strong&gt;Soft&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Which inputs are used and whether a pre-limit is applied. See below.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Position input only, with a pre-limit applied. &lt;strong&gt;The recommended value.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Position input, no pre-limit. The source records that this mode is not robust — avoid it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Velocity and acceleration inputs are used as well.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Position input only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not used.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All parameters are persistent and survive a restart.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consider migrating first.&lt;/strong&gt; If this is a new installation, use
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;. The rest of this page is for a machine that
already runs this block.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set each channel&amp;rsquo;s position band, &lt;code&gt;velocityLimit&lt;/code&gt;, &lt;code&gt;accelerationLimit&lt;/code&gt; and
&lt;code&gt;jerkLimit&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;mode&lt;/code&gt; to 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;gainReturnTime&lt;/code&gt; to 2.0 and leave the two gains at whatever your
configuration ships with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true. Command a move well inside the limits and confirm
&lt;code&gt;output&lt;/code&gt; tracks &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;gainOutput&lt;/code&gt; stays at 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit. Confirm &lt;code&gt;gainOutput&lt;/code&gt; falls,
the matching &lt;code&gt;State&lt;/code&gt; flag goes true, and &lt;code&gt;output&lt;/code&gt; settles against the limit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6 will let the setpoint sit slightly past the limit.&lt;/strong&gt; That is how
this block works — the limit is where the loop settles, not a wall. Leave
margin, and if the boundary is a safety limit, migrate to
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Release the limit and time how long &lt;code&gt;gainOutput&lt;/code&gt; takes to return to 1. It
will be longer than &lt;code&gt;gainReturnTime&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the four limits from the machine.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;mode&lt;/code&gt; at 0. Mode 1 is documented in the source as not robust, and
modes 2 and 3 change which inputs matter.&lt;/li&gt;
&lt;li&gt;Tune &lt;code&gt;gainReturnTime&lt;/code&gt; for how quickly the block should let go after a limit
event. Shorter recovers sooner and can re-enter the limit; longer keeps the
setpoint soft for a while afterwards. The accepted range is 0.1 to 5.0.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;positionGain&lt;/code&gt; and &lt;code&gt;velocityGain&lt;/code&gt; alone unless tracking is visibly
poor. They are a matched pair, and changing one without the other changes
the loop&amp;rsquo;s damping.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;gainOutput&lt;/code&gt; during commissioning. It is the clearest picture of what
this block is doing: a dip means a limit was hit, and the width of the
recovery is your &lt;code&gt;gainReturnTime&lt;/code&gt; in practice.&lt;/li&gt;
&lt;li&gt;Supply &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; only if they are exact. Differenced
derivatives make the gain schedule behave worse than leaving them at zero.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/gainscheduling-pvalimiter-schedule-c96258be.svg&#34; alt=&#34;Scheduled gain through a 0.6 s limit event at three return times: all threedrop to near zero while limiting, then recover to 1 — the shortest in about1.4 s and the longest still recovering after 3 s.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the recovery time off how long each curve takes to climb back to 1.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The setpoint sits slightly past a position limit&lt;/td&gt;
&lt;td&gt;Expected: this block&amp;rsquo;s position limit is soft — it settles against the limit rather than clamping&lt;/td&gt;
&lt;td&gt;Leave margin, or migrate to &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine passed the position limit by more than expected&lt;/td&gt;
&lt;td&gt;The soft limit plus the servo&amp;rsquo;s own following error&lt;/td&gt;
&lt;td&gt;Back the limits off, and consider migrating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block behaves worse when the derivative inputs are wired&lt;/td&gt;
&lt;td&gt;Those derivatives are differenced rather than exact, and the gain schedule folds&lt;/td&gt;
&lt;td&gt;Leave &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; at zero unless your source produces true values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery after a limit takes longer than &lt;code&gt;gainReturnTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the gain is smoothed as well as ramped, so recovery is about that time divided by 0.7&lt;/td&gt;
&lt;td&gt;Shorten &lt;code&gt;gainReturnTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; reads back different from what was written&lt;/td&gt;
&lt;td&gt;It is outside the accepted 0.1 – 5.0 range and was corrected&lt;/td&gt;
&lt;td&gt;Write a value in range; the correction is logged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The setpoint keeps re-entering the limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; too short, so the gain recovers before the situation has&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The setpoint stays soft long after the limit cleared&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; too long&lt;/td&gt;
&lt;td&gt;Shorten it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is rough or unstable near a limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mode&lt;/code&gt; is 1, which the source records as not robust&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;mode&lt;/code&gt; to 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block cannot be configured from the application&lt;/td&gt;
&lt;td&gt;Expected: its limits are reachable only through the parameter tree&lt;/td&gt;
&lt;td&gt;Configure it in the configuration package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainOutput&lt;/code&gt; never returns to 1&lt;/td&gt;
&lt;td&gt;Some limit is still active — check the &lt;code&gt;State&lt;/code&gt; flags for that channel&lt;/td&gt;
&lt;td&gt;Widen the limit, or fix what is commanding past it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The gain schedule resumed mid-recovery after a restart&lt;/td&gt;
&lt;td&gt;The gain is not reset at start&lt;/td&gt;
&lt;td&gt;Expected; it recovers on its own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need the position limit guaranteed&lt;/td&gt;
&lt;td&gt;This block cannot do that&lt;/td&gt;
&lt;td&gt;Use &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a channel with 1 m of travel:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable                        = true
Settings/gainReturnTime       = 2.0
Limits01/positionLowerLimit   = -0.5
Limits01/positionUpperLimit   =  0.5
Limits01/velocityLimit        =  0.5
Limits01/accelerationLimit    =  5.0
Limits01/jerkLimit            = 50.0
Limits01/mode                 = 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are the block&amp;rsquo;s own defaults, and they are the limit set the comparison
test uses.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position&lt;/td&gt;
&lt;td&gt;The position band&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Soft.&lt;/strong&gt; The setpoint settles against the limit and may sit about 1e-6 outside it. This is not a guarantee&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;State&lt;/code&gt; position flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; velocity, acceleration&lt;/td&gt;
&lt;td&gt;Their limits&lt;/td&gt;
&lt;td&gt;Held to about 1e-9&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;State&lt;/code&gt; velocity and acceleration flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jerk&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bounded&lt;/td&gt;
&lt;td&gt;Not separately reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; within 0.1 – 5.0&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Corrected to the nearest edge&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged&lt;/strong&gt; when corrected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual recovery time&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;About &lt;code&gt;gainReturnTime&lt;/code&gt; divided by 0.7, because the gain is smoothed as well as ramped&lt;/td&gt;
&lt;td&gt;Watch &lt;code&gt;gainOutput&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Derivative inputs&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Not checked. Differenced derivatives degrade the gain schedule — worse than supplying none&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration from C++&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;The limits are writable only through the parameter tree&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The mechanism&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;This block bounds the setpoint. The machine passes the limit by its servo following error, on top of the soft limit above&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gain schedule state&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Not reset at start; it recovers on its own&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gainOutput&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts. Sub-trees are numbered from 1&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block logs when it corrects a setting outside its accepted range. Every
other condition above shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: GainSchedulingPVALimiter</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;select class=&#34;c3-version__select&#34;
            aria-label=&#34;Show this page as it was in another Control3 version&#34;
            onchange=&#34;if(this.value)window.location.href=this.value;&#34;&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter/&#34; selected&gt;3.32–3.34 (latest)&lt;/option&gt;
      &lt;option value=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/gainscheduling-pvalimiter-3.30/&#34;&gt;3.30&lt;/option&gt;
    &lt;/select&gt;
  &lt;/span&gt;
  &lt;span class=&#34;c3-version__note&#34;&gt;Current release&lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;GainSchedulingPVALimiter&lt;/code&gt; bounds a position reference in position, velocity,
acceleration and jerk. It uses a feedback loop whose gain is &lt;strong&gt;scheduled&lt;/strong&gt;:
when the trajectory runs into a limit the gain is reduced so the limited
setpoint parks smoothly against the limit rather than fighting it, and once
every signal is back inside its limits the gain returns to normal over
&lt;code&gt;gainReturnTime&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Deprecated — scheduled for removal.&lt;/strong&gt; &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt; is
the only setpoint limiter that may be used for new work. This block is kept
only until the last machine is off it, and will then be deleted. Plan the
migration; do not start a new installation on it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Its &lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, … leaf names were deliberately chosen to match
these ones, so an existing configuration package and dashboard keep applying
across the swap. &lt;strong&gt;The rest does not carry over.&lt;/strong&gt; &lt;code&gt;Settings/omega&lt;/code&gt;,
&lt;code&gt;Settings/positionGain&lt;/code&gt;, &lt;code&gt;Settings/velocityGain&lt;/code&gt;, &lt;code&gt;Settings/gainReturnTime&lt;/code&gt;,
&lt;code&gt;velocityFactor&lt;/code&gt;, &lt;code&gt;gainOutput&lt;/code&gt; and the &lt;code&gt;adaptive&lt;/code&gt; group have no counterpart —
there is no gain scheduling and no input filter in the replacement. Config
entries that set those leaves will not resolve. The important behavioural
difference is the position limit:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Block&lt;/th&gt;
&lt;th&gt;How closely the position limit is held&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Exactly. No tolerance at all&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;This block&lt;/td&gt;
&lt;td&gt;To about 1e-6 — &lt;strong&gt;a soft limit&lt;/strong&gt;, not a guarantee&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Those figures come from a test that runs both against the same limit set. If
your position limit is a safety boundary rather than a shaping preference,
that difference is the reason to migrate.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — unlimited position reference&amp;quot;]) --&amp;gt; B[&amp;quot;GainSchedulingPVALimiter&amp;quot;]
    i2([&amp;quot;inputDot — unlimited velocity&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;inputDDot — unlimited acceleration&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — limited position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — limited velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — limited acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;gainOutput — the scheduled gain&amp;quot;])
    B --&amp;gt; o5([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each channel also publishes &lt;code&gt;State01&lt;/code&gt;, &lt;code&gt;State02&lt;/code&gt;, … with six limit flags and an
&lt;code&gt;active&lt;/code&gt; flag, plus &lt;code&gt;Limits01/activePositionLowerLimit&lt;/code&gt; and
&lt;code&gt;activePositionUpperLimit&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The scheduled gain falls toward zero while any limit is active and returns to
1 once everything is inside. &lt;code&gt;gainReturnTime&lt;/code&gt; sets that recovery, but the
gain is also smoothed, so &lt;strong&gt;the actual recovery takes about
&lt;code&gt;gainReturnTime&lt;/code&gt; ÷ 0.7&lt;/strong&gt; — roughly 2.9 s for a setting of 2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Supply exact derivatives or none.&lt;/strong&gt; This block&amp;rsquo;s gain schedule degrades when
&lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; are differenced from a noisy input. If your motion
source does not produce true derivatives, leave those inputs at zero.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block cannot be configured from an application in C++&lt;/strong&gt; — its limits are
reachable only through the parameter tree.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The unlimited position reference. One element per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The unlimited velocity reference, used in the modes that take it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The unlimited acceleration reference.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True passes &lt;code&gt;input&lt;/code&gt; straight to &lt;code&gt;output&lt;/code&gt;. Use it for a runtime override; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The limited position. &lt;strong&gt;It settles against the limit rather than being clamped to it&lt;/strong&gt;, so it may sit a fraction outside — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The limited velocity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The limited acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The scheduled gain, one element per channel. 1 while free, near zero while a limit is active, recovering in between. &lt;strong&gt;Watch this to see when the block is limiting and how long it takes to let go.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Per channel, &lt;code&gt;State01&lt;/code&gt;, &lt;code&gt;State02&lt;/code&gt;, …: &lt;code&gt;positionUpperLimitActive&lt;/code&gt;,
&lt;code&gt;positionLowerLimitActive&lt;/code&gt;, &lt;code&gt;velocityUpperLimitActive&lt;/code&gt;,
&lt;code&gt;velocityLowerLimitActive&lt;/code&gt;, &lt;code&gt;accelerationUpperLimitActive&lt;/code&gt;,
&lt;code&gt;accelerationLowerLimitActive&lt;/code&gt; and &lt;code&gt;active&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;p&gt;Block level: &lt;code&gt;enable&lt;/code&gt;, and &lt;code&gt;adaptive&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Settings&lt;/code&gt; holds the loop tuning:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s²&lt;/td&gt;
&lt;td&gt;Position gain of the feedback loop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityGain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s&lt;/td&gt;
&lt;td&gt;Velocity gain. The two together are really one bandwidth-and-damping choice.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;How long the gain takes to recover after the last limit clears. &lt;strong&gt;Accepted range 0.1 – 5.0&lt;/strong&gt;; outside that it is corrected and logged. The real recovery is about this divided by 0.7.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;omega&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rad/s&lt;/td&gt;
&lt;td&gt;Cut-off of the input pre-filter.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;Limits01&lt;/code&gt;, &lt;code&gt;Limits02&lt;/code&gt;, … hold each channel&amp;rsquo;s limits:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionLowerLimit&lt;/code&gt;, &lt;code&gt;positionUpperLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The position band. &lt;strong&gt;Soft&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;Symmetric.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Which inputs are used and whether a pre-limit is applied. See below.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Position input only, with a pre-limit applied. &lt;strong&gt;The recommended value.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Position input, no pre-limit. The source records that this mode is not robust — avoid it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Velocity and acceleration inputs are used as well.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Position input only, with the position limit applied as a &lt;strong&gt;taper&lt;/strong&gt; rather than a clamp. See the note below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not used.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In mode 3 the limit is approached through a taper instead of a clamp. The
taper begins one braking distance inside each active position limit:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Break-point offset $= V^2/2A$ [m], with $V$ &lt;code&gt;velocityLimit&lt;/code&gt; and $A$
&lt;code&gt;accelerationLimit&lt;/code&gt; — the distance an axis at full speed needs to stop at the
acceleration limit. It is capped at half the width of the active band, so the
two break points can never cross. &lt;strong&gt;On a band narrower than twice the braking
distance the two meet in the middle and the taper degenerates into a hard
limit&lt;/strong&gt;, which is the correct behaviour for a band shorter than the stop it
has to absorb.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Raising &lt;code&gt;velocityLimit&lt;/code&gt; or lowering &lt;code&gt;accelerationLimit&lt;/code&gt; therefore starts the
taper further from the limit and softens the approach over a longer distance.&lt;/p&gt;
&lt;p&gt;All parameters are persistent and survive a restart.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consider migrating first.&lt;/strong&gt; If this is a new installation, use
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;. The rest of this page is for a machine that
already runs this block.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set each channel&amp;rsquo;s position band, &lt;code&gt;velocityLimit&lt;/code&gt;, &lt;code&gt;accelerationLimit&lt;/code&gt; and
&lt;code&gt;jerkLimit&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;mode&lt;/code&gt; to 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;gainReturnTime&lt;/code&gt; to 2.0 and leave the two gains at whatever your
configuration ships with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true. Command a move well inside the limits and confirm
&lt;code&gt;output&lt;/code&gt; tracks &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;gainOutput&lt;/code&gt; stays at 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Command a move that runs into a position limit. Confirm &lt;code&gt;gainOutput&lt;/code&gt; falls,
the matching &lt;code&gt;State&lt;/code&gt; flag goes true, and &lt;code&gt;output&lt;/code&gt; settles against the limit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6 will let the setpoint sit slightly past the limit.&lt;/strong&gt; That is how
this block works — the limit is where the loop settles, not a wall. Leave
margin, and if the boundary is a safety limit, migrate to
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Release the limit and time how long &lt;code&gt;gainOutput&lt;/code&gt; takes to return to 1. It
will be longer than &lt;code&gt;gainReturnTime&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the four limits from the machine.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;mode&lt;/code&gt; at 0. Mode 1 is documented in the source as not robust, and
modes 2 and 3 change which inputs matter.&lt;/li&gt;
&lt;li&gt;Tune &lt;code&gt;gainReturnTime&lt;/code&gt; for how quickly the block should let go after a limit
event. Shorter recovers sooner and can re-enter the limit; longer keeps the
setpoint soft for a while afterwards. The accepted range is 0.1 to 5.0.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;positionGain&lt;/code&gt; and &lt;code&gt;velocityGain&lt;/code&gt; alone unless tracking is visibly
poor. They are a matched pair, and changing one without the other changes
the loop&amp;rsquo;s damping.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;gainOutput&lt;/code&gt; during commissioning. It is the clearest picture of what
this block is doing: a dip means a limit was hit, and the width of the
recovery is your &lt;code&gt;gainReturnTime&lt;/code&gt; in practice.&lt;/li&gt;
&lt;li&gt;Supply &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; only if they are exact. Differenced
derivatives make the gain schedule behave worse than leaving them at zero.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/gainscheduling-pvalimiter-schedule-c96258be.svg&#34; alt=&#34;Scheduled gain through a 0.6 s limit event at three return times: all threedrop to near zero while limiting, then recover to 1 — the shortest in about1.4 s and the longest still recovering after 3 s.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the recovery time off how long each curve takes to climb back to 1.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The setpoint sits slightly past a position limit&lt;/td&gt;
&lt;td&gt;Expected: this block&amp;rsquo;s position limit is soft — it settles against the limit rather than clamping&lt;/td&gt;
&lt;td&gt;Leave margin, or migrate to &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine passed the position limit by more than expected&lt;/td&gt;
&lt;td&gt;The soft limit plus the servo&amp;rsquo;s own following error&lt;/td&gt;
&lt;td&gt;Back the limits off, and consider migrating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block behaves worse when the derivative inputs are wired&lt;/td&gt;
&lt;td&gt;Those derivatives are differenced rather than exact, and the gain schedule folds&lt;/td&gt;
&lt;td&gt;Leave &lt;code&gt;inputDot&lt;/code&gt; and &lt;code&gt;inputDDot&lt;/code&gt; at zero unless your source produces true values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery after a limit takes longer than &lt;code&gt;gainReturnTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the gain is smoothed as well as ramped, so recovery is about that time divided by 0.7&lt;/td&gt;
&lt;td&gt;Shorten &lt;code&gt;gainReturnTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; reads back different from what was written&lt;/td&gt;
&lt;td&gt;It is outside the accepted 0.1 – 5.0 range and was corrected&lt;/td&gt;
&lt;td&gt;Write a value in range; the correction is logged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The setpoint keeps re-entering the limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; too short, so the gain recovers before the situation has&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The setpoint stays soft long after the limit cleared&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; too long&lt;/td&gt;
&lt;td&gt;Shorten it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In mode 3 the setpoint starts easing off a long way before the limit&lt;/td&gt;
&lt;td&gt;Expected: the taper begins one braking distance $V^2/2A$ inside the limit&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;velocityLimit&lt;/code&gt; or raise &lt;code&gt;accelerationLimit&lt;/code&gt; to shorten it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In mode 3 the limit behaves like a hard clamp with no taper at all&lt;/td&gt;
&lt;td&gt;Expected: the position band is narrower than twice the braking distance, so the two break points met in the middle&lt;/td&gt;
&lt;td&gt;Widen the band, or lower &lt;code&gt;velocityLimit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motion is rough or unstable near a limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mode&lt;/code&gt; is 1, which the source records as not robust&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;mode&lt;/code&gt; to 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block cannot be configured from the application&lt;/td&gt;
&lt;td&gt;Expected: its limits are reachable only through the parameter tree&lt;/td&gt;
&lt;td&gt;Configure it in the configuration package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainOutput&lt;/code&gt; never returns to 1&lt;/td&gt;
&lt;td&gt;Some limit is still active — check the &lt;code&gt;State&lt;/code&gt; flags for that channel&lt;/td&gt;
&lt;td&gt;Widen the limit, or fix what is commanding past it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The gain schedule resumed mid-recovery after a restart&lt;/td&gt;
&lt;td&gt;The gain is not reset at start&lt;/td&gt;
&lt;td&gt;Expected; it recovers on its own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need the position limit guaranteed&lt;/td&gt;
&lt;td&gt;This block cannot do that&lt;/td&gt;
&lt;td&gt;Use &lt;a href=&#34;/docs/developing-control-applications/control-blocks/limiters-and-shaping/pvajlimiter/&#34;&gt;&lt;code&gt;PvajLimiter&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a channel with 1 m of travel:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable                        = true
Settings/gainReturnTime       = 2.0
Limits01/positionLowerLimit   = -0.5
Limits01/positionUpperLimit   =  0.5
Limits01/velocityLimit        =  0.5
Limits01/accelerationLimit    =  5.0
Limits01/jerkLimit            = 50.0
Limits01/mode                 = 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are the block&amp;rsquo;s own defaults, and they are the limit set the comparison
test uses.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; position&lt;/td&gt;
&lt;td&gt;The position band&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Soft.&lt;/strong&gt; The setpoint settles against the limit and may sit about 1e-6 outside it. This is not a guarantee&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;State&lt;/code&gt; position flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; velocity, acceleration&lt;/td&gt;
&lt;td&gt;Their limits&lt;/td&gt;
&lt;td&gt;Held to about 1e-9&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;State&lt;/code&gt; velocity and acceleration flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jerk&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jerkLimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bounded&lt;/td&gt;
&lt;td&gt;Not separately reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gainReturnTime&lt;/code&gt; within 0.1 – 5.0&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Corrected to the nearest edge&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged&lt;/strong&gt; when corrected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual recovery time&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;About &lt;code&gt;gainReturnTime&lt;/code&gt; divided by 0.7, because the gain is smoothed as well as ramped&lt;/td&gt;
&lt;td&gt;Watch &lt;code&gt;gainOutput&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Derivative inputs&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Not checked. Differenced derivatives degrade the gain schedule — worse than supplying none&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration from C++&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;The limits are writable only through the parameter tree&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The mechanism&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;This block bounds the setpoint. The machine passes the limit by its servo following error, on top of the soft limit above&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gain schedule state&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Not reset at start; it recovers on its own&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gainOutput&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts. Sub-trees are numbered from 1&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block logs when it corrects a setting outside its accepted range. Every
other condition above shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.32.1 (340db23).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: SmoothStop</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/smooth-stop/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/smooth-stop/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SmoothStop&lt;/code&gt; brings a moving axis to a controlled standstill on command. When
you raise &lt;code&gt;gotoStandstill&lt;/code&gt; it takes over from the live motion reference, follows
a jerk-limited braking profile down to zero velocity, and holds there. Release
the command and it fades back to the live reference.&lt;/p&gt;
&lt;p&gt;The stop is bounded three ways at once — by deceleration, by jerk, and by
whichever of a time budget or a distance budget runs out first. If the natural
profile would exceed a budget, &lt;strong&gt;the block computes a shorter one&lt;/strong&gt; rather than
letting the stop overrun.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;u — live position reference&amp;quot;]) --&amp;gt; B[&amp;quot;SmoothStop&amp;quot;]
    i2([&amp;quot;uDot — live velocity reference&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;uDDot — live acceleration reference&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;gotoStandstill&amp;quot;]) --&amp;gt; B
    i5([&amp;quot;resetStandstill&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;y — position output&amp;quot;])
    B --&amp;gt; o2([&amp;quot;ydot — velocity output&amp;quot;])
    B --&amp;gt; o3([&amp;quot;yddot — acceleration output&amp;quot;])
    B --&amp;gt; o4([&amp;quot;yss — braking profile position&amp;quot;])
    B --&amp;gt; o5([&amp;quot;yssDot — braking profile velocity&amp;quot;])
    B --&amp;gt; o6([&amp;quot;yssDDot — braking profile acceleration&amp;quot;])
    B --&amp;gt; o7([&amp;quot;smoothStopActive — per channel&amp;quot;])
    B --&amp;gt; o8([&amp;quot;isAtStandstill&amp;quot;])
    B --&amp;gt; o9([&amp;quot;standstillSwitchIsOn&amp;quot;])
    B --&amp;gt; o10([&amp;quot;standstillSwitchIsOff&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Stopping distance from velocity $v$ with deceleration $a$ is roughly
$v^2/2a$, and jerk rounds the corners at each end. The stop takes about
$v/a + a/j$ seconds. &lt;code&gt;maxStopJerkFactor&lt;/code&gt; is the fraction of the stop spent
ramping the deceleration, from 0 (a pure trapezoid, sharpest) to 0.5 (a pure
triangle, gentlest).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Both limits default to zero, which means &amp;ldquo;stop instantly&amp;rdquo;.&lt;/strong&gt; With
&lt;code&gt;smoothStopAcc&lt;/code&gt; and &lt;code&gt;smoothStopJerk&lt;/code&gt; at 0 the block jumps the output to where
the axis was and holds it — a hard stop from a block called SmoothStop. &lt;strong&gt;Set
both before you use it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;gotoStandstill&lt;/code&gt; is a level, not a pulse.&lt;/strong&gt; Hold it true and the axis stays
stopped; release it and the block fades back to the live reference.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The live position reference the axis normally follows. One element per channel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;uDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The live velocity reference.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;uDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The live acceleration reference.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gotoStandstill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Raise it to begin stopping; hold it to stay stopped; release it to fade back to the live reference. A &lt;strong&gt;level&lt;/strong&gt;, and one value for the whole block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resetStandstill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Makes the changeover between the live reference and the braking profile happen &lt;strong&gt;instantly&lt;/strong&gt; rather than fading. Use it when a fade would itself be a disturbance.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The position to follow — the live reference, the braking profile, or a fade between them. This is what the axis should track.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ydot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The matching velocity. Note the lower-case path name, where the input is &lt;code&gt;uDot&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yddot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The matching acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yss&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;The braking profile&amp;rsquo;s own position, whether or not it is currently selected. Useful for watching a stop that has not been engaged.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yssDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s or rad/s&lt;/td&gt;
&lt;td&gt;The braking profile&amp;rsquo;s velocity — &lt;strong&gt;watch this to see the stop shape&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yssDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;The braking profile&amp;rsquo;s acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;smoothStopActive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True per channel while that channel&amp;rsquo;s braking profile is still running.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isAtStandstill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;strong&gt;every&lt;/strong&gt; channel has finished stopping and is at rest. One value for the whole block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;standstillSwitchIsOn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The changeover has fully reached the braking profile.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;standstillSwitchIsOff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The changeover has fully reached the live reference.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;smoothStopAcc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s² or rad/s²&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0, per channel&lt;/td&gt;
&lt;td&gt;Deceleration limit. &lt;strong&gt;0 means an instant stop.&lt;/strong&gt; Higher stops sooner and harder. Negative values are used as their magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;smoothStopJerk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m/s³ or rad/s³&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0, per channel&lt;/td&gt;
&lt;td&gt;Jerk limit — how fast the deceleration may build. &lt;strong&gt;0 means an instant stop.&lt;/strong&gt; Higher gives sharper corners.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxStopTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;at least one task period, per channel&lt;/td&gt;
&lt;td&gt;The longest the stop may take. If the natural profile would exceed it, the block computes a harder one that fits. Corrected up to one task period if set lower.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxStopDistance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;m or rad&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 upward, per channel&lt;/td&gt;
&lt;td&gt;The furthest the axis may travel while stopping. Same treatment as the time budget.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxStopJerkFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 – 0.5, per channel&lt;/td&gt;
&lt;td&gt;Only used when a budget forces a recomputed profile. 0 gives the sharpest stop that fits, 0.5 the gentlest. Corrected silently if out of range.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;startAtStandstill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;When true, the block comes up stopped on the first cycle instead of following the reference.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All six are persistent and survive a restart, and the first five are &lt;strong&gt;per
channel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One parameter lives below this block&lt;/strong&gt;: the changeover&amp;rsquo;s fade time, in the
&lt;code&gt;standstillSwitch&lt;/code&gt; sub-tree. See &lt;a href=&#34;/docs/developing-control-applications/control-blocks/switching-and-routing/soft-switch/&#34;&gt;&lt;code&gt;soft-switch.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set &lt;code&gt;smoothStopAcc&lt;/code&gt; and &lt;code&gt;smoothStopJerk&lt;/code&gt; first.&lt;/strong&gt; Both default to zero,
which makes the block stop the axis instantly. Start with the deceleration
the machine uses for a normal decelerating move, and a jerk about ten times
that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxStopTime&lt;/code&gt; and &lt;code&gt;maxStopDistance&lt;/code&gt; from the machine&amp;rsquo;s real safety
budget — how long and how far the axis may keep moving after a stop is
commanded.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;maxStopJerkFactor&lt;/code&gt; to 0.25 as a starting point. It only matters when a
budget forces a shorter profile.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link &lt;code&gt;u&lt;/code&gt;, &lt;code&gt;uDot&lt;/code&gt; and &lt;code&gt;uDDot&lt;/code&gt; from the motion source, and &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;ydot&lt;/code&gt;,
&lt;code&gt;yddot&lt;/code&gt; to whatever follows. Confirm the outputs track the inputs exactly
with &lt;code&gt;gotoStandstill&lt;/code&gt; false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With the axis moving slowly, raise &lt;code&gt;gotoStandstill&lt;/code&gt;. Watch &lt;code&gt;yssDot&lt;/code&gt; come
down to zero and &lt;code&gt;isAtStandstill&lt;/code&gt; go true.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 stops a moving machine.&lt;/strong&gt; Do it at low speed first, with the axis
clear, and confirm the distance travelled is inside your budget before
trying it at full speed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Measure the stop: time it, and measure how far the axis travelled. Compare
both against &lt;code&gt;maxStopTime&lt;/code&gt; and &lt;code&gt;maxStopDistance&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Release &lt;code&gt;gotoStandstill&lt;/code&gt; and confirm the outputs fade back to the live
reference without a bump.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the deceleration from the machine — what the mechanics, the drive and
the load can take. This is a physical limit, not a preference.&lt;/li&gt;
&lt;li&gt;Set the jerk from what the structure tolerates. Lower jerk gives rounder
corners and a longer stop; higher jerk stops sooner and shakes more.&lt;/li&gt;
&lt;li&gt;Check the resulting stopping distance at full speed: roughly $v^2/2a$ plus a
little for the jerk ramps. If it exceeds the budget, either raise the
deceleration or accept that the block will override your limits.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;yssDot&lt;/code&gt; on a trace during a stop. It should fall smoothly to zero
with no overshoot and no residual crawl.&lt;/li&gt;
&lt;li&gt;If a budget is forcing a recomputed profile, the actual deceleration and
jerk used will be higher than what you configured — and &lt;strong&gt;the block does not
publish them&lt;/strong&gt;. Infer them from the trace.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;maxStopJerkFactor&lt;/code&gt; to shape those forced stops: lower for the shortest
stop that fits, higher for the gentlest.&lt;/li&gt;
&lt;li&gt;Set the changeover fade time in the &lt;code&gt;standstillSwitch&lt;/code&gt; sub-tree so releasing
the stop is smooth. The engagement is instant by design — the profile starts
exactly where the axis is, so there is nothing to fade.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/smooth-stop-profile-1e36f16d.svg&#34; alt=&#34;Velocity during a stop from 1.0 with a deceleration of 2, at three jerklimits: a jerk of 100 is nearly a straight ramp stopping at 0.53 s, 10 roundsthe corners and stops at 0.71 s, and 4 is gentlest and takes just over asecond.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the deceleration off the slope of the straight section and the jerk off
how rounded the corners are.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The axis stops dead instead of smoothly&lt;/td&gt;
&lt;td&gt;&lt;code&gt;smoothStopAcc&lt;/code&gt; or &lt;code&gt;smoothStopJerk&lt;/code&gt; is 0 — the default&lt;/td&gt;
&lt;td&gt;Set both to real values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The stop is harsher than configured&lt;/td&gt;
&lt;td&gt;A budget forced a shorter profile&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;maxStopTime&lt;/code&gt; or &lt;code&gt;maxStopDistance&lt;/code&gt;, or accept it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The stop overshoots the distance budget&lt;/td&gt;
&lt;td&gt;The budget branch cannot fully compensate when the axis is still accelerating at the moment of the stop&lt;/td&gt;
&lt;td&gt;Command the stop from a steady speed where possible, and leave margin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A jolt at the start of the stop&lt;/td&gt;
&lt;td&gt;The axis was accelerating when the stop was commanded, and the recomputed profile starts from zero acceleration&lt;/td&gt;
&lt;td&gt;Leave margin in the budgets so the natural profile is used&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The stop takes longer than expected&lt;/td&gt;
&lt;td&gt;Jerk too low, so the corners dominate&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;smoothStopJerk&lt;/code&gt;, or lower &lt;code&gt;maxStopJerkFactor&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine shakes during the stop&lt;/td&gt;
&lt;td&gt;Jerk too high&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;smoothStopJerk&lt;/code&gt;, or raise &lt;code&gt;maxStopJerkFactor&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isAtStandstill&lt;/code&gt; never goes true&lt;/td&gt;
&lt;td&gt;One channel has not finished — it needs &lt;strong&gt;every&lt;/strong&gt; channel stopped&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;smoothStopActive&lt;/code&gt; per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis crawls instead of settling exactly at zero&lt;/td&gt;
&lt;td&gt;Not possible — the profile lands on exactly zero by construction&lt;/td&gt;
&lt;td&gt;Check what consumes &lt;code&gt;y&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A bump when the stop is released&lt;/td&gt;
&lt;td&gt;The changeover fade is too fast&lt;/td&gt;
&lt;td&gt;Lengthen the fade time in the &lt;code&gt;standstillSwitch&lt;/code&gt; sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A bump when the stop is engaged&lt;/td&gt;
&lt;td&gt;Expected: engagement is instant, but the profile starts where the axis is, so it should be seamless. A bump means &lt;code&gt;u&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; had already diverged&lt;/td&gt;
&lt;td&gt;Check the outputs were tracking before the stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The changeover jumps instead of fading&lt;/td&gt;
&lt;td&gt;&lt;code&gt;resetStandstill&lt;/code&gt; is being held true&lt;/td&gt;
&lt;td&gt;Release it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis comes up stopped after a restart&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;startAtStandstill&lt;/code&gt; is set&lt;/td&gt;
&lt;td&gt;Clear it if the axis should follow the reference immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One channel stops differently from the others&lt;/td&gt;
&lt;td&gt;Expected: all five limits are per channel&lt;/td&gt;
&lt;td&gt;Check every element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot tell what deceleration is actually being used&lt;/td&gt;
&lt;td&gt;The block does not publish the limits it computes when a budget binds&lt;/td&gt;
&lt;td&gt;Measure the slope of &lt;code&gt;yssDot&lt;/code&gt; on a trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A non-numeric value appeared and will not clear&lt;/td&gt;
&lt;td&gt;There is no reset input&lt;/td&gt;
&lt;td&gt;Restart the controller&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for an axis that decelerates at 2 units/s² and must stop within
half a second and a quarter of a unit:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;smoothStopAcc     = 2.0
smoothStopJerk    = 20.0
maxStopTime       = 0.5
maxStopDistance   = 0.25
maxStopJerkFactor = 0.25
startAtStandstill = false
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a starting point, not a final tuning. Work Setup step 6 with your own
machine.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;smoothStopAcc&lt;/code&gt;, &lt;code&gt;smoothStopJerk&lt;/code&gt; above 0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked, and both default to 0&lt;/strong&gt;, which makes the stop instant. Negative values are used as their magnitude&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxStopTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If the natural profile is longer, a harder profile is computed to fit. Corrected up to one task period if set below it&lt;/td&gt;
&lt;td&gt;Not reported; the actual limits used are not published&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop distance&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxStopDistance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same treatment. Corrected up to 0 if set negative&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxStopJerkFactor&lt;/code&gt; within 0 – 0.5&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Corrected to the nearest edge&lt;/td&gt;
&lt;td&gt;Silently; read it back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starting acceleration&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not handled in the budget branch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When a budget forces a recomputed profile, the axis&amp;rsquo;s acceleration at the moment of the stop is &lt;strong&gt;ignored&lt;/strong&gt;, so the deceleration begins with a step&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual deceleration and jerk&lt;/td&gt;
&lt;td&gt;Not published&lt;/td&gt;
&lt;td&gt;When a budget binds, the limits actually used are higher than the configured ones and &lt;strong&gt;cannot be read from the parameter tree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;y&lt;/code&gt;, &lt;code&gt;ydot&lt;/code&gt;, &lt;code&gt;yddot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded — the block shapes the stop, it does not bound the reference&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;The latched profile and the changeover state are &lt;strong&gt;not cleared at start&lt;/strong&gt;. There is no reset input&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Not guarded anywhere&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings. It writes one debug log line per
channel at the moment a stop is triggered, recording the position, velocity and
acceleration it latched. Every failure above shows as a value on a trace, not
as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Deadzone</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/deadzone/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/deadzone/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Deadzone&lt;/code&gt; blanks a band around zero and passes everything outside it. Use it
to stop a machine reacting to a signal that is close to but not exactly zero —
a noisy force reading, a joystick at rest — or to simulate backlash in a
mechanism.&lt;/p&gt;
&lt;p&gt;Outside the band the output is &lt;strong&gt;shifted inward by the band&amp;rsquo;s width&lt;/strong&gt;, not
passed through unchanged. That keeps the output continuous at the band edge:
the signal leaves zero smoothly instead of jumping.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — signal to blank&amp;quot;]) --&amp;gt; B[&amp;quot;Deadzone&amp;quot;]
    B --&amp;gt; o1([&amp;quot;output — blanked and shifted signal&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Inside ±&lt;code&gt;amplitude&lt;/code&gt; the output is 0. Outside it, the output is the input
&lt;strong&gt;minus&lt;/strong&gt; &lt;code&gt;amplitude&lt;/code&gt; in the direction of travel — so an input of twice the
amplitude gives an output of one amplitude, not two. The output is continuous
at the band edge and passes through zero without a step.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable, no disable and no &lt;code&gt;isEnabled&lt;/code&gt;.&lt;/strong&gt; It is always
running. Set &lt;code&gt;amplitude&lt;/code&gt; to 0 to pass the signal through untouched, which is
the default. It is &lt;strong&gt;single channel&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The signal to blank. A single value, not an array.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;Zero while the input is inside the band; outside it, the input shifted toward zero by &lt;code&gt;amplitude&lt;/code&gt;. A single value. It never lags — the output depends only on this cycle&amp;rsquo;s input.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amplitude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;any; used as its magnitude&lt;/td&gt;
&lt;td&gt;Half the width of the band. 0 passes the signal through unchanged. A negative value behaves as its positive equivalent. Not checked.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;amplitude&lt;/code&gt; is persistent and survives a controller restart. &lt;strong&gt;No parameters
exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Trace &lt;code&gt;input&lt;/code&gt; with the machine at rest and note how far it wanders from
zero. That wander is what you are blanking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;amplitude&lt;/code&gt; a little above that. Confirm &lt;code&gt;output&lt;/code&gt; sits at exactly zero
with the machine at rest.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move the machine slowly and confirm &lt;code&gt;output&lt;/code&gt; leaves zero smoothly, with no
jump at the moment it starts moving.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3 is what distinguishes this from a threshold.&lt;/strong&gt; If the output
jumps, you are looking at the wrong block — this one is continuous at the
band edge by construction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move the machine to a known value well outside the band and check the
output. It should read the input &lt;strong&gt;minus&lt;/strong&gt; &lt;code&gt;amplitude&lt;/code&gt;, not the input.
That offset is normal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;amplitude&lt;/code&gt; from the measurement in Setup step 1, not by feel. It is the
noise floor of your signal.&lt;/li&gt;
&lt;li&gt;Raise it until the machine stops reacting at rest, and no further. Every
increase also shifts the signal outside the band by the same amount.&lt;/li&gt;
&lt;li&gt;Check the offset at your normal working amplitude. If the dead zone is a
large fraction of the signal you care about, the shift is a real gain error
— reduce the dead zone or compensate downstream.&lt;/li&gt;
&lt;li&gt;If you need the signal outside the band passed through &lt;strong&gt;unshifted&lt;/strong&gt;, this
block cannot do it. Use a comparison and a switch instead.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/deadzone-transfer-2ae2d1f6.svg&#34; alt=&#34;Output against input at three dead-zone amplitudes: amplitude 0 passes thesignal through unchanged, and amplitudes 0.5 and 1.0 flatten the middle andshift the two outer branches inward.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the band width off the flat section, and the shift off the horizontal
offset of either sloped branch.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The machine still creeps at rest&lt;/td&gt;
&lt;td&gt;&lt;code&gt;amplitude&lt;/code&gt; below the signal&amp;rsquo;s noise floor&lt;/td&gt;
&lt;td&gt;Raise it, per Setup steps 1 and 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is smaller than the input by a constant&lt;/td&gt;
&lt;td&gt;Expected: the output is shifted inward by &lt;code&gt;amplitude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compensate downstream, or reduce the dead zone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output jumps as the signal leaves the band&lt;/td&gt;
&lt;td&gt;Not possible — this block is continuous at the band edge&lt;/td&gt;
&lt;td&gt;Check you are looking at this block&amp;rsquo;s output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stays at zero no matter what&lt;/td&gt;
&lt;td&gt;&lt;code&gt;amplitude&lt;/code&gt; is larger than the signal ever gets&lt;/td&gt;
&lt;td&gt;Lower it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is blanked at all&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;amplitude&lt;/code&gt; defaults to 0&lt;/td&gt;
&lt;td&gt;Set an amplitude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A negative &lt;code&gt;amplitude&lt;/code&gt; behaved like a positive one&lt;/td&gt;
&lt;td&gt;Expected: the magnitude is used&lt;/td&gt;
&lt;td&gt;Write a positive value for clarity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output reads zero when the input is not a number&lt;/td&gt;
&lt;td&gt;Expected: a non-numeric input falls inside the band and gives zero&lt;/td&gt;
&lt;td&gt;Fix the source — note this block will hide such a value from anything downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot switch the block off&lt;/td&gt;
&lt;td&gt;Expected: there is no enable&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;amplitude&lt;/code&gt; to 0, which is an exact pass-through&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need this on several channels&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The gain of the signal changed after adding the dead zone&lt;/td&gt;
&lt;td&gt;Expected: the shift is a constant offset, which looks like a gain change on a small signal&lt;/td&gt;
&lt;td&gt;Size the dead zone against your working range&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for blanking a force reading whose noise floor is about 0.3 N:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;amplitude = 0.5
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amplitude&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. Any finite value is accepted and used as its magnitude. 0 is an exact pass-through&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded — whatever the input carries, less the band width, reaches the output. Limit it downstream if the consumer needs a bound&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output continuity&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Continuous at both band edges by construction. The slope changes there, but the value does not jump&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signal offset&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Everything outside the band is shifted toward zero by &lt;code&gt;amplitude&lt;/code&gt;. This is the design, not a fault&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-numeric input&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Falls inside the band and produces &lt;strong&gt;zero&lt;/strong&gt;, so this block silently hides a non-numeric value from anything downstream&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;The block has no memory. Nothing survives a stop and there is nothing to reset&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;One channel per instance, always&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Decay</title>
      <link>/docs/developing-control-applications/control-blocks/limiters-and-shaping/decay/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/limiters-and-shaping/decay/</guid>
      <description>
        
        
        &lt;div class=&#34;c3-version&#34;&gt;
  &lt;span class=&#34;c3-version__control c3-version__control--static&#34;&gt;
    &lt;span class=&#34;c3-version__label&#34; aria-hidden=&#34;true&#34;&gt;Control3&lt;/span&gt;
    &lt;span class=&#34;c3-version__value&#34;&gt;3.30–3.34&lt;/span&gt;
  &lt;/span&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Decay&lt;/code&gt; adds an amount to its output on command, holds it, then ramps it
linearly back to a resting level. Use it for an event-driven offset that should
fade on its own — a nudge after a collision, a kick on a jog command, a
temporary allowance that expires. The ramp is straight, not exponential:
despite the name, there is no time constant.&lt;/p&gt;
&lt;p&gt;The amount &lt;strong&gt;accumulates&lt;/strong&gt;. A second command before the first has finished adds
to what is already there and restarts the hold.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    i1([&amp;quot;input — amount to add&amp;quot;]) --&amp;gt; B[&amp;quot;Decay&amp;quot;]
    i2([&amp;quot;set&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;reset&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — the decaying value&amp;quot;])
    B --&amp;gt; o2([&amp;quot;decaySlope — fall per cycle&amp;quot;])
    B --&amp;gt; o3([&amp;quot;busy&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;After a &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt; jumps by &lt;code&gt;input&lt;/code&gt;, holds for &lt;code&gt;decayStartTimeSec&lt;/code&gt;, then
falls to &lt;code&gt;defaultValue&lt;/code&gt; over &lt;code&gt;decayDurationSec&lt;/code&gt; and stops. The fall rate is
$($ height above &lt;code&gt;defaultValue&lt;/code&gt; $) / ($ &lt;code&gt;decayDurationSec&lt;/code&gt; $)$ per second, and
it is fixed at the moment of the &lt;code&gt;set&lt;/code&gt;. Total event length is
&lt;code&gt;decayStartTimeSec&lt;/code&gt; + &lt;code&gt;decayDurationSec&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable, no disable and no &lt;code&gt;isEnabled&lt;/code&gt;.&lt;/strong&gt; It is always
running, and while idle it drives &lt;code&gt;output&lt;/code&gt; to &lt;code&gt;defaultValue&lt;/code&gt; on every cycle —
nothing else can hold that path at another value. &lt;strong&gt;&lt;code&gt;decayDurationSec&lt;/code&gt; must
never be 0&lt;/strong&gt;; see Limits and errors.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The amount to &lt;strong&gt;add&lt;/strong&gt; to &lt;code&gt;output&lt;/code&gt;, one element per channel. It is a magnitude, not a signal — it is read only at the moment of a &lt;code&gt;set&lt;/code&gt;, and changing it at any other time has no effect.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;A rising value starts an event: &lt;code&gt;input&lt;/code&gt; is added to &lt;code&gt;output&lt;/code&gt;, the hold begins, and &lt;code&gt;busy&lt;/code&gt; goes true. The block clears this input itself, so it is a one-shot. Do not drive it from a link that writes every cycle — the block would fire continuously.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;While true, &lt;code&gt;output&lt;/code&gt; is forced to &lt;code&gt;defaultValue&lt;/code&gt; and any event in progress is abandoned as a step, not a ramp. &lt;strong&gt;This input is a level, not a pulse&lt;/strong&gt; — the block does not clear it, so holding it true pins the output.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The decaying value, one element per channel. Equals &lt;code&gt;defaultValue&lt;/code&gt; whenever no event is in progress, and is rewritten every cycle while idle. Starts at &lt;code&gt;defaultValue&lt;/code&gt; after every controller start.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;decaySlope&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per cycle&lt;/td&gt;
&lt;td&gt;How much &lt;code&gt;output&lt;/code&gt; falls each cycle during the ramp, one element per channel. Fixed when the event starts and unchanged for its duration. Use it to confirm the event was set up as you intended.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;busy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True from the moment of a &lt;code&gt;set&lt;/code&gt; until the ramp has finished. A single value for the whole block, not one per channel. It stays true for &lt;code&gt;decayStartTimeSec&lt;/code&gt; + &lt;code&gt;decayDurationSec&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;parameters&#34;&gt;Parameters&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;defaultValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;The resting level the output returns to, one element per channel. The output is driven here whenever no event is in progress.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;decayStartTimeSec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How long &lt;code&gt;output&lt;/code&gt; holds at its full height before the ramp begins. 0 starts the ramp immediately. &lt;strong&gt;Not checked&lt;/strong&gt; — a negative value makes the event never finish.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;decayDurationSec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;must be greater than one task period&lt;/td&gt;
&lt;td&gt;How long the ramp takes. Longer is gentler. &lt;strong&gt;Not checked, and 0 breaks the block&lt;/strong&gt; — see Limits and errors.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All three parameters are persistent and survive a controller restart. The
inputs and outputs do not. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;defaultValue&lt;/code&gt; to the level the output should rest at — usually 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;decayDurationSec&lt;/code&gt; to a real value before anything else.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never leave &lt;code&gt;decayDurationSec&lt;/code&gt; at 0.&lt;/strong&gt; A zero duration makes &lt;code&gt;output&lt;/code&gt;
and &lt;code&gt;decaySlope&lt;/code&gt; go to a non-numeric value on the first &lt;code&gt;set&lt;/code&gt;, and only a
&lt;code&gt;reset&lt;/code&gt; clears it. Check this before you wire &lt;code&gt;set&lt;/code&gt; to anything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;decayStartTimeSec&lt;/code&gt; to the hold you want, or 0 for none.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;input&lt;/code&gt; to the amount you want added. Confirm &lt;code&gt;output&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt;
move — the amount is only read on a &lt;code&gt;set&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pulse &lt;code&gt;set&lt;/code&gt; true for one cycle. &lt;code&gt;output&lt;/code&gt; should jump by &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;busy&lt;/code&gt;
should go true, and &lt;code&gt;decaySlope&lt;/code&gt; should read the amount divided by the
duration in cycles.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Watch &lt;code&gt;output&lt;/code&gt; hold, then fall in a straight line to &lt;code&gt;defaultValue&lt;/code&gt;. Time
the whole event: it should equal &lt;code&gt;decayStartTimeSec&lt;/code&gt; +
&lt;code&gt;decayDurationSec&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;busy&lt;/code&gt; goes false at the end and &lt;code&gt;output&lt;/code&gt; sits exactly on
&lt;code&gt;defaultValue&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element of &lt;code&gt;output&lt;/code&gt;. All channels share one schedule, so they
must start and finish together.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the amount first, with &lt;code&gt;input&lt;/code&gt;, and confirm the height of the jump on a
trace of &lt;code&gt;output&lt;/code&gt;. That height is what the consumer downstream has to
tolerate.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;decayStartTimeSec&lt;/code&gt; from the process, not from feel: it is how long the
offset must stay at full strength to do its job.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;decayDurationSec&lt;/code&gt; from what the machine can absorb. Read &lt;code&gt;decaySlope&lt;/code&gt;
after a &lt;code&gt;set&lt;/code&gt; and check that fall rate against whatever consumes &lt;code&gt;output&lt;/code&gt; —
a rate that is too steep shows up as a bump downstream.&lt;/li&gt;
&lt;li&gt;Work out how often your event source can fire. If it can fire faster than
&lt;code&gt;decayStartTimeSec&lt;/code&gt; + &lt;code&gt;decayDurationSec&lt;/code&gt;, the amounts will stack and there
is &lt;strong&gt;no upper limit&lt;/strong&gt; on how high &lt;code&gt;output&lt;/code&gt; goes. Either lengthen the gap or
bound the value downstream.&lt;/li&gt;
&lt;li&gt;Re-check nothing after a task-rate change. Both durations are in seconds, so
they hold their meaning — unlike the sample-counted blocks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/decay-ramp-7821a3b7.svg&#34; alt=&#34;One set event with a 0.2 s hold at three decay durations: all three hold at1.0 for 0.2 s, then fall in straight lines reaching 0 at 0.4 s, 0.7 s and1.2 s.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the fall rate off any curve as its slope during the ramp.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; and &lt;code&gt;decaySlope&lt;/code&gt; went to a non-numeric value on the first &lt;code&gt;set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;decayDurationSec&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set a real duration, then hold &lt;code&gt;reset&lt;/code&gt; true for a cycle to clear it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;busy&lt;/code&gt; went true and never came back down&lt;/td&gt;
&lt;td&gt;A negative &lt;code&gt;decayStartTimeSec&lt;/code&gt; or &lt;code&gt;decayDurationSec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write non-negative values, then pulse &lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; climbed higher and higher&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;set&lt;/code&gt; adds to what is already there, and the events are firing faster than they finish&lt;/td&gt;
&lt;td&gt;Lengthen the gap between events, or bound &lt;code&gt;output&lt;/code&gt; downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The hold restarted part way through a ramp&lt;/td&gt;
&lt;td&gt;Expected: a &lt;code&gt;set&lt;/code&gt; during an event restarts the hold from the new height&lt;/td&gt;
&lt;td&gt;Gate your event source on &lt;code&gt;busy&lt;/code&gt; being false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; will not stay where I write it&lt;/td&gt;
&lt;td&gt;Expected: the block drives &lt;code&gt;output&lt;/code&gt; to &lt;code&gt;defaultValue&lt;/code&gt; every idle cycle&lt;/td&gt;
&lt;td&gt;Use the block&amp;rsquo;s own &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt;; nothing else can hold this path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing happened when I changed &lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;input&lt;/code&gt; is only read at the moment of a &lt;code&gt;set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;set&lt;/code&gt; after setting the amount&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block fires continuously&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set&lt;/code&gt; is driven from a link that writes it every cycle&lt;/td&gt;
&lt;td&gt;Drive &lt;code&gt;set&lt;/code&gt; from a one-shot source; the block clears it itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The block is stuck at &lt;code&gt;defaultValue&lt;/code&gt; and ignores &lt;code&gt;set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt; is being held true&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt; is a level, not a pulse — write it false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt; stopped the event with a jump rather than a fade&lt;/td&gt;
&lt;td&gt;Expected: a reset is a step to &lt;code&gt;defaultValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Let the ramp finish, or use a longer duration and reset later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The ramp finished early and snapped the last part&lt;/td&gt;
&lt;td&gt;&lt;code&gt;decayDurationSec&lt;/code&gt; was shortened while the event was running&lt;/td&gt;
&lt;td&gt;Change the durations only while &lt;code&gt;busy&lt;/code&gt; is false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; went below &lt;code&gt;defaultValue&lt;/code&gt; and then came back up&lt;/td&gt;
&lt;td&gt;&lt;code&gt;decayDurationSec&lt;/code&gt; was lengthened while the event was running&lt;/td&gt;
&lt;td&gt;Change the durations only while &lt;code&gt;busy&lt;/code&gt; is false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One channel decayed and the others did not&lt;/td&gt;
&lt;td&gt;Not possible — all channels share one schedule&lt;/td&gt;
&lt;td&gt;Check the other channels&#39; &lt;code&gt;input&lt;/code&gt; values; a zero amount gives a zero jump&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channels finished at different levels&lt;/td&gt;
&lt;td&gt;Expected: each channel returns to its own &lt;code&gt;defaultValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set every element of &lt;code&gt;defaultValue&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fall is curved, not straight&lt;/td&gt;
&lt;td&gt;Not possible — the ramp is always linear&lt;/td&gt;
&lt;td&gt;Nothing to change; this block has no exponential mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a 0.5-unit nudge that holds briefly and fades over half a
second:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;defaultValue      = 0.0
decayStartTimeSec = 0.1
decayDurationSec  = 0.5
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;decayDurationSec&lt;/code&gt; &amp;gt; one task period&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked. A value of 0 makes &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;decaySlope&lt;/code&gt; non-numeric on the next &lt;code&gt;set&lt;/code&gt;&lt;/strong&gt;, and only &lt;code&gt;reset&lt;/code&gt; clears it. Always set a real duration&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;decayStartTimeSec&lt;/code&gt; ≥ 0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked.&lt;/strong&gt; A negative value makes the event never finish and &lt;code&gt;busy&lt;/code&gt; stay true forever. Clear it with &lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded, and it accumulates across overlapping events. Bound it downstream if the consumer needs a limit&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event schedule&lt;/td&gt;
&lt;td&gt;Shared&lt;/td&gt;
&lt;td&gt;One schedule for all channels. A &lt;code&gt;set&lt;/code&gt; starts every channel, and there is no per-channel event&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Durations after a task-rate change&lt;/td&gt;
&lt;td&gt;Task rate&lt;/td&gt;
&lt;td&gt;Both are in seconds and keep their meaning, so nothing needs rescaling&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts; it cannot be changed at runtime&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
  </channel>
</rss>
