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
|
|
|
|
2025-11-07 19:55:43 -05:00
|
|
|
package org.wpilib.drive;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2025-11-07 19:55:43 -05:00
|
|
|
import static org.wpilib.util.ErrorMessages.requireNonNullParam;
|
2021-06-09 07:01:00 -07:00
|
|
|
|
2025-11-07 19:57:21 -05:00
|
|
|
import java.util.function.DoubleConsumer;
|
2025-11-07 19:55:43 -05:00
|
|
|
import org.wpilib.hardware.hal.HAL;
|
2025-11-07 19:57:21 -05:00
|
|
|
import org.wpilib.hardware.motor.MotorController;
|
2025-11-07 19:55:43 -05:00
|
|
|
import org.wpilib.math.util.MathUtil;
|
|
|
|
|
import org.wpilib.util.sendable.Sendable;
|
|
|
|
|
import org.wpilib.util.sendable.SendableBuilder;
|
|
|
|
|
import org.wpilib.util.sendable.SendableRegistry;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A class for driving differential drive/skid-steer drive platforms such as the Kit of Parts drive
|
|
|
|
|
* base, "tank drive", or West Coast Drive.
|
|
|
|
|
*
|
|
|
|
|
* <p>These drive bases typically have drop-center / skid-steer with two or more wheels per side
|
2024-01-01 13:37:51 -08:00
|
|
|
* (e.g., 6WD or 8WD). This class takes a setter per side. For four and six motor drivetrains, use
|
|
|
|
|
* CAN motor controller followers or {@link
|
2025-11-07 19:55:43 -05:00
|
|
|
* org.wpilib.hardware.motor.PWMMotorController#addFollower(PWMMotorController)}.
|
2017-09-28 23:30:00 -07:00
|
|
|
*
|
|
|
|
|
* <p>A differential drive robot has left and right wheels separated by an arbitrary width.
|
|
|
|
|
*
|
|
|
|
|
* <p>Drive base diagram:
|
2020-12-29 22:45:16 -08:00
|
|
|
*
|
2017-09-28 23:30:00 -07:00
|
|
|
* <pre>
|
|
|
|
|
* |_______|
|
|
|
|
|
* | | | |
|
|
|
|
|
* | |
|
|
|
|
|
* |_|___|_|
|
|
|
|
|
* | |
|
|
|
|
|
* </pre>
|
|
|
|
|
*
|
2022-03-14 10:07:06 -07:00
|
|
|
* <p>Each drive function provides different inverse kinematic relations for a differential drive
|
|
|
|
|
* robot.
|
2017-11-26 18:36:51 -08:00
|
|
|
*
|
2022-10-27 21:59:11 -07:00
|
|
|
* <p>This library uses the NWU axes convention (North-West-Up as external reference in the world
|
|
|
|
|
* frame). The positive X axis points ahead, the positive Y axis points to the left, and the
|
|
|
|
|
* positive Z axis points up. Rotations follow the right-hand rule, so counterclockwise rotation
|
|
|
|
|
* around the Z axis is positive.
|
2017-11-29 21:41:00 -08:00
|
|
|
*
|
2026-03-17 16:41:17 -07:00
|
|
|
* <p>Inputs smaller then {@value org.wpilib.drive.RobotDriveBase#DEFAULT_DEADBAND} will be set to
|
2025-11-07 19:57:21 -05:00
|
|
|
* 0, and larger values will be scaled so that the full range is still used. This deadband value can
|
|
|
|
|
* be changed with {@link #setDeadband}.
|
2022-03-20 21:54:43 -07:00
|
|
|
*
|
2025-11-07 19:57:21 -05:00
|
|
|
* <p>{@link org.wpilib.hardware.motor.MotorSafety} is enabled by default. The tankDrive,
|
|
|
|
|
* arcadeDrive, or curvatureDrive methods should be called periodically to avoid Motor Safety
|
|
|
|
|
* timeouts.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2019-10-05 23:42:53 -07:00
|
|
|
public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoCloseable {
|
2018-06-03 10:00:53 -07:00
|
|
|
private static int instances;
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2024-01-01 13:37:51 -08:00
|
|
|
private final DoubleConsumer m_leftMotor;
|
|
|
|
|
private final DoubleConsumer m_rightMotor;
|
|
|
|
|
|
|
|
|
|
// Used for Sendable property getters
|
|
|
|
|
private double m_leftOutput;
|
|
|
|
|
private double m_rightOutput;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2018-06-03 10:00:53 -07:00
|
|
|
private boolean m_reported;
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2022-01-21 15:51:28 -08:00
|
|
|
/**
|
2026-03-06 14:19:15 -08:00
|
|
|
* Wheel velocities for a differential drive.
|
2022-01-21 15:51:28 -08:00
|
|
|
*
|
|
|
|
|
* <p>Uses normalized voltage [-1.0..1.0].
|
|
|
|
|
*/
|
2021-05-21 22:34:16 -07:00
|
|
|
@SuppressWarnings("MemberName")
|
2026-03-06 14:19:15 -08:00
|
|
|
public static class WheelVelocities {
|
|
|
|
|
/** Left wheel velocity. */
|
2021-05-21 22:34:16 -07:00
|
|
|
public double left;
|
2024-01-05 07:35:59 -08:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
/** Right wheel velocity. */
|
2021-05-21 22:34:16 -07:00
|
|
|
public double right;
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
/** Constructs a WheelVelocities with zeroes for left and right velocities. */
|
|
|
|
|
public WheelVelocities() {}
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
/**
|
2026-03-06 14:19:15 -08:00
|
|
|
* Constructs a WheelVelocities.
|
2021-05-21 22:34:16 -07:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param left The left velocity [-1.0..1.0].
|
|
|
|
|
* @param right The right velocity [-1.0..1.0].
|
2021-05-21 22:34:16 -07:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public WheelVelocities(double left, double right) {
|
2021-05-21 22:34:16 -07:00
|
|
|
this.left = left;
|
|
|
|
|
this.right = right;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
/**
|
|
|
|
|
* Construct a DifferentialDrive.
|
|
|
|
|
*
|
2024-01-19 20:34:58 -08:00
|
|
|
* <p>To pass multiple motors per side, use CAN motor controller followers or {@link
|
2025-11-07 19:57:21 -05:00
|
|
|
* org.wpilib.hardware.motor.PWMMotorController#addFollower(PWMMotorController)}. If a motor needs
|
|
|
|
|
* to be inverted, do so before passing it in.
|
2021-06-10 20:46:47 -07:00
|
|
|
*
|
|
|
|
|
* @param leftMotor Left motor.
|
|
|
|
|
* @param rightMotor Right motor.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2024-01-01 13:37:51 -08:00
|
|
|
@SuppressWarnings({"removal", "this-escape"})
|
2022-05-04 20:37:27 -07:00
|
|
|
public DifferentialDrive(MotorController leftMotor, MotorController rightMotor) {
|
2026-03-06 14:19:15 -08:00
|
|
|
this(
|
2026-04-09 22:28:01 -07:00
|
|
|
(double output) -> leftMotor.setThrottle(output),
|
|
|
|
|
(double output) -> rightMotor.setThrottle(output));
|
2024-01-01 13:37:51 -08:00
|
|
|
SendableRegistry.addChild(this, leftMotor);
|
|
|
|
|
SendableRegistry.addChild(this, rightMotor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Construct a DifferentialDrive.
|
|
|
|
|
*
|
|
|
|
|
* <p>To pass multiple motors per side, use CAN motor controller followers or {@link
|
2025-11-07 19:57:21 -05:00
|
|
|
* org.wpilib.hardware.motor.PWMMotorController#addFollower(PWMMotorController)}. If a motor needs
|
|
|
|
|
* to be inverted, do so before passing it in.
|
2024-01-01 13:37:51 -08:00
|
|
|
*
|
|
|
|
|
* @param leftMotor Left motor setter.
|
|
|
|
|
* @param rightMotor Right motor setter.
|
|
|
|
|
*/
|
|
|
|
|
@SuppressWarnings("this-escape")
|
|
|
|
|
public DifferentialDrive(DoubleConsumer leftMotor, DoubleConsumer rightMotor) {
|
2022-12-07 21:46:26 -08:00
|
|
|
requireNonNullParam(leftMotor, "leftMotor", "DifferentialDrive");
|
|
|
|
|
requireNonNullParam(rightMotor, "rightMotor", "DifferentialDrive");
|
2021-06-09 07:01:00 -07:00
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
m_leftMotor = leftMotor;
|
|
|
|
|
m_rightMotor = rightMotor;
|
2017-12-04 23:28:33 -08:00
|
|
|
instances++;
|
2025-01-25 10:52:19 -08:00
|
|
|
SendableRegistry.add(this, "DifferentialDrive", instances);
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-05 23:42:53 -07:00
|
|
|
@Override
|
|
|
|
|
public void close() {
|
|
|
|
|
SendableRegistry.remove(this);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Arcade drive method for differential drive platform. The calculated values will be squared to
|
2026-03-06 14:19:15 -08:00
|
|
|
* decrease sensitivity at low velocities.
|
2017-09-28 23:30:00 -07:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param xVelocity The robot's velocity along the X axis [-1.0..1.0]. Forward is positive.
|
2022-10-27 21:59:11 -07:00
|
|
|
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Counterclockwise is
|
2020-12-29 22:45:16 -08:00
|
|
|
* positive.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public void arcadeDrive(double xVelocity, double zRotation) {
|
|
|
|
|
arcadeDrive(xVelocity, zRotation, true);
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Arcade drive method for differential drive platform.
|
|
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param xVelocity The robot's velocity along the X axis [-1.0..1.0]. Forward is positive.
|
2022-10-27 21:59:11 -07:00
|
|
|
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Counterclockwise is
|
2020-12-29 22:45:16 -08:00
|
|
|
* positive.
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param squareInputs If set, decreases the input sensitivity at low velocities.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public void arcadeDrive(double xVelocity, double zRotation, boolean squareInputs) {
|
2017-09-28 23:30:00 -07:00
|
|
|
if (!m_reported) {
|
2025-02-07 12:37:23 -08:00
|
|
|
HAL.reportUsage("RobotDrive", "DifferentialArcade");
|
2017-09-28 23:30:00 -07:00
|
|
|
m_reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
xVelocity = MathUtil.applyDeadband(xVelocity, m_deadband);
|
2021-08-28 20:52:05 -07:00
|
|
|
zRotation = MathUtil.applyDeadband(zRotation, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
var velocities = arcadeDriveIK(xVelocity, zRotation, squareInputs);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
m_leftOutput = velocities.left * m_maxOutput;
|
|
|
|
|
m_rightOutput = velocities.right * m_maxOutput;
|
2024-01-01 13:37:51 -08:00
|
|
|
|
|
|
|
|
m_leftMotor.accept(m_leftOutput);
|
|
|
|
|
m_rightMotor.accept(m_rightOutput);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Curvature drive method for differential drive platform.
|
|
|
|
|
*
|
|
|
|
|
* <p>The rotation argument controls the curvature of the robot's path rather than its rate of
|
2026-03-06 14:19:15 -08:00
|
|
|
* heading change. This makes the robot more controllable at high velocities.
|
2017-09-28 23:30:00 -07:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param xVelocity The robot's velocity along the X axis [-1.0..1.0]. Forward is positive.
|
2022-10-27 21:59:11 -07:00
|
|
|
* @param zRotation The normalized curvature [-1.0..1.0]. Counterclockwise is positive.
|
2021-05-21 22:34:16 -07:00
|
|
|
* @param allowTurnInPlace If set, overrides constant-curvature turning for turn-in-place
|
2021-12-12 17:59:04 -08:00
|
|
|
* maneuvers. zRotation will control turning rate instead of curvature.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public void curvatureDrive(double xVelocity, double zRotation, boolean allowTurnInPlace) {
|
2017-09-28 23:30:00 -07:00
|
|
|
if (!m_reported) {
|
2025-02-07 12:37:23 -08:00
|
|
|
HAL.reportUsage("RobotDrive", "DifferentialCurvature");
|
2017-09-28 23:30:00 -07:00
|
|
|
m_reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
xVelocity = MathUtil.applyDeadband(xVelocity, m_deadband);
|
2021-08-28 20:52:05 -07:00
|
|
|
zRotation = MathUtil.applyDeadband(zRotation, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
var velocities = curvatureDriveIK(xVelocity, zRotation, allowTurnInPlace);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
m_leftOutput = velocities.left * m_maxOutput;
|
|
|
|
|
m_rightOutput = velocities.right * m_maxOutput;
|
2024-01-01 13:37:51 -08:00
|
|
|
|
|
|
|
|
m_leftMotor.accept(m_leftOutput);
|
|
|
|
|
m_rightMotor.accept(m_rightOutput);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Tank drive method for differential drive platform. The calculated values will be squared to
|
2026-03-06 14:19:15 -08:00
|
|
|
* decrease sensitivity at low velocities.
|
2017-09-28 23:30:00 -07:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param leftVelocity The robot's left side velocity along the X axis [-1.0..1.0]. Forward is
|
|
|
|
|
* positive.
|
|
|
|
|
* @param rightVelocity The robot's right side velocity along the X axis [-1.0..1.0]. Forward is
|
2020-12-29 22:45:16 -08:00
|
|
|
* positive.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public void tankDrive(double leftVelocity, double rightVelocity) {
|
|
|
|
|
tankDrive(leftVelocity, rightVelocity, true);
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tank drive method for differential drive platform.
|
|
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param leftVelocity The robot left side's velocity along the X axis [-1.0..1.0]. Forward is
|
|
|
|
|
* positive.
|
|
|
|
|
* @param rightVelocity The robot right side's velocity along the X axis [-1.0..1.0]. Forward is
|
2020-12-29 22:45:16 -08:00
|
|
|
* positive.
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param squareInputs If set, decreases the input sensitivity at low velocities.
|
2017-09-28 23:30:00 -07:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public void tankDrive(double leftVelocity, double rightVelocity, boolean squareInputs) {
|
2017-09-28 23:30:00 -07:00
|
|
|
if (!m_reported) {
|
2025-02-07 12:37:23 -08:00
|
|
|
HAL.reportUsage("RobotDrive", "DifferentialTank");
|
2017-09-28 23:30:00 -07:00
|
|
|
m_reported = true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
leftVelocity = MathUtil.applyDeadband(leftVelocity, m_deadband);
|
|
|
|
|
rightVelocity = MathUtil.applyDeadband(rightVelocity, m_deadband);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
var velocities = tankDriveIK(leftVelocity, rightVelocity, squareInputs);
|
2017-09-28 23:30:00 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
m_leftOutput = velocities.left * m_maxOutput;
|
|
|
|
|
m_rightOutput = velocities.right * m_maxOutput;
|
2024-01-01 13:37:51 -08:00
|
|
|
|
|
|
|
|
m_leftMotor.accept(m_leftOutput);
|
|
|
|
|
m_rightMotor.accept(m_rightOutput);
|
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
|
|
|
/**
|
2021-05-21 22:34:16 -07:00
|
|
|
* Arcade drive inverse kinematics for differential drive platform.
|
2017-11-26 18:36:51 -08:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param xVelocity The robot's velocity along the X axis [-1.0..1.0]. Forward is positive.
|
2022-10-27 21:59:11 -07:00
|
|
|
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Counterclockwise is
|
2021-05-21 22:34:16 -07:00
|
|
|
* positive.
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param squareInputs If set, decreases the input sensitivity at low velocities.
|
|
|
|
|
* @return Wheel velocities [-1.0..1.0].
|
2017-11-26 18:36:51 -08:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public static WheelVelocities arcadeDriveIK(
|
|
|
|
|
double xVelocity, double zRotation, boolean squareInputs) {
|
|
|
|
|
xVelocity = Math.clamp(xVelocity, -1.0, 1.0);
|
2025-08-23 06:01:51 -10:00
|
|
|
zRotation = Math.clamp(zRotation, -1.0, 1.0);
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
// Square the inputs (while preserving the sign) to increase fine control
|
|
|
|
|
// while permitting full power.
|
|
|
|
|
if (squareInputs) {
|
2026-03-06 14:19:15 -08:00
|
|
|
xVelocity = MathUtil.copyDirectionPow(xVelocity, 2);
|
2025-10-11 09:24:10 -07:00
|
|
|
zRotation = MathUtil.copyDirectionPow(zRotation, 2);
|
2021-05-21 22:34:16 -07:00
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
double leftVelocity = xVelocity - zRotation;
|
|
|
|
|
double rightVelocity = xVelocity + zRotation;
|
2021-05-21 22:34:16 -07:00
|
|
|
|
2022-10-27 21:59:11 -07:00
|
|
|
// Find the maximum possible value of (throttle + turn) along the vector
|
2026-03-06 14:19:15 -08:00
|
|
|
// that the joystick is pointing, then desaturate the wheel velocities
|
|
|
|
|
double greaterInput = Math.max(Math.abs(xVelocity), Math.abs(zRotation));
|
|
|
|
|
double lesserInput = Math.min(Math.abs(xVelocity), Math.abs(zRotation));
|
2022-10-27 21:59:11 -07:00
|
|
|
if (greaterInput == 0.0) {
|
2026-03-06 14:19:15 -08:00
|
|
|
return new WheelVelocities(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;
|
2026-03-06 14:19:15 -08:00
|
|
|
leftVelocity /= saturatedInput;
|
|
|
|
|
rightVelocity /= saturatedInput;
|
2021-05-21 22:34:16 -07:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
return new WheelVelocities(leftVelocity, rightVelocity);
|
2017-11-26 18:36:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-05-21 22:34:16 -07:00
|
|
|
* Curvature drive inverse kinematics for differential drive platform.
|
2017-11-26 18:36:51 -08:00
|
|
|
*
|
2021-05-21 22:34:16 -07:00
|
|
|
* <p>The rotation argument controls the curvature of the robot's path rather than its rate of
|
2026-03-06 14:19:15 -08:00
|
|
|
* heading change. This makes the robot more controllable at high velocities.
|
2017-11-26 18:36:51 -08:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param xVelocity The robot's velocity along the X axis [-1.0..1.0]. Forward is positive.
|
2022-10-27 21:59:11 -07:00
|
|
|
* @param zRotation The normalized curvature [-1.0..1.0]. Counterclockwise is positive.
|
2021-05-21 22:34:16 -07:00
|
|
|
* @param allowTurnInPlace If set, overrides constant-curvature turning for turn-in-place
|
2021-12-12 17:59:04 -08:00
|
|
|
* maneuvers. zRotation will control rotation rate around the Z axis instead of curvature.
|
2026-03-06 14:19:15 -08:00
|
|
|
* @return Wheel velocities [-1.0..1.0].
|
2017-11-26 18:36:51 -08:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public static WheelVelocities curvatureDriveIK(
|
|
|
|
|
double xVelocity, double zRotation, boolean allowTurnInPlace) {
|
|
|
|
|
xVelocity = Math.clamp(xVelocity, -1.0, 1.0);
|
2025-08-23 06:01:51 -10:00
|
|
|
zRotation = Math.clamp(zRotation, -1.0, 1.0);
|
2017-11-26 18:36:51 -08:00
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
double leftVelocity;
|
|
|
|
|
double rightVelocity;
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
if (allowTurnInPlace) {
|
2026-03-06 14:19:15 -08:00
|
|
|
leftVelocity = xVelocity - zRotation;
|
|
|
|
|
rightVelocity = xVelocity + zRotation;
|
2021-05-21 22:34:16 -07:00
|
|
|
} else {
|
2026-03-06 14:19:15 -08:00
|
|
|
leftVelocity = xVelocity - Math.abs(xVelocity) * zRotation;
|
|
|
|
|
rightVelocity = xVelocity + Math.abs(xVelocity) * zRotation;
|
2021-05-21 22:34:16 -07:00
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
// Desaturate wheel velocities
|
|
|
|
|
double maxMagnitude = Math.max(Math.abs(leftVelocity), Math.abs(rightVelocity));
|
2021-05-21 22:34:16 -07:00
|
|
|
if (maxMagnitude > 1.0) {
|
2026-03-06 14:19:15 -08:00
|
|
|
leftVelocity /= maxMagnitude;
|
|
|
|
|
rightVelocity /= maxMagnitude;
|
2021-05-21 22:34:16 -07:00
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
return new WheelVelocities(leftVelocity, rightVelocity);
|
2018-05-19 04:22:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-05-21 22:34:16 -07:00
|
|
|
* Tank drive inverse kinematics for differential drive platform.
|
2018-05-19 04:22:20 -04:00
|
|
|
*
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param leftVelocity The robot left side's velocity along the X axis [-1.0..1.0]. Forward is
|
|
|
|
|
* positive.
|
|
|
|
|
* @param rightVelocity The robot right side's velocity along the X axis [-1.0..1.0]. Forward is
|
2021-05-21 22:34:16 -07:00
|
|
|
* positive.
|
2026-03-06 14:19:15 -08:00
|
|
|
* @param squareInputs If set, decreases the input sensitivity at low velocities.
|
|
|
|
|
* @return Wheel velocities [-1.0..1.0].
|
2018-05-19 04:22:20 -04:00
|
|
|
*/
|
2026-03-06 14:19:15 -08:00
|
|
|
public static WheelVelocities tankDriveIK(
|
|
|
|
|
double leftVelocity, double rightVelocity, boolean squareInputs) {
|
|
|
|
|
leftVelocity = Math.clamp(leftVelocity, -1.0, 1.0);
|
|
|
|
|
rightVelocity = Math.clamp(rightVelocity, -1.0, 1.0);
|
2021-05-21 22:34:16 -07:00
|
|
|
|
|
|
|
|
// Square the inputs (while preserving the sign) to increase fine control
|
|
|
|
|
// while permitting full power.
|
|
|
|
|
if (squareInputs) {
|
2026-03-06 14:19:15 -08:00
|
|
|
leftVelocity = MathUtil.copyDirectionPow(leftVelocity, 2);
|
|
|
|
|
rightVelocity = MathUtil.copyDirectionPow(rightVelocity, 2);
|
2021-05-21 22:34:16 -07:00
|
|
|
}
|
|
|
|
|
|
2026-03-06 14:19:15 -08:00
|
|
|
return new WheelVelocities(leftVelocity, rightVelocity);
|
2018-05-19 04:22:20 -04:00
|
|
|
}
|
|
|
|
|
|
2017-09-28 23:30:00 -07:00
|
|
|
@Override
|
|
|
|
|
public void stopMotor() {
|
2024-01-01 13:37:51 -08:00
|
|
|
m_leftOutput = 0.0;
|
|
|
|
|
m_rightOutput = 0.0;
|
|
|
|
|
|
|
|
|
|
m_leftMotor.accept(0.0);
|
|
|
|
|
m_rightMotor.accept(0.0);
|
|
|
|
|
|
2018-11-22 21:15:26 -08:00
|
|
|
feed();
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String getDescription() {
|
|
|
|
|
return "DifferentialDrive";
|
|
|
|
|
}
|
2017-12-04 23:28:33 -08:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void initSendable(SendableBuilder builder) {
|
|
|
|
|
builder.setSmartDashboardType("DifferentialDrive");
|
2018-07-28 14:04:46 -07:00
|
|
|
builder.setActuator(true);
|
2026-03-06 14:19:15 -08:00
|
|
|
builder.addDoubleProperty("Left Motor Velocity", () -> m_leftOutput, m_leftMotor);
|
|
|
|
|
builder.addDoubleProperty("Right Motor Velocity", () -> m_rightOutput, m_rightMotor);
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|
2017-09-28 23:30:00 -07:00
|
|
|
}
|