[wpimath] Move controller from wpilibj to wpimath (#3439)

This commit is contained in:
Noam Zaks
2021-06-16 17:45:51 +03:00
committed by GitHub
parent 9ce9188ff6
commit 791770cf6e
64 changed files with 106 additions and 91 deletions

View File

@@ -0,0 +1,78 @@
// 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/controller/HolonomicDriveController.h"
#include <utility>
#include "units/angular_velocity.h"
using namespace frc;
HolonomicDriveController::HolonomicDriveController(
frc2::PIDController xController, frc2::PIDController yController,
ProfiledPIDController<units::radian> thetaController)
: m_xController(std::move(xController)),
m_yController(std::move(yController)),
m_thetaController(std::move(thetaController)) {}
bool HolonomicDriveController::AtReference() const {
const auto& eTranslate = m_poseError.Translation();
const auto& eRotate = m_rotationError;
const auto& tolTranslate = m_poseTolerance.Translation();
const auto& tolRotate = m_poseTolerance.Rotation();
return units::math::abs(eTranslate.X()) < tolTranslate.X() &&
units::math::abs(eTranslate.Y()) < tolTranslate.Y() &&
units::math::abs(eRotate.Radians()) < tolRotate.Radians();
}
void HolonomicDriveController::SetTolerance(const Pose2d& tolerance) {
m_poseTolerance = tolerance;
}
ChassisSpeeds HolonomicDriveController::Calculate(
const Pose2d& currentPose, const Pose2d& poseRef,
units::meters_per_second_t linearVelocityRef, const Rotation2d& angleRef) {
// If this is the first run, then we need to reset the theta controller to the
// current pose's heading.
if (m_firstRun) {
m_thetaController.Reset(currentPose.Rotation().Radians());
m_firstRun = false;
}
// Calculate feedforward velocities (field-relative)
auto xFF = linearVelocityRef * poseRef.Rotation().Cos();
auto yFF = linearVelocityRef * poseRef.Rotation().Sin();
auto thetaFF = units::radians_per_second_t(m_thetaController.Calculate(
currentPose.Rotation().Radians(), angleRef.Radians()));
m_poseError = poseRef.RelativeTo(currentPose);
m_rotationError = angleRef - currentPose.Rotation();
if (!m_enabled) {
return ChassisSpeeds::FromFieldRelativeSpeeds(xFF, yFF, thetaFF,
currentPose.Rotation());
}
// Calculate feedback velocities (based on position error).
auto xFeedback = units::meters_per_second_t(m_xController.Calculate(
currentPose.X().to<double>(), poseRef.X().to<double>()));
auto yFeedback = units::meters_per_second_t(m_yController.Calculate(
currentPose.Y().to<double>(), poseRef.Y().to<double>()));
// Return next output.
return ChassisSpeeds::FromFieldRelativeSpeeds(
xFF + xFeedback, yFF + yFeedback, thetaFF, currentPose.Rotation());
}
ChassisSpeeds HolonomicDriveController::Calculate(
const Pose2d& currentPose, const Trajectory::State& desiredState,
const Rotation2d& angleRef) {
return Calculate(currentPose, desiredState.pose, desiredState.velocity,
angleRef);
}
void HolonomicDriveController::SetEnabled(bool enabled) {
m_enabled = enabled;
}

View File

@@ -0,0 +1,175 @@
// 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/controller/PIDController.h"
#include <algorithm>
#include <cmath>
#include <wpi/sendable/SendableBuilder.h>
#include <wpi/sendable/SendableRegistry.h>
#include "frc/MathUtil.h"
#include "wpimath/MathShared.h"
using namespace frc2;
PIDController::PIDController(double Kp, double Ki, double Kd,
units::second_t period)
: m_Kp(Kp), m_Ki(Ki), m_Kd(Kd), m_period(period) {
if (period <= 0_s) {
wpi::math::MathSharedStore::ReportError(
"Controller period must be a non-zero positive number, got {}!",
period.to<double>());
m_period = 20_ms;
wpi::math::MathSharedStore::ReportWarning(
"{}", "Controller period defaulted to 20ms.");
}
static int instances = 0;
instances++;
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kController_PIDController2, instances);
wpi::SendableRegistry::Add(this, "PIDController", instances);
}
void PIDController::SetPID(double Kp, double Ki, double Kd) {
m_Kp = Kp;
m_Ki = Ki;
m_Kd = Kd;
}
void PIDController::SetP(double Kp) {
m_Kp = Kp;
}
void PIDController::SetI(double Ki) {
m_Ki = Ki;
}
void PIDController::SetD(double Kd) {
m_Kd = Kd;
}
double PIDController::GetP() const {
return m_Kp;
}
double PIDController::GetI() const {
return m_Ki;
}
double PIDController::GetD() const {
return m_Kd;
}
units::second_t PIDController::GetPeriod() const {
return units::second_t(m_period);
}
void PIDController::SetSetpoint(double setpoint) {
m_setpoint = setpoint;
}
double PIDController::GetSetpoint() const {
return m_setpoint;
}
bool PIDController::AtSetpoint() const {
double positionError;
if (m_continuous) {
double errorBound = (m_maximumInput - m_minimumInput) / 2.0;
positionError =
frc::InputModulus(m_setpoint - m_measurement, -errorBound, errorBound);
} else {
positionError = m_setpoint - m_measurement;
}
double velocityError = (positionError - m_prevError) / m_period.to<double>();
return std::abs(positionError) < m_positionTolerance &&
std::abs(velocityError) < m_velocityTolerance;
}
void PIDController::EnableContinuousInput(double minimumInput,
double maximumInput) {
m_continuous = true;
m_minimumInput = minimumInput;
m_maximumInput = maximumInput;
}
void PIDController::DisableContinuousInput() {
m_continuous = false;
}
bool PIDController::IsContinuousInputEnabled() const {
return m_continuous;
}
void PIDController::SetIntegratorRange(double minimumIntegral,
double maximumIntegral) {
m_minimumIntegral = minimumIntegral;
m_maximumIntegral = maximumIntegral;
}
void PIDController::SetTolerance(double positionTolerance,
double velocityTolerance) {
m_positionTolerance = positionTolerance;
m_velocityTolerance = velocityTolerance;
}
double PIDController::GetPositionError() const {
return m_positionError;
}
double PIDController::GetVelocityError() const {
return m_velocityError;
}
double PIDController::Calculate(double measurement) {
m_measurement = measurement;
m_prevError = m_positionError;
if (m_continuous) {
double errorBound = (m_maximumInput - m_minimumInput) / 2.0;
m_positionError =
frc::InputModulus(m_setpoint - m_measurement, -errorBound, errorBound);
} else {
m_positionError = m_setpoint - measurement;
}
m_velocityError = (m_positionError - m_prevError) / m_period.to<double>();
if (m_Ki != 0) {
m_totalError =
std::clamp(m_totalError + m_positionError * m_period.to<double>(),
m_minimumIntegral / m_Ki, m_maximumIntegral / m_Ki);
}
return m_Kp * m_positionError + m_Ki * m_totalError + m_Kd * m_velocityError;
}
double PIDController::Calculate(double measurement, double setpoint) {
// Set setpoint to provided value
SetSetpoint(setpoint);
return Calculate(measurement);
}
void PIDController::Reset() {
m_prevError = 0;
m_totalError = 0;
}
void PIDController::InitSendable(wpi::SendableBuilder& builder) {
builder.SetSmartDashboardType("PIDController");
builder.AddDoubleProperty(
"p", [this] { return GetP(); }, [this](double value) { SetP(value); });
builder.AddDoubleProperty(
"i", [this] { return GetI(); }, [this](double value) { SetI(value); });
builder.AddDoubleProperty(
"d", [this] { return GetD(); }, [this](double value) { SetD(value); });
builder.AddDoubleProperty(
"setpoint", [this] { return GetSetpoint(); },
[this](double value) { SetSetpoint(value); });
}

View File

@@ -0,0 +1,12 @@
// 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/controller/ProfiledPIDController.h"
void frc::detail::ReportProfiledPIDController() {
static int instances = 0;
++instances;
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kController_ProfiledPIDController, instances);
}

View File

@@ -0,0 +1,77 @@
// 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/controller/RamseteController.h"
#include <cmath>
#include "units/math.h"
using namespace frc;
/**
* Returns sin(x) / x.
*
* @param x Value of which to take sinc(x).
*/
static double Sinc(double x) {
if (std::abs(x) < 1e-9) {
return 1.0 - 1.0 / 6.0 * x * x;
} else {
return std::sin(x) / x;
}
}
RamseteController::RamseteController(double b, double zeta)
: m_b{b}, m_zeta{zeta} {}
bool RamseteController::AtReference() const {
const auto& eTranslate = m_poseError.Translation();
const auto& eRotate = m_poseError.Rotation();
const auto& tolTranslate = m_poseTolerance.Translation();
const auto& tolRotate = m_poseTolerance.Rotation();
return units::math::abs(eTranslate.X()) < tolTranslate.X() &&
units::math::abs(eTranslate.Y()) < tolTranslate.Y() &&
units::math::abs(eRotate.Radians()) < tolRotate.Radians();
}
void RamseteController::SetTolerance(const Pose2d& poseTolerance) {
m_poseTolerance = poseTolerance;
}
ChassisSpeeds RamseteController::Calculate(
const Pose2d& currentPose, const Pose2d& poseRef,
units::meters_per_second_t linearVelocityRef,
units::radians_per_second_t angularVelocityRef) {
if (!m_enabled) {
return ChassisSpeeds{linearVelocityRef, 0_mps, angularVelocityRef};
}
m_poseError = poseRef.RelativeTo(currentPose);
// Aliases for equation readability
double eX = m_poseError.X().to<double>();
double eY = m_poseError.Y().to<double>();
double eTheta = m_poseError.Rotation().Radians().to<double>();
double vRef = linearVelocityRef.to<double>();
double omegaRef = angularVelocityRef.to<double>();
double k =
2.0 * m_zeta * std::sqrt(std::pow(omegaRef, 2) + m_b * std::pow(vRef, 2));
units::meters_per_second_t v{vRef * m_poseError.Rotation().Cos() + k * eX};
units::radians_per_second_t omega{omegaRef + k * eTheta +
m_b * vRef * Sinc(eTheta) * eY};
return ChassisSpeeds{v, 0_mps, omega};
}
ChassisSpeeds RamseteController::Calculate(
const Pose2d& currentPose, const Trajectory::State& desiredState) {
return Calculate(currentPose, desiredState.pose, desiredState.velocity,
desiredState.velocity * desiredState.curvature);
}
void RamseteController::SetEnabled(bool enabled) {
m_enabled = enabled;
}