<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title> – Setpoints and motion</title>
    <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/</link>
    <description>Recent content in Setpoints and motion on </description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="/docs/developing-control-applications/control-blocks/setpoints-and-motion/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: SetpointGenerator</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/setpoint-generator/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/setpoint-generator/</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;SetpointGenerator&lt;/code&gt; turns a step change in a target into a smooth profiled
move. Write a new number to &lt;code&gt;input&lt;/code&gt; and the output travels there while
respecting velocity, acceleration and jerk limits — and publishes the matching
velocity and acceleration as it goes, so a feedforward path can use them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The move time is computed, not configured.&lt;/strong&gt; You give it the limits; it works
out the fastest move that respects them.&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 target value&amp;quot;]) --&amp;gt; B[&amp;quot;SetpointGenerator&amp;quot;]
    i2([&amp;quot;timeScaleFactor&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;timeScaleFactorDot&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — profiled position&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot — velocity&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot — acceleration&amp;quot;])
    B --&amp;gt; o4([&amp;quot;done&amp;quot;])
    B --&amp;gt; o5([&amp;quot;numTargets — how many are queued&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; stretches the profile&amp;rsquo;s clock while it runs — 0.5 makes the
move take twice as long at half the velocity and a quarter of the
acceleration. That is what a jog-override wheel needs.
&lt;code&gt;timeScaleFactorDot&lt;/code&gt; lets the override itself be turned smoothly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;All three limits default to 0, and a generator with a zero limit refuses
every target.&lt;/strong&gt; Nothing moves, an error is logged once, and no output changes
to tell you why. Set &lt;code&gt;maxVel&lt;/code&gt;, &lt;code&gt;maxAcc&lt;/code&gt; and &lt;code&gt;maxJerk&lt;/code&gt; before anything else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An unachievable target is discarded, not clamped.&lt;/strong&gt; The generator keeps the
previous target and carries on. That is the safe failure, but it is silent
apart from that one log line.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The target. &lt;strong&gt;A change starts a new move&lt;/strong&gt;; writing the same value again does nothing. If the move cannot be profiled with the current limits, the target is discarded and the previous one kept.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Stretches or compresses the profile&amp;rsquo;s clock while it runs. 1 is normal speed, 0.5 is half speed, 0 freezes the move. &lt;strong&gt;Not checked.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactorDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;How fast &lt;code&gt;timeScaleFactor&lt;/code&gt; is itself changing, so an override can be turned without a jolt.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The profiled value on its way to the target.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;Its velocity — feed this to a feedforward path.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;done&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when the profile has finished. &lt;strong&gt;It starts true&lt;/strong&gt;, so a freshly started generator reports done before it has done anything.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many targets are queued. Writing a new target while a move is running adds to the queue rather than replacing 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;maxVel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&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;Velocity limit. &lt;strong&gt;A zero here makes every target be refused.&lt;/strong&gt; Negative values are used as their magnitude and written back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxAcc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&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;Acceleration limit. Same treatment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxJerk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second³&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;Jerk limit. Only used by the jerk-limited profile, but still needs a value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;faderType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 or 1&lt;/td&gt;
&lt;td&gt;Which profile shape. See the table below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delayTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How long to wait after a new target before the move starts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;applyTimeScaleToDelay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Whether &lt;code&gt;timeScaleFactor&lt;/code&gt; stretches the delay as well as the move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1 upward&lt;/td&gt;
&lt;td&gt;How many targets may be queued at once.&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;faderType&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;th&gt;Parameters that matter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; &lt;code&gt;QUINTIC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Position, velocity &lt;strong&gt;and&lt;/strong&gt; acceleration all start and end at zero. The smoothest shape, and the default&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxVel&lt;/code&gt;, &lt;code&gt;maxAcc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; &lt;code&gt;JERK_LIMITED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reaches the acceleration and velocity limits and holds them, so the move is &lt;strong&gt;faster&lt;/strong&gt; for the same limits, with a slightly harsher start&lt;/td&gt;
&lt;td&gt;all three limits&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;No parameters exist
below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set &lt;code&gt;maxVel&lt;/code&gt;, &lt;code&gt;maxAcc&lt;/code&gt; and &lt;code&gt;maxJerk&lt;/code&gt; first.&lt;/strong&gt; They default to 0, and a
generator with a zero limit refuses every target you give it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;faderType&lt;/code&gt; at 0 for a first pass — the quintic profile is the gentler
of the two.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Have your application seed the generator at the machine&amp;rsquo;s current position
before enabling anything downstream, so the first move does not start from
zero.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write a small target to &lt;code&gt;input&lt;/code&gt; and watch &lt;code&gt;output&lt;/code&gt; travel there. Confirm
&lt;code&gt;done&lt;/code&gt; goes false at the start and true at the end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 moves the machine.&lt;/strong&gt; The generator will use the full velocity and
acceleration you configured, immediately. Start with a small target and
limits well below the machine&amp;rsquo;s capability.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check &lt;code&gt;outputDot&lt;/code&gt; peaks at or below &lt;code&gt;maxVel&lt;/code&gt;, and &lt;code&gt;outputDDot&lt;/code&gt; at or below
&lt;code&gt;maxAcc&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write a second target while the first move is running and watch
&lt;code&gt;numTargets&lt;/code&gt;. The moves queue rather than replacing each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set the three limits from the machine, not from the move you want. They are
what the mechanics can take.&lt;/li&gt;
&lt;li&gt;Choose the profile shape from what the machine minds more. Quintic is
smoother and slower; jerk-limited reaches the limits and holds them, so it
is faster for the same numbers.&lt;/li&gt;
&lt;li&gt;Time a move and compare it against what the limits imply. If it is slower
than expected, the quintic shape is the reason — switch to jerk-limited.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;delayTime&lt;/code&gt; when several axes should start together after a common
trigger.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;timeScaleFactor&lt;/code&gt; for a speed override. Ramp it with
&lt;code&gt;timeScaleFactorDot&lt;/code&gt; rather than stepping it, or the move&amp;rsquo;s velocity jumps.&lt;/li&gt;
&lt;li&gt;Raise &lt;code&gt;maxTargets&lt;/code&gt; if your application streams targets faster than the moves
complete. Watch &lt;code&gt;numTargets&lt;/code&gt; to see whether the queue is filling.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change — but note the block
captures the task period once at startup, so if the rate changes while
running, restart the controller.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/setpoint-generator-profiles-598b27a5.svg&#34; alt=&#34;The two profile shapes over one fade time: the quintic eases in and outthroughout, and the two jerk-limited settings reach a constant slope in themiddle.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read how much of the move is spent at constant speed off the straight section
in the middle.&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 moves and no output changes&lt;/td&gt;
&lt;td&gt;A limit is 0 — the default — so every target is refused&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;maxVel&lt;/code&gt;, &lt;code&gt;maxAcc&lt;/code&gt; and &lt;code&gt;maxJerk&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A new target had no effect&lt;/td&gt;
&lt;td&gt;Either it was refused, or it is the same value as the last one&lt;/td&gt;
&lt;td&gt;Check the limits; the generator only reacts to a &lt;strong&gt;change&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An error about invalid settings appeared once&lt;/td&gt;
&lt;td&gt;The limits cannot produce a valid profile&lt;/td&gt;
&lt;td&gt;Fix the limits; the previous target is still in force&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;done&lt;/code&gt; reads true before the first move&lt;/td&gt;
&lt;td&gt;Expected: it starts true&lt;/td&gt;
&lt;td&gt;Wait for it to go false after a target is written&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The move is slower than the limits suggest&lt;/td&gt;
&lt;td&gt;Expected with the quintic profile, which eases throughout&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;faderType&lt;/code&gt; to 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The start of a move is harsher than expected&lt;/td&gt;
&lt;td&gt;Expected with the jerk-limited profile, which pushes to its limits&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;faderType&lt;/code&gt; to 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The move takes the wrong time after a task-rate change&lt;/td&gt;
&lt;td&gt;The block captured the task period at startup&lt;/td&gt;
&lt;td&gt;Restart the controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A limit reads back as a positive number after writing a negative one&lt;/td&gt;
&lt;td&gt;Expected: the magnitude is used&lt;/td&gt;
&lt;td&gt;Write positive values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The move froze part-way&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set it above 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The velocity jumped when the override was changed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; was stepped&lt;/td&gt;
&lt;td&gt;Ramp it, using &lt;code&gt;timeScaleFactorDot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Targets are being dropped&lt;/td&gt;
&lt;td&gt;The queue is full — check &lt;code&gt;numTargets&lt;/code&gt; against &lt;code&gt;maxTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;maxTargets&lt;/code&gt;, or write targets less often&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The first move went to the wrong place&lt;/td&gt;
&lt;td&gt;The generator was not seeded at the machine&amp;rsquo;s position&lt;/td&gt;
&lt;td&gt;Have the application seed it before enabling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot change the jerk-limited profile&amp;rsquo;s shape&lt;/td&gt;
&lt;td&gt;Those two shape factors are not exposed&lt;/td&gt;
&lt;td&gt;Only the two profile types are selectable&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 for an axis that may move at 0.5 units per second:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;maxVel                = 0.5
maxAcc                = 5.0
maxJerk               = 50.0
faderType             = 0
delayTime             = 0.0
maxTargets            = 10
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxVel&lt;/code&gt;, &lt;code&gt;maxAcc&lt;/code&gt;, &lt;code&gt;maxJerk&lt;/code&gt; above 0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked, and all three default to 0.&lt;/strong&gt; A zero limit makes every target be refused&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged once&lt;/strong&gt; when the settings first become invalid; no output changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target achievability&lt;/td&gt;
&lt;td&gt;Checked on every change&lt;/td&gt;
&lt;td&gt;A target that cannot be profiled is &lt;strong&gt;discarded&lt;/strong&gt; and the previous one kept — the generator keeps running on the last valid profile&lt;/td&gt;
&lt;td&gt;Logged once on the transition. &lt;strong&gt;No output flag&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The profile&lt;/td&gt;
&lt;td&gt;Reaches the target exactly. Velocity and acceleration stay inside their limits&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit signs&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Negative limits are used as their magnitude and &lt;strong&gt;written back&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. 0 freezes the move and a negative value is not guarded&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Profile shape factors&lt;/td&gt;
&lt;td&gt;Not exposed&lt;/td&gt;
&lt;td&gt;The jerk-limited shape&amp;rsquo;s two factors are fixed and cannot be configured&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task period&lt;/td&gt;
&lt;td&gt;Captured at startup&lt;/td&gt;
&lt;td&gt;Read once when the controller starts. &lt;strong&gt;A task-rate change while running is not picked up&lt;/strong&gt; and the move takes the wrong time&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target queue&lt;/td&gt;
&lt;td&gt;&lt;code&gt;maxTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Targets written while a move is running are queued, up to this depth&lt;/td&gt;
&lt;td&gt;&lt;code&gt;numTargets&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 channel per instance, always&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block logs one error when the limit set first becomes invalid. Every other
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: SetpointGenerator4thOrder</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/setpoint-generator-4th-order/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/setpoint-generator-4th-order/</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;SetpointGenerator4thOrder&lt;/code&gt; generates a motion profile bounded in &lt;strong&gt;four&lt;/strong&gt;
derivatives: velocity, acceleration, jerk and snap. Bounding the fourth means
&lt;strong&gt;jerk itself ramps instead of stepping&lt;/strong&gt;, which is what a machine with a
lightly damped structure needs — a stepped jerk rings it, a ramped one does
not.&lt;/p&gt;
&lt;p&gt;It moves to a position, or holds a velocity as a jog, and switches between the
two while running.&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;command/start&amp;quot;]) --&amp;gt; B[&amp;quot;SetpointGenerator4thOrder&amp;quot;]
    i2([&amp;quot;command/abort&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;command/type&amp;quot;]) --&amp;gt; B
    i4([&amp;quot;command/jogVelocity&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;targetProfile/position, velocity, acceleration, jerk, snap&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;outputProfile/position, velocity, acceleration, jerk, snap&amp;quot;])
    B --&amp;gt; o2([&amp;quot;status/isDone, isAborted&amp;quot;])
    B --&amp;gt; o3([&amp;quot;status/isMovingToPosition, isMovingToVelocity, isAtConstantVelocity&amp;quot;])
    B --&amp;gt; o4([&amp;quot;status/currentSample, currentIndex&amp;quot;])
    B --&amp;gt; o5([&amp;quot;calc/sampleArray, snapArray, numberOfSamples, totalTime&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;The four numbers under &lt;code&gt;targetProfile&lt;/code&gt; other than &lt;code&gt;position&lt;/code&gt; are &lt;strong&gt;bounds,
not targets&lt;/strong&gt;. The generator uses as much of each as it needs and no more, so
a short move may never reach any of them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Two things about this block will catch you out. Read them before using it.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;command/start&lt;/code&gt; must be held true for the whole move.&lt;/strong&gt; It is not a pulse.
Clearing it mid-move &lt;strong&gt;aborts&lt;/strong&gt; the move as soon as the axis reaches its
cruise speed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;command/abort&lt;/code&gt; only works in jog mode.&lt;/strong&gt; To abort a position move, clear
&lt;code&gt;command/start&lt;/code&gt;. And an abort of either kind &lt;strong&gt;only takes effect during a
constant-speed phase&lt;/strong&gt; — requested during acceleration or braking, it waits.
This is not an emergency stop.&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;command/start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;true or false&lt;/td&gt;
&lt;td&gt;Starts a position move, and &lt;strong&gt;must stay true until it finishes&lt;/strong&gt;. The block clears it when the move ends.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command/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;Aborts a &lt;strong&gt;jog&lt;/strong&gt; only. Ignored during a position move. Cleared by the block once acted on.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command/type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0, 1, 2&lt;/td&gt;
&lt;td&gt;0 relative, 1 absolute, 2 velocity (jog). See the table below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command/jogVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;The jog target speed. &lt;strong&gt;Only read every hundredth cycle&lt;/strong&gt;, and only while the axis is at constant speed, so a jog change can take that long to act.&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;outputProfile/position&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The setpoint to follow.&lt;/strong&gt; Held where it stopped when a move ends.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputProfile/velocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second&lt;/td&gt;
&lt;td&gt;Its speed — feed this to a feedforward path.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputProfile/acceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second²&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputProfile/jerk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second³&lt;/td&gt;
&lt;td&gt;Its jerk. Continuous, which is the point of this block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputProfile/snap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second⁴&lt;/td&gt;
&lt;td&gt;The driving quantity, which steps between sixteen fixed values.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/isDone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The move has finished. &lt;strong&gt;Reads false until the first move completes&lt;/strong&gt;, including straight after a restart.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/isAborted&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The last move was aborted rather than completed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/isMovingToPosition&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;A position move is running.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/isMovingToVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;A jog is running.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/isAtConstantVelocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Acceleration, jerk and snap are all zero. &lt;strong&gt;An abort can only act while this is true.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/currentSample&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many cycles into the profile the axis is.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/currentIndex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Which of the eighteen profile segments is playing, 0 to 17.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calc/numberOfSamples&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many cycles the whole move will take.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calc/totalTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;How long it will take. &lt;strong&gt;Check this after starting&lt;/strong&gt; — a very small bound makes it enormous.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calc/sampleArray&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many cycles each profile segment lasts. Diagnostic. Shows 17 of the 18 segments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calc/snapArray&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second⁴&lt;/td&gt;
&lt;td&gt;The snap value of each segment. Diagnostic. Shows 17 of the 18.&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;targetProfile/position&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;unbounded&lt;/td&gt;
&lt;td&gt;The target. Absolute or relative depending on &lt;code&gt;command/type&lt;/code&gt;. In relative mode a value of exactly 0 is refused.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;targetProfile/velocity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Speed bound. A zero refuses the move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;targetProfile/acceleration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second²&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Acceleration bound. A zero refuses the move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;targetProfile/jerk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second³&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Jerk bound. A zero refuses the move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;targetProfile/snap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;axis unit per second⁴&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Snap bound — how fast jerk may change. &lt;strong&gt;This is the parameter that makes the profile gentle.&lt;/strong&gt; A zero refuses the move.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All five are persistent and survive a controller restart. Negative values are
used as their magnitude. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;command/type&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;th&gt;What &lt;code&gt;targetProfile/position&lt;/code&gt; means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; &lt;code&gt;RELATIVE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Moves a given distance from where it is&lt;/td&gt;
&lt;td&gt;The distance to travel. &lt;strong&gt;Exactly 0 is refused&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; &lt;code&gt;ABSOLUTE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Moves to a given position — the default&lt;/td&gt;
&lt;td&gt;The position to arrive at&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt; &lt;code&gt;VELOCITY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Jogs at &lt;code&gt;command/jogVelocity&lt;/code&gt; until aborted&lt;/td&gt;
&lt;td&gt;Not used&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;Set the four bounds from what the machine can take. All four have non-zero
defaults, so the block will move without being configured — check them
before you start it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;command/type&lt;/code&gt; to 0 for a first move, so the distance is relative to
wherever the axis already is.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;targetProfile/position&lt;/code&gt; to a small distance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;command/start&lt;/code&gt; true &lt;strong&gt;and leave it true&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 moves the machine&lt;/strong&gt;, immediately and at the bounds you
configured. Set them well below the machine&amp;rsquo;s capability first, and use a
distance you can afford to overshoot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Watch &lt;code&gt;status/isMovingToPosition&lt;/code&gt; go true, then &lt;code&gt;status/isDone&lt;/code&gt; go true when
it arrives. The block clears &lt;code&gt;command/start&lt;/code&gt; itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read &lt;code&gt;calc/totalTime&lt;/code&gt; and check it against the distance and the speed bound.
A much larger number means a bound is far smaller than you meant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;outputProfile/position&lt;/code&gt; ends exactly at the target. It should be
exact, not close.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;targetProfile/velocity&lt;/code&gt; and &lt;code&gt;targetProfile/acceleration&lt;/code&gt; first — they
are what the machine&amp;rsquo;s mechanics allow.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;targetProfile/jerk&lt;/code&gt; to what the drivetrain tolerates. Lower means
gentler load reversals.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;targetProfile/snap&lt;/code&gt; last, and use it to trade smoothness against move
time. It is the only bound the third-order generators do not have, and the
reason to use this block at all.&lt;/li&gt;
&lt;li&gt;Run a move and watch &lt;code&gt;outputProfile/jerk&lt;/code&gt;. With snap bounded it ramps
between levels; the flatter the ramps, the gentler the move.&lt;/li&gt;
&lt;li&gt;If the machine rings at a known frequency, lower &lt;code&gt;targetProfile/snap&lt;/code&gt; until
the ringing stops. Every reduction lengthens the move.&lt;/li&gt;
&lt;li&gt;Compare &lt;code&gt;calc/totalTime&lt;/code&gt; before and after each change, so you can see what
the smoothness cost.&lt;/li&gt;
&lt;li&gt;Short moves take longer than the bounds imply. Every profile segment is
rounded up to a whole cycle, which matters most when the move is only a few
cycles long.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/setpoint-generator-4th-order-acceleration-0beb9896.svg&#34; alt=&#34;Acceleration at the start of a move. A second-order profile stepsacceleration straight to its limit; a third-order profile ramps it, so jerksteps; a fourth-order profile eases it in, so jerk iscontinuous.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The gentler the curve leaves zero, the less the machine is excited — and the
longer the move takes.&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 move stopped part-way&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command/start&lt;/code&gt; was cleared, which aborts&lt;/td&gt;
&lt;td&gt;Hold &lt;code&gt;command/start&lt;/code&gt; true for the whole move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command/abort&lt;/code&gt; did nothing&lt;/td&gt;
&lt;td&gt;It only aborts a jog&lt;/td&gt;
&lt;td&gt;Clear &lt;code&gt;command/start&lt;/code&gt; to stop a position move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An abort did not act for a while&lt;/td&gt;
&lt;td&gt;Aborts only take effect at constant speed&lt;/td&gt;
&lt;td&gt;Expected. Do not use this as an emergency stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The axis stopped in the wrong place after an abort&lt;/td&gt;
&lt;td&gt;An abort plays out the braking half, wherever that ends&lt;/td&gt;
&lt;td&gt;Expected. The stopping point is not predictable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing moved and an error was logged&lt;/td&gt;
&lt;td&gt;A bound is 0, or a relative move of exactly 0 was requested&lt;/td&gt;
&lt;td&gt;Set all four bounds above 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The same error keeps repeating&lt;/td&gt;
&lt;td&gt;The block retries every hundredth cycle&lt;/td&gt;
&lt;td&gt;Fix the bound or the move type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The first absolute move went to the wrong place&lt;/td&gt;
&lt;td&gt;The block starts from position 0, and cannot be told the machine&amp;rsquo;s real position from the parameter tree&lt;/td&gt;
&lt;td&gt;Use relative moves, or drive the block from an application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status/isDone&lt;/code&gt; reads false after a restart&lt;/td&gt;
&lt;td&gt;Expected: it only becomes true when a move finishes&lt;/td&gt;
&lt;td&gt;Run one move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calc/totalTime&lt;/code&gt; is enormous&lt;/td&gt;
&lt;td&gt;A bound is far smaller than intended&lt;/td&gt;
&lt;td&gt;Check all four&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A short move took much longer than expected&lt;/td&gt;
&lt;td&gt;Each segment is rounded up to a whole cycle&lt;/td&gt;
&lt;td&gt;Expected. It matters only for very short moves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A jog change took a long time to act&lt;/td&gt;
&lt;td&gt;Jog targets are read every hundredth cycle, at constant speed only&lt;/td&gt;
&lt;td&gt;Expected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The machine rings during acceleration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;targetProfile/snap&lt;/code&gt; is too high&lt;/td&gt;
&lt;td&gt;Lower it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The move is smooth but too slow&lt;/td&gt;
&lt;td&gt;A bound is limiting it — read &lt;code&gt;calc/totalTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;snap&lt;/code&gt; first, then &lt;code&gt;jerk&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;calc/snapArray&lt;/code&gt; shows 17 entries, not 18&lt;/td&gt;
&lt;td&gt;Expected: the last segment is not published&lt;/td&gt;
&lt;td&gt;The missing entry is always 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A bound reads back positive after writing a negative one&lt;/td&gt;
&lt;td&gt;Expected: the magnitude is used&lt;/td&gt;
&lt;td&gt;Write positive values&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 an axis that may move at 0.5 units per second:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;targetProfile/velocity     = 0.5
targetProfile/acceleration = 5.0
targetProfile/jerk         = 100.0
targetProfile/snap         = 1000.0
command/type               = 1
&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;The four bounds&lt;/td&gt;
&lt;td&gt;&lt;code&gt;targetProfile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Respected exactly. The profile uses as much of each as it needs; a short move reaches none of them&lt;/td&gt;
&lt;td&gt;&lt;code&gt;calc/totalTime&lt;/code&gt; and &lt;code&gt;calc/numberOfSamples&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A bound of 0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The move is &lt;strong&gt;refused&lt;/strong&gt; and the output does not change&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged, and repeated&lt;/strong&gt; every hundredth cycle while it persists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A relative move of exactly 0&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;Refused as an incorrect move command&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Logged, and repeated&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bound signs&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Negative bounds are used as their magnitude&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A very small bound&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Accepted, and produces an enormous move time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;calc/totalTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arrival&lt;/td&gt;
&lt;td&gt;The profile&lt;/td&gt;
&lt;td&gt;The move lands &lt;strong&gt;exactly&lt;/strong&gt; on the target, not within a rounding error&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outputProfile/position&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Segment durations&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Rounded up to whole cycles, so short moves take longer than the bounds imply&lt;/td&gt;
&lt;td&gt;&lt;code&gt;calc/totalTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Position move abort&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command/start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clearing it aborts, but only once the axis is at constant speed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status/isAborted&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jog abort&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command/abort&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Aborts, but only once the axis is at constant speed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status/isAborted&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abort stopping point&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The braking half plays out and the axis stops wherever it ends. &lt;strong&gt;Not the target, and not predicted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starting position&lt;/td&gt;
&lt;td&gt;Not settable from the tree&lt;/td&gt;
&lt;td&gt;An absolute move always starts from 0 unless the block is driven from an application&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jog latency&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A new jog target is read every hundredth cycle, at constant speed only&lt;/td&gt;
&lt;td&gt;Not reported&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;The block logs an error, repeatedly, when a bound is 0 or the move command is
not valid. Every other 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: Interpolator</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/interpolator/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/interpolator/</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;Interpolator&lt;/code&gt; fills in the gaps between values that arrive more slowly than
the control loop runs. A trajectory point every 10 ms on a 1 ms task leaves
nine cycles with nothing new to follow; this block generates those nine, so the
controller downstream sees a continuous command instead of a staircase.&lt;/p&gt;
&lt;p&gt;It offers two shapes. Straight-line segments are the default and cost one
segment of delay. Cubic segments with matched slopes at the joins are smoother
— the only interpolation here with no corner at a join — and cost two.&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 slowly arriving value&amp;quot;]) --&amp;gt; B[&amp;quot;Interpolator&amp;quot;]
    i2([&amp;quot;disable&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — interpolated value, every cycle&amp;quot;])
    B --&amp;gt; o2([&amp;quot;isEnabled&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Set &lt;code&gt;sampleFactor&lt;/code&gt; to &lt;strong&gt;the number of task cycles between arrivals&lt;/strong&gt;: input
every 10 ms on a 1 ms task means 10. Delay is &lt;code&gt;sampleFactor&lt;/code&gt; × task period
with &lt;code&gt;lookAhead&lt;/code&gt; false, and twice that with &lt;code&gt;lookAhead&lt;/code&gt; true — 10 ms and
20 ms in that example. With &lt;code&gt;filterSamples&lt;/code&gt; at 0 the output passes exactly
through every arrived value; above 0 it no longer does, and adds a lag of
(&lt;code&gt;filterSamples&lt;/code&gt; + 1) × task period on top.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nothing here detects when a new value actually arrives.&lt;/strong&gt; The block counts
cycles, so &lt;code&gt;sampleFactor&lt;/code&gt; must match the arrival rate — see the symptom table.
&lt;strong&gt;&lt;code&gt;outputFiltered&lt;/code&gt; no longer exists&lt;/strong&gt;; if you are upgrading, see Limits and
errors.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;unbounded&lt;/td&gt;
&lt;td&gt;The slowly arriving value. One element per channel; the channel count is fixed by the machine configuration. The block reads it once per segment, not every cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True bypasses the interpolation: &lt;code&gt;input&lt;/code&gt; passes straight to &lt;code&gt;output&lt;/code&gt;. Use it for a runtime override from a supervisor; use &lt;code&gt;enable&lt;/code&gt; for the configured intent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The interpolated value, fresh every cycle, one element per channel. Equals &lt;code&gt;input&lt;/code&gt; exactly while bypassed. &lt;strong&gt;Ramps from zero to the first arrived value&lt;/strong&gt; over one segment after every controller start. With &lt;code&gt;filterSamples&lt;/code&gt; at 0 it passes exactly through each arrived value at the end of its segment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True when &lt;code&gt;enable&lt;/code&gt; is true and &lt;code&gt;disable&lt;/code&gt; is false. A single value for the whole block, not one per channel.&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;sampleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cycles&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1 – 1000&lt;/td&gt;
&lt;td&gt;Task cycles per arriving value. &lt;strong&gt;Must match your input&amp;rsquo;s arrival rate.&lt;/strong&gt; Out-of-range values are corrected silently, and 1 makes the block a one-cycle delay.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filterSamples&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;samples&lt;/td&gt;
&lt;td&gt;0 (off)&lt;/td&gt;
&lt;td&gt;0 – 1000&lt;/td&gt;
&lt;td&gt;Extra smoothing applied after interpolation. 0 is off and is the right default. Above 0 it adds a lag of (&lt;code&gt;filterSamples&lt;/code&gt; + 1) cycles and the output stops passing exactly through the arrived values. Corrected silently if out of range.&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;False bypasses the interpolation: &lt;code&gt;input&lt;/code&gt; passes through unchanged.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lookAhead&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;False gives straight segments with a corner at each join. True gives cubic segments with matched slopes and no corner, at &lt;strong&gt;twice the delay&lt;/strong&gt;. Change it with the machine at rest.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All four parameters are persistent and survive a controller restart. The inputs
and outputs do not. &lt;strong&gt;No parameters exist below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Measure how often the source updates &lt;code&gt;input&lt;/code&gt;, in task cycles. Divide the
update period by the task period: a 10 ms source on a 1 ms task is 10.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link the source into &lt;code&gt;input&lt;/code&gt; and confirm on a trace that &lt;code&gt;input&lt;/code&gt; moves in
steps at the rate you measured.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; false. &lt;code&gt;output&lt;/code&gt; equals &lt;code&gt;input&lt;/code&gt; sample for sample and
&lt;code&gt;isEnabled&lt;/code&gt; reads false.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;sampleFactor&lt;/code&gt; to the number from step 1, &lt;code&gt;filterSamples&lt;/code&gt; to 0, and
&lt;code&gt;lookAhead&lt;/code&gt; false. Read both numbers back to confirm they were accepted.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;enable&lt;/code&gt; true. &lt;code&gt;output&lt;/code&gt; should now move smoothly every cycle instead of
in steps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overlay &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;output&lt;/code&gt; on one trace. &lt;code&gt;output&lt;/code&gt; should reach each
arrived value exactly at the moment the next one arrives, and never hold
flat mid-segment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6 is the check that &lt;code&gt;sampleFactor&lt;/code&gt; matches.&lt;/strong&gt; A flat stretch at the
end of each segment means the value is too low; &lt;code&gt;output&lt;/code&gt; still moving in
steps means it is too high. Get this right before tuning anything else.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trace every element of &lt;code&gt;input&lt;/code&gt; and &lt;code&gt;output&lt;/code&gt;. An element that reads zero
while the machine moves is an unwired channel.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Get &lt;code&gt;sampleFactor&lt;/code&gt; right first, with Setup step 6. Nothing else in this
block works until the segment length matches the arrival rate.&lt;/li&gt;
&lt;li&gt;Decide whether you need &lt;code&gt;lookAhead&lt;/code&gt;. Leave it false unless the corner at
each join is visibly reaching the machine — as a tick in the velocity, a
bump in the torque, or audible roughness at the update rate.&lt;/li&gt;
&lt;li&gt;If you enable &lt;code&gt;lookAhead&lt;/code&gt;, re-measure your total delay. It doubles, and
whatever loop consumes &lt;code&gt;output&lt;/code&gt; pays for it in phase margin.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;lookAhead&lt;/code&gt; true, watch a sharp change of direction on a trace.
&lt;strong&gt;Cubic segments overshoot on a corner&lt;/strong&gt; — the output will go past the
commanded value and come back. If that overshoot is beyond what the machine
can accept, use straight segments instead.&lt;/li&gt;
&lt;li&gt;Leave &lt;code&gt;filterSamples&lt;/code&gt; at 0 unless you have residual noise the interpolation
itself cannot handle. It costs lag on top of the interpolation delay and it
stops the output passing through the arrived values exactly.&lt;/li&gt;
&lt;li&gt;Re-check &lt;code&gt;sampleFactor&lt;/code&gt; after any task-rate change. It counts cycles, so
the same value is a different segment length in seconds — rescale it by the
ratio of the task periods, and re-check that it still matches the arrival
rate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/interpolator-smoothing-69d887c6.svg&#34; alt=&#34;A 1 Hz source arriving every 10 samples: the dashed input moves in steps,straight-line interpolation follows it in flat segments, and cubicinterpolation follows a smooth curve one segment furtherbehind.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read the delay off either curve as its horizontal offset from the dashed input.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; holds flat at the end of every segment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sampleFactor&lt;/code&gt; is lower than the actual arrival rate, so each segment finishes early&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;sampleFactor&lt;/code&gt; to the measured number of cycles between arrivals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; still moves in visible steps&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sampleFactor&lt;/code&gt; is higher than the arrival rate, so segments are cut short&lt;/td&gt;
&lt;td&gt;Lower &lt;code&gt;sampleFactor&lt;/code&gt; to the measured number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; drifts in and out of matching the input&lt;/td&gt;
&lt;td&gt;The source&amp;rsquo;s update rate is not constant&lt;/td&gt;
&lt;td&gt;Fix the source&amp;rsquo;s timing; this block cannot follow a varying rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A tick in velocity or torque at the update rate&lt;/td&gt;
&lt;td&gt;Expected with straight segments: the slope jumps at each join&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;lookAhead&lt;/code&gt; true, and accept twice the delay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; overshoots past a commanded value on a sharp turn&lt;/td&gt;
&lt;td&gt;Expected with &lt;code&gt;lookAhead&lt;/code&gt; true: cubic segments overshoot at a corner&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;lookAhead&lt;/code&gt; false, or bound the output downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The delay doubled after switching to &lt;code&gt;lookAhead&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: cubic segments need the next value before they can start&lt;/td&gt;
&lt;td&gt;Budget for it, or go back to straight segments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A glitch when &lt;code&gt;lookAhead&lt;/code&gt; was changed while running&lt;/td&gt;
&lt;td&gt;The block does not clean up its state on a mode change&lt;/td&gt;
&lt;td&gt;Change &lt;code&gt;lookAhead&lt;/code&gt; with the machine at rest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; no longer reaches the arrived values exactly&lt;/td&gt;
&lt;td&gt;&lt;code&gt;filterSamples&lt;/code&gt; is above 0&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;filterSamples&lt;/code&gt; to 0 if the arrived values must be honoured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The loop consuming &lt;code&gt;output&lt;/code&gt; went soft after raising &lt;code&gt;filterSamples&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expected: the extra smoothing adds lag on top of the interpolation delay&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;filterSamples&lt;/code&gt; back to 0 and fix noise at its source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; ramps up from zero for one segment after every start&lt;/td&gt;
&lt;td&gt;Expected: the block has no previous value to interpolate from&lt;/td&gt;
&lt;td&gt;Gate the consumer off &lt;code&gt;isEnabled&lt;/code&gt; plus one segment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A large ramp on &lt;code&gt;output&lt;/code&gt; after re-enabling with straight segments&lt;/td&gt;
&lt;td&gt;Expected: the block interpolates from the value it last held to the current input&lt;/td&gt;
&lt;td&gt;Re-enable at rest, or use &lt;code&gt;lookAhead&lt;/code&gt;, whose first segment after a re-enable is deliberately straight and clean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sampleFactor&lt;/code&gt; or &lt;code&gt;filterSamples&lt;/code&gt; reads back different from what you wrote&lt;/td&gt;
&lt;td&gt;Outside the accepted range&lt;/td&gt;
&lt;td&gt;Work within the value you read back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setting &lt;code&gt;sampleFactor&lt;/code&gt; to 0 gave 1&lt;/td&gt;
&lt;td&gt;Expected: 1 is the minimum, and it makes the block a one-cycle delay&lt;/td&gt;
&lt;td&gt;Set the real cycle count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The delay in seconds changed after a task-rate change&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;sampleFactor&lt;/code&gt; counts cycles, not seconds&lt;/td&gt;
&lt;td&gt;Rescale it by the ratio of the task periods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Some channels interpolate differently from others&lt;/td&gt;
&lt;td&gt;Not possible — all channels share one segment length and one mode&lt;/td&gt;
&lt;td&gt;Use a separate instance per channel group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt; went to a non-numeric value&lt;/td&gt;
&lt;td&gt;A non-numeric value reached &lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fix the source, then bypass the block for one cycle — that clears its state completely&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a 10 ms trajectory source on a 1 ms task, with straight
segments and no extra smoothing:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;sampleFactor  = 10
filterSamples = 0
lookAhead     = false
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;&lt;code&gt;sampleFactor&lt;/code&gt; within 1 – 1000&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A value outside the range is replaced by the nearest edge. 1 is a one-cycle delay&lt;/td&gt;
&lt;td&gt;Silently; read &lt;code&gt;sampleFactor&lt;/code&gt; back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filterSamples&lt;/code&gt; within 0 – 1000&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;A value outside the range is replaced by the nearest edge. 0 switches the extra smoothing off&lt;/td&gt;
&lt;td&gt;Silently; read &lt;code&gt;filterSamples&lt;/code&gt; back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arrival rate&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 block counts cycles and never looks at whether &lt;code&gt;input&lt;/code&gt; actually changed, so a mismatch between &lt;code&gt;sampleFactor&lt;/code&gt; and the real arrival rate is silent — it shows only as the shape of &lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overshoot with &lt;code&gt;lookAhead&lt;/code&gt; true&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Cubic segments overshoot at a corner, and there is no limit on by how much. Bound the output downstream if the machine cannot accept it&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Unbounded. Limit it downstream if the consumer needs a bound&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;A bypassed cycle&lt;/td&gt;
&lt;td&gt;Bypassing the block clears its state completely. There is no separate reset&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputFiltered&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;This path no longer exists.&lt;/strong&gt; It was removed in an earlier release and its value was always identical to &lt;code&gt;output&lt;/code&gt;. A linking file still referencing it will not resolve — point it at &lt;code&gt;output&lt;/code&gt; instead&lt;/td&gt;
&lt;td&gt;Not reported; the link fails to resolve&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel count&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Fixed once the controller starts; it cannot be changed at runtime&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: MotionPlayer</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/motion-player/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/motion-player/</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;MotionPlayer&lt;/code&gt; replays recorded motion from files on disk. It reads a folder of
profile files at startup, keeps them in memory, and streams one row at a time
onto a fifty-wide output. Play, pause, stop and reload are commanded from the
tree.&lt;/p&gt;
&lt;p&gt;Use it to replay a taught motion, a test sequence or a recorded trajectory.&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;command&amp;quot;]) --&amp;gt; B[&amp;quot;MotionPlayer&amp;quot;]
    i2([&amp;quot;timeScaleFactor&amp;quot;]) --&amp;gt; B
    p1([&amp;quot;profileID&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output — 50 columns&amp;quot;])
    B --&amp;gt; o2([&amp;quot;state&amp;quot;])
    B --&amp;gt; o3([&amp;quot;error&amp;quot;])
    B --&amp;gt; o4([&amp;quot;activeProfileID&amp;quot;])
    B --&amp;gt; o5([&amp;quot;activeProfileTimestamp&amp;quot;])
    B --&amp;gt; o6([&amp;quot;activeProfileEndTime&amp;quot;])
    B --&amp;gt; o7([&amp;quot;activeProfileEnding&amp;quot;])
    B --&amp;gt; o8([&amp;quot;fractionComplete&amp;quot;])
    B --&amp;gt; o9([&amp;quot;numberOfProfiles&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The output is never interpolated.&lt;/strong&gt; It holds each file row until the next
one is due, so the output is a staircase whose step size is set entirely by
how finely the file was recorded. This is the single most important thing to
know about the block.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Two behaviours will surprise you. Both are by design.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stopping rewinds. Pausing holds.&lt;/strong&gt; A stopped player drives its output back
to the profile&amp;rsquo;s first row and keeps it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When a non-looping profile ends, the output jumps back to the first row&lt;/strong&gt;,
one cycle after it completes. If the file does not end where it starts, that
is a step of the whole profile range on your output. Make the file end where
it begins, or stop using its output before it finishes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;file-format&#34;&gt;File format&lt;/h3&gt;
&lt;p&gt;Files live in a folder chosen when the controller is built, and are read once
at startup.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The filename must begin with a &lt;strong&gt;number followed by an underscore&lt;/strong&gt; —
&lt;code&gt;00_home.csv&lt;/code&gt;, &lt;code&gt;12_pick.csv&lt;/code&gt;. That number is the &lt;code&gt;profileID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lines beginning with &lt;code&gt;#&lt;/code&gt; are comments.&lt;/li&gt;
&lt;li&gt;A line reading &lt;code&gt;loop = 1&lt;/code&gt; makes the profile repeat; &lt;code&gt;loop = 0&lt;/code&gt;, or no such
line, plays it once.&lt;/li&gt;
&lt;li&gt;Every other line is one row: &lt;strong&gt;the first number is the time in seconds&lt;/strong&gt;, and
the rest are the data columns, separated by spaces or tabs.&lt;/li&gt;
&lt;li&gt;Times start at zero and must increase down the file. &lt;strong&gt;This is not checked&lt;/strong&gt;
— a file whose time column goes backwards will skip rows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;At most 50 data columns.&lt;/strong&gt; Extra columns are dropped silently, and unused
columns read 0.&lt;/li&gt;
&lt;li&gt;Avoid blank lines. Each one adds an invisible all-zero row.&lt;/li&gt;
&lt;/ul&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;command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0 to 4&lt;/td&gt;
&lt;td&gt;0 none, &lt;strong&gt;1 play&lt;/strong&gt;, &lt;strong&gt;2 pause&lt;/strong&gt;, &lt;strong&gt;3 stop&lt;/strong&gt;, &lt;strong&gt;4 reload&lt;/strong&gt;. Write the number; the block clears it back to 0 once acted on, so it is a pulse, not a level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;Multiplies the playback speed. 1 is normal, 0.5 is half speed. &lt;strong&gt;Not checked.&lt;/strong&gt; 0 freezes playback; a negative value stalls it rather than rewinding; a large value skips rows.&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;file unit&lt;/td&gt;
&lt;td&gt;The 50 columns of the row being played. Columns your file does not have read 0.&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;0 stopped, 1 playing, 2 paused, 3 finished, 4 and 5 reloading.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;error&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0 none, 1 no profile loaded, 2 the requested id does not exist.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeProfileID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The profile actually loaded. &lt;strong&gt;-1 means none&lt;/strong&gt; — check this first when nothing plays.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeProfileTimestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;The &lt;strong&gt;file timestamp of the current row&lt;/strong&gt;, not the elapsed time. It advances in jumps, one per row.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeProfileEndTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;The last timestamp in the loaded file — how long the profile runs at normal speed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeProfileEnding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0 the profile plays once, 1 it loops. Read from the file&amp;rsquo;s &lt;code&gt;loop =&lt;/code&gt; line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fractionComplete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How far through the profile, 0 to 1. &lt;strong&gt;Reads 1.0 when no profile is loaded&lt;/strong&gt;, so read &lt;code&gt;activeProfileID&lt;/code&gt; alongside it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numberOfProfiles&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many files loaded successfully. &lt;strong&gt;0 means the folder was missing, empty, or every file was rejected.&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;profileID&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;Which profile to play &lt;strong&gt;next&lt;/strong&gt;. Changing it while a profile is playing does nothing until that profile ends — which is how profiles are sequenced back to back. If no file has this id, &lt;code&gt;error&lt;/code&gt; reads 2 and &lt;code&gt;activeProfileID&lt;/code&gt; reads -1.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;profileID&lt;/code&gt; is persistent and survives a controller restart, so the player
comes back with the same profile selected. &lt;strong&gt;No parameters exist below this
block&lt;/strong&gt;, and the folder the files are read from is not visible in the tree.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Put your profile files in the player&amp;rsquo;s folder, named &lt;code&gt;&amp;lt;number&amp;gt;_&amp;lt;name&amp;gt;.csv&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the controller and read &lt;code&gt;numberOfProfiles&lt;/code&gt;. It should match the number
of files you provided. &lt;strong&gt;A 0 here means the folder was not found&lt;/strong&gt; — nothing
else in the tree will tell you that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read &lt;code&gt;activeProfileID&lt;/code&gt;. It should be 0 at startup, or -1 if no file has id
0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read &lt;code&gt;activeProfileEndTime&lt;/code&gt; and check it against the last timestamp in your
file. A mismatch means the file did not parse as you expected.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;profileID&lt;/code&gt; to the profile you want and confirm &lt;code&gt;activeProfileID&lt;/code&gt;
follows it and &lt;code&gt;error&lt;/code&gt; reads 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write 1 to &lt;code&gt;command&lt;/code&gt; to play.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6 moves the machine&lt;/strong&gt;, immediately and at whatever rate the file
was recorded. Confirm the file&amp;rsquo;s first row matches where the machine
already is, or the first output will be a step.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Watch &lt;code&gt;fractionComplete&lt;/code&gt; climb to 1 and &lt;code&gt;state&lt;/code&gt; go to 0 or 3.&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;
&lt;p&gt;Check that the file&amp;rsquo;s &lt;strong&gt;first row matches the machine&amp;rsquo;s resting position&lt;/strong&gt;.
The player makes no attempt to blend into the profile.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check that a non-looping file &lt;strong&gt;ends where it starts&lt;/strong&gt;, or arrange for its
output to be ignored once &lt;code&gt;fractionComplete&lt;/code&gt; reaches 1. Otherwise the snap
back to row 0 is a step.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Read &lt;code&gt;activeProfileEndTime&lt;/code&gt; and divide it by the number of rows to get the
average row interval. That interval is your output&amp;rsquo;s step size.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the machine is rough during playback, the file is too sparsely sampled.
Re-record it more finely, or filter the output downstream.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;timeScaleFactor&lt;/code&gt; to slow a profile down while commissioning. Halving it
halves the speed and doubles the duration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sequence profiles by writing the next &lt;code&gt;profileID&lt;/code&gt; while the current one is
still playing. The switch happens exactly at the end, with no gap.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After changing files on disk, write 4 to &lt;code&gt;command&lt;/code&gt; to reload. Wait for
&lt;code&gt;state&lt;/code&gt; to leave 4 and 5 before playing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reloading while a profile is selected is not safe in this version.&lt;/strong&gt;
Stop the player, set &lt;code&gt;profileID&lt;/code&gt; to a different value and back again after
the reload completes, so the profile is re-resolved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/motion-player-row-spacing-da523288.svg&#34; alt=&#34;The same motion recorded at three row spacings. Coarse rows produce visiblesteps in the output; fine rows produce a smooth curve. The block holds each rowand never interpolates between them.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read your file&amp;rsquo;s step size off the height of the treads.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numberOfProfiles&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;The folder is missing, empty, or every file was rejected&lt;/td&gt;
&lt;td&gt;Check the controller log — every rejected file is logged by name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A file was not loaded&lt;/td&gt;
&lt;td&gt;Its name does not start with a number and an underscore, or another file already claims that id&lt;/td&gt;
&lt;td&gt;Rename it. The log message mentions an &amp;ldquo;id: tag&amp;rdquo;, which is wrong — it is the &lt;strong&gt;filename&lt;/strong&gt; that carries the id&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeProfileID&lt;/code&gt; reads -1&lt;/td&gt;
&lt;td&gt;No file has the requested &lt;code&gt;profileID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;profileID&lt;/code&gt; to an id that exists; &lt;code&gt;error&lt;/code&gt; reads 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fractionComplete&lt;/code&gt; reads 1.0 and nothing plays&lt;/td&gt;
&lt;td&gt;No profile is loaded&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;activeProfileID&lt;/code&gt; — 1.0 here means &amp;ldquo;nothing&amp;rdquo;, not &amp;ldquo;finished&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stepped at the start of playback&lt;/td&gt;
&lt;td&gt;The file&amp;rsquo;s first row does not match where the machine is&lt;/td&gt;
&lt;td&gt;Re-record the file from the resting position&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output stepped at the end of playback&lt;/td&gt;
&lt;td&gt;Expected: a finished non-looping profile snaps back to row 0&lt;/td&gt;
&lt;td&gt;End the file where it starts, or ignore the output past &lt;code&gt;fractionComplete&lt;/code&gt; 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stopping caused a jump&lt;/td&gt;
&lt;td&gt;Expected: stop rewinds to row 0&lt;/td&gt;
&lt;td&gt;Use pause, which holds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output is a visible staircase&lt;/td&gt;
&lt;td&gt;The file&amp;rsquo;s rows are too far apart, and the block never interpolates&lt;/td&gt;
&lt;td&gt;Re-record more finely, or filter downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The motion is jerky at the loop point&lt;/td&gt;
&lt;td&gt;The file&amp;rsquo;s last row does not match its first&lt;/td&gt;
&lt;td&gt;Make them match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playback froze&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&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;Rows appear to be skipped&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is large, or the file&amp;rsquo;s time column is not increasing&lt;/td&gt;
&lt;td&gt;Check both. Non-monotonic times are not validated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Some columns read 0&lt;/td&gt;
&lt;td&gt;The file has fewer than 50 columns&lt;/td&gt;
&lt;td&gt;Expected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Columns past the 50th are missing&lt;/td&gt;
&lt;td&gt;Only 50 are carried&lt;/td&gt;
&lt;td&gt;Split the profile across two players&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A &lt;code&gt;profileID&lt;/code&gt; change had no effect&lt;/td&gt;
&lt;td&gt;Expected: it is deferred until the current profile ends&lt;/td&gt;
&lt;td&gt;Stop the player first if you need it immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The player misbehaved after a reload&lt;/td&gt;
&lt;td&gt;Reloading while a profile is selected is not safe in this version&lt;/td&gt;
&lt;td&gt;Follow the callout in Tuning step 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A &lt;code&gt;command&lt;/code&gt; write disappeared&lt;/td&gt;
&lt;td&gt;Expected: the block clears it once acted on&lt;/td&gt;
&lt;td&gt;Read &lt;code&gt;state&lt;/code&gt; to confirm the command took&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;profileID       = 0
timeScaleFactor = 1.0
command         = 1     (play)
&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;Folder&lt;/td&gt;
&lt;td&gt;Fixed at build time&lt;/td&gt;
&lt;td&gt;Read once at startup. &lt;strong&gt;Not visible in the tree.&lt;/strong&gt; A missing folder is logged and leaves nothing loaded&lt;/td&gt;
&lt;td&gt;&lt;code&gt;numberOfProfiles&lt;/code&gt; reads 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File names&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Must be &lt;code&gt;&amp;lt;number&amp;gt;_&amp;lt;name&amp;gt;.csv&lt;/code&gt;. Others are logged and skipped&lt;/td&gt;
&lt;td&gt;Controller log only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate ids&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;The first file wins; the second is logged and skipped&lt;/td&gt;
&lt;td&gt;Controller log only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data columns&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;Extra columns are &lt;strong&gt;dropped silently&lt;/strong&gt;; missing ones read 0&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Row timestamps&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Must increase down the file. &lt;strong&gt;Not validated&lt;/strong&gt; — a backwards step makes rows be skipped&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blank lines&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each one adds an all-zero row&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interpolation&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None.&lt;/strong&gt; Each row is held until the next is due&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. 0 freezes; negative stalls; large skips rows&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Profile switch&lt;/td&gt;
&lt;td&gt;Deferred&lt;/td&gt;
&lt;td&gt;A new &lt;code&gt;profileID&lt;/code&gt; takes effect only when the current profile ends&lt;/td&gt;
&lt;td&gt;&lt;code&gt;activeProfileID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End of a non-looping profile&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;The output &lt;strong&gt;jumps back to row 0&lt;/strong&gt; one cycle after completion&lt;/td&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;, &lt;code&gt;fractionComplete&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Rewinds the output to row 0 and holds it there&lt;/td&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt; reads 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pause&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Holds the output where it is&lt;/td&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt; reads 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reload&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command&lt;/code&gt; 4&lt;/td&gt;
&lt;td&gt;Re-reads the folder on a background thread. &lt;strong&gt;Not safe while a profile is selected in this version&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt; reads 4 then 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loading time&lt;/td&gt;
&lt;td&gt;The files&lt;/td&gt;
&lt;td&gt;The player reports reloading and cannot play until parsing finishes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block logs every file it loads, skips or fails to parse, at startup and on
every reload. Nothing is logged during playback. Every other 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: Sequencer</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequencer/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequencer/</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;Sequencer&lt;/code&gt; steps through a table of values on a timer. Each output channel has
its own row of values and they all advance together, holding each column for
the time you give it. Use it for a pattern — a sequence of beeps on a speaker,
a blink pattern for an indicator light, a fixed series of setpoints.&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 — true runs the sequence&amp;quot;]) --&amp;gt; B[&amp;quot;Sequencer&amp;quot;]
    B --&amp;gt; o1([&amp;quot;output — one value per channel&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;While &lt;code&gt;input&lt;/code&gt; is true the block advances one element every &lt;code&gt;durations[e]&lt;/code&gt;
seconds and wraps at the end of the table. While it is false the outputs sit
at &lt;strong&gt;element 0&lt;/strong&gt; and the sequence is reset, so it always restarts from the
beginning.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Element 0 is the idle value, not the first step.&lt;/strong&gt; When the sequence starts
it goes straight to element 1. A five-element table plays 1, 2, 3, 4, 0, 1, 2 …
— element 0 is what you see at rest and once per loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Set the durations before you use it.&lt;/strong&gt; They default to zero, and a
zero-duration element advances every task cycle, so an unconfigured sequencer
flickers through its table at the task rate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable, no disable and no &lt;code&gt;isEnabled&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;input&lt;/code&gt; false is
the idle state.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;True runs the sequence; false parks every channel on element 0 and resets the timer. It is a &lt;strong&gt;level&lt;/strong&gt;, not a trigger — the sequence restarts from the beginning each time it goes true.&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;whatever you put in the table&lt;/td&gt;
&lt;td&gt;The active element&amp;rsquo;s value, one per channel. All channels step together.&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;durations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;all 0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How long each element is held, one per element, &lt;strong&gt;shared by every channel&lt;/strong&gt;. &lt;strong&gt;A zero or negative duration advances in one task cycle&lt;/strong&gt;, which is what the defaults do.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;channel_01&lt;/code&gt;, &lt;code&gt;channel_02&lt;/code&gt;, …&lt;/td&gt;
&lt;td&gt;table unit&lt;/td&gt;
&lt;td&gt;all 0&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;One row per output channel, one value per element. Element 0 is the idle value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ids&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;all −1&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;The IDs this sequencer answers to, used by &lt;a href=&#34;/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequence-selector/&#34;&gt;&lt;code&gt;SequenceSelector&lt;/code&gt;&lt;/a&gt; to choose between several. Ignored when the block is used on its own.&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;No parameters exist
below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The table&amp;rsquo;s shape — how many elements and how many channels — is fixed when the
machine is built. Read the length of &lt;code&gt;durations&lt;/code&gt; and of &lt;code&gt;output&lt;/code&gt; to discover
it.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read the length of &lt;code&gt;durations&lt;/code&gt; to find how many elements the table has, and
the length of &lt;code&gt;output&lt;/code&gt; for the channel count. Both are fixed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fill in &lt;code&gt;durations&lt;/code&gt; first.&lt;/strong&gt; Every element needs a positive time, or the
sequence will race through it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fill each &lt;code&gt;channel_NN&lt;/code&gt; row with the values that channel should take at each
element. &lt;strong&gt;Put the idle value in element 0&lt;/strong&gt; — that is what the channel
shows while the sequence is not running.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;input&lt;/code&gt; false and confirm every channel sits at its element 0 value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;input&lt;/code&gt; true and watch the outputs step. Time one full loop against the
sum of your durations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5 drives whatever is connected to the outputs.&lt;/strong&gt; If these values
command real motion rather than an indicator, check the whole table before
you start it — the sequence loops until the input goes false.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;input&lt;/code&gt; false and confirm every channel returns to its element 0 value
immediately.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;There is nothing to tune — the table is the configuration.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep every duration positive. A zero means &amp;ldquo;one task cycle&amp;rdquo;, which is almost
never what you want.&lt;/li&gt;
&lt;li&gt;Remember the sequence starts at element &lt;strong&gt;1&lt;/strong&gt;. If you want a specific value
at the moment it starts, put it there, not in element 0.&lt;/li&gt;
&lt;li&gt;Put the rest value in element 0. It is what shows at idle and it is also
part of the loop, so it acts as a gap at the end of each pass.&lt;/li&gt;
&lt;li&gt;All channels share one duration row, so they cannot step at different rates.
Use a second sequencer for a second rhythm.&lt;/li&gt;
&lt;li&gt;Nothing here needs re-checking after a task-rate change — the durations are
in seconds.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/sequencer-pattern-339f0d33.svg&#34; alt=&#34;One channel stepping through a five-element sequence while the input is truefrom 0.6 s to 2.0 s, with a second channel showing a different row of the sametable.&#34;&gt;&lt;/p&gt;
&lt;p&gt;Read each element&amp;rsquo;s dwell off the width of a step.&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 outputs flicker rapidly through the table&lt;/td&gt;
&lt;td&gt;The durations are zero — the default&lt;/td&gt;
&lt;td&gt;Set a positive duration for every element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The first value of the pattern never appears&lt;/td&gt;
&lt;td&gt;Expected: the sequence starts at element 1, and element 0 is the idle value&lt;/td&gt;
&lt;td&gt;Put the first step in element 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The outputs sit at one value and never move&lt;/td&gt;
&lt;td&gt;&lt;code&gt;input&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;The sequence restarts from the beginning every time&lt;/td&gt;
&lt;td&gt;Expected: &lt;code&gt;input&lt;/code&gt; is a level, and going false resets it&lt;/td&gt;
&lt;td&gt;This is the designed behaviour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One element is much shorter than configured&lt;/td&gt;
&lt;td&gt;Its duration is zero or negative&lt;/td&gt;
&lt;td&gt;Write a positive value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The channels do not step together&lt;/td&gt;
&lt;td&gt;Not possible — they share one timer and one element index&lt;/td&gt;
&lt;td&gt;Check what consumes the outputs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The channels need different rhythms&lt;/td&gt;
&lt;td&gt;Not possible — one duration row for all of them&lt;/td&gt;
&lt;td&gt;Use a second sequencer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The loop takes longer than the sum of the durations&lt;/td&gt;
&lt;td&gt;Expected: each element is held for its own listed time, and element 0 is part of the loop&lt;/td&gt;
&lt;td&gt;Include element 0&amp;rsquo;s duration in the total&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot tell which element is active&lt;/td&gt;
&lt;td&gt;The block does not publish it&lt;/td&gt;
&lt;td&gt;Infer it from the output values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The table is too short&lt;/td&gt;
&lt;td&gt;Its size is fixed when the machine is built&lt;/td&gt;
&lt;td&gt;It needs a configuration change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The sequencer never runs inside a selector&lt;/td&gt;
&lt;td&gt;Its &lt;code&gt;ids&lt;/code&gt; do not match the selector&amp;rsquo;s input&lt;/td&gt;
&lt;td&gt;Check the &lt;code&gt;ids&lt;/code&gt; array&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for a three-element blink pattern on one channel, half a
second per step:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;durations  = 0.5, 0.5, 0.5
channel_01 = 0.0, 1.0, 0.0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At rest the channel reads 0. Running, it plays 1.0, then 0.0, then 0.0, and
loops.&lt;/p&gt;
&lt;h2 id=&#34;limits-and-errors&#34;&gt;Limits and errors&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Set by&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Reported&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;durations&lt;/code&gt; above 0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not checked.&lt;/strong&gt; A zero or negative duration advances that element in one task cycle. All zeros — the default — makes the whole table free-run at the task rate&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active element&lt;/td&gt;
&lt;td&gt;Not published&lt;/td&gt;
&lt;td&gt;Which step is running cannot be read from the parameter tree&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table shape&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;The element count and channel count are fixed when the machine is built. Read the array lengths to discover them&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Whatever is in the table. Bound it downstream if the consumer needs a limit&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing&lt;/td&gt;
&lt;td&gt;Task rate independent&lt;/td&gt;
&lt;td&gt;Durations are in seconds and keep their meaning at any task period&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt; false&lt;/td&gt;
&lt;td&gt;Going idle resets the timer and the element. There is no separate reset&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: SequenceSelector</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequence-selector/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequence-selector/</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;SequenceSelector&lt;/code&gt; holds several &lt;a href=&#34;/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequencer/&#34;&gt;&lt;code&gt;Sequencer&lt;/code&gt;&lt;/a&gt; patterns and picks
between them by &lt;strong&gt;ID&lt;/strong&gt;. Give it a number and whichever sequencer lists that
number in its &lt;code&gt;ids&lt;/code&gt; drives the output. If none matches, a configured default is
emitted.&lt;/p&gt;
&lt;p&gt;Use it to map a machine state to an indicator pattern, or an error code to a
beep sequence.&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 ID to select&amp;quot;]) --&amp;gt; B[&amp;quot;SequenceSelector&amp;quot;]
    B --&amp;gt; o1([&amp;quot;output — the selected pattern&#39;s values&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;Every sequencer runs every cycle. The ones that do not match are held at
their element 0 and their timers reset — so &lt;strong&gt;a pattern always starts from
the beginning when it is selected&lt;/strong&gt;, never part-way through.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;If two sequencers list the same ID, the later one wins&lt;/strong&gt; and the earlier one
runs invisibly. Nothing warns about it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sequencer IDs default to −1&lt;/strong&gt;, so an unconfigured selector driven with −1
matches every sequencer at once. Give each one a real ID.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This block has no enable and no disable.&lt;/strong&gt; To emit the default, send an ID
that no sequencer lists.&lt;/p&gt;
&lt;h2 id=&#34;signals&#34;&gt;Signals&lt;/h2&gt;
&lt;h3 id=&#34;inputs&#34;&gt;Inputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;any integer&lt;/td&gt;
&lt;td&gt;The ID to select on. Every sequencer is asked whether this number is in its &lt;code&gt;ids&lt;/code&gt; list.&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;whatever the patterns contain&lt;/td&gt;
&lt;td&gt;The selected sequencer&amp;rsquo;s output, one value per channel — or &lt;code&gt;defaultOutput&lt;/code&gt; when nothing matches.&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;defaultOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pattern unit&lt;/td&gt;
&lt;td&gt;all 0&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;What every channel shows when no sequencer matches the input.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;defaultOutput&lt;/code&gt; is persistent and survives a controller restart.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The patterns live below this block&lt;/strong&gt;, in sub-trees named &lt;code&gt;Sequencer01&lt;/code&gt;,
&lt;code&gt;Sequencer02&lt;/code&gt; and so on — one per sequencer, numbered from 1. Each carries its
own &lt;code&gt;ids&lt;/code&gt;, &lt;code&gt;durations&lt;/code&gt; and &lt;code&gt;channel_NN&lt;/code&gt; rows. See
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequencer/&#34;&gt;&lt;code&gt;sequencer.md&lt;/code&gt;&lt;/a&gt; for how to fill one in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All sequencers share one shape&lt;/strong&gt;: the same number of elements, the same
number of channels and the same ID-list length, fixed when the machine is
built.&lt;/p&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read how many sequencers this instance has by looking for the &lt;code&gt;SequencerNN&lt;/code&gt;
sub-trees, and note they are numbered from 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Give every sequencer a distinct ID.&lt;/strong&gt; They default to −1, so an
unconfigured set all match the same input and only the last one shows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure each sequencer&amp;rsquo;s &lt;code&gt;durations&lt;/code&gt; and &lt;code&gt;channel_NN&lt;/code&gt; rows, per
&lt;a href=&#34;/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequencer/&#34;&gt;&lt;code&gt;sequencer.md&lt;/code&gt;&lt;/a&gt;. Remember each pattern starts at its element
&lt;strong&gt;1&lt;/strong&gt;, and element 0 is its rest value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;defaultOutput&lt;/code&gt; to what the machine should show when nothing is
selected — usually the same as the sequencers&#39; element 0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Send an ID that no sequencer lists and confirm every channel reads
&lt;code&gt;defaultOutput&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Send each configured ID in turn and confirm the right pattern runs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6 is the only check that the IDs are distinct.&lt;/strong&gt; If two sequencers
share an ID you will see the later one and never know the earlier one is
also running.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;tuning&#34;&gt;Tuning&lt;/h2&gt;
&lt;p&gt;There is nothing to tune. The work is assigning IDs and filling in the
patterns.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep the IDs distinct across sequencers. Nothing checks this and nothing
reports a clash.&lt;/li&gt;
&lt;li&gt;Choose an ID that means &amp;ldquo;nothing&amp;rdquo; and make sure no sequencer lists it. That
is how you get the default.&lt;/li&gt;
&lt;li&gt;A sequencer may list several IDs, so one pattern can serve several machine
states.&lt;/li&gt;
&lt;li&gt;Adding an unused sequencer costs the same processing time as a used one —
they all run every cycle. Size the instance to what you need.&lt;/li&gt;
&lt;li&gt;Nothing here depends on the task rate; the sequencers&#39; own durations are in
seconds.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/sequence-selector-switching-53bebc85.svg&#34; alt=&#34;The output as the selecting id changes. While no id matches, the output sitsat the default; each matching id hands the output to that sequencer&amp;rsquo;s pattern,which restarts from its first element every time it isselected.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The flat section is the default. Each pattern restarts from its first element
whenever its id is selected — see &lt;a href=&#34;/docs/developing-control-applications/control-blocks/setpoints-and-motion/sequencer/&#34;&gt;&lt;code&gt;sequencer.md&lt;/code&gt;&lt;/a&gt; for how a
single sequence steps.&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;Every ID produces the same pattern&lt;/td&gt;
&lt;td&gt;The sequencers&#39; &lt;code&gt;ids&lt;/code&gt; are all at their default of −1, so they all match&lt;/td&gt;
&lt;td&gt;Give each a distinct ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An ID produces the wrong pattern&lt;/td&gt;
&lt;td&gt;Two sequencers list it, and the later one wins&lt;/td&gt;
&lt;td&gt;Make the IDs distinct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A pattern seems to run but is not visible&lt;/td&gt;
&lt;td&gt;It matched, but a later sequencer matched too and overwrote it&lt;/td&gt;
&lt;td&gt;Check every &lt;code&gt;ids&lt;/code&gt; list for duplicates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output sits at the default for a valid ID&lt;/td&gt;
&lt;td&gt;No sequencer lists that ID&lt;/td&gt;
&lt;td&gt;Check the &lt;code&gt;ids&lt;/code&gt; arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A pattern starts part-way through&lt;/td&gt;
&lt;td&gt;Not possible — non-matching sequencers are reset, so a selected pattern always starts at the beginning&lt;/td&gt;
&lt;td&gt;Check what consumes the output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The pattern flickers rapidly&lt;/td&gt;
&lt;td&gt;That sequencer&amp;rsquo;s &lt;code&gt;durations&lt;/code&gt; are zero&lt;/td&gt;
&lt;td&gt;Set positive durations in its sub-tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The first value of a pattern never appears&lt;/td&gt;
&lt;td&gt;Expected: a sequence starts at its element 1&lt;/td&gt;
&lt;td&gt;Put the first step in element 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switching IDs restarts the new pattern from the beginning&lt;/td&gt;
&lt;td&gt;Expected, and deliberate&lt;/td&gt;
&lt;td&gt;This is the designed behaviour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot tell which sequencer is selected&lt;/td&gt;
&lt;td&gt;The block does not publish it&lt;/td&gt;
&lt;td&gt;Compare &lt;code&gt;input&lt;/code&gt; against each sub-tree&amp;rsquo;s &lt;code&gt;ids&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need more patterns&lt;/td&gt;
&lt;td&gt;The count is fixed when the machine is built&lt;/td&gt;
&lt;td&gt;It needs a configuration change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need a longer pattern than the others&lt;/td&gt;
&lt;td&gt;All sequencers share one shape&lt;/td&gt;
&lt;td&gt;It needs a configuration change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point for three patterns selected by machine state, with state 0
meaning idle:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;defaultOutput      = 0.0
Sequencer01/ids    = 1, -1, -1, ...
Sequencer02/ids    = 2, -1, -1, ...
Sequencer03/ids    = 3, -1, -1, ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sending 0 gives the default; 1, 2 and 3 give the three patterns. Note the
unused ID slots are left at −1, so &lt;strong&gt;do not send −1&lt;/strong&gt; as a selection.&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;ID uniqueness&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; If two sequencers list the same ID, the later one&amp;rsquo;s output wins and the earlier one runs unseen&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unconfigured IDs&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Sequencer IDs default to −1, so &lt;strong&gt;an ID of −1 matches every unconfigured sequencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selected sequencer&lt;/td&gt;
&lt;td&gt;Not published&lt;/td&gt;
&lt;td&gt;Which pattern is running cannot be read from the parameter tree&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No match&lt;/td&gt;
&lt;td&gt;&lt;code&gt;defaultOutput&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every channel takes the default. This is the only way to select &amp;ldquo;nothing&amp;rdquo;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sequencer shape&lt;/td&gt;
&lt;td&gt;Machine configuration&lt;/td&gt;
&lt;td&gt;Element count, channel count and ID-list length are the same for every sequencer and fixed when the machine is built&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Processing cost&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Every sequencer runs every cycle whether selected or not&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;Whatever the patterns contain. Bound it downstream if the consumer needs a limit&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block state&lt;/td&gt;
&lt;td&gt;None at this level&lt;/td&gt;
&lt;td&gt;Each sequencer resets itself as soon as it stops matching&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The block raises no errors or warnings and logs nothing. Every failure above
shows as a value on a trace, not as a message.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Verified against motorcortex-control3 3.30.0 (bc348fd).&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Fader</title>
      <link>/docs/developing-control-applications/control-blocks/setpoints-and-motion/fader/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/developing-control-applications/control-blocks/setpoints-and-motion/fader/</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;Fader&lt;/code&gt; moves its output smoothly to whatever value its input holds, over a
configured fade time, and publishes the matching velocity and acceleration as
it goes.&lt;/p&gt;
&lt;p&gt;Write a new number to &lt;code&gt;input&lt;/code&gt; and the output travels there. Write another
before it arrives and the fade &lt;strong&gt;blends into the new target&lt;/strong&gt; rather than
restarting — the output, its velocity and its acceleration all stay continuous.&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;Fader&amp;quot;]
    i2([&amp;quot;timeScaleFactor&amp;quot;]) --&amp;gt; B
    i3([&amp;quot;timeScaleFactorDot&amp;quot;]) --&amp;gt; B
    B --&amp;gt; o1([&amp;quot;output&amp;quot;])
    B --&amp;gt; o2([&amp;quot;outputDot&amp;quot;])
    B --&amp;gt; o3([&amp;quot;outputDDot&amp;quot;])
    B --&amp;gt; o4([&amp;quot;done&amp;quot;])
    B --&amp;gt; o5([&amp;quot;delaying&amp;quot;])
    B --&amp;gt; o6([&amp;quot;numTargets&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The fade time is what you set.&lt;/strong&gt; Unlike &lt;code&gt;SetpointGenerator&lt;/code&gt;, this block does
not work out how fast it may go — it takes exactly &lt;code&gt;fadeTime&lt;/code&gt; seconds
whatever the distance, so a large jump means a fast move. Size &lt;code&gt;fadeTime&lt;/code&gt;
from the largest jump you expect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Targets queue up.&lt;/strong&gt; Each change to &lt;code&gt;input&lt;/code&gt; adds one. When the queue is full
the &lt;strong&gt;oldest is dropped&lt;/strong&gt;, and the only sign is that &lt;code&gt;numTargets&lt;/code&gt; stops
growing. Watch it if your application writes targets quickly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Four of the parameters below may not exist on your instance.&lt;/strong&gt; &lt;code&gt;fadeTime&lt;/code&gt;,
&lt;code&gt;delayTime&lt;/code&gt;, &lt;code&gt;jerkFactor&lt;/code&gt; and &lt;code&gt;accelerationFactor&lt;/code&gt; are hidden when the block
that contains this fader controls them itself. If you cannot find them, they
are being set for you.&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 target. &lt;strong&gt;A change queues a new fade&lt;/strong&gt;; writing the same value again does nothing. Compared exactly, so an input that dithers in its last digit will queue a target every cycle and keep the queue full. Feed it settled values.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;Stretches the fade&amp;rsquo;s clock. 1 is normal, 0.5 is half speed, &lt;strong&gt;0 freezes the fade&lt;/strong&gt; exactly where it is and nothing is lost — it resumes when you set it back. A negative value is used as its magnitude; the fade does &lt;strong&gt;not&lt;/strong&gt; run backwards.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactorDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1/s&lt;/td&gt;
&lt;td&gt;any&lt;/td&gt;
&lt;td&gt;How fast &lt;code&gt;timeScaleFactor&lt;/code&gt; is itself changing. &lt;strong&gt;Set this whenever you ramp the scale factor&lt;/strong&gt;, or the published acceleration will be wrong.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;outputs&#34;&gt;Outputs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit&lt;/td&gt;
&lt;td&gt;The value on its way to the target.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second&lt;/td&gt;
&lt;td&gt;Its velocity — this really is the rate of change of &lt;code&gt;output&lt;/code&gt;, including across a retarget.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;signal unit per second²&lt;/td&gt;
&lt;td&gt;Its acceleration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;done&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The queue is empty and the output has arrived. &lt;strong&gt;Starts true.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delaying&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;The newest target is still waiting out its delay and has not started moving.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;How many targets are queued. &lt;strong&gt;If this stops growing while you keep writing, the oldest are being dropped.&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;faderType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 or 1&lt;/td&gt;
&lt;td&gt;Which profile shape. See the table below. &lt;strong&gt;Changing it while a fade is running switches that fade&amp;rsquo;s shape part-way&lt;/strong&gt;, which produces a kink — change it only when &lt;code&gt;done&lt;/code&gt; is true.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1 upward&lt;/td&gt;
&lt;td&gt;How many targets may be queued. Values below 1 are treated as 1. When the queue is full the oldest target is dropped and its position becomes the new starting point.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;applyTimeScaleToDelay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;true&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Whether &lt;code&gt;timeScaleFactor&lt;/code&gt; stretches &lt;code&gt;delayTime&lt;/code&gt; as well as the fade itself.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;above 0&lt;/td&gt;
&lt;td&gt;How long the fade takes, &lt;strong&gt;whatever the distance&lt;/strong&gt;. Negative values are used as their magnitude and written back. A fade shorter than one task period &lt;strong&gt;snaps&lt;/strong&gt; instead.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delayTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;s&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;0 upward&lt;/td&gt;
&lt;td&gt;How long to wait after a new target before moving. Negatives are used as their magnitude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.333&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 to 0.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only used by the jerk-limited shape. The fraction of the profile spent changing acceleration. Values outside the range are clamped and written back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;accelerationFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0.429&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 to 0.5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only used by the jerk-limited shape. The fraction spent accelerating. Also clamped and written back.&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;No parameters exist
below this block.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;faderType&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the machine does&lt;/th&gt;
&lt;th&gt;Parameters that matter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; quintic&lt;/td&gt;
&lt;td&gt;Position, velocity &lt;strong&gt;and&lt;/strong&gt; acceleration all start and end at zero. The smoothest shape, and the default&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; jerk-limited&lt;/td&gt;
&lt;td&gt;Reaches its acceleration and velocity plateaus and holds them, so more of the move happens at full speed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fadeTime&lt;/code&gt;, &lt;code&gt;jerkFactor&lt;/code&gt;, &lt;code&gt;accelerationFactor&lt;/code&gt;&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;Have your application seed the fader at the machine&amp;rsquo;s current value before
enabling anything downstream, so the first fade does not start from zero.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;fadeTime&lt;/code&gt; from the largest jump you expect and what the machine can
take at that distance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Leave &lt;code&gt;faderType&lt;/code&gt; at 0 for a first pass.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write a small change to &lt;code&gt;input&lt;/code&gt; and watch &lt;code&gt;output&lt;/code&gt; travel there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4 moves the machine&lt;/strong&gt;, over &lt;code&gt;fadeTime&lt;/code&gt; seconds regardless of how
far it has to go. Start with a small change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm &lt;code&gt;done&lt;/code&gt; goes false at the start and true on arrival.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write a second target while the first is still moving. &lt;code&gt;output&lt;/code&gt; should bend
towards the new value with no step in &lt;code&gt;outputDot&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check &lt;code&gt;numTargets&lt;/code&gt; grows and falls back to 0.&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;&lt;code&gt;fadeTime&lt;/code&gt; is the only number that matters for most uses. Set it from the
biggest jump: the peak velocity is roughly twice the distance divided by the
fade time for the quintic shape.&lt;/li&gt;
&lt;li&gt;If the fade is smooth but too slow for small jumps and too fast for large
ones, this block is the wrong one — &lt;code&gt;SetpointGenerator&lt;/code&gt; derives its duration
from velocity and acceleration limits instead.&lt;/li&gt;
&lt;li&gt;Switch to the jerk-limited shape if you need more of the move spent at full
speed. It reaches its plateaus and holds them, so it covers ground faster
for the same duration.&lt;/li&gt;
&lt;li&gt;With the jerk-limited shape, tune &lt;code&gt;jerkFactor&lt;/code&gt; and &lt;code&gt;accelerationFactor&lt;/code&gt;
together. Both are fractions of the profile and both cap at 0.5. The pairs
0.333 with 0.333, and 0.333 with 0.429, are the two standard settings.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;delayTime&lt;/code&gt; when several faders should start together after a common
trigger. Decide whether the delay should stretch with the time scale and set
&lt;code&gt;applyTimeScaleToDelay&lt;/code&gt; to match.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;timeScaleFactor&lt;/code&gt; for a speed override. &lt;strong&gt;Ramp it rather than stepping
it, and set &lt;code&gt;timeScaleFactorDot&lt;/code&gt; while you do&lt;/strong&gt;, or &lt;code&gt;outputDDot&lt;/code&gt; will be
wrong for as long as the ramp lasts.&lt;/li&gt;
&lt;li&gt;Raise &lt;code&gt;maxTargets&lt;/code&gt; if your application writes targets faster than the fades
complete, and watch &lt;code&gt;numTargets&lt;/code&gt; to see whether the queue is filling.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;/control3/img/fader-retarget-f8347f93.svg&#34; alt=&#34;A single fade compared with one that receives a second target part-way. Theretargeted output bends towards the new value instead of restarting, and itsvelocity stays smooth right through the change.&#34;&gt;&lt;/p&gt;
&lt;p&gt;The velocity trace has no step where the second target arrives. That
continuity is what this block is for.&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 large jump moved much faster than a small one&lt;/td&gt;
&lt;td&gt;Expected: every fade takes &lt;code&gt;fadeTime&lt;/code&gt; regardless of distance&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;SetpointGenerator&lt;/code&gt; if you need a velocity limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The move was instant&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fadeTime&lt;/code&gt; plus &lt;code&gt;delayTime&lt;/code&gt; is under one task period&lt;/td&gt;
&lt;td&gt;Lengthen &lt;code&gt;fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A kink appeared mid-fade&lt;/td&gt;
&lt;td&gt;&lt;code&gt;faderType&lt;/code&gt; was changed while a fade was running&lt;/td&gt;
&lt;td&gt;Change it only when &lt;code&gt;done&lt;/code&gt; is true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numTargets&lt;/code&gt; stopped growing while I kept writing&lt;/td&gt;
&lt;td&gt;The queue is full and the oldest targets are being dropped&lt;/td&gt;
&lt;td&gt;Raise &lt;code&gt;maxTargets&lt;/code&gt;, or write less often&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output jumped to an unexpected place&lt;/td&gt;
&lt;td&gt;An old target was dropped from a full queue, moving the starting point&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The output never settles&lt;/td&gt;
&lt;td&gt;&lt;code&gt;input&lt;/code&gt; is dithering, so a new target is queued every cycle&lt;/td&gt;
&lt;td&gt;Feed it settled values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything became invalid and stayed that way&lt;/td&gt;
&lt;td&gt;An input that is not a number queues a target every cycle&lt;/td&gt;
&lt;td&gt;Fix the upstream signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The fade froze part-way&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt; is 0&lt;/td&gt;
&lt;td&gt;Set it above 0. Nothing was lost — it resumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I set a negative &lt;code&gt;timeScaleFactor&lt;/code&gt; and it went forwards anyway&lt;/td&gt;
&lt;td&gt;Expected: the magnitude is used&lt;/td&gt;
&lt;td&gt;This block cannot run backwards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDDot&lt;/code&gt; was wrong while I changed the speed override&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactorDot&lt;/code&gt; was left at 0&lt;/td&gt;
&lt;td&gt;Set it while ramping &lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt; disagrees with &lt;code&gt;output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;It should not — this block carries derivatives correctly&lt;/td&gt;
&lt;td&gt;Check what is consuming them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The delay did not scale with the override&lt;/td&gt;
&lt;td&gt;&lt;code&gt;applyTimeScaleToDelay&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;fadeTime&lt;/code&gt; reads back positive after I wrote a negative&lt;/td&gt;
&lt;td&gt;Expected: the magnitude is used&lt;/td&gt;
&lt;td&gt;Write positive values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkFactor&lt;/code&gt; reads back as 0.5&lt;/td&gt;
&lt;td&gt;Expected: it is capped at 0.5&lt;/td&gt;
&lt;td&gt;Use a value in range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The first fade went to the wrong place&lt;/td&gt;
&lt;td&gt;The fader was not seeded at the machine&amp;rsquo;s value&lt;/td&gt;
&lt;td&gt;Seed it from your application before enabling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A fade resumed after a restart&lt;/td&gt;
&lt;td&gt;The queue is not cleared at startup&lt;/td&gt;
&lt;td&gt;Seed the fader after every start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I cannot find &lt;code&gt;fadeTime&lt;/code&gt; in the tree&lt;/td&gt;
&lt;td&gt;The block containing this fader controls it&lt;/td&gt;
&lt;td&gt;Set it there instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I need this on several channels&lt;/td&gt;
&lt;td&gt;Not possible — this block is single channel&lt;/td&gt;
&lt;td&gt;Use one instance per channel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A starting point:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fadeTime              = 1.0
delayTime             = 0.0
faderType             = 0
maxTargets            = 10
applyTimeScaleToDelay = 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;Fade duration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fadeTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exactly that long, &lt;strong&gt;whatever the distance&lt;/strong&gt;. Not derived from any velocity or acceleration limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;done&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output velocity&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not limited.&lt;/strong&gt; It is whatever the distance and fade time imply&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outputDot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub-cycle fades&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;fadeTime&lt;/code&gt; plus &lt;code&gt;delayTime&lt;/code&gt; under one scaled task period &lt;strong&gt;snaps&lt;/strong&gt; to the target&lt;/td&gt;
&lt;td&gt;&lt;code&gt;done&lt;/code&gt; stays true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fadeTime&lt;/code&gt;, &lt;code&gt;delayTime&lt;/code&gt; signs&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;Negatives are used as their magnitude and &lt;strong&gt;written back&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jerkFactor&lt;/code&gt;, &lt;code&gt;accelerationFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;Clamped to &lt;strong&gt;0 to 0.5&lt;/strong&gt; and written back&lt;/td&gt;
&lt;td&gt;Read the values back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxTargets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Checked&lt;/td&gt;
&lt;td&gt;Forced to at least 1. When the queue is full the &lt;strong&gt;oldest target is dropped&lt;/strong&gt; and its position becomes the new start&lt;/td&gt;
&lt;td&gt;&lt;code&gt;numTargets&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Partly checked&lt;/td&gt;
&lt;td&gt;Negatives are negated. &lt;strong&gt;0 freezes the fade with nothing lost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeScaleFactorDot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not checked. Leaving it at 0 while ramping the scale makes &lt;code&gt;outputDDot&lt;/code&gt; wrong&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;faderType&lt;/code&gt; mid-fade&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not guarded. An in-flight fade switches shape and keeps the old shape&amp;rsquo;s timing, producing a kink&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;Not checked. Such an input queues a new target &lt;strong&gt;every cycle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;numTargets&lt;/code&gt; sits at its maximum&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 queue is &lt;strong&gt;not&lt;/strong&gt; cleared, so a fade in flight resumes after a restart&lt;/td&gt;
&lt;td&gt;&lt;code&gt;done&lt;/code&gt;, &lt;code&gt;numTargets&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 channel per instance, always&lt;/td&gt;
&lt;td&gt;Not reported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;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>
    
  </channel>
</rss>
