Watchdog Timer — Robotics/Safety Supervision
Robotics/Safety_Supervision/Watchdog_Timer · 1 input / 2 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text
Description#
The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.
Watchdog Timer
Robotics / Safety Supervision
Reports a signal that has stopped moving. With frozen = ( |u[k] − u[k−1]| ≤ Freeze Tolerance ), the block counts consecutive frozen samples – count ← frozen ? min(count + 1, Stuck Samples) : 0 – and drives ok to 0 once that run reaches Stuck Samples.
A dead sensor rarely reports an impossible number: a frozen encoder, a CAN frame repeating its last payload and an unplugged input all hold a perfectly plausible value. Checking the LEVEL cannot see any of them, which is what this block adds to the Model Verification family.
Ports
- u – the monitored signal, a scalar [1,1]: a wheel speed, a joint angle, a pressure, a battery voltage. To watch several, use one block per signal – the run length is per signal and cannot be shared.
- ok – a scalar [1,1]: 1 while the signal is considered live, 0 once it has been frozen for Stuck Samples consecutive samples. Ready to drive an enable, a switch or an Assertion.
- count – a scalar [1,1]: how many consecutive samples the input has been frozen for, saturating at Stuck Samples. Useful as a health margin – it climbs before ok falls.
Parameters
- Freeze Tolerance – a scalar ≥ 0: how much movement between consecutive samples still counts as frozen. Size it above the signal's quantization step (an encoder's LSB, an ADC count) and below its smallest real motion; at exactly 0 only a bit-identical repeat counts, which a noisy analogue input will never produce.
- Stuck Samples – a whole number ≥ 1: how many consecutive frozen samples raise the alarm. It is a count, not a time – at a 10 ms rate 50 samples is half a second.
- Initial Input – a scalar: the value that stands in for u[−1], since the first sample has no predecessor. It decides only whether the run starts at 0 or 1.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. Every parameter is baked into the body at export time; there is no tunable parameter object.
The three HDL targets are genuine synthesizable Q16.16: one subtraction, one absolute value, two comparisons and an increment, with no division and nothing transcendental. The counter is carried as a fixed-point whole number and compared against one, so it never has to be converted out of fixed point.
Simulink bridge
None. Nothing in the installed libraries latches on signal
staleness: the Model Verification blocks assert on a value against
a bound, and Detect Change reports the single sample on which a signal
differs from its previous one rather than accumulating a run of samples on which
it did not. The watchdog blocks that do exist ship in toolboxes this machine does
not carry. The bridge entry therefore reports the block with that reason instead
of dropping it silently, and no parity testbench is owed – the
documented consequence of Support::None. Code export verification
still covers all ten languages.
Notes
- Stateful and inherently discrete
(
setDiscreteOnlyBlock(true)): "the previous sample" only means anything per sample, and there is no derivative to integrate. - It does not latch. ok returns to 1 on the first sample that moves, because a watchdog reports current health. To hold a fault until an operator clears it, feed ok into Emergency Stop Ramp, whose latch is exactly that; for a hard stop, feed it into Assertion.
- The counter saturates at Stuck Samples rather than running free – nothing downstream needs a larger number, and an unbounded counter would leave the fixed-point range on the HDL targets after a few minutes of a genuinely dead signal.
- Nonlinear, and deliberately carries no state space. The comparison and the counter are not describable by A/B/C/D, so model reduction correctly refuses the block.
- On the HDL targets the comparison is made in Q16.16, so a sample whose movement sits within one quantum (about 1.5e−5) of Freeze Tolerance can be classified the other way from the software targets. The consequence is a run length off by one, which can move ok by a sample – a decision output, not a rounding error, exactly as in Argmax Decision. Choose a tolerance the signal's own steps do not sit on top of.
- Choosing the pair is the whole design. A tolerance below the signal's own noise floor never fires; one above its slowest real motion fires on a healthy signal held briefly at a limit. Read count on a healthy run before choosing either.
Code facts#
| Fact | Value |
|---|---|
| registered type | Robotics/Safety_Supervision/Watchdog_Timer |
| family | Robotics/Safety_Supervision |
| solver environment class | ICoreBlock_0_Robotics_1_Safety_Supervision_2_Watchdog_Timer |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Robotics/Safety_Supervision/Watchdog_Timer/ICoreBlock_0_Robotics_1_Safety_Supervision_2_Watchdog_Timer.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Robotics/Safety_Supervision/Watchdog_Timer/ICoreBlock_0_Robotics_1_Safety_Supervision_2_Watchdog_Timer.h |
| default size on canvas | 132 × 80 px |
| ports at insert | 1 in, 2 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | u |
| 2 | out | ICoreDouble | ok |
| 3 | out | ICoreDouble | count |
Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.
Configuration variables#
| Config variable | Default | Simulink parameter |
|---|---|---|
Freeze Tolerance | 1e-6 | — |
Stuck Samples | 10 | — |
Initial Input | 0 | — |
Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): no Simulink equivalent available: nothing in the installed libraries latches on signal STALENESS. The Model Verification blocks assert on a value against a bound, and Detect Change reports the one sample on which a signal differs from its previous value rather than counting a run of samples on which it did not; the watchdog blocks that do exist belong to toolboxes not installed on this machine. Rebuild it on the Simulink side from a Unit Delay, an Abs, a Compare To Constant and a counter, keeping the saturating count this block documents
Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.
The verdict above is
tools/docs/check_block_descriptions.py(P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.
File banner (developer view)#
The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).
Watchdog Timer — is this sensor still alive? It watches how far the input MOVES, not what it is worth:
frozen = ( |u[k] - u[k-1]| <= Freeze Tolerance ) count = frozen ? min(count + 1, Stuck Samples) : 0 ok = ( count >= Stuck Samples ) ? 0 : 1
A frozen encoder, a repeated CAN frame and an unplugged ADC all hold a PLAUSIBLE value, so no amount of range checking sees them. That is the gap this block fills, and it is why the Model Verification family (which asserts on levels) is not this block.
Three properties, each load-bearing:
- NO DIVISION, NO TRANSCENDENTAL, AND NO CONVERSION OUT OF FIXED POINT. One subtraction, one
absolute value, two comparisons and an increment -- so the three HDL targets are genuine synthesizable Q16.16. The counter is held as a fixed-point WHOLE NUMBER and compared against one, so §4's fx_to_int is not needed here at all.
- THE COUNTER SATURATES at Stuck Samples. Nothing downstream needs "frozen for 40,000
samples" rather than "frozen for 40", and a free-running counter leaves Q16.16's range in about five minutes at 10 ms -- passing on the bench and wrapping NEGATIVE in the field.
- THE PREVIOUS-SAMPLE SEED IS A CONFIG. There is no sample before the first one, so
something has to stand in for it, and only a config is visible to the user.
⚠ It does NOT latch:
okrecovers on the first sample that moves. Latching until an operator clears the fault belongs to Emergency_Stop_Ramp, and duplicating it here would put the same behaviour in two blocks that a diagram is likely to hold at once.
Sample results#
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 0 … 1 |
ramp | Ramp: slope 1 from t = 0 | 1 … 1 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 1 … 1 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | 1 … 1 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Robotics__Safety_Supervision__Watchdog_Timer.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).