mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-04 03:11:43 +00:00
Add Debouncer (#3590)
Supersedes #2358 with updates and cleanups. Closes #2482 and closes #2487 because we shouldn't support both time-based and count-based debouncing approaches. Co-authored-by: oblarg <emichaelbarnett@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ package edu.wpi.first.wpilibj2.command.button;
|
||||
|
||||
import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.wpilibj.Debouncer;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.CommandScheduler;
|
||||
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
||||
@@ -359,4 +360,23 @@ public class Trigger {
|
||||
public Trigger negate() {
|
||||
return new Trigger(() -> !get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new debounced trigger from this trigger - it will become active when this trigger has
|
||||
* been active for longer than the specified period.
|
||||
*
|
||||
* @param seconds the debounce period
|
||||
* @return the debounced trigger
|
||||
*/
|
||||
public Trigger debounce(double seconds) {
|
||||
return new Trigger(
|
||||
new BooleanSupplier() {
|
||||
Debouncer m_debouncer = new Debouncer(seconds);
|
||||
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
return m_debouncer.calculate(get());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "frc2/command/button/Trigger.h"
|
||||
|
||||
#include <frc/Debouncer.h>
|
||||
|
||||
#include "frc2/command/InstantCommand.h"
|
||||
|
||||
using namespace frc2;
|
||||
@@ -136,3 +138,9 @@ Trigger Trigger::CancelWhenActive(Command* command) {
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::Debounce(units::second_t debounceTime) {
|
||||
return Trigger([debouncer = frc::Debouncer(debounceTime), *this]() mutable {
|
||||
return debouncer.Calculate(m_isActive());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <units/time.h>
|
||||
#include <wpi/span.h>
|
||||
|
||||
#include "frc2/command/Command.h"
|
||||
@@ -345,6 +346,15 @@ class Trigger {
|
||||
return Trigger([*this] { return !m_isActive(); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new debounced trigger from this trigger - it will become active
|
||||
* when this trigger has been active for longer than the specified period.
|
||||
*
|
||||
* @param debounceTime the debounce period
|
||||
* @return the debounced trigger
|
||||
*/
|
||||
Trigger Debounce(units::second_t debounceTime);
|
||||
|
||||
private:
|
||||
std::function<bool()> m_isActive;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import edu.wpi.first.wpilibj.simulation.SimHooks;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.CommandScheduler;
|
||||
import edu.wpi.first.wpilibj2.command.CommandTestBase;
|
||||
@@ -172,4 +173,26 @@ class ButtonTest extends CommandTestBase {
|
||||
assertFalse(button1.negate().get());
|
||||
assertTrue(button1.and(button2.negate()).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void debounceTest() {
|
||||
CommandScheduler scheduler = CommandScheduler.getInstance();
|
||||
MockCommandHolder commandHolder = new MockCommandHolder(true);
|
||||
Command command = commandHolder.getMock();
|
||||
|
||||
InternalButton button = new InternalButton();
|
||||
Trigger debounced = button.debounce(0.1);
|
||||
|
||||
debounced.whenActive(command);
|
||||
|
||||
button.setPressed(true);
|
||||
scheduler.run();
|
||||
verify(command, never()).schedule(true);
|
||||
|
||||
SimHooks.stepTiming(0.3);
|
||||
|
||||
button.setPressed(true);
|
||||
scheduler.run();
|
||||
verify(command).schedule(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
// 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 "CommandTestBase.h"
|
||||
#include <frc/simulation/SimHooks.h>
|
||||
|
||||
#include "../CommandTestBase.h"
|
||||
#include "frc2/command/CommandScheduler.h"
|
||||
#include "frc2/command/RunCommand.h"
|
||||
#include "frc2/command/WaitUntilCommand.h"
|
||||
@@ -190,3 +192,19 @@ TEST_F(ButtonTest, RValueButton) {
|
||||
scheduler.Run();
|
||||
EXPECT_EQ(counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(ButtonTest, DebounceTest) {
|
||||
auto& scheduler = CommandScheduler::GetInstance();
|
||||
bool pressed = false;
|
||||
RunCommand command([] {});
|
||||
|
||||
Trigger([&pressed] { return pressed; }).Debounce(100_ms).WhenActive(&command);
|
||||
pressed = true;
|
||||
scheduler.Run();
|
||||
EXPECT_FALSE(scheduler.IsScheduled(&command));
|
||||
|
||||
frc::sim::StepTiming(300_ms);
|
||||
|
||||
scheduler.Run();
|
||||
EXPECT_TRUE(scheduler.IsScheduled(&command));
|
||||
}
|
||||
Reference in New Issue
Block a user