Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debounce has issues and can be more accurate and precise #38

Open
chran554 opened this issue Nov 20, 2023 · 1 comment
Open

Debounce has issues and can be more accurate and precise #38

chran554 opened this issue Nov 20, 2023 · 1 comment

Comments

@chran554
Copy link

Problem
There are issues with the current implementation of debounce. All of them are not severe but the implementation can be more accurate and precise.

Current implementation of debounce use sleep
Current implementation of debounce use two parameters (both denoise and debounce)
Current implementation do not wait for bounce to subside but merely wait yet another duration (denoise) after first edge and hope bouncing is all done.
Attribute debounce is never used.
Parameter "edge" in constructor is never used.

What kind of new feature are you looking for?
(Keep the one that applies, please describe)

  • Software: new implementation of debounce for WaitForEdge and possibly Read (might be up for diskussion of wanted behaviour)
    New implementation will consider signal stable when no signal change occur during a whole debounce period. Otherwise it will keep debouncing/filter noise until signal is stable for a whole debounce period.
    New implementation will solely rely on underlying WaitForEdge no sleep.
    New implementation will only use one attribute "debounce" (which actually resembles more the former "denoise")
    New implementation of WaitForEdge will be less prone to block longer than stated timeout.

Do you plan to:

  • Contribute an initial package: No
  • Contribute with a merge request
  • Write unit tests: Yes (update existing tests to new code)
  • Update documentation: Yes (if I can find it)
@chran554
Copy link
Author

chran554 commented Nov 24, 2023

Implementation suggestion for debounced WaitForEdge and Read (work in progress, not final!).

// debounced is a gpio.PinIO where reading and edge detection pass through a
// debouncing algorithm.
type debounced struct {
	// Immutable.
	gpio.PinIO
	// debounce is the time to wait for a changing signal to stabilize
	// if say a button introduces signal chatter.
	debounce time.Duration

	// Mutable.
	clock clockwork.Clock
}
// WaitForEdge implements gpio.PinIO.
//
// Waits for the edge of a changed (stable) signal.
// Any intermittent signal chatter from bounce is filtered even though the stable signal does not change.
// A signal is considered stable when there is no new signal change (edge) for a debounce amount of time.
func (d *debounced) WaitForEdge(timeout time.Duration) bool {
	start := d.clock.Now()

	// Cannot decide if signal change is stable if timeout is less than debounce time.
	if (timeout != -1) && (timeout < d.debounce) {
		return false
	}

	initialLevel := d.PinIO.Read()

	for timeLeft := max(0, timeout-d.clock.Since(start)); (timeout == -1) || (timeLeft >= d.debounce); timeLeft = max(0, timeout-d.clock.Since(start)) {
		if timeout == -1 {
			timeLeft = -1
		}

		// Wait for initial change of signal (edge)
		if !d.PinIO.WaitForEdge(timeLeft) {
			return false
		}

		// Wait for signal (edge) bounce to subside.
		// Bounce/edge chatter is considered filtered and the signal stable
		// when debounce delay has surpassed without any further signal change (edges).
		//
		// Debounce wait can be applied several consecutive times (until timeout kicks in)
		// as long as new signal changes occur during the debounce period.
		for (timeout == -1) || ((timeout - d.clock.Since(start)) >= d.debounce) {
			if !d.PinIO.WaitForEdge(d.debounce) {
				// Stable signal is achieved
				currentLevel := d.PinIO.Read()
				if currentLevel != initialLevel {
					// An edge is only detected in the stable signal (after bounce filtering)
					// if the signal is changed from its initial level.
					return true
				} else {
					// Stable signal does not differ from the initial level
					break // Break debounce loop and continue another round and wait for a new initial signal change
				}
			}
		}
	}

	return false
}
// Read implements gpio.PinIO.
//
// Reads the value of stable signal.
// Note that this read always takes at least debounce amount of time.
//
// A signal is considered stable when there is no new signal edge for a debounce amount of time.
func (d *debounced) Read() gpio.Level {
	for d.PinIO.WaitForEdge(d.debounce) {
		// Nothing by intention
	}
	return d.PinIO.Read()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant