2020-12-26 14:12:05 -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.
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "frc/drive/DifferentialDrive.h"
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-02-01 21:17:04 -08:00
|
|
|
#include <algorithm>
|
2017-09-28 23:30:00 -07:00
|
|
|
#include <cmath>
|
|
|
|
|
|
2019-11-08 22:53:20 -08:00
|
|
|
#include <hal/FRCUsageReporting.h>
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "frc/SpeedController.h"
|
|
|
|
|
#include "frc/smartdashboard/SendableBuilder.h"
|
2019-09-14 15:22:54 -05:00
|
|
|
#include "frc/smartdashboard/SendableRegistry.h"
|
2017-09-28 23:30:00 -07:00
|
|
|
|
|
|
|
|
using namespace frc;
|
|
|
|
|
|
2021-04-17 11:27:16 -07:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
|
#pragma warning(disable : 4996) // was declared deprecated
|
|
|
|
|
#elif defined(__clang__)
|
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
|
#elif defined(__GNUC__)
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
DifferentialDrive::DifferentialDrive(SpeedController& leftMotor,
|
|
|
|
|
SpeedController& rightMotor)
|
2019-10-19 11:36:44 -07:00
|
|
|
: m_leftMotor(&leftMotor), m_rightMotor(&rightMotor) {
|
2019-09-14 15:22:54 -05:00
|
|
|
auto& registry = SendableRegistry::GetInstance();
|
2019-10-19 11:36:44 -07:00
|
|
|
registry.AddChild(this, m_leftMotor);
|
|
|
|
|
registry.AddChild(this, m_rightMotor);
|
2017-12-04 23:28:33 -08:00
|
|
|
static int instances = 0;
|
|
|
|
|
++instances;
|
2019-09-14 15:22:54 -05:00
|
|
|
registry.AddLW(this, "DifferentialDrive", instances);
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
void DifferentialDrive::ArcadeDrive(double xSpeed, double zRotation,
|
2018-10-14 17:10:16 +11:00
|
|
|
bool squareInputs) {
|
2017-09-28 23:30:00 -07:00
|
|
|
static bool reported = false;
|
|
|
|
|
if (!reported) {
|
2019-09-29 20:35:04 -07:00
|
|
|
HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
|
|
|
|
|
HALUsageReporting::kRobotDrive2_DifferentialArcade, 2);
|
2017-09-28 23:30:00 -07:00
|
|
|
reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 23:24:30 -07:00
|
|
|
xSpeed = std::clamp(xSpeed, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
xSpeed = ApplyDeadband(xSpeed, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2019-08-28 23:24:30 -07:00
|
|
|
zRotation = std::clamp(zRotation, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
zRotation = ApplyDeadband(zRotation, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
// Square the inputs (while preserving the sign) to increase fine control
|
|
|
|
|
// while permitting full power.
|
2018-10-14 17:10:16 +11:00
|
|
|
if (squareInputs) {
|
2017-11-26 18:36:51 -08:00
|
|
|
xSpeed = std::copysign(xSpeed * xSpeed, xSpeed);
|
|
|
|
|
zRotation = std::copysign(zRotation * zRotation, zRotation);
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double leftMotorOutput;
|
|
|
|
|
double rightMotorOutput;
|
|
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
double maxInput =
|
|
|
|
|
std::copysign(std::max(std::abs(xSpeed), std::abs(zRotation)), xSpeed);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
if (xSpeed >= 0.0) {
|
2017-09-28 23:30:00 -07:00
|
|
|
// First quadrant, else second quadrant
|
2017-11-26 18:36:51 -08:00
|
|
|
if (zRotation >= 0.0) {
|
2017-09-28 23:30:00 -07:00
|
|
|
leftMotorOutput = maxInput;
|
2017-11-26 18:36:51 -08:00
|
|
|
rightMotorOutput = xSpeed - zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
} else {
|
2017-11-26 18:36:51 -08:00
|
|
|
leftMotorOutput = xSpeed + zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
rightMotorOutput = maxInput;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Third quadrant, else fourth quadrant
|
2017-11-26 18:36:51 -08:00
|
|
|
if (zRotation >= 0.0) {
|
|
|
|
|
leftMotorOutput = xSpeed + zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
rightMotorOutput = maxInput;
|
|
|
|
|
} else {
|
|
|
|
|
leftMotorOutput = maxInput;
|
2017-11-26 18:36:51 -08:00
|
|
|
rightMotorOutput = xSpeed - zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-19 11:36:44 -07:00
|
|
|
m_leftMotor->Set(std::clamp(leftMotorOutput, -1.0, 1.0) * m_maxOutput);
|
2019-08-28 23:24:30 -07:00
|
|
|
double maxOutput = m_maxOutput * m_rightSideInvertMultiplier;
|
2019-10-19 11:36:44 -07:00
|
|
|
m_rightMotor->Set(std::clamp(rightMotorOutput, -1.0, 1.0) * maxOutput);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-11-22 21:15:26 -08:00
|
|
|
Feed();
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
void DifferentialDrive::CurvatureDrive(double xSpeed, double zRotation,
|
2017-09-28 23:30:00 -07:00
|
|
|
bool isQuickTurn) {
|
|
|
|
|
static bool reported = false;
|
|
|
|
|
if (!reported) {
|
2019-09-29 20:35:04 -07:00
|
|
|
HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
|
|
|
|
|
HALUsageReporting::kRobotDrive2_DifferentialCurvature, 2);
|
2017-09-28 23:30:00 -07:00
|
|
|
reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 23:24:30 -07:00
|
|
|
xSpeed = std::clamp(xSpeed, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
xSpeed = ApplyDeadband(xSpeed, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2019-08-28 23:24:30 -07:00
|
|
|
zRotation = std::clamp(zRotation, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
zRotation = ApplyDeadband(zRotation, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
|
|
|
|
double angularPower;
|
|
|
|
|
bool overPower;
|
|
|
|
|
|
|
|
|
|
if (isQuickTurn) {
|
2017-11-26 18:36:51 -08:00
|
|
|
if (std::abs(xSpeed) < m_quickStopThreshold) {
|
2019-08-28 23:24:30 -07:00
|
|
|
m_quickStopAccumulator =
|
|
|
|
|
(1 - m_quickStopAlpha) * m_quickStopAccumulator +
|
|
|
|
|
m_quickStopAlpha * std::clamp(zRotation, -1.0, 1.0) * 2;
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
overPower = true;
|
2017-11-26 18:36:51 -08:00
|
|
|
angularPower = zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
} else {
|
|
|
|
|
overPower = false;
|
2017-11-26 18:36:51 -08:00
|
|
|
angularPower = std::abs(xSpeed) * zRotation - m_quickStopAccumulator;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
|
|
|
|
if (m_quickStopAccumulator > 1) {
|
|
|
|
|
m_quickStopAccumulator -= 1;
|
|
|
|
|
} else if (m_quickStopAccumulator < -1) {
|
|
|
|
|
m_quickStopAccumulator += 1;
|
|
|
|
|
} else {
|
|
|
|
|
m_quickStopAccumulator = 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
double leftMotorOutput = xSpeed + angularPower;
|
|
|
|
|
double rightMotorOutput = xSpeed - angularPower;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
|
|
|
|
// If rotation is overpowered, reduce both outputs to within acceptable range
|
|
|
|
|
if (overPower) {
|
|
|
|
|
if (leftMotorOutput > 1.0) {
|
|
|
|
|
rightMotorOutput -= leftMotorOutput - 1.0;
|
|
|
|
|
leftMotorOutput = 1.0;
|
|
|
|
|
} else if (rightMotorOutput > 1.0) {
|
|
|
|
|
leftMotorOutput -= rightMotorOutput - 1.0;
|
|
|
|
|
rightMotorOutput = 1.0;
|
|
|
|
|
} else if (leftMotorOutput < -1.0) {
|
|
|
|
|
rightMotorOutput -= leftMotorOutput + 1.0;
|
|
|
|
|
leftMotorOutput = -1.0;
|
|
|
|
|
} else if (rightMotorOutput < -1.0) {
|
|
|
|
|
leftMotorOutput -= rightMotorOutput + 1.0;
|
|
|
|
|
rightMotorOutput = -1.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-01 21:17:04 -08:00
|
|
|
// Normalize the wheel speeds
|
|
|
|
|
double maxMagnitude =
|
|
|
|
|
std::max(std::abs(leftMotorOutput), std::abs(rightMotorOutput));
|
|
|
|
|
if (maxMagnitude > 1.0) {
|
|
|
|
|
leftMotorOutput /= maxMagnitude;
|
|
|
|
|
rightMotorOutput /= maxMagnitude;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-19 11:36:44 -07:00
|
|
|
m_leftMotor->Set(leftMotorOutput * m_maxOutput);
|
|
|
|
|
m_rightMotor->Set(rightMotorOutput * m_maxOutput *
|
|
|
|
|
m_rightSideInvertMultiplier);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-11-22 21:15:26 -08:00
|
|
|
Feed();
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
void DifferentialDrive::TankDrive(double leftSpeed, double rightSpeed,
|
2018-10-14 17:10:16 +11:00
|
|
|
bool squareInputs) {
|
2017-09-28 23:30:00 -07:00
|
|
|
static bool reported = false;
|
|
|
|
|
if (!reported) {
|
2019-09-29 20:35:04 -07:00
|
|
|
HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
|
|
|
|
|
HALUsageReporting::kRobotDrive2_DifferentialTank, 2);
|
2017-09-28 23:30:00 -07:00
|
|
|
reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 23:24:30 -07:00
|
|
|
leftSpeed = std::clamp(leftSpeed, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
leftSpeed = ApplyDeadband(leftSpeed, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2019-08-28 23:24:30 -07:00
|
|
|
rightSpeed = std::clamp(rightSpeed, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
rightSpeed = ApplyDeadband(rightSpeed, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
// Square the inputs (while preserving the sign) to increase fine control
|
|
|
|
|
// while permitting full power.
|
2018-10-14 17:10:16 +11:00
|
|
|
if (squareInputs) {
|
2017-11-26 18:36:51 -08:00
|
|
|
leftSpeed = std::copysign(leftSpeed * leftSpeed, leftSpeed);
|
|
|
|
|
rightSpeed = std::copysign(rightSpeed * rightSpeed, rightSpeed);
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-19 11:36:44 -07:00
|
|
|
m_leftMotor->Set(leftSpeed * m_maxOutput);
|
|
|
|
|
m_rightMotor->Set(rightSpeed * m_maxOutput * m_rightSideInvertMultiplier);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-11-22 21:15:26 -08:00
|
|
|
Feed();
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
void DifferentialDrive::SetQuickStopThreshold(double threshold) {
|
|
|
|
|
m_quickStopThreshold = threshold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DifferentialDrive::SetQuickStopAlpha(double alpha) {
|
|
|
|
|
m_quickStopAlpha = alpha;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-19 04:22:20 -04:00
|
|
|
bool DifferentialDrive::IsRightSideInverted() const {
|
|
|
|
|
return m_rightSideInvertMultiplier == -1.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DifferentialDrive::SetRightSideInverted(bool rightSideInverted) {
|
|
|
|
|
m_rightSideInvertMultiplier = rightSideInverted ? -1.0 : 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
void DifferentialDrive::StopMotor() {
|
2019-10-19 11:36:44 -07:00
|
|
|
m_leftMotor->StopMotor();
|
|
|
|
|
m_rightMotor->StopMotor();
|
2018-11-22 21:15:26 -08:00
|
|
|
Feed();
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
void DifferentialDrive::GetDescription(wpi::raw_ostream& desc) const {
|
2017-09-28 23:30:00 -07:00
|
|
|
desc << "DifferentialDrive";
|
|
|
|
|
}
|
2017-12-04 23:28:33 -08:00
|
|
|
|
|
|
|
|
void DifferentialDrive::InitSendable(SendableBuilder& builder) {
|
|
|
|
|
builder.SetSmartDashboardType("DifferentialDrive");
|
2018-07-28 14:04:46 -07:00
|
|
|
builder.SetActuator(true);
|
|
|
|
|
builder.SetSafeState([=] { StopMotor(); });
|
2020-06-27 20:39:00 -07:00
|
|
|
builder.AddDoubleProperty(
|
|
|
|
|
"Left Motor Speed", [=]() { return m_leftMotor->Get(); },
|
|
|
|
|
[=](double value) { m_leftMotor->Set(value); });
|
2018-05-19 04:22:20 -04:00
|
|
|
builder.AddDoubleProperty(
|
|
|
|
|
"Right Motor Speed",
|
2019-10-19 11:36:44 -07:00
|
|
|
[=]() { return m_rightMotor->Get() * m_rightSideInvertMultiplier; },
|
2018-05-19 04:22:20 -04:00
|
|
|
[=](double value) {
|
2019-10-19 11:36:44 -07:00
|
|
|
m_rightMotor->Set(value * m_rightSideInvertMultiplier);
|
2018-05-19 04:22:20 -04:00
|
|
|
});
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|