2021-01-01 16:22:00 -08:00
|
|
|
// 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
|
|
|
|
|
|
2022-10-15 16:33:14 -07:00
|
|
|
#include <numbers>
|
2023-06-07 09:50:09 -07:00
|
|
|
#include <type_traits>
|
2022-10-15 16:33:14 -07:00
|
|
|
|
2021-08-20 09:02:01 -07:00
|
|
|
#include <wpi/SymbolExports.h>
|
2021-01-01 16:22:00 -08:00
|
|
|
|
|
|
|
|
#include "units/angle.h"
|
2022-04-30 23:29:48 -04:00
|
|
|
#include "units/base.h"
|
|
|
|
|
#include "units/math.h"
|
2021-01-01 16:22:00 -08:00
|
|
|
|
|
|
|
|
namespace frc {
|
|
|
|
|
|
2021-08-28 20:52:05 -07:00
|
|
|
/**
|
2022-04-30 23:29:48 -04:00
|
|
|
* Returns 0.0 if the given value is within the specified range around zero. The
|
|
|
|
|
* remaining range between the deadband and the maximum magnitude is scaled from
|
|
|
|
|
* 0.0 to the maximum magnitude.
|
2021-08-28 20:52:05 -07:00
|
|
|
*
|
2022-04-30 23:29:48 -04:00
|
|
|
* @param value Value to clip.
|
2021-08-28 20:52:05 -07:00
|
|
|
* @param deadband Range around zero.
|
2022-04-30 23:29:48 -04:00
|
|
|
* @param maxMagnitude The maximum magnitude of the input (defaults to 1). Can
|
|
|
|
|
* be infinite.
|
|
|
|
|
* @return The value after the deadband is applied.
|
2021-08-28 20:52:05 -07:00
|
|
|
*/
|
2023-06-07 09:50:09 -07:00
|
|
|
template <typename T>
|
|
|
|
|
requires std::is_arithmetic_v<T> || units::traits::is_unit_t_v<T>
|
2022-04-30 23:29:48 -04:00
|
|
|
T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
|
|
|
|
|
T magnitude;
|
2023-06-07 09:50:09 -07:00
|
|
|
if constexpr (std::is_arithmetic_v<T>) {
|
2022-04-30 23:29:48 -04:00
|
|
|
magnitude = std::abs(value);
|
|
|
|
|
} else {
|
|
|
|
|
magnitude = units::math::abs(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (magnitude > deadband) {
|
|
|
|
|
if (maxMagnitude / deadband > 1.0E12) {
|
|
|
|
|
// If max magnitude is sufficiently large, the implementation encounters
|
|
|
|
|
// roundoff error. Implementing the limiting behavior directly avoids
|
|
|
|
|
// the problem.
|
|
|
|
|
return value > T{0.0} ? value - deadband : value + deadband;
|
|
|
|
|
}
|
|
|
|
|
if (value > T{0.0}) {
|
|
|
|
|
// Map deadband to 0 and map max to max.
|
|
|
|
|
//
|
|
|
|
|
// y - y₁ = m(x - x₁)
|
|
|
|
|
// y - y₁ = (y₂ - y₁)/(x₂ - x₁) (x - x₁)
|
|
|
|
|
// y = (y₂ - y₁)/(x₂ - x₁) (x - x₁) + y₁
|
|
|
|
|
//
|
|
|
|
|
// (x₁, y₁) = (deadband, 0) and (x₂, y₂) = (max, max).
|
|
|
|
|
// x₁ = deadband
|
|
|
|
|
// y₁ = 0
|
|
|
|
|
// x₂ = max
|
|
|
|
|
// y₂ = max
|
|
|
|
|
//
|
|
|
|
|
// y = (max - 0)/(max - deadband) (x - deadband) + 0
|
|
|
|
|
// y = max/(max - deadband) (x - deadband)
|
|
|
|
|
// y = max (x - deadband)/(max - deadband)
|
|
|
|
|
return maxMagnitude * (value - deadband) / (maxMagnitude - deadband);
|
|
|
|
|
} else {
|
|
|
|
|
// Map -deadband to 0 and map -max to -max.
|
|
|
|
|
//
|
|
|
|
|
// y - y₁ = m(x - x₁)
|
|
|
|
|
// y - y₁ = (y₂ - y₁)/(x₂ - x₁) (x - x₁)
|
|
|
|
|
// y = (y₂ - y₁)/(x₂ - x₁) (x - x₁) + y₁
|
|
|
|
|
//
|
|
|
|
|
// (x₁, y₁) = (-deadband, 0) and (x₂, y₂) = (-max, -max).
|
|
|
|
|
// x₁ = -deadband
|
|
|
|
|
// y₁ = 0
|
|
|
|
|
// x₂ = -max
|
|
|
|
|
// y₂ = -max
|
|
|
|
|
//
|
|
|
|
|
// y = (-max - 0)/(-max + deadband) (x + deadband) + 0
|
|
|
|
|
// y = max/(max - deadband) (x + deadband)
|
|
|
|
|
// y = max (x + deadband)/(max - deadband)
|
|
|
|
|
return maxMagnitude * (value + deadband) / (maxMagnitude - deadband);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return T{0.0};
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-28 20:52:05 -07:00
|
|
|
|
2021-01-01 16:22:00 -08:00
|
|
|
/**
|
|
|
|
|
* Returns modulus of input.
|
|
|
|
|
*
|
|
|
|
|
* @param input Input value to wrap.
|
|
|
|
|
* @param minimumInput The minimum value expected from the input.
|
|
|
|
|
* @param maximumInput The maximum value expected from the input.
|
|
|
|
|
*/
|
|
|
|
|
template <typename T>
|
|
|
|
|
constexpr T InputModulus(T input, T minimumInput, T maximumInput) {
|
|
|
|
|
T modulus = maximumInput - minimumInput;
|
|
|
|
|
|
|
|
|
|
// Wrap input if it's above the maximum input
|
|
|
|
|
int numMax = (input - minimumInput) / modulus;
|
|
|
|
|
input -= numMax * modulus;
|
|
|
|
|
|
|
|
|
|
// Wrap input if it's below the minimum input
|
|
|
|
|
int numMin = (input - maximumInput) / modulus;
|
|
|
|
|
input -= numMin * modulus;
|
|
|
|
|
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wraps an angle to the range -pi to pi radians (-180 to 180 degrees).
|
|
|
|
|
*
|
|
|
|
|
* @param angle Angle to wrap.
|
|
|
|
|
*/
|
2021-08-20 09:02:01 -07:00
|
|
|
WPILIB_DLLEXPORT
|
2021-01-01 16:22:00 -08:00
|
|
|
constexpr units::radian_t AngleModulus(units::radian_t angle) {
|
2021-05-26 00:09:36 -07:00
|
|
|
return InputModulus<units::radian_t>(angle,
|
2022-10-15 16:33:14 -07:00
|
|
|
units::radian_t{-std::numbers::pi},
|
|
|
|
|
units::radian_t{std::numbers::pi});
|
2021-01-01 16:22:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace frc
|