<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title> – Detection and safety</title>
    <link>/docs/developing-control-applications/control-blocks/detection-and-safety/</link>
    <description>Recent content in Detection and safety on </description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="/docs/developing-control-applications/control-blocks/detection-and-safety/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: CollisionDetector</title>
      <link>/docs/developing-control-applications/control-blocks/detection-and-safety/collision-detector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/detection-and-safety/collision-detector/</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;CollisionDetector&lt;/code&gt; notices when an actuator meets something it was not
expecting. It compares the torque the controller asked for against the torque
the machine actually developed, and flags a discrepancy that persists.&lt;/p&gt;
&lt;p&gt;The trick is that the commanded torque is &lt;strong&gt;delayed to match the measurement&amp;rsquo;s
own lag&lt;/strong&gt; before the two are compared, so the difference stays flat during
ordinary motion and the threshold can be tight.&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;torqueReference&amp;quot;]) --&amp;gt; B[&amp;quot;CollisionDetector&amp;quot;]
    i2([&amp;quot;torqueActual&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;reset&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;enable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;torqueError&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isEnabled&amp;quot;])
    B --&amp;gt; s1([&amp;quot;collisionDetector — the detection settings and results&amp;quot;])
    B --&amp;gt; s2([&amp;quot;collisionReferenceFilter — the delay matching&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The thresholds are not on this block.&lt;/strong&gt; They live one level down, under
&lt;code&gt;collisionDetector&lt;/code&gt;. Set &lt;code&gt;collisionDetector/tooHigh&lt;/code&gt; and
&lt;code&gt;collisionDetector/tooLow&lt;/code&gt; to your collision thresholds and
&lt;code&gt;collisionDetector/timeWindow&lt;/code&gt; to how long the discrepancy must persist.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The detection result is also one level down&lt;/strong&gt;, at
&lt;code&gt;collisionDetector/noError&lt;/code&gt;. This block publishes only &lt;code&gt;torqueError&lt;/code&gt; — read
&lt;code&gt;noError&lt;/code&gt; from the sub-tree to know whether a collision was detected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The block ships disabled.&lt;/strong&gt; &lt;code&gt;enable&lt;/code&gt; defaults to false. Nothing happens
until you set it.&lt;/p&gt;
&lt;/blockquote&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;torqueReference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;torque unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The torque the controller is asking for. Delayed internally before the comparison.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;torqueActual&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;torque unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The torque the machine actually developed — from a sensor or the drive.&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;true or false&lt;/td&gt;
&lt;td&gt;Clears the detection. Passed through to the detector below. The block clears it for you.&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;true or false&lt;/td&gt;
&lt;td&gt;Suspends detection. The error is still computed and published.&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;torqueError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;torque unit&lt;/td&gt;
&lt;td&gt;The measured torque minus the delay-matched reference. &lt;strong&gt;This is the signal to trace when setting thresholds.&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;Detection is running.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The detection flags themselves — &lt;code&gt;isTooLow&lt;/code&gt;, &lt;code&gt;isTooHigh&lt;/code&gt;, &lt;code&gt;noError&lt;/code&gt; — are under
&lt;code&gt;collisionDetector&lt;/code&gt;.&lt;/p&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;Turns detection on. &lt;strong&gt;The block does nothing until you set this.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That is the only parameter at this level. Everything that shapes the detection
is in the two sub-trees below:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Default&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;collisionDetector/tooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.05&lt;/td&gt;
&lt;td&gt;The upper collision threshold on &lt;code&gt;torqueError&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/tooLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.05&lt;/td&gt;
&lt;td&gt;The lower collision threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/high&lt;/code&gt;, &lt;code&gt;…/low&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.02, -0.02&lt;/td&gt;
&lt;td&gt;Warning levels, if you want an early indication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;How long the error must exceed a threshold before it is flagged. &lt;strong&gt;At 0 a single noisy sample trips it.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;collisionReferenceFilter/enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;The delay matching. &lt;strong&gt;Leave this on&lt;/strong&gt; — turning it off produces false collisions on every move.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect the controller&amp;rsquo;s torque command to &lt;code&gt;torqueReference&lt;/code&gt; and the
measured torque to &lt;code&gt;torqueActual&lt;/code&gt;. &lt;strong&gt;Both must be in the same units&lt;/strong&gt; —
nothing converts between them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;enable&lt;/code&gt; false for now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the machine through its normal motion and trace &lt;code&gt;torqueError&lt;/code&gt;. It should
stay small and flat. &lt;strong&gt;If it swings during acceleration, the two signals are
not in the same units, or one is scaled differently.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Note the largest excursion of &lt;code&gt;torqueError&lt;/code&gt; during normal motion, including
the fastest move and the hardest acceleration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;collisionDetector/tooHigh&lt;/code&gt; and &lt;code&gt;collisionDetector/tooLow&lt;/code&gt; outside that,
with margin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;collisionDetector/timeWindow&lt;/code&gt; — go to Tuning.&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Whatever acts on &lt;code&gt;collisionDetector/noError&lt;/code&gt; will act the moment it goes
false.&lt;/strong&gt; If that is a stop, confirm the thresholds are wide enough for
normal motion before you enable, or the machine will stop on its own first
move.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Push against the actuator by hand, gently, and confirm the detection comes
up.&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;Trace &lt;code&gt;torqueError&lt;/code&gt; for a full working cycle before setting any threshold.
The whole design aims to keep this flat; if it is not flat, fix that first.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;torqueError&lt;/code&gt; swings during acceleration, the delay matching is not
suiting your drive. The internal delay is fixed at about 15 milliseconds at
a 1 kHz task rate and is not adjustable. Widen the thresholds, or filter
&lt;code&gt;torqueActual&lt;/code&gt; upstream so its lag is closer to that.&lt;/li&gt;
&lt;li&gt;Set the collision thresholds from the largest normal excursion, with margin
— typically twice it.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;timeWindow&lt;/code&gt; longer than the transient you want to ignore and shorter
than the time you can afford to keep pushing. Ten to fifty milliseconds is a
reasonable range.&lt;/li&gt;
&lt;li&gt;Test with a real obstruction, not just by hand. A soft obstruction produces
a slower error rise and needs a longer &lt;code&gt;timeWindow&lt;/code&gt; to be tolerated, or a
lower threshold to be caught.&lt;/li&gt;
&lt;li&gt;Set the warning levels inside the collision thresholds if you want an early
indication before stopping.&lt;/li&gt;
&lt;li&gt;Re-check &lt;code&gt;torqueError&lt;/code&gt; after any change to the drive tuning or to the
feedforward path — both change the lag this block is matching.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/collision-detector-error-ba2f5b25.svg&#34; alt=&#34;The measured torque follows the commanded torque with a lag. The delay-matcheddifference stays near zero through the normal move and rises sharply when anunexpected load appears.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The flat section is what makes a tight threshold possible.&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 ever detected&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt; defaults to false&lt;/td&gt;
&lt;td&gt;Set it true and check &lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is detected even when enabled&lt;/td&gt;
&lt;td&gt;The thresholds are on the sub-tree, not here&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;collisionDetector/tooHigh&lt;/code&gt; and &lt;code&gt;…/tooLow&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot find the detection result&lt;/td&gt;
&lt;td&gt;It is at &lt;code&gt;collisionDetector/noError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read it from the sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;torqueError&lt;/code&gt; swings during every move&lt;/td&gt;
&lt;td&gt;The internal delay does not match your drive&amp;rsquo;s lag, or the two inputs are scaled differently&lt;/td&gt;
&lt;td&gt;Check units first, then widen the thresholds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;torqueError&lt;/code&gt; is huge and grows with speed&lt;/td&gt;
&lt;td&gt;The two inputs are in different units&lt;/td&gt;
&lt;td&gt;Fix the scaling upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False collisions on every move&lt;/td&gt;
&lt;td&gt;The delay matching may be off — check &lt;code&gt;collisionReferenceFilter/enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Turn it back on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False collisions on noise&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/timeWindow&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A real collision was missed&lt;/td&gt;
&lt;td&gt;The thresholds are too wide, or &lt;code&gt;timeWindow&lt;/code&gt; too long&lt;/td&gt;
&lt;td&gt;Trace &lt;code&gt;torqueError&lt;/code&gt; during the collision and set from that&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False collisions in torque mode&lt;/td&gt;
&lt;td&gt;Detection cannot be suppressed from the tree in this version&lt;/td&gt;
&lt;td&gt;Disable the block while in torque mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A burst of error right after startup&lt;/td&gt;
&lt;td&gt;The delay matching needs about 30 cycles to fill&lt;/td&gt;
&lt;td&gt;Enable the block a moment after start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flags will not clear&lt;/td&gt;
&lt;td&gt;The detector below latches&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything is flagged at once&lt;/td&gt;
&lt;td&gt;One of the inputs is not a valid number&lt;/td&gt;
&lt;td&gt;Fix the upstream signal; this is the detector telling you so&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need this on several axes&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per axis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point, once you have traced &lt;code&gt;torqueError&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;enable                          = true
collisionDetector/tooHigh       =  &amp;lt;twice the largest normal excursion&amp;gt;
collisionDetector/tooLow        = -&amp;lt;the same&amp;gt;
collisionDetector/timeWindow    = 0.02
collisionReferenceFilter/enable = 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;Detection thresholds&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/tooHigh&lt;/code&gt;, &lt;code&gt;…/tooLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The detector below flags a persistent discrepancy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/noError&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debounce&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collisionDetector/timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The error must exceed a threshold for this long. &lt;strong&gt;At the default of 0 a single sample trips it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delay matching&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The reference is delayed by about &lt;strong&gt;15 milliseconds at a 1 kHz task rate&lt;/strong&gt;. Not adjustable, and not matched to any particular drive&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delay matching startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Takes about &lt;strong&gt;30 cycles&lt;/strong&gt; to fill after a start, during which &lt;code&gt;torqueError&lt;/code&gt; reads high&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input units&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; The two torque inputs must already be in the same units&lt;/td&gt;
&lt;td&gt;&lt;code&gt;torqueError&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Torque-mode suppression&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not reachable from the tree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The block can suppress detection while the drive is in torque mode, but only when driven from an application&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detection output&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not published at this level.&lt;/strong&gt; Read it from the sub-tree&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed at &lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The block ships disabled&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;Handled below&lt;/td&gt;
&lt;td&gt;A bad input makes &lt;code&gt;torqueError&lt;/code&gt; invalid, and the detector below &lt;strong&gt;raises every flag&lt;/strong&gt; — the safe direction&lt;/td&gt;
&lt;td&gt;The detector&amp;rsquo;s flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clears the detection below. Cleared for you&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 actuator 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;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&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: MotionDetector</title>
      <link>/docs/developing-control-applications/control-blocks/detection-and-safety/motion-detector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/detection-and-safety/motion-detector/</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;MotionDetector&lt;/code&gt; remembers a reference value and raises a flag when the signal
drifts further than a threshold from it, in either direction. The flag stays
raised until you reset it.&lt;/p&gt;
&lt;p&gt;Use it to notice that something which should be standing still has moved — a
brake slipping, a load settling, a clamped part creeping.&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;MotionDetector&amp;quot;]
    i2([&amp;quot;activate&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;reset&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;threshold&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;enable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;isTriggered&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isEnabled&amp;quot;])
    B --&amp;gt; o3([&amp;quot;reference&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pulse &lt;code&gt;reset&lt;/code&gt; whenever you raise &lt;code&gt;activate&lt;/code&gt;.&lt;/strong&gt; Raising &lt;code&gt;activate&lt;/code&gt; on its own
does &lt;strong&gt;not&lt;/strong&gt; capture a new reference — the detector keeps comparing against
whatever &lt;code&gt;reference&lt;/code&gt; already holds, which is &lt;strong&gt;0&lt;/strong&gt; after a controller start.
&lt;code&gt;reset&lt;/code&gt; is what captures the current input as the reference. Always send both.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Read &lt;code&gt;reference&lt;/code&gt; to see what it is actually comparing against.&lt;/strong&gt; It is
published for exactly this reason, and it is the fastest way to tell whether
the reference was captured when you expected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;There is no noise filtering.&lt;/strong&gt; A single sample past the threshold latches
the flag permanently. If your signal is noisy, filter it before this block or
use &lt;code&gt;WindowDetector&lt;/code&gt;, which has a time window.&lt;/p&gt;
&lt;/blockquote&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 being watched.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Detection runs while this is true. A &lt;strong&gt;level&lt;/strong&gt;, not a pulse. &lt;strong&gt;On its own it does not capture a reference&lt;/strong&gt; — see the callout above.&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;true or false&lt;/td&gt;
&lt;td&gt;Clears the flag &lt;strong&gt;and captures the current input as the new reference&lt;/strong&gt;. The block clears it for you, so it is a pulse. Holding it true holds the detector re-armed.&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;true or false&lt;/td&gt;
&lt;td&gt;Suspends detection. While disabled the reference &lt;strong&gt;tracks the input&lt;/strong&gt;, so disabling and re-enabling is another way to re-arm cleanly.&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;isTriggered&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The input has drifted past the threshold. &lt;strong&gt;Latches&lt;/strong&gt; until reset or 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;Detection is permitted.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The value the input is being compared against. &lt;strong&gt;Check this first when the detector behaves unexpectedly.&lt;/strong&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;threshold&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How far the input may drift from &lt;code&gt;reference&lt;/code&gt; before the flag latches, in either direction. &lt;strong&gt;At the default of 0 any change at all triggers.&lt;/strong&gt; A negative value makes it trigger immediately and permanently, and is not rejected.&lt;/td&gt;
&lt;/tr&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;Turns detection on. When off, the flag is held clear and the reference follows the input.&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;Connect the signal you want to watch to &lt;code&gt;input&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;threshold&lt;/code&gt; to how much movement you are willing to accept. &lt;strong&gt;It
defaults to 0&lt;/strong&gt;, which triggers on anything.&lt;/li&gt;
&lt;li&gt;Bring the machine to the state you want to monitor and hold it there.&lt;/li&gt;
&lt;li&gt;Raise &lt;code&gt;activate&lt;/code&gt; &lt;strong&gt;and pulse &lt;code&gt;reset&lt;/code&gt; in the same write&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Read &lt;code&gt;reference&lt;/code&gt; and confirm it matches the current input. If it reads 0,
the reset did not land — send it again.&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;isTriggered&lt;/code&gt; is false and stays false while the machine is still.&lt;/li&gt;
&lt;li&gt;Nudge the machine past the threshold and confirm &lt;code&gt;isTriggered&lt;/code&gt; latches.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This block only watches a signal and raises a flag. It does not move anything
and cannot be made to — but whatever acts on &lt;code&gt;isTriggered&lt;/code&gt; downstream will act
the moment it latches.&lt;/p&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Trace &lt;code&gt;input&lt;/code&gt; while the machine is in the state you want to monitor, for as
long as you would normally leave it there.&lt;/li&gt;
&lt;li&gt;Note the total spread — both the noise and any slow settling that is
acceptable.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;threshold&lt;/code&gt; above that spread, with margin. Too tight and you get false
trips from noise; too loose and real movement goes unnoticed.&lt;/li&gt;
&lt;li&gt;Re-arm and leave it for a realistic dwell. Confirm it does not trip.&lt;/li&gt;
&lt;li&gt;If it trips on noise, either widen &lt;code&gt;threshold&lt;/code&gt; or filter &lt;code&gt;input&lt;/code&gt; upstream.
&lt;strong&gt;Filtering is usually the better answer&lt;/strong&gt; — a wide threshold hides real
movement, whereas a filter only delays detection.&lt;/li&gt;
&lt;li&gt;If you need to ignore short spikes rather than steady noise, &lt;code&gt;WindowDetector&lt;/code&gt;
with a &lt;code&gt;timeWindow&lt;/code&gt; is the better block, at the cost of fixed levels instead
of a captured reference.&lt;/li&gt;
&lt;li&gt;Nothing here depends on the task rate, so none of this needs re-checking
after a rate change.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/motion-detector-drift-541108b8.svg&#34; alt=&#34;The input drifting away from its reference. With a threshold of 0.05 the flaglatches as soon as the drift leaves the band; with 0.12 it latches later, andthe earlier oscillation is ignored in both cases.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The flag never falls once raised. That is what makes it useful between polls.&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;It triggered immediately after activating&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt; is 0 because &lt;code&gt;reset&lt;/code&gt; was not sent with &lt;code&gt;activate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;reference&lt;/code&gt;; pulse &lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;It triggered immediately even after a reset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;threshold&lt;/code&gt; is 0 — the default — or negative&lt;/td&gt;
&lt;td&gt;Set a positive threshold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt; reads 0&lt;/td&gt;
&lt;td&gt;The reference has never been captured&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt; is not what I expected&lt;/td&gt;
&lt;td&gt;It was captured at a different moment, or while disabled it tracked the input&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt; at the moment you want captured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;It trips on noise&lt;/td&gt;
&lt;td&gt;There is no debounce in this block&lt;/td&gt;
&lt;td&gt;Filter the input, or use &lt;code&gt;WindowDetector&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag will not clear&lt;/td&gt;
&lt;td&gt;Expected: it latches&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt;, or disable and re-enable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag cleared on its own&lt;/td&gt;
&lt;td&gt;The block was disabled, which clears it&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real movement was not detected&lt;/td&gt;
&lt;td&gt;&lt;code&gt;threshold&lt;/code&gt; is wider than the movement&lt;/td&gt;
&lt;td&gt;Narrow it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is ever detected&lt;/td&gt;
&lt;td&gt;&lt;code&gt;activate&lt;/code&gt; is false, or &lt;code&gt;enable&lt;/code&gt; is false, or &lt;code&gt;disable&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;isEnabled&lt;/code&gt; and &lt;code&gt;activate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A dead sensor was not detected&lt;/td&gt;
&lt;td&gt;A signal that is not a number reads as &lt;strong&gt;no motion&lt;/strong&gt; here&lt;/td&gt;
&lt;td&gt;Supervise the sensor with &lt;code&gt;WindowDetector&lt;/code&gt;, which trips on it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flag survived a restart&lt;/td&gt;
&lt;td&gt;It is not cleared at startup, and &lt;code&gt;reference&lt;/code&gt; returns to 0&lt;/td&gt;
&lt;td&gt;Re-arm after every start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to watch several signals&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per signal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for an axis in metres that should not move:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;threshold = 0.002
enable    = 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;Detection band&lt;/td&gt;
&lt;td&gt;&lt;code&gt;threshold&lt;/code&gt;, &lt;code&gt;reference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The flag latches outside &lt;code&gt;reference&lt;/code&gt; plus or minus &lt;code&gt;threshold&lt;/code&gt;. Exactly at the edge does &lt;strong&gt;not&lt;/strong&gt; trigger&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isTriggered&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference capture&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt;, and disabling&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Only&lt;/strong&gt; &lt;code&gt;reset&lt;/code&gt; and being disabled capture a reference. Raising &lt;code&gt;activate&lt;/code&gt; does not&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;threshold&lt;/code&gt; sign&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 triggers immediately and permanently&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;threshold&lt;/code&gt; default&lt;/td&gt;
&lt;td&gt;Fixed at &lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any change at all triggers&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debounce&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A single sample past the threshold latches the flag&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&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; The flag is held, so a dead sensor reads as no motion&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latching&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The flag stays raised until reset or disabled&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;, &lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detection stops, the flag clears, and the reference &lt;strong&gt;tracks the input&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt; starts at &lt;strong&gt;0&lt;/strong&gt; and the flag is not cleared&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reference&lt;/code&gt;&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 signal 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;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&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: WindowDetector</title>
      <link>/docs/developing-control-applications/control-blocks/detection-and-safety/window-detector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/detection-and-safety/window-detector/</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;WindowDetector&lt;/code&gt; watches one signal against &lt;strong&gt;four&lt;/strong&gt; levels and raises a flag
for each. The inner pair — &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; — is a warning band; the outer pair
— &lt;code&gt;tooLow&lt;/code&gt; and &lt;code&gt;tooHigh&lt;/code&gt; — is an error band. A time window stops noise from
tripping them.&lt;/p&gt;
&lt;p&gt;Use it to supervise a pressure, a temperature, a torque or a following error,
and to distinguish &amp;ldquo;worth knowing about&amp;rdquo; from &amp;ldquo;stop now&amp;rdquo;.&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;WindowDetector&amp;quot;]
    i2([&amp;quot;reset&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;tooLow, low, high, tooHigh&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;timeWindow, enable, autoreset, id&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;isTooLow, isLow, isHigh, isTooHigh&amp;quot;])
    B --&amp;gt; o2([&amp;quot;noWarning, noError&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isEnabled&amp;quot;])
    B --&amp;gt; o4([&amp;quot;state&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The bands are nested, not exclusive.&lt;/strong&gt; A signal below &lt;code&gt;tooLow&lt;/code&gt; is also
below &lt;code&gt;low&lt;/code&gt;, so &lt;code&gt;isTooLow&lt;/code&gt; and &lt;code&gt;isLow&lt;/code&gt; are both true. For &amp;ldquo;warning but not
error&amp;rdquo;, test &lt;code&gt;isLow&lt;/code&gt; and not &lt;code&gt;isTooLow&lt;/code&gt; yourself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The flags latch.&lt;/strong&gt; Once raised they stay raised until you reset, disable, or
turn &lt;code&gt;autoreset&lt;/code&gt; on. That is what you want for a fault you might otherwise
miss between polls.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A signal that is not a number trips all four flags&lt;/strong&gt; and clears both
summaries. This is deliberate: a broken sensor reads as an error rather than
as perfectly in range.&lt;/p&gt;
&lt;/blockquote&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 watch. A value that is not a number raises every flag.&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;true or false&lt;/td&gt;
&lt;td&gt;Clears all four flags and their timers. &lt;strong&gt;You do not need to write it back to false&lt;/strong&gt; — the block notices when you stop writing it and clears it for you.&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;true or false&lt;/td&gt;
&lt;td&gt;Suspends detection and &lt;strong&gt;clears the flags&lt;/strong&gt;. Re-enabling starts clean.&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;isTooLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The input has been at or below &lt;code&gt;tooLow&lt;/code&gt; for &lt;code&gt;timeWindow&lt;/code&gt;. &lt;strong&gt;Error level.&lt;/strong&gt; Latches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;At or below &lt;code&gt;low&lt;/code&gt;. &lt;strong&gt;Warning level.&lt;/strong&gt; Latches. Also true whenever &lt;code&gt;isTooLow&lt;/code&gt; is.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;At or above &lt;code&gt;high&lt;/code&gt;. Warning level. Latches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isTooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;At or above &lt;code&gt;tooHigh&lt;/code&gt;. Error level. Latches. Also raises &lt;code&gt;isHigh&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noWarning&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Neither warning flag is raised. &lt;strong&gt;Starts true.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Neither error flag is raised. &lt;strong&gt;Starts true.&lt;/strong&gt; Test this one to decide whether to stop.&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;Detection is running.&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;All of the above as a &lt;strong&gt;single signal&lt;/strong&gt;, plus &lt;code&gt;id&lt;/code&gt;. Subscribe to this instead of seven separate flags when a supervising task needs the whole picture.&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;tooLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-0.05&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Lower &lt;strong&gt;error&lt;/strong&gt; level. Trips at or below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-0.02&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Lower &lt;strong&gt;warning&lt;/strong&gt; level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.02&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Upper warning level. Trips at or above.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.05&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Upper &lt;strong&gt;error&lt;/strong&gt; level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How long the input must stay out of range before the flag latches. &lt;strong&gt;At the default of 0 a single sample trips it&lt;/strong&gt;, so a noisy signal will chatter. Each band times independently.&lt;/td&gt;
&lt;/tr&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;Turns detection on. When off, the flags are held clear.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;autoreset&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;Clears the flags every cycle, so they follow the current condition instead of latching. Useful when a supervising task polls faster than the condition changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;A number carried inside &lt;code&gt;state&lt;/code&gt;, so a task receiving several detectors&#39; states can tell them apart.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart. &lt;strong&gt;Nothing checks that the
four levels are in order&lt;/strong&gt; — an inverted pair is accepted and is a legitimate
way to disable a band. &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;Connect the signal you want to supervise to &lt;code&gt;input&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the two &lt;strong&gt;error&lt;/strong&gt; levels first, from what the machine cannot tolerate.&lt;/li&gt;
&lt;li&gt;Set the two &lt;strong&gt;warning&lt;/strong&gt; levels inside them, from what you want to know about
early.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;timeWindow&lt;/code&gt; at 0 and watch the machine run normally. If any flag
trips, either a level is too tight or the signal is noisy.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;timeWindow&lt;/code&gt; — go to Tuning.&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;noError&lt;/code&gt; is true during normal operation and goes false when you
deliberately push the signal past an error level.&lt;/li&gt;
&lt;li&gt;Pulse &lt;code&gt;reset&lt;/code&gt; and confirm all four flags clear.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This block only watches a signal and raises flags. It does not move anything
and cannot be made to — but whatever acts on &lt;code&gt;noError&lt;/code&gt; downstream will act the
moment it goes false.&lt;/p&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Trace &lt;code&gt;input&lt;/code&gt; for a full normal cycle of the machine, including startup.
Note the largest excursion that is not a fault — startup spikes are the
usual culprit.&lt;/li&gt;
&lt;li&gt;Set the error levels outside that, with margin.&lt;/li&gt;
&lt;li&gt;Set the warning levels where you want to be told early. There is no rule
here; halfway between normal and the error level is a reasonable start.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;timeWindow&lt;/code&gt; longer than the longest spike you want to ignore and
shorter than the fastest fault you must catch. For a noisy signal this is
usually tens of milliseconds.&lt;/li&gt;
&lt;li&gt;Re-run and confirm the flags stay clear through the normal cycle.&lt;/li&gt;
&lt;li&gt;Push the signal past each level in turn and confirm the right flag latches,
after roughly &lt;code&gt;timeWindow&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you cannot find a &lt;code&gt;timeWindow&lt;/code&gt; that ignores the noise and still catches
the fault, filter the input upstream instead of widening the levels.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timeWindow&lt;/code&gt; is in seconds, so a task-rate change does not move it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/window-detector-timewindow-2dae67e0.svg&#34; alt=&#34;The same noisy signal watched with and without a time window. With no windowthe first noise spike latches isHigh; with a 0.1 second window only the realexcursion does.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The time window is what separates a spike from an excursion.&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 flag trips on noise&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeWindow&lt;/code&gt; is 0 or too short&lt;/td&gt;
&lt;td&gt;Lengthen it, or filter the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A flag tripped during startup&lt;/td&gt;
&lt;td&gt;A startup spike crossed a level&lt;/td&gt;
&lt;td&gt;Lengthen &lt;code&gt;timeWindow&lt;/code&gt;, or hold &lt;code&gt;disable&lt;/code&gt; true until the machine is running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLow&lt;/code&gt; and &lt;code&gt;isTooLow&lt;/code&gt; are both true&lt;/td&gt;
&lt;td&gt;Expected: the bands are nested&lt;/td&gt;
&lt;td&gt;Test &lt;code&gt;isLow&lt;/code&gt; and not &lt;code&gt;isTooLow&lt;/code&gt; for warning only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A flag will not clear&lt;/td&gt;
&lt;td&gt;Expected: the flags latch&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt;, or set &lt;code&gt;autoreset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flags clear on their own&lt;/td&gt;
&lt;td&gt;&lt;code&gt;autoreset&lt;/code&gt; is on&lt;/td&gt;
&lt;td&gt;Turn it off if you need latching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I wrote &lt;code&gt;reset&lt;/code&gt; and it went back to false&lt;/td&gt;
&lt;td&gt;Expected: the block clears it once you stop writing&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing is ever detected&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 levels are outside anything the signal reaches&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;isEnabled&lt;/code&gt; first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flags cleared when I disabled it&lt;/td&gt;
&lt;td&gt;Expected: disabling clears them and re-enabling starts clean&lt;/td&gt;
&lt;td&gt;Read them before disabling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything trips at once and stays tripped&lt;/td&gt;
&lt;td&gt;The input is not a valid number&lt;/td&gt;
&lt;td&gt;Fix the upstream signal; this is the block telling you so&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A flag trips later than &lt;code&gt;timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the window is rounded up to a whole number of cycles&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flags disagree with the levels I set&lt;/td&gt;
&lt;td&gt;The levels may be inverted — nothing checks their order&lt;/td&gt;
&lt;td&gt;Read all four back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A flag tripped one cycle after I disabled it&lt;/td&gt;
&lt;td&gt;Expected: the check runs once more, and the result is then cleared&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The timers seem stale right after a restart&lt;/td&gt;
&lt;td&gt;The flags clear at startup but the timers do not&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt; after starting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to watch several signals&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per signal, each with its own &lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a following error in metres:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;tooLow     = -0.05
low        = -0.02
high       =  0.02
tooHigh    =  0.05
timeWindow =  0.02
enable     =  true
autoreset  =  false
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Those are also the defaults for the four levels, so an unconfigured detector
already watches a symmetric band around zero.&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;Warning band&lt;/td&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flags latch at or beyond the level, after &lt;code&gt;timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isLow&lt;/code&gt;, &lt;code&gt;isHigh&lt;/code&gt;, &lt;code&gt;noWarning&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error band&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tooLow&lt;/code&gt;, &lt;code&gt;tooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same, at the outer levels&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isTooLow&lt;/code&gt;, &lt;code&gt;isTooHigh&lt;/code&gt;, &lt;code&gt;noError&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Band nesting&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The bands &lt;strong&gt;overlap by design&lt;/strong&gt;: an error also raises its warning&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Level ordering&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; Inverted levels are accepted and produce overlapping bands&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debounce&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Each band times &lt;strong&gt;independently&lt;/strong&gt;. The window is rounded up to a whole number of cycles&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latching&lt;/td&gt;
&lt;td&gt;Fixed, unless &lt;code&gt;autoreset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flags stay raised until reset, disabled, or auto-reset&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Checked&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;All four flags are raised&lt;/strong&gt; and both summaries cleared&lt;/td&gt;
&lt;td&gt;The flags themselves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clears the flags &lt;strong&gt;and&lt;/strong&gt; the timers. Clears itself when you stop writing it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;, &lt;code&gt;enable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detection stops and the flags clear. Re-enabling starts clean&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The flags clear, &lt;strong&gt;the timers do not&lt;/strong&gt;&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 signal 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;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&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: AverageValueCheck</title>
      <link>/docs/developing-control-applications/control-blocks/detection-and-safety/average-value-check/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/detection-and-safety/average-value-check/</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;AverageValueCheck&lt;/code&gt; measures the true average of a signal over a fixed
duration, on demand, and compares that average against four levels.&lt;/p&gt;
&lt;p&gt;Use it for a bounded test rather than continuous supervision: sample a pressure
for two seconds after a valve closes, or a torque after a move settles, and
decide whether the result is acceptable.&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;AverageValueCheck&amp;quot;]
    i2([&amp;quot;activate&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;duration&amp;quot;]) --&amp;gt; B
    p2([&amp;quot;tooLow, low, high, tooHigh&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;average&amp;quot;])
    B --&amp;gt; o2([&amp;quot;sum&amp;quot;])
    B --&amp;gt; o3([&amp;quot;counter&amp;quot;])
    B --&amp;gt; o4([&amp;quot;busy&amp;quot;])
    B --&amp;gt; o5([&amp;quot;isTooLow, isLow, isHigh, isTooHigh&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The average is exact&lt;/strong&gt;, not filtered — every sample over the window carries
equal weight. &lt;code&gt;sum&lt;/code&gt; and &lt;code&gt;counter&lt;/code&gt; are published so you can check the
arithmetic yourself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;All four levels default to 0.&lt;/strong&gt; Until you set them, &lt;code&gt;isHigh&lt;/code&gt; and &lt;code&gt;isTooHigh&lt;/code&gt;
are true for any positive average. Set all four before reading any flag.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The result persists after the measurement ends&lt;/strong&gt;, which is what makes the
block useful — but the flags are also computed &lt;em&gt;before&lt;/em&gt; any measurement has
run, from an average of zero. &lt;strong&gt;Read &lt;code&gt;counter&lt;/code&gt; alongside them&lt;/strong&gt;: a &lt;code&gt;counter&lt;/code&gt;
of 0 means no measurement has happened.&lt;/p&gt;
&lt;/blockquote&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;Sampled once per cycle while the measurement runs. &lt;strong&gt;A value that is not a number spoils the whole measurement&lt;/strong&gt; and makes all four flags read false — see Limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;A rising edge starts a measurement.&lt;/strong&gt; Holding it true does not start another. &lt;strong&gt;The block does not clear it&lt;/strong&gt; — lower it yourself, or no further measurement can ever be triggered.&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;average&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The average so far, and the final result once &lt;code&gt;busy&lt;/code&gt; falls. &lt;strong&gt;Readable while the measurement runs.&lt;/strong&gt; Holds the last result until the next measurement.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sum&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The running total.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;counter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many samples have been taken. &lt;strong&gt;0 means no measurement has ever run&lt;/strong&gt; — check this before trusting the flags.&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;The measurement is running. Falls when the duration elapses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isTooLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;code&gt;average&lt;/code&gt; is below &lt;code&gt;tooLow&lt;/code&gt;. &lt;strong&gt;Does not latch&lt;/strong&gt; — it always describes the current &lt;code&gt;average&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Below &lt;code&gt;low&lt;/code&gt;. Also true whenever &lt;code&gt;isTooLow&lt;/code&gt; is.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Above &lt;code&gt;high&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isTooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Above &lt;code&gt;tooHigh&lt;/code&gt;. Also raises &lt;code&gt;isHigh&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;duration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How long a measurement runs. The number of samples is the duration divided by the task period, rounded up. &lt;strong&gt;A value of 0 or below is not rejected&lt;/strong&gt;: the measurement ends immediately, &lt;code&gt;counter&lt;/code&gt; and &lt;code&gt;sum&lt;/code&gt; read 0, and &lt;code&gt;average&lt;/code&gt; keeps its previous value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tooLow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Lower &lt;strong&gt;error&lt;/strong&gt; level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Lower &lt;strong&gt;warning&lt;/strong&gt; level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Upper warning level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Upper &lt;strong&gt;error&lt;/strong&gt; level.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart. &lt;strong&gt;Nothing checks that the
four levels are in order.&lt;/strong&gt; &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The bands are nested: with the intended ordering, an error also raises its
warning. For &amp;ldquo;warning but not error&amp;rdquo;, test &lt;code&gt;isLow&lt;/code&gt; and not &lt;code&gt;isTooLow&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Connect the signal you want to measure to &lt;code&gt;input&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;duration&lt;/code&gt; to how long you want to sample for.&lt;/li&gt;
&lt;li&gt;Set all four levels. &lt;strong&gt;They default to 0&lt;/strong&gt;, and until you set them the flags
are meaningless.&lt;/li&gt;
&lt;li&gt;Bring the machine to the state you want to measure.&lt;/li&gt;
&lt;li&gt;Raise &lt;code&gt;activate&lt;/code&gt; from false to true and confirm &lt;code&gt;busy&lt;/code&gt; goes true.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lower &lt;code&gt;activate&lt;/code&gt; again.&lt;/strong&gt; The block will not clear it for you, and a
second measurement needs a fresh rising edge.&lt;/li&gt;
&lt;li&gt;Wait for &lt;code&gt;busy&lt;/code&gt; to fall, then read &lt;code&gt;average&lt;/code&gt; and &lt;code&gt;counter&lt;/code&gt;. Confirm &lt;code&gt;counter&lt;/code&gt;
matches the duration divided by your task period.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This block only measures and compares. It does not move anything and cannot be
made to.&lt;/p&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;duration&lt;/code&gt; from the physics, not from convenience. It must be long
enough to average out the noise and short enough that the quantity has not
changed by the end.&lt;/li&gt;
&lt;li&gt;Trigger a measurement with the machine in a known-good state and record the
&lt;code&gt;average&lt;/code&gt;. Repeat it a few times to see the spread between runs.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;error&lt;/strong&gt; levels outside that spread, with margin.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;warning&lt;/strong&gt; levels inside them, where you want to be told early.&lt;/li&gt;
&lt;li&gt;Trigger with the machine in a known-bad state and confirm the right flags
come up.&lt;/li&gt;
&lt;li&gt;If the spread between runs is too wide to place levels, lengthen &lt;code&gt;duration&lt;/code&gt;
— the spread falls roughly with the square root of the sample count.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;average&lt;/code&gt; while a measurement runs to see how quickly it settles. If
it is still moving at the end, &lt;code&gt;duration&lt;/code&gt; is too short.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;duration&lt;/code&gt; is in seconds, so a task-rate change does not move it — but
&lt;code&gt;counter&lt;/code&gt; will change, because the sample count depends on the rate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/average-value-check-window-b7e7a4fb.svg&#34; alt=&#34;The running average over the measurement window, for two durations. Thelonger window settles close to the true mean; the shorter one stops while theaverage is still wandering.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The average is readable while the measurement runs. Only the value once &lt;code&gt;busy&lt;/code&gt;
falls is the result.&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 flags are set and nothing has been measured&lt;/td&gt;
&lt;td&gt;The levels default to 0, and the flags describe an average of 0&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;counter&lt;/code&gt; — 0 means no measurement. Set the four levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A second measurement never started&lt;/td&gt;
&lt;td&gt;&lt;code&gt;activate&lt;/code&gt; is still true; the trigger is a rising edge&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;activate&lt;/code&gt; before raising it again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;counter&lt;/code&gt; reads 0 after triggering&lt;/td&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt; is 0 or negative&lt;/td&gt;
&lt;td&gt;Set it above 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;average&lt;/code&gt; looks stale and &lt;code&gt;counter&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Same cause: the measurement ended immediately and left the old result&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;duration&lt;/code&gt; above 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;average&lt;/code&gt; is still moving when &lt;code&gt;busy&lt;/code&gt; falls&lt;/td&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt; is too short for the signal&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Results vary a lot between runs&lt;/td&gt;
&lt;td&gt;The window is too short to average out the noise&lt;/td&gt;
&lt;td&gt;Lengthen &lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isLow&lt;/code&gt; and &lt;code&gt;isTooLow&lt;/code&gt; are both true&lt;/td&gt;
&lt;td&gt;Expected: the bands are nested&lt;/td&gt;
&lt;td&gt;Test &lt;code&gt;isLow&lt;/code&gt; and not &lt;code&gt;isTooLow&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The flags cleared by themselves&lt;/td&gt;
&lt;td&gt;Expected: they do not latch, they follow &lt;code&gt;average&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;WindowDetector&lt;/code&gt; if you need latching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All four flags are false and the reading looks wrong&lt;/td&gt;
&lt;td&gt;A sample that was not a valid number spoiled the measurement&lt;/td&gt;
&lt;td&gt;Fix the upstream signal; check &lt;code&gt;average&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A measurement carried on after a restart&lt;/td&gt;
&lt;td&gt;The block does not clear its state at startup&lt;/td&gt;
&lt;td&gt;Trigger a fresh measurement after every start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;counter&lt;/code&gt; changed after a task-rate change&lt;/td&gt;
&lt;td&gt;Expected: the sample count depends on the rate, the duration does not&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need continuous supervision, not a one-shot test&lt;/td&gt;
&lt;td&gt;Wrong block&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;WindowDetector&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need a continuously updating average&lt;/td&gt;
&lt;td&gt;Wrong block&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;MovingAverageFilter&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to suspend it&lt;/td&gt;
&lt;td&gt;Not possible — there is no enable&lt;/td&gt;
&lt;td&gt;Leave &lt;code&gt;activate&lt;/code&gt; low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need to measure several signals&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per signal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a settled-torque check:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;duration = 2.0
tooLow   = -5.0
low      = -2.0
high     =  2.0
tooHigh  =  5.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;Measurement window&lt;/td&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs for that long, then stops on its own&lt;/td&gt;
&lt;td&gt;&lt;code&gt;busy&lt;/code&gt;, &lt;code&gt;counter&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt; at 0 or below&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; The measurement ends immediately, &lt;code&gt;counter&lt;/code&gt; and &lt;code&gt;sum&lt;/code&gt; read 0, and &lt;strong&gt;&lt;code&gt;average&lt;/code&gt; keeps its previous value&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;counter&lt;/code&gt; reads 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger&lt;/td&gt;
&lt;td&gt;&lt;code&gt;activate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Rising edge only.&lt;/strong&gt; The block never clears it, so a stuck-true input prevents all further measurements&lt;/td&gt;
&lt;td&gt;&lt;code&gt;busy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Averaging&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The exact arithmetic mean, every sample weighted equally&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;counter&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Level ordering&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; The bands are nested by design&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Level defaults&lt;/td&gt;
&lt;td&gt;Fixed at &lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every flag is meaningful from startup, describing an average of zero&lt;/td&gt;
&lt;td&gt;&lt;code&gt;counter&lt;/code&gt; reads 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flag latching&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The flags &lt;strong&gt;do not latch&lt;/strong&gt; — they always describe the current &lt;code&gt;average&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&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; One bad sample spoils the whole average, and &lt;strong&gt;all four flags then read false&lt;/strong&gt; — a broken sensor reads as acceptable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;average&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;No state is cleared. A measurement interrupted by a restart &lt;strong&gt;resumes&lt;/strong&gt; and keeps accumulating into the same total&lt;/td&gt;
&lt;td&gt;&lt;code&gt;busy&lt;/code&gt;, &lt;code&gt;counter&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enable&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;There is no enable, disable or isEnabled&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 signal 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;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt;. Every condition above shows as a value on a
trace, or not at all.&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: HomingSwitch</title>
      <link>/docs/developing-control-applications/control-blocks/detection-and-safety/homing-switch/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/detection-and-safety/homing-switch/</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;HomingSwitch&lt;/code&gt; finds a machine&amp;rsquo;s reference position. It sits &lt;strong&gt;in the path of
the axis setpoint&lt;/strong&gt;: normally it passes the nominal setpoint straight through,
and when you command a homing run it substitutes a smooth jog of its own,
watches up to three trigger signals, and stops when one of them fires.&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 nominal axis setpoint&amp;quot;]) --&amp;gt; B[&amp;quot;HomingSwitch&amp;quot;]
    i2([&amp;quot;triggerSignal1, triggerSignal2, triggerSignal3&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;gotoHoming&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;manualJogPositive, manualJogNegative&amp;quot;]) --&amp;gt; B
    i5([&amp;quot;reset, abort&amp;quot;]) --&amp;gt; B
    i6([&amp;quot;positionReference&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — the setpoint to pass downstream&amp;quot;])
    B --&amp;gt; o2([&amp;quot;homingState&amp;quot;])
    B --&amp;gt; o3([&amp;quot;isHomed&amp;quot;])
    B --&amp;gt; o4([&amp;quot;homingInProgress&amp;quot;])
    B --&amp;gt; o5([&amp;quot;doReferenceOutput&amp;quot;])
    B --&amp;gt; o6([&amp;quot;actuatorUnitRatio&amp;quot;])
    B --&amp;gt; s1([&amp;quot;trigger1Detector, trigger2Detector, trigger3Detector&amp;quot;])
    B --&amp;gt; s2([&amp;quot;homingVelocityFader, homingIntegrator, homingSwitch, homingResetOffsetSwitch&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Four things about this block will catch you out. Read them before commissioning.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;There is no timeout.&lt;/strong&gt; If no trigger ever fires, the axis keeps jogging
until it hits something. Nothing stops it and nothing reports a problem. The
three trigger detectors are your only protection, so wire and configure them
before you set a non-zero &lt;code&gt;homingVelocity&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lowering &lt;code&gt;gotoHoming&lt;/code&gt; does not stop a run.&lt;/strong&gt; Only the &lt;code&gt;abort&lt;/code&gt; input does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The trigger levels are not on this block.&lt;/strong&gt; They are the &lt;code&gt;tooLow&lt;/code&gt; and
&lt;code&gt;tooHigh&lt;/code&gt; levels of the three detectors below — &lt;code&gt;trigger1Detector/tooHigh&lt;/code&gt;
and so on. The warning levels (&lt;code&gt;low&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;) are &lt;strong&gt;not&lt;/strong&gt; used as triggers
and are yours to use for an approach indication.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The jog directions are fixed.&lt;/strong&gt; Moving to a trigger always goes positive;
moving off one always goes negative. The only way to reverse is a negative
&lt;code&gt;homingVelocity&lt;/code&gt;, which reverses &lt;strong&gt;both&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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;axis unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The nominal axis setpoint. Passed straight to &lt;code&gt;output&lt;/code&gt; when not homing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerSignal1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;First trigger — a switch, a sensor, a torque. Watched by &lt;code&gt;trigger1Detector&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerSignal2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Second trigger. &lt;strong&gt;Any&lt;/strong&gt; of the three firing ends the approach.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerSignal3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;Third trigger. Leave unused ones at 0 with their levels wide.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gotoHoming&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;A rising edge starts a run&lt;/strong&gt;, and only if &lt;code&gt;isHomed&lt;/code&gt; is false. Lowering it does &lt;strong&gt;not&lt;/strong&gt; stop the run.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manualJogPositive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Jog positive. &lt;strong&gt;Only has any effect in method 6&lt;/strong&gt; — every other method overwrites it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manualJogNegative&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Jog negative. Same restriction.&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;true or false&lt;/td&gt;
&lt;td&gt;Clears &lt;code&gt;isHomed&lt;/code&gt; and the three detectors, so a new run can start. Cleared for you.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;abort&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Stops a run.&lt;/strong&gt; The only way to. Cleared for you.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;positionReference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The position the homing move starts from. Held while not homing.&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;axis unit&lt;/td&gt;
&lt;td&gt;The setpoint to send downstream — the nominal input, or the homing move, cross-faded between the two.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingState&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;1 off, 2 initialise, 3 moving off a trigger, 4 moving to a trigger, 5 referencing, 6 auto-return, 7 done, 8 aborted. &lt;strong&gt;Note it starts at 1, not 0.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isHomed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The axis has been homed. &lt;strong&gt;Blocks another run until you &lt;code&gt;reset&lt;/code&gt;.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingInProgress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Jogging, or the pull-back is still fading in.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doReferenceOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;A single-cycle pulse&lt;/strong&gt; telling your encoder handling to zero the position. Latch it yourself if you need it longer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;actuatorUnitRatio&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Reads &lt;strong&gt;1.0 always&lt;/strong&gt;. Nothing in the tree can change it.&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;homingMethod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 to 6&lt;/td&gt;
&lt;td&gt;Which sequence to run. See the table below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;The jog speed, applied at &lt;strong&gt;full magnitude&lt;/strong&gt; — there is no proportional jog. &lt;strong&gt;At the default of 0 the axis never moves&lt;/strong&gt; and, in a move-to-trigger method, waits forever. A negative value reverses both jog directions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pullBackOffset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;Added to the final setpoint after the trigger fires, faded in, to retract off the switch.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;autoReferenceOnHome&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;Whether &lt;code&gt;doReferenceOutput&lt;/code&gt; pulses when the run reaches the referencing step.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingAutoReturn&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;&lt;strong&gt;Has no effect.&lt;/strong&gt; The auto-return step is not implemented in this version.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All are persistent and survive a controller restart. The rest of the
configuration is in the sub-trees:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&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;trigger1Detector/tooLow&lt;/code&gt;, &lt;code&gt;…/tooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The trigger levels for signal 1.&lt;/strong&gt; Defaults are -0.05 and 0.05.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trigger1Detector/timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How long the signal must be past the level before it counts. &lt;strong&gt;At the default of 0 a single noisy sample triggers.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trigger2Detector/…&lt;/code&gt;, &lt;code&gt;trigger3Detector/…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same for signals 2 and 3.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingVelocityFader/fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How smoothly the jog starts and stops.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingSwitch/fadeInTime&lt;/code&gt;, &lt;code&gt;…/fadeOutTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How smoothly control passes between the nominal setpoint and the homing move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;homingResetOffsetSwitch/fadeInTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How smoothly the pull-back offset is applied.&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;homingMethod&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; bypass&lt;/td&gt;
&lt;td&gt;Marks the axis homed &lt;strong&gt;without moving&lt;/strong&gt;. Use to skip homing on an axis that does not need it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; reference&lt;/td&gt;
&lt;td&gt;Zeroes in place, without moving. The &lt;strong&gt;default&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt; move to trigger&lt;/td&gt;
&lt;td&gt;Jogs &lt;strong&gt;positive&lt;/strong&gt; until any trigger fires&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt; move off trigger&lt;/td&gt;
&lt;td&gt;Jogs &lt;strong&gt;negative&lt;/strong&gt; until all three triggers are clear&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt; off then to&lt;/td&gt;
&lt;td&gt;Backs off the switch, then approaches it. The usual choice for a repeatable home&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt; to then off&lt;/td&gt;
&lt;td&gt;Approaches the switch, then backs off it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;6&lt;/strong&gt; manual jog to trigger&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;You&lt;/strong&gt; jog with &lt;code&gt;manualJogPositive&lt;/code&gt; and &lt;code&gt;manualJogNegative&lt;/code&gt; until a trigger fires&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Wire your home switch, or whichever signal marks the reference, to
&lt;code&gt;triggerSignal1&lt;/code&gt;. Leave the other two at 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set the trigger levels before anything else.&lt;/strong&gt; Trace &lt;code&gt;triggerSignal1&lt;/code&gt;
through the switch being made and broken, and set
&lt;code&gt;trigger1Detector/tooHigh&lt;/code&gt; and &lt;code&gt;…/tooLow&lt;/code&gt; so the switch reliably crosses
one of them. Set the other two detectors&#39; levels wide so they never fire.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;trigger1Detector/timeWindow&lt;/code&gt; to a few milliseconds so contact bounce
does not trigger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Verify the trigger works before enabling any motion.&lt;/strong&gt; With
&lt;code&gt;homingVelocity&lt;/code&gt; still at 0, operate the switch by hand and watch
&lt;code&gt;trigger1Detector/noError&lt;/code&gt; go false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;homingMethod&lt;/code&gt; to 2 and &lt;code&gt;homingVelocity&lt;/code&gt; to a &lt;strong&gt;slow&lt;/strong&gt; speed — a tenth
of what you eventually want.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;homingVelocityFader/fadeTime&lt;/code&gt; to a few hundred milliseconds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Raise &lt;code&gt;gotoHoming&lt;/code&gt; and watch &lt;code&gt;output&lt;/code&gt; move.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 7 drives the axis, and it will not stop on its own.&lt;/strong&gt; Stand by the
&lt;code&gt;abort&lt;/code&gt; input, or an external limit. There is no timeout in this block: if
the trigger does not fire, the axis jogs until something stops it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm the axis stops when the switch is made, &lt;code&gt;isHomed&lt;/code&gt; goes true, and
&lt;code&gt;homingState&lt;/code&gt; returns to 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pulse &lt;code&gt;reset&lt;/code&gt; before running again.&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;Get the trigger detection right first. Everything else depends on it, and it
is the only thing preventing a runaway.&lt;/li&gt;
&lt;li&gt;Raise &lt;code&gt;homingVelocity&lt;/code&gt; in steps, re-testing each time. The faster the
approach, the further the axis travels between the switch being made and the
jog fading out.&lt;/li&gt;
&lt;li&gt;Measure that overtravel: home several times and compare the final &lt;code&gt;output&lt;/code&gt;.
The spread is your homing repeatability.&lt;/li&gt;
&lt;li&gt;Shorten &lt;code&gt;homingVelocityFader/fadeTime&lt;/code&gt; to reduce overtravel, or lower
&lt;code&gt;homingVelocity&lt;/code&gt;. Lowering the speed usually helps repeatability more.&lt;/li&gt;
&lt;li&gt;Use method 4 for the best repeatability: backing off the switch first means
every run approaches from the same side at the same speed.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;pullBackOffset&lt;/code&gt; to retract clear of the switch after homing, so the
axis does not sit on it.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;homingSwitch/fadeOutTime&lt;/code&gt; so control returns to the nominal setpoint
smoothly after the run.&lt;/li&gt;
&lt;li&gt;Re-check the whole sequence after any change to the axis&amp;rsquo;s speed limits or
task rate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/homing-switch-sequence-ba06eaca.svg&#34; alt=&#34;One homing move: the jog fades in, the trigger fires part-way, the motionfades out, and the pull-back offset fades in to retract off theswitch.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The distance travelled between the trigger firing and the motion stopping is
your overtravel. It scales with both the jog speed and the fade-out time.&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 jogged until it hit something&lt;/td&gt;
&lt;td&gt;No trigger fired and &lt;strong&gt;there is no timeout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Verify the trigger detection before enabling motion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis never moved&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingVelocity&lt;/code&gt; is 0 — the default — or the method is 0 or 1&lt;/td&gt;
&lt;td&gt;Set a velocity and a moving method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing happened when I raised &lt;code&gt;gotoHoming&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isHomed&lt;/code&gt; is already true, or it was already high&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;reset&lt;/code&gt;, then give a fresh rising edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lowering &lt;code&gt;gotoHoming&lt;/code&gt; did not stop it&lt;/td&gt;
&lt;td&gt;Expected: only &lt;code&gt;abort&lt;/code&gt; stops a run&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;abort&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis homed in the wrong direction&lt;/td&gt;
&lt;td&gt;The directions are fixed; only a negative &lt;code&gt;homingVelocity&lt;/code&gt; reverses them, and it reverses both phases&lt;/td&gt;
&lt;td&gt;Use a negative velocity, or a different method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Homing repeatability is poor&lt;/td&gt;
&lt;td&gt;The approach is too fast, or the fade-out too long&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;homingVelocity&lt;/code&gt; first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;It triggered before reaching the switch&lt;/td&gt;
&lt;td&gt;A detector level is too tight, or &lt;code&gt;timeWindow&lt;/code&gt; is 0 and it caught noise&lt;/td&gt;
&lt;td&gt;Widen the level, lengthen the window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;It triggered on a signal I am not using&lt;/td&gt;
&lt;td&gt;An unused trigger signal sits inside its detector&amp;rsquo;s default levels of ±0.05&lt;/td&gt;
&lt;td&gt;Widen the unused detectors&#39; levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setting &lt;code&gt;homingAutoReturn&lt;/code&gt; did nothing&lt;/td&gt;
&lt;td&gt;Expected: the auto-return step is not implemented&lt;/td&gt;
&lt;td&gt;Do the return move in your own logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doReferenceOutput&lt;/code&gt; was missed&lt;/td&gt;
&lt;td&gt;Expected: it is a &lt;strong&gt;single-cycle&lt;/strong&gt; pulse&lt;/td&gt;
&lt;td&gt;Latch it in your own logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doReferenceOutput&lt;/code&gt; never pulsed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;autoReferenceOnHome&lt;/code&gt; is false&lt;/td&gt;
&lt;td&gt;Set it true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;actuatorUnitRatio&lt;/code&gt; always reads 1&lt;/td&gt;
&lt;td&gt;Expected: nothing in the tree can change it&lt;/td&gt;
&lt;td&gt;Ignore it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method 4&amp;rsquo;s first phase did nothing&lt;/td&gt;
&lt;td&gt;Expected: if the axis is already clear of the switch, &amp;ldquo;move off&amp;rdquo; completes at once&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A run resumed after a controller restart&lt;/td&gt;
&lt;td&gt;The block does not reset its state at startup&lt;/td&gt;
&lt;td&gt;Pulse &lt;code&gt;abort&lt;/code&gt; then &lt;code&gt;reset&lt;/code&gt; after every start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis lurched when the run ended&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingSwitch/fadeOutTime&lt;/code&gt; is too short&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis lurched when the run started&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingVelocityFader/fadeTime&lt;/code&gt; is too short&lt;/td&gt;
&lt;td&gt;Lengthen it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything triggered at once&lt;/td&gt;
&lt;td&gt;A trigger signal is not a valid number, which raises all of that detector&amp;rsquo;s flags&lt;/td&gt;
&lt;td&gt;Fix the upstream signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need this on several axes&lt;/td&gt;
&lt;td&gt;Not possible — this block is single axis&lt;/td&gt;
&lt;td&gt;Use one instance per axis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a switch-homed linear axis:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;homingMethod                 = 4
homingVelocity               = 0.01
pullBackOffset               = 0.005
autoReferenceOnHome          = true
homingAutoReturn             = false
trigger1Detector/tooHigh     = &amp;lt;set from a trace of the switch&amp;gt;
trigger1Detector/timeWindow  = 0.005
homingVelocityFader/fadeTime = 0.3
&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;Homing timeout&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;There is none.&lt;/strong&gt; A run whose trigger never fires jogs indefinitely&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingInProgress&lt;/code&gt; stays true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger levels&lt;/td&gt;
&lt;td&gt;The three detectors&#39; &lt;code&gt;tooLow&lt;/code&gt; and &lt;code&gt;tooHigh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any of the three firing ends the approach. &lt;strong&gt;The warning levels are not used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trigger1Detector/noError&lt;/code&gt; and so on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trigger debounce&lt;/td&gt;
&lt;td&gt;Each detector&amp;rsquo;s &lt;code&gt;timeWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Defaults to 0&lt;/strong&gt;, so a single sample triggers&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jog speed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Applied at &lt;strong&gt;full magnitude&lt;/strong&gt;, faded in and out&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jog direction&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fixed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Move-to-trigger is positive, move-off-trigger negative. Only the velocity&amp;rsquo;s sign reverses them, and it reverses both&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stopping a run&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abort&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;Lowering &lt;code&gt;gotoHoming&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; stop it&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingState&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Re-homing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isHomed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blocked until &lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isHomed&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overtravel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingVelocity&lt;/code&gt;, the fader&amp;rsquo;s fade time&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not bounded.&lt;/strong&gt; The axis travels while the jog fades out&lt;/td&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-return&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not implemented.&lt;/strong&gt; The parameter selects a step that does nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingState&lt;/code&gt; passes through 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;actuatorUnitRatio&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not settable from the tree&lt;/td&gt;
&lt;td&gt;Reads 1.0 always&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manualJog&lt;/code&gt; inputs&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Overwritten&lt;/strong&gt; by every method except 6&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doReferenceOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A &lt;strong&gt;single-cycle&lt;/strong&gt; pulse, gated on &lt;code&gt;autoReferenceOnHome&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No state is reset.&lt;/strong&gt; A run interrupted by a restart resumes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;homingState&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values that are not numbers&lt;/td&gt;
&lt;td&gt;Handled below&lt;/td&gt;
&lt;td&gt;A bad trigger signal raises all of that detector&amp;rsquo;s flags, which reads as a trigger and ends the run early&lt;/td&gt;
&lt;td&gt;The detector&amp;rsquo;s flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Axis count&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;One axis 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;This block &lt;strong&gt;logs nothing, ever&lt;/strong&gt; — including when a homing run fails to find
its trigger. Every condition above shows as a value on a trace, or not at all.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

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