DEV Community

Cover image for Filter a Chattering Proximity Sensor in Python Without Blocking the Control Loop
Orion Jiang
Orion Jiang

Posted on

Filter a Chattering Proximity Sensor in Python Without Blocking the Control Loop

A proximity sensor near its switching threshold may change state several times before settling.

The cause might be vibration, target movement, electrical interference or an incorrectly selected sensing distance. Software filtering cannot repair bad hardware, but it can prevent brief transitions from being treated as valid machine events.

Here is a non-blocking Python state filter that can run inside an existing control loop.

Why sleep() Is Usually the Wrong Filter

A simple approach might look like this:

if read_sensor():
time.sleep(0.05)

if read_sensor():
    handle_detection()
Enter fullscreen mode Exit fullscreen mode

It works in a tiny demonstration, but it pauses the entire loop.

During that pause, the program may delay:

Other input checks
Communication updates
Motion commands
Alarm handling
User-interface refreshes
Data logging

A timestamp-based filter lets the rest of the program continue running.

A Non-Blocking State Filter
from dataclasses import dataclass
from typing import Optional

@dataclass
class StableDigitalInput:
on_delay_s: float = 0.03
off_delay_s: float = 0.03
state: bool = False
candidate: bool = False
candidate_since: Optional[float] = None

def update(
    self,
    raw_state: bool,
    now_s: float,
) -> bool:
    # The input returned to the accepted state.
    if raw_state == self.state:
        self.candidate = raw_state
        self.candidate_since = None
        return self.state

    # A new possible state has appeared.
    if raw_state != self.candidate:
        self.candidate = raw_state
        self.candidate_since = now_s
        return self.state

    delay_s = (
        self.on_delay_s
        if raw_state
        else self.off_delay_s
    )

    # Accept the state only after it remains stable.
    if (
        self.candidate_since is not None
        and now_s - self.candidate_since >= delay_s
    ):
        self.state = raw_state
        self.candidate_since = None

    return self.state
Enter fullscreen mode Exit fullscreen mode

Using It in a Control Loop
import time

sensor_filter = StableDigitalInput(
on_delay_s=0.03,
off_delay_s=0.05,
)

previous_state = False

while True:
raw_state = read_sensor_input()

stable_state = sensor_filter.update(
    raw_state=raw_state,
    now_s=time.monotonic(),
)

if stable_state and not previous_state:
    print("Object detected")

if not stable_state and previous_state:
    print("Object cleared")

previous_state = stable_state

update_other_tasks()
Enter fullscreen mode Exit fullscreen mode

read_sensor_input() and update_other_tasks() are placeholders. They can be replaced with GPIO, PLC, fieldbus or simulation functions appropriate for the system.

time.monotonic() is used because it only moves forward and is not affected by changes to the computer’s clock.

Separate ON and OFF Delays

The example uses different qualification times:

ON delay: 30 ms
OFF delay: 50 ms

Separate values can be useful when detecting an object should happen quickly but confirming that it has left requires slightly more stability.

The correct delays depend on the machine. A fast counting application may need much shorter values, while a slowly moving fixture can tolerate longer filtering.

Filtering should never be longer than the process can safely accept.

Hardware Selection Still Matters

Before adjusting software, verify:

Target material
Required sensing distance
Inductive or capacitive sensing method
NPN or PNP output
Normally open or normally closed operation
Supply voltage
Response frequency
Shielded or unshielded installation
Nearby metal and sensor spacing
Cable routing and electrical noise

This proximity sensor selection provides examples of inductive, capacitive, cylindrical, rectangular, NPN and PNP configurations.

Industrial sensors must also be connected through an interface compatible with their voltage and output type. A 24 V sensor output should not be connected directly to a low-voltage GPIO input unless an appropriate interface, level conversion or isolation circuit is provided.

Do Not Hide a Mechanical Problem

If the filter requires hundreds of milliseconds to produce a stable result, investigate the application.

Possible causes include:

Target positioned at the edge of the sensing range
Loose sensor bracket
Excessive machine vibration
Incorrect sensor technology
Electrical interference
Unstable target geometry
Metal buildup on the sensing face

Software filtering is useful for rejecting brief disturbances. It should not be used to make an unsuitable installation appear reliable.

A good control system filters noise—and keeps enough evidence to notice when the noise is trying to tell you something.

Top comments (0)