Unit 10 · lesson

Detection, Diagnosis, and Recovery Are Three Different Jobs

A robot component can detect a problem correctly and still recover badly. It can also recover successfully without proving that anyone understands the root cause.

Those distinctions matter because failure reports often collapse several events into one sentence:

The sensor failed, the software caught it, and the robot recovered.

That sentence sounds complete. It may hide three separate questions.

  1. What evidence showed something was wrong?
  2. What evidence identified why it happened?
  3. What action changed the system afterward?

This lesson keeps those jobs separate.

Detection: a rule was violated

Start with the validated range component.

The declared interval is:

0.10..2.00 m

The incoming value is:

3.70 m

The component rejects the update and throws:

IllegalArgumentException

That is detection.

The software has enough evidence to say:

The supplied value 3.70 m violated the component's declared range rule.

It does not yet know why the value appeared.

Diagnosis: determine the cause or narrow the possibilities

Possible causes include:

  • the source generated a real but out-of-model value;
  • the configured maximum is wrong;
  • centimeters were interpreted as meters;
  • stale or corrupted input reached the component;
  • the wrong sensor channel was read;
  • a test intentionally injected a bad value.

The exception alone cannot choose among those possibilities.

Diagnosis requires additional evidence.

Useful evidence might include:

  • raw input history;
  • previous accepted values;
  • timestamps;
  • configuration values;
  • source identity;
  • conversion code;
  • other sensor readings;
  • a test or replay that reproduces the condition.

A diagnosis becomes stronger when it rules out competing explanations.

Recovery: decide what to do next

After the invalid input is detected, the program needs a policy.

Possible policies include:

  • keep the last valid reading and mark it stale;
  • request another sample;
  • stop accepting motion decisions from that source;
  • switch to another source;
  • stop a mechanism;
  • stop the entire robot;
  • continue while recording the anomaly.

None of those is universally correct.

The correct recovery depends on the system requirement and the risk of acting on bad information.

A lab example may choose a safe, bounded policy for teaching. Do not treat that example as a universal robotics rule.

Why "caught exception" is not a recovery result

This code catches the exception:

try {
  sensor.updateRange(3.70);
} catch (IllegalArgumentException error) {
  DataLogManager.log(
      "range update rejected id="
      + sensor.getId()
  );
}

The program did not crash at this point.

That tells you the exception was handled by the catch block.

It does not tell you whether later code used a stale reading, whether motion was inhibited, or whether another sample succeeded.

The phrase:

exception handled

is narrower than:

system recovered.

Make recovery state visible

If the design decides that a rejected update should mark the source unhealthy, model that state explicitly.

class ValidatedRangeSensor {
  private boolean healthy = true;

  void updateRange(double newRangeMeters) {
    if (newRangeMeters < minRangeMeters
        || newRangeMeters > maxRangeMeters) {
      healthy = false;

      throw new IllegalArgumentException(
          "range outside declared interval"
      );
    }

    rangeMeters = newRangeMeters;
    healthy = true;
  }

  boolean isHealthy() {
    return healthy;
  }
}

Now the application can inspect a defined state instead of guessing from whether an exception occurred earlier.

This is only one possible design. The important lesson is that recovery policy should leave inspectable state or evidence.

Do not silently convert detection into diagnosis

Suppose the log says:

range update rejected id=range-front value=3.70 m

A weak incident report says:

The front sensor malfunctioned.

That conclusion goes beyond the evidence.

A stronger report says:

The front range component rejected an input of 3.70 m because it exceeded its configured 2.00 m maximum. The source of the invalid input has not yet been determined.

The second report distinguishes observation from diagnosis.

Build a timeline before choosing a cause

Suppose the log contains these records:

TimeEvent
12.100 sraw range 0.42 m
12.120 saccepted range 0.42 m
12.140 sraw range 3.70 m
12.141 srejection event logged
12.160 sraw range 0.41 m
12.161 saccepted range 0.41 m

This chronology supports several useful facts.

The invalid value was isolated between valid values.

The component later accepted another value.

The evidence does not prove the source hardware briefly failed. A test injector or conversion error could produce the same pattern.

The timeline narrows the investigation. It does not finish it.

Compare a persistent failure

Now consider:

TimeEvent
12.100 sraw range 3.70 m
12.101 srejected
12.120 sraw range 3.70 m
12.121 srejected
12.140 sraw range 3.70 m
12.141 srejected

This pattern is different.

Repeated identical invalid values may suggest a persistent source or configuration problem. That is a clue, not a final diagnosis.

A next step might be to inspect the raw source, unit conversion, or configuration.

The logs help choose the next question.

Recovery can create new failures

Imagine this recovery code:

catch (IllegalArgumentException error) {
  sensor.updateRange(0.0);
}

The program replaces the rejected reading with zero.

That may trigger a stop decision:

0.0 < 0.50

The recovery action has created a new state with a different meaning.

If zero is not a documented fallback value, the code may have turned one invalid measurement into a false obstacle condition.

Recovery code deserves the same testing discipline as normal behavior.

A fallback should be explicit

If the system requirement says:

When the range source becomes invalid, the guard must enter an unavailable state and prohibit automatic movement.

then model that requirement directly.

For example, the guard could require a healthy source before returning a movement decision.

The exact implementation is less important here than the principle: failure policy should be represented in the code rather than hidden in an arbitrary number.

Use logs to prove the recovery action occurred

Suppose the policy marks the source unhealthy.

A useful event could record:

range source unhealthy id=range-front reason=out-of-range input

If a later valid update restores it:

range source healthy id=range-front value=0.41 m

Now the log supports a software-state transition.

It still does not prove the physical sensor repaired itself.

The evidence says the application changed its modeled health state based on the inputs it received.

Worked incident review

Evidence:

12.140 raw input       range-front 3.70 m
12.141 validation      rejected above 2.00 m maximum
12.141 health state    unhealthy
12.160 raw input       range-front 0.41 m
12.161 validation      accepted
12.161 health state    healthy

A defensible summary is:

The software rejected one out-of-range input, marked the modeled source unhealthy, then accepted a later 0.41 m input and returned the modeled health state to healthy.

An overclaim is:

The sensor broke and repaired itself in 21 milliseconds.

Nothing in the software record proves that physical story.

Your diagnosis challenge

You receive this event sequence:

batteryPercent raw=140.0
BatteryMonitor rejected value above 100.0
battery state remains 76.0
warning decision=false

Write three separate statements:

Detection

State exactly what rule was violated.

Diagnosis status

List at least two plausible causes that remain open.

Recovery status

State what the software did after rejection and one question you still need answered before calling the system recovered.

In the next lesson, you will compare how WPILib and ROS 2 record runtime information. Both produce logs, but their APIs, formats, and runtime contexts are different.