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>
|
2021-06-13 16:38:05 -07:00
|
|
|
#include <wpi/sendable/SendableBuilder.h>
|
|
|
|
|
#include <wpi/sendable/SendableRegistry.h>
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2021-08-28 20:52:05 -07:00
|
|
|
#include "frc/MathUtil.h"
|
2022-05-04 20:37:27 -07:00
|
|
|
#include "frc/motorcontrol/MotorController.h"
|
2017-09-28 23:30:00 -07:00
|
|
|
|
|
|
|
|
using namespace frc;
|
|
|
|
|
|
2024-01-01 13:37:51 -08:00
|
|
|
WPI_IGNORE_DEPRECATED
|
|
|
|
|
|
2022-05-04 20:37:27 -07:00
|
|
|
DifferentialDrive::DifferentialDrive(MotorController& leftMotor,
|
|
|
|
|
MotorController& rightMotor)
|
2024-01-01 13:37:51 -08:00
|
|
|
: DifferentialDrive{[&](double output) { leftMotor.Set(output); },
|
|
|
|
|
[&](double output) { rightMotor.Set(output); }} {
|
|
|
|
|
wpi::SendableRegistry::AddChild(this, &leftMotor);
|
|
|
|
|
wpi::SendableRegistry::AddChild(this, &rightMotor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WPI_UNIGNORE_DEPRECATED
|
|
|
|
|
|
|
|
|
|
DifferentialDrive::DifferentialDrive(std::function<void(double)> leftMotor,
|
|
|
|
|
std::function<void(double)> rightMotor)
|
|
|
|
|
: m_leftMotor{std::move(leftMotor)}, m_rightMotor{std::move(rightMotor)} {
|
2017-12-04 23:28:33 -08:00
|
|
|
static int instances = 0;
|
|
|
|
|
++instances;
|
2021-06-15 23:06:03 -07:00
|
|
|
wpi::SendableRegistry::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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-26 18:36:51 -08:00
|
|
|
xSpeed = ApplyDeadband(xSpeed, m_deadband);
|
2021-05-21 22:34:16 -07:00
|
|
|
zRotation = ApplyDeadband(zRotation, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
auto [left, right] = ArcadeDriveIK(xSpeed, zRotation, squareInputs);
|
|
|
|
|
|
2024-01-01 13:37:51 -08:00
|
|
|
m_leftOutput = left * m_maxOutput;
|
|
|
|
|
m_rightOutput = right * m_maxOutput;
|
|
|
|
|
|
|
|
|
|
m_leftMotor(m_leftOutput);
|
|
|
|
|
m_rightMotor(m_rightOutput);
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
Feed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DifferentialDrive::CurvatureDrive(double xSpeed, double zRotation,
|
|
|
|
|
bool allowTurnInPlace) {
|
|
|
|
|
static bool reported = false;
|
|
|
|
|
if (!reported) {
|
|
|
|
|
HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
|
|
|
|
|
HALUsageReporting::kRobotDrive2_DifferentialCurvature, 2);
|
|
|
|
|
reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xSpeed = ApplyDeadband(xSpeed, m_deadband);
|
2017-11-26 18:36:51 -08:00
|
|
|
zRotation = ApplyDeadband(zRotation, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
auto [left, right] = CurvatureDriveIK(xSpeed, zRotation, allowTurnInPlace);
|
|
|
|
|
|
2024-01-01 13:37:51 -08:00
|
|
|
m_leftOutput = left * m_maxOutput;
|
|
|
|
|
m_rightOutput = right * m_maxOutput;
|
|
|
|
|
|
|
|
|
|
m_leftMotor(m_leftOutput);
|
|
|
|
|
m_rightMotor(m_rightOutput);
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
Feed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DifferentialDrive::TankDrive(double leftSpeed, double rightSpeed,
|
|
|
|
|
bool squareInputs) {
|
|
|
|
|
static bool reported = false;
|
|
|
|
|
if (!reported) {
|
|
|
|
|
HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
|
|
|
|
|
HALUsageReporting::kRobotDrive2_DifferentialTank, 2);
|
|
|
|
|
reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leftSpeed = ApplyDeadband(leftSpeed, m_deadband);
|
|
|
|
|
rightSpeed = ApplyDeadband(rightSpeed, m_deadband);
|
|
|
|
|
|
|
|
|
|
auto [left, right] = TankDriveIK(leftSpeed, rightSpeed, squareInputs);
|
|
|
|
|
|
2024-01-01 13:37:51 -08:00
|
|
|
m_leftOutput = left * m_maxOutput;
|
|
|
|
|
m_rightOutput = right * m_maxOutput;
|
|
|
|
|
|
|
|
|
|
m_leftMotor(m_leftOutput);
|
|
|
|
|
m_rightMotor(m_rightOutput);
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
Feed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DifferentialDrive::WheelSpeeds DifferentialDrive::ArcadeDriveIK(
|
|
|
|
|
double xSpeed, double zRotation, bool squareInputs) {
|
|
|
|
|
xSpeed = std::clamp(xSpeed, -1.0, 1.0);
|
|
|
|
|
zRotation = std::clamp(zRotation, -1.0, 1.0);
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2022-10-27 21:59:11 -07:00
|
|
|
double leftSpeed = xSpeed - zRotation;
|
|
|
|
|
double rightSpeed = xSpeed + zRotation;
|
|
|
|
|
|
|
|
|
|
// Find the maximum possible value of (throttle + turn) along the vector that
|
|
|
|
|
// the joystick is pointing, then desaturate the wheel speeds
|
2022-12-31 12:00:45 -08:00
|
|
|
double greaterInput = (std::max)(std::abs(xSpeed), std::abs(zRotation));
|
|
|
|
|
double lesserInput = (std::min)(std::abs(xSpeed), std::abs(zRotation));
|
2022-10-27 21:59:11 -07:00
|
|
|
if (greaterInput == 0.0) {
|
|
|
|
|
return {0.0, 0.0};
|
2021-05-21 22:34:16 -07:00
|
|
|
}
|
2022-10-27 21:59:11 -07:00
|
|
|
double saturatedInput = (greaterInput + lesserInput) / greaterInput;
|
|
|
|
|
leftSpeed /= saturatedInput;
|
|
|
|
|
rightSpeed /= saturatedInput;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
return {leftSpeed, rightSpeed};
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
DifferentialDrive::WheelSpeeds DifferentialDrive::CurvatureDriveIK(
|
|
|
|
|
double xSpeed, double zRotation, bool allowTurnInPlace) {
|
2019-08-28 23:24:30 -07:00
|
|
|
xSpeed = std::clamp(xSpeed, -1.0, 1.0);
|
|
|
|
|
zRotation = std::clamp(zRotation, -1.0, 1.0);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
double leftSpeed = 0.0;
|
|
|
|
|
double rightSpeed = 0.0;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
if (allowTurnInPlace) {
|
2022-10-27 21:59:11 -07:00
|
|
|
leftSpeed = xSpeed - zRotation;
|
|
|
|
|
rightSpeed = xSpeed + zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
} else {
|
2022-10-27 21:59:11 -07:00
|
|
|
leftSpeed = xSpeed - std::abs(xSpeed) * zRotation;
|
|
|
|
|
rightSpeed = xSpeed + std::abs(xSpeed) * zRotation;
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-27 21:59:11 -07:00
|
|
|
// Desaturate wheel speeds
|
2021-05-21 22:34:16 -07:00
|
|
|
double maxMagnitude = std::max(std::abs(leftSpeed), std::abs(rightSpeed));
|
2018-02-01 21:17:04 -08:00
|
|
|
if (maxMagnitude > 1.0) {
|
2021-05-21 22:34:16 -07:00
|
|
|
leftSpeed /= maxMagnitude;
|
|
|
|
|
rightSpeed /= maxMagnitude;
|
2018-02-01 21:17:04 -08:00
|
|
|
}
|
|
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
return {leftSpeed, rightSpeed};
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
DifferentialDrive::WheelSpeeds DifferentialDrive::TankDriveIK(
|
|
|
|
|
double leftSpeed, double rightSpeed, bool squareInputs) {
|
2019-08-28 23:24:30 -07:00
|
|
|
leftSpeed = std::clamp(leftSpeed, -1.0, 1.0);
|
|
|
|
|
rightSpeed = std::clamp(rightSpeed, -1.0, 1.0);
|
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
|
|
|
}
|
|
|
|
|
|
2021-05-21 22:34:16 -07:00
|
|
|
return {leftSpeed, rightSpeed};
|
2018-05-19 04:22:20 -04:00
|
|
|
}
|
|
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
void DifferentialDrive::StopMotor() {
|
2024-01-01 13:37:51 -08:00
|
|
|
m_leftOutput = 0.0;
|
|
|
|
|
m_rightOutput = 0.0;
|
|
|
|
|
|
|
|
|
|
m_leftMotor(0.0);
|
|
|
|
|
m_rightMotor(0.0);
|
|
|
|
|
|
2018-11-22 21:15:26 -08:00
|
|
|
Feed();
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-26 07:25:32 -07:00
|
|
|
std::string DifferentialDrive::GetDescription() const {
|
|
|
|
|
return "DifferentialDrive";
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2021-06-13 16:38:05 -07:00
|
|
|
void DifferentialDrive::InitSendable(wpi::SendableBuilder& builder) {
|
2017-12-04 23:28:33 -08:00
|
|
|
builder.SetSmartDashboardType("DifferentialDrive");
|
2018-07-28 14:04:46 -07:00
|
|
|
builder.SetActuator(true);
|
2022-10-15 16:33:14 -07:00
|
|
|
builder.SetSafeState([=, this] { StopMotor(); });
|
2020-06-27 20:39:00 -07:00
|
|
|
builder.AddDoubleProperty(
|
2024-01-01 13:37:51 -08:00
|
|
|
"Left Motor Speed", [&] { return m_leftOutput; }, m_leftMotor);
|
2018-05-19 04:22:20 -04:00
|
|
|
builder.AddDoubleProperty(
|
2024-01-01 13:37:51 -08:00
|
|
|
"Right Motor Speed", [&] { return m_rightOutput; }, m_rightMotor);
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|