mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-30 02:31:44 +00:00
[wpimath,cmd] Add multi tap boolean stream filter and multi tap trigger modifier (double tap detector) (#8307)
Add a simple tap counting filter for boolean streams.
The filter activates when the input has risen (transitioned from false
to true, like when a button is tapped) the required number of times
within the time window after the first rising edge. Once activated, the
output remains true as long as the input is true. The tap count resets
when the time window expires or when the input goes false after
activation.
Example usage:
```java
xbox.a()
.multiPress(2, 0.2) // Detect a double tap within 0.2 seconds
.onTrue(Commands.print("Double tapped A button"));
xbox.y()
.multiPress(2, 0.5) // Detect a double tap within 0.5 seconds
.whileTrue(Commands.print("Y held after tap").repeatedly());
```
This is not a noise reduction and/or input smoothing filter, but it is
similar in usage to debounce, so I believe it could be considered a
filter, but am open to a better location.
I believe this would be a useful addition, as double/triple tapping a
button is a common control option in games, yet is not often utilized by
newer FRC teams. I believe adding it to WPILib in a standard way will
allow more teams to make the most out of their controls.
This commit is contained in:
46
wpimath/src/main/native/cpp/filter/EdgeCountFilter.cpp
Normal file
46
wpimath/src/main/native/cpp/filter/EdgeCountFilter.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "frc/filter/EdgeCountFilter.h"
|
||||
|
||||
#include "wpimath/MathShared.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
EdgeCounterFilter::EdgeCounterFilter(int requiredEdges, units::second_t window)
|
||||
: m_requiredEdges(requiredEdges), m_windowTime(window) {
|
||||
ResetTimer();
|
||||
}
|
||||
|
||||
void EdgeCounterFilter::ResetTimer() {
|
||||
m_firstEdgeTime = wpi::math::MathSharedStore::GetTimestamp();
|
||||
}
|
||||
|
||||
bool EdgeCounterFilter::HasElapsed() const {
|
||||
return wpi::math::MathSharedStore::GetTimestamp() - m_firstEdgeTime >=
|
||||
m_windowTime;
|
||||
}
|
||||
|
||||
bool EdgeCounterFilter::Calculate(bool input) {
|
||||
bool enoughEdges = m_currentCount >= m_requiredEdges;
|
||||
|
||||
bool expired = HasElapsed() && !enoughEdges;
|
||||
bool activationEnded = !input && enoughEdges;
|
||||
|
||||
if (expired || activationEnded) {
|
||||
m_currentCount = 0;
|
||||
}
|
||||
|
||||
if (input && !m_lastInput) {
|
||||
if (m_currentCount == 0) {
|
||||
ResetTimer(); // Start timer on first rising edge
|
||||
}
|
||||
|
||||
m_currentCount++;
|
||||
}
|
||||
|
||||
m_lastInput = input;
|
||||
|
||||
return input && m_currentCount >= m_requiredEdges;
|
||||
}
|
||||
94
wpimath/src/main/native/include/frc/filter/EdgeCountFilter.h
Normal file
94
wpimath/src/main/native/include/frc/filter/EdgeCountFilter.h
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
|
||||
#include "units/time.h"
|
||||
|
||||
namespace frc {
|
||||
/**
|
||||
* A rising edge counter for boolean streams. Requires that the boolean change
|
||||
* value to true for a specified number of times within a specified time window
|
||||
* after the first rising edge before the filtered value changes.
|
||||
*
|
||||
* The filter activates when the input has risen (transitioned from false to
|
||||
* true) the required number of times within the time window. Once activated,
|
||||
* the output remains true as long as the input is true. The edge count resets
|
||||
* when the time window expires or when the input goes false after activation.
|
||||
*
|
||||
* Input must be stable; consider using a Debouncer before this filter to avoid
|
||||
* counting noise as multiple edges.
|
||||
*/
|
||||
class WPILIB_DLLEXPORT EdgeCounterFilter {
|
||||
public:
|
||||
/**
|
||||
* Creates a new EdgeCounterFilter.
|
||||
*
|
||||
* @param requiredEdges The number of rising edges required before the output
|
||||
* goes true.
|
||||
* @param windowTime The maximum time window in which all required edges must
|
||||
* occur after the first rising edge.
|
||||
*/
|
||||
explicit EdgeCounterFilter(int requiredEdges, units::second_t windowTime);
|
||||
|
||||
/**
|
||||
* Applies the edge counter filter to the input stream.
|
||||
*
|
||||
* @param input The current value of the input stream.
|
||||
* @return True if the required number of edges have occurred within the time
|
||||
* window and the input is currently true; false otherwise.
|
||||
*/
|
||||
bool Calculate(bool input);
|
||||
|
||||
/**
|
||||
* Sets the time window duration.
|
||||
*
|
||||
* @param windowTime The maximum time window in which all required edges must
|
||||
* occur after the first rising edge.
|
||||
*/
|
||||
constexpr void SetWindowTime(units::second_t windowTime) {
|
||||
m_windowTime = windowTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time window duration.
|
||||
*
|
||||
* @return The maximum time window in which all required edges must occur
|
||||
* after the first rising edge.
|
||||
*/
|
||||
constexpr units::second_t GetWindowTime() const { return m_windowTime; }
|
||||
|
||||
/**
|
||||
* Sets the required number of edges.
|
||||
*
|
||||
* @param requiredEdges The number of rising edges required before the output
|
||||
* goes true.
|
||||
*/
|
||||
constexpr void SetRequiredEdges(int requiredEdges) {
|
||||
m_requiredEdges = requiredEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the required number of edges.
|
||||
*
|
||||
* @return The number of rising edges required before the output goes true.
|
||||
*/
|
||||
constexpr int GetRequiredEdges() const { return m_requiredEdges; }
|
||||
|
||||
private:
|
||||
int m_requiredEdges;
|
||||
units::second_t m_windowTime;
|
||||
|
||||
units::second_t m_firstEdgeTime;
|
||||
int m_currentCount = 0;
|
||||
|
||||
bool m_lastInput = false;
|
||||
|
||||
void ResetTimer();
|
||||
|
||||
bool HasElapsed() const;
|
||||
};
|
||||
} // namespace frc
|
||||
Reference in New Issue
Block a user