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.
|
2020-09-20 09:39:52 -07:00
|
|
|
|
|
|
|
|
package edu.wpi.first.wpilibj.simulation;
|
|
|
|
|
|
2021-05-01 15:53:30 +00:00
|
|
|
import edu.wpi.first.math.Matrix;
|
|
|
|
|
import edu.wpi.first.math.Nat;
|
2021-05-21 22:29:52 -07:00
|
|
|
import edu.wpi.first.math.StateSpaceUtil;
|
2021-05-01 15:53:30 +00:00
|
|
|
import edu.wpi.first.math.VecBuilder;
|
|
|
|
|
import edu.wpi.first.math.geometry.Pose2d;
|
|
|
|
|
import edu.wpi.first.math.geometry.Rotation2d;
|
|
|
|
|
import edu.wpi.first.math.numbers.N1;
|
|
|
|
|
import edu.wpi.first.math.numbers.N2;
|
|
|
|
|
import edu.wpi.first.math.numbers.N7;
|
|
|
|
|
import edu.wpi.first.math.system.LinearSystem;
|
|
|
|
|
import edu.wpi.first.math.system.NumericalIntegration;
|
|
|
|
|
import edu.wpi.first.math.system.plant.DCMotor;
|
|
|
|
|
import edu.wpi.first.math.system.plant.LinearSystemId;
|
|
|
|
|
import edu.wpi.first.math.util.Units;
|
2020-12-28 13:03:31 -08:00
|
|
|
import edu.wpi.first.wpilibj.RobotController;
|
2020-09-20 09:39:52 -07:00
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* This class simulates the state of the drivetrain. In simulationPeriodic, users should first set
|
|
|
|
|
* inputs from motors with {@link #setInputs(double, double)}, call {@link #update(double)} to
|
|
|
|
|
* update the simulation, and set estimated encoder and gyro positions, as well as estimated
|
|
|
|
|
* odometry pose. Teams can use {@link edu.wpi.first.wpilibj.smartdashboard.Field2d} to visualize
|
|
|
|
|
* their robot on the Sim GUI's field.
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>Our state-space system is:
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
2021-07-29 22:42:43 -07:00
|
|
|
* <p>x = [[x, y, theta, vel_l, vel_r, dist_l, dist_r]]ᵀ in the field coordinate system (dist_* are
|
2020-12-29 22:45:16 -08:00
|
|
|
* wheel distances.)
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
2021-07-29 22:42:43 -07:00
|
|
|
* <p>u = [[voltage_l, voltage_r]]ᵀ This is typically the control input of the last timestep from a
|
2020-12-29 22:45:16 -08:00
|
|
|
* LTVDiffDriveController.
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
2020-12-04 18:46:50 -08:00
|
|
|
* <p>y = x
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
|
|
|
|
public class DifferentialDrivetrainSim {
|
|
|
|
|
private final DCMotor m_motor;
|
|
|
|
|
private final double m_originalGearing;
|
2020-12-04 18:46:50 -08:00
|
|
|
private final Matrix<N7, N1> m_measurementStdDevs;
|
2020-09-20 09:39:52 -07:00
|
|
|
private double m_currentGearing;
|
2025-02-10 07:23:04 -08:00
|
|
|
private final double m_wheelRadius;
|
2020-12-29 22:45:16 -08:00
|
|
|
|
2020-09-20 09:39:52 -07:00
|
|
|
private Matrix<N2, N1> m_u;
|
|
|
|
|
private Matrix<N7, N1> m_x;
|
2020-12-04 18:46:50 -08:00
|
|
|
private Matrix<N7, N1> m_y;
|
2020-09-20 09:39:52 -07:00
|
|
|
|
|
|
|
|
private final double m_rb;
|
|
|
|
|
private final LinearSystem<N2, N2, N2> m_plant;
|
|
|
|
|
|
|
|
|
|
/**
|
2023-07-31 19:18:17 -07:00
|
|
|
* Creates a simulated differential drivetrain.
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param driveMotor A {@link DCMotor} representing the left side of the drivetrain.
|
2021-01-11 21:55:45 -08:00
|
|
|
* @param gearing The gearing ratio between motor and wheel, as output over input. This must be
|
|
|
|
|
* the same ratio as the ratio used to identify or create the drivetrainPlant.
|
2025-02-10 07:23:04 -08:00
|
|
|
* @param j The moment of inertia of the drivetrain about its center in kg-m².
|
|
|
|
|
* @param mass The mass of the drivebase in kg.
|
|
|
|
|
* @param wheelRadius The radius of the wheels on the drivetrain in meters.
|
|
|
|
|
* @param trackwidth The robot's trackwidth, or distance between left and right wheels, in meters.
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
|
2021-07-29 22:42:43 -07:00
|
|
|
* left velocity, right velocity, left distance, right distance]ᵀ. Can be null if no noise is
|
2020-12-29 22:45:16 -08:00
|
|
|
* desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
|
|
|
|
|
* m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
|
|
|
|
|
* point.
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
2020-12-29 22:45:16 -08:00
|
|
|
public DifferentialDrivetrainSim(
|
|
|
|
|
DCMotor driveMotor,
|
|
|
|
|
double gearing,
|
2025-02-10 07:23:04 -08:00
|
|
|
double j,
|
|
|
|
|
double mass,
|
|
|
|
|
double wheelRadius,
|
|
|
|
|
double trackwidth,
|
2020-12-29 22:45:16 -08:00
|
|
|
Matrix<N7, N1> measurementStdDevs) {
|
|
|
|
|
this(
|
|
|
|
|
LinearSystemId.createDrivetrainVelocitySystem(
|
2025-02-10 07:23:04 -08:00
|
|
|
driveMotor, mass, wheelRadius, trackwidth / 2.0, j, gearing),
|
2020-12-29 22:45:16 -08:00
|
|
|
driveMotor,
|
|
|
|
|
gearing,
|
2025-02-10 07:23:04 -08:00
|
|
|
trackwidth,
|
|
|
|
|
wheelRadius,
|
2020-12-29 22:45:16 -08:00
|
|
|
measurementStdDevs);
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-07-31 19:18:17 -07:00
|
|
|
* Creates a simulated differential drivetrain.
|
2020-12-29 22:45:16 -08:00
|
|
|
*
|
2023-07-31 19:18:17 -07:00
|
|
|
* @param plant The {@link LinearSystem} representing the robot's drivetrain. This system can be
|
|
|
|
|
* created with {@link
|
2021-05-01 15:53:30 +00:00
|
|
|
* edu.wpi.first.math.system.plant.LinearSystemId#createDrivetrainVelocitySystem(DCMotor,
|
2020-12-29 22:45:16 -08:00
|
|
|
* double, double, double, double, double)} or {@link
|
2021-05-01 15:53:30 +00:00
|
|
|
* edu.wpi.first.math.system.plant.LinearSystemId#identifyDrivetrainSystem(double, double,
|
2020-12-29 22:45:16 -08:00
|
|
|
* double, double)}.
|
|
|
|
|
* @param driveMotor A {@link DCMotor} representing the drivetrain.
|
|
|
|
|
* @param gearing The gearingRatio ratio of the robot, as output over input. This must be the same
|
|
|
|
|
* ratio as the ratio used to identify or create the drivetrainPlant.
|
2025-02-10 07:23:04 -08:00
|
|
|
* @param trackwidth The distance between the two sides of the drivetrain in meters. Can be found
|
|
|
|
|
* with SysId.
|
|
|
|
|
* @param wheelRadius The radius of the wheels on the drivetrain, in meters.
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
|
2021-07-29 22:42:43 -07:00
|
|
|
* left velocity, right velocity, left distance, right distance]ᵀ. Can be null if no noise is
|
2020-12-29 22:45:16 -08:00
|
|
|
* desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
|
|
|
|
|
* m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
|
|
|
|
|
* point.
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
2020-12-29 22:45:16 -08:00
|
|
|
public DifferentialDrivetrainSim(
|
2023-07-31 19:18:17 -07:00
|
|
|
LinearSystem<N2, N2, N2> plant,
|
2020-12-29 22:45:16 -08:00
|
|
|
DCMotor driveMotor,
|
|
|
|
|
double gearing,
|
2025-02-10 07:23:04 -08:00
|
|
|
double trackwidth,
|
|
|
|
|
double wheelRadius,
|
2020-12-29 22:45:16 -08:00
|
|
|
Matrix<N7, N1> measurementStdDevs) {
|
2023-07-31 19:18:17 -07:00
|
|
|
this.m_plant = plant;
|
2025-02-10 07:23:04 -08:00
|
|
|
this.m_rb = trackwidth / 2.0;
|
2020-09-20 09:39:52 -07:00
|
|
|
this.m_motor = driveMotor;
|
|
|
|
|
this.m_originalGearing = gearing;
|
2020-12-04 18:46:50 -08:00
|
|
|
this.m_measurementStdDevs = measurementStdDevs;
|
2025-02-10 07:23:04 -08:00
|
|
|
m_wheelRadius = wheelRadius;
|
2020-09-20 09:39:52 -07:00
|
|
|
m_currentGearing = m_originalGearing;
|
|
|
|
|
|
|
|
|
|
m_x = new Matrix<>(Nat.N7(), Nat.N1());
|
2020-11-13 21:06:46 +02:00
|
|
|
m_u = VecBuilder.fill(0, 0);
|
2020-12-04 18:46:50 -08:00
|
|
|
m_y = new Matrix<>(Nat.N7(), Nat.N1());
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Sets the applied voltage to the drivetrain. Note that positive voltage must make that side of
|
|
|
|
|
* the drivetrain travel forward (+X).
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param leftVoltageVolts The left voltage.
|
2020-09-20 09:39:52 -07:00
|
|
|
* @param rightVoltageVolts The right voltage.
|
|
|
|
|
*/
|
|
|
|
|
public void setInputs(double leftVoltageVolts, double rightVoltageVolts) {
|
2020-12-28 13:03:31 -08:00
|
|
|
m_u = clampInput(VecBuilder.fill(leftVoltageVolts, rightVoltageVolts));
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/**
|
|
|
|
|
* Update the drivetrain states with the current time difference.
|
|
|
|
|
*
|
2025-02-10 07:23:04 -08:00
|
|
|
* @param dt the time difference in seconds
|
2021-01-11 21:55:45 -08:00
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public void update(double dt) {
|
|
|
|
|
m_x = NumericalIntegration.rkdp(this::getDynamics, m_x, m_u, dt);
|
2020-12-04 18:46:50 -08:00
|
|
|
m_y = m_x;
|
|
|
|
|
if (m_measurementStdDevs != null) {
|
|
|
|
|
m_y = m_y.plus(StateSpaceUtil.makeWhiteNoiseVector(m_measurementStdDevs));
|
|
|
|
|
}
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Returns the full simulated state of the drivetrain. */
|
2020-12-04 18:46:50 -08:00
|
|
|
Matrix<N7, N1> getState() {
|
2020-09-20 09:39:52 -07:00
|
|
|
return m_x;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/**
|
|
|
|
|
* Get one of the drivetrain states.
|
|
|
|
|
*
|
|
|
|
|
* @param state the state to get
|
|
|
|
|
* @return the state
|
|
|
|
|
*/
|
2020-12-04 18:46:50 -08:00
|
|
|
double getState(State state) {
|
|
|
|
|
return m_x.get(state.value, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double getOutput(State output) {
|
|
|
|
|
return m_y.get(output.value, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-20 09:39:52 -07:00
|
|
|
/**
|
2020-09-27 16:25:17 -04:00
|
|
|
* Returns the direction the robot is pointing.
|
|
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>Note that this angle is counterclockwise-positive, while most gyros are clockwise positive.
|
2021-06-10 20:46:47 -07:00
|
|
|
*
|
|
|
|
|
* @return The direction the robot is pointing.
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
|
|
|
|
public Rotation2d getHeading() {
|
2020-12-04 18:46:50 -08:00
|
|
|
return new Rotation2d(getOutput(State.kHeading));
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
2021-06-10 20:46:47 -07:00
|
|
|
/**
|
|
|
|
|
* Returns the current pose.
|
|
|
|
|
*
|
|
|
|
|
* @return The current pose.
|
|
|
|
|
*/
|
2020-09-27 16:25:17 -04:00
|
|
|
public Pose2d getPose() {
|
2020-12-29 22:45:16 -08:00
|
|
|
return new Pose2d(getOutput(State.kX), getOutput(State.kY), getHeading());
|
2020-12-04 18:46:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-02-10 07:23:04 -08:00
|
|
|
* Get the right encoder position.
|
2020-12-29 22:45:16 -08:00
|
|
|
*
|
2025-02-10 07:23:04 -08:00
|
|
|
* @return The encoder position in meters.
|
2020-12-04 18:46:50 -08:00
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getRightPosition() {
|
2020-12-04 18:46:50 -08:00
|
|
|
return getOutput(State.kRightPosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-02-10 07:23:04 -08:00
|
|
|
* Get the right encoder velocity.
|
2020-12-29 22:45:16 -08:00
|
|
|
*
|
2025-02-10 07:23:04 -08:00
|
|
|
* @return The encoder velocity in meters per second.
|
2020-12-04 18:46:50 -08:00
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getRightVelocity() {
|
2020-12-04 18:46:50 -08:00
|
|
|
return getOutput(State.kRightVelocity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-02-10 07:23:04 -08:00
|
|
|
* Get the left encoder position.
|
2020-12-29 22:45:16 -08:00
|
|
|
*
|
2025-02-10 07:23:04 -08:00
|
|
|
* @return The encoder position in meters.
|
2020-12-04 18:46:50 -08:00
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getLeftPosition() {
|
2020-12-04 18:46:50 -08:00
|
|
|
return getOutput(State.kLeftPosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-02-10 07:23:04 -08:00
|
|
|
* Get the left encoder velocity.
|
2020-12-29 22:45:16 -08:00
|
|
|
*
|
2025-02-10 07:23:04 -08:00
|
|
|
* @return The encoder velocity in meters per second.
|
2020-12-04 18:46:50 -08:00
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getLeftVelocity() {
|
2020-12-04 18:46:50 -08:00
|
|
|
return getOutput(State.kLeftVelocity);
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/**
|
|
|
|
|
* Get the current draw of the left side of the drivetrain.
|
|
|
|
|
*
|
|
|
|
|
* @return the drivetrain's left side current draw, in amps
|
|
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getLeftCurrentDraw() {
|
2023-12-03 16:21:32 -08:00
|
|
|
return m_motor.getCurrent(
|
2025-02-10 07:23:04 -08:00
|
|
|
getState(State.kLeftVelocity) * m_currentGearing / m_wheelRadius, m_u.get(0, 0))
|
2023-12-03 16:21:32 -08:00
|
|
|
* Math.signum(m_u.get(0, 0));
|
2020-12-29 23:46:51 -05:00
|
|
|
}
|
2020-09-20 09:39:52 -07:00
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/**
|
|
|
|
|
* Get the current draw of the right side of the drivetrain.
|
|
|
|
|
*
|
|
|
|
|
* @return the drivetrain's right side current draw, in amps
|
|
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getRightCurrentDraw() {
|
2023-12-03 16:21:32 -08:00
|
|
|
return m_motor.getCurrent(
|
2025-02-10 07:23:04 -08:00
|
|
|
getState(State.kRightVelocity) * m_currentGearing / m_wheelRadius, m_u.get(1, 0))
|
2023-12-03 16:21:32 -08:00
|
|
|
* Math.signum(m_u.get(1, 0));
|
2020-12-29 23:46:51 -05:00
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/**
|
|
|
|
|
* Get the current draw of the drivetrain.
|
|
|
|
|
*
|
|
|
|
|
* @return the current draw, in amps
|
|
|
|
|
*/
|
2025-02-10 07:23:04 -08:00
|
|
|
public double getCurrentDraw() {
|
|
|
|
|
return getLeftCurrentDraw() + getRightCurrentDraw();
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/**
|
|
|
|
|
* Get the drivetrain gearing.
|
|
|
|
|
*
|
|
|
|
|
* @return the gearing ration
|
|
|
|
|
*/
|
2020-09-20 09:39:52 -07:00
|
|
|
public double getCurrentGearing() {
|
|
|
|
|
return m_currentGearing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Sets the gearing reduction on the drivetrain. This is commonly used for shifting drivetrains.
|
2020-09-20 09:39:52 -07:00
|
|
|
*
|
|
|
|
|
* @param newGearRatio The new gear ratio, as output over input.
|
|
|
|
|
*/
|
|
|
|
|
public void setCurrentGearing(double newGearRatio) {
|
|
|
|
|
this.m_currentGearing = newGearRatio;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-27 13:26:47 -07:00
|
|
|
/**
|
|
|
|
|
* Sets the system state.
|
|
|
|
|
*
|
|
|
|
|
* @param state The state.
|
|
|
|
|
*/
|
|
|
|
|
public void setState(Matrix<N7, N1> state) {
|
|
|
|
|
m_x = state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the system pose.
|
|
|
|
|
*
|
|
|
|
|
* @param pose The pose.
|
|
|
|
|
*/
|
|
|
|
|
public void setPose(Pose2d pose) {
|
|
|
|
|
m_x.set(State.kX.value, 0, pose.getX());
|
|
|
|
|
m_x.set(State.kY.value, 0, pose.getY());
|
|
|
|
|
m_x.set(State.kHeading.value, 0, pose.getRotation().getRadians());
|
2020-11-12 01:37:14 -05:00
|
|
|
m_x.set(State.kLeftPosition.value, 0, 0);
|
|
|
|
|
m_x.set(State.kRightPosition.value, 0, 0);
|
2020-09-27 13:26:47 -07:00
|
|
|
}
|
|
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/**
|
|
|
|
|
* The differential drive dynamics function.
|
|
|
|
|
*
|
|
|
|
|
* @param x The state.
|
|
|
|
|
* @param u The input.
|
|
|
|
|
* @return The state derivative with respect to time.
|
|
|
|
|
*/
|
2020-09-20 09:39:52 -07:00
|
|
|
protected Matrix<N7, N1> getDynamics(Matrix<N7, N1> x, Matrix<N2, N1> u) {
|
|
|
|
|
// Because G can be factored out of B, we can divide by the old ratio and multiply
|
|
|
|
|
// by the new ratio to get a new drivetrain model.
|
|
|
|
|
var B = new Matrix<>(Nat.N4(), Nat.N2());
|
|
|
|
|
B.assignBlock(0, 0, m_plant.getB().times(this.m_currentGearing / this.m_originalGearing));
|
|
|
|
|
|
2022-05-20 15:16:56 -07:00
|
|
|
// Because G² can be factored out of A, we can divide by the old ratio squared and multiply
|
2020-09-20 09:39:52 -07:00
|
|
|
// by the new ratio squared to get a new drivetrain model.
|
|
|
|
|
var A = new Matrix<>(Nat.N4(), Nat.N4());
|
2020-12-29 22:45:16 -08:00
|
|
|
A.assignBlock(
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
m_plant
|
|
|
|
|
.getA()
|
|
|
|
|
.times(
|
|
|
|
|
(this.m_currentGearing * this.m_currentGearing)
|
|
|
|
|
/ (this.m_originalGearing * this.m_originalGearing)));
|
2020-09-20 09:39:52 -07:00
|
|
|
|
|
|
|
|
A.assignBlock(2, 0, Matrix.eye(Nat.N2()));
|
|
|
|
|
|
|
|
|
|
var v = (x.get(State.kLeftVelocity.value, 0) + x.get(State.kRightVelocity.value, 0)) / 2.0;
|
|
|
|
|
|
|
|
|
|
var xdot = new Matrix<>(Nat.N7(), Nat.N1());
|
|
|
|
|
xdot.set(0, 0, v * Math.cos(x.get(State.kHeading.value, 0)));
|
|
|
|
|
xdot.set(1, 0, v * Math.sin(x.get(State.kHeading.value, 0)));
|
2020-12-29 22:45:16 -08:00
|
|
|
xdot.set(
|
|
|
|
|
2,
|
|
|
|
|
0,
|
|
|
|
|
(x.get(State.kRightVelocity.value, 0) - x.get(State.kLeftVelocity.value, 0))
|
|
|
|
|
/ (2.0 * m_rb));
|
|
|
|
|
xdot.assignBlock(3, 0, A.times(x.block(Nat.N4(), Nat.N1(), 3, 0)).plus(B.times(u)));
|
2020-09-20 09:39:52 -07:00
|
|
|
|
|
|
|
|
return xdot;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-28 13:03:31 -08:00
|
|
|
/**
|
2021-10-14 18:09:38 -07:00
|
|
|
* Clamp the input vector such that no element exceeds the battery voltage. If any does, the
|
2020-12-29 22:45:16 -08:00
|
|
|
* relative magnitudes of the input will be maintained.
|
2020-12-28 13:03:31 -08:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param u The input vector.
|
2020-12-28 13:03:31 -08:00
|
|
|
* @return The normalized input.
|
|
|
|
|
*/
|
|
|
|
|
protected Matrix<N2, N1> clampInput(Matrix<N2, N1> u) {
|
2021-12-30 21:30:08 -05:00
|
|
|
return StateSpaceUtil.desaturateInputVector(u, RobotController.getBatteryVoltage());
|
2020-12-28 13:03:31 -08:00
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/** Represents the different states of the drivetrain. */
|
2020-12-04 18:46:50 -08:00
|
|
|
enum State {
|
2020-09-20 09:39:52 -07:00
|
|
|
kX(0),
|
|
|
|
|
kY(1),
|
|
|
|
|
kHeading(2),
|
|
|
|
|
kLeftVelocity(3),
|
|
|
|
|
kRightVelocity(4),
|
|
|
|
|
kLeftPosition(5),
|
|
|
|
|
kRightPosition(6);
|
|
|
|
|
|
|
|
|
|
public final int value;
|
|
|
|
|
|
|
|
|
|
State(int i) {
|
|
|
|
|
this.value = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Represents a gearing option of the Toughbox mini. 12.75:1 -- 14:50 and 14:50 10.71:1 -- 14:50
|
|
|
|
|
* and 16:48 8.45:1 -- 14:50 and 19:45 7.31:1 -- 14:50 and 21:43 5.95:1 -- 14:50 and 24:40
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
|
|
|
|
public enum KitbotGearing {
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Gear ratio of 12.75:1. */
|
2020-09-20 09:39:52 -07:00
|
|
|
k12p75(12.75),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Gear ratio of 10.71:1. */
|
2020-09-20 09:39:52 -07:00
|
|
|
k10p71(10.71),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Gear ratio of 8.45:1. */
|
2020-09-20 09:39:52 -07:00
|
|
|
k8p45(8.45),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Gear ratio of 7.31:1. */
|
2020-09-20 09:39:52 -07:00
|
|
|
k7p31(7.31),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Gear ratio of 5.95:1. */
|
2020-09-20 09:39:52 -07:00
|
|
|
k5p95(5.95);
|
|
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/** KitbotGearing value. */
|
2020-09-20 09:39:52 -07:00
|
|
|
public final double value;
|
|
|
|
|
|
|
|
|
|
KitbotGearing(double i) {
|
|
|
|
|
this.value = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/** Represents common motor layouts of the kit drivetrain. */
|
2020-09-20 09:39:52 -07:00
|
|
|
public enum KitbotMotor {
|
2024-01-05 00:36:26 -05:00
|
|
|
/** One CIM motor per drive side. */
|
2020-09-20 09:39:52 -07:00
|
|
|
kSingleCIMPerSide(DCMotor.getCIM(1)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Two CIM motors per drive side. */
|
2020-09-20 09:39:52 -07:00
|
|
|
kDualCIMPerSide(DCMotor.getCIM(2)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** One Mini CIM motor per drive side. */
|
2020-09-20 09:39:52 -07:00
|
|
|
kSingleMiniCIMPerSide(DCMotor.getMiniCIM(1)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Two Mini CIM motors per drive side. */
|
2021-12-06 16:46:58 -06:00
|
|
|
kDualMiniCIMPerSide(DCMotor.getMiniCIM(2)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** One Falcon 500 motor per drive side. */
|
2021-12-06 16:46:58 -06:00
|
|
|
kSingleFalcon500PerSide(DCMotor.getFalcon500(1)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Two Falcon 500 motors per drive side. */
|
2021-12-06 16:46:58 -06:00
|
|
|
kDoubleFalcon500PerSide(DCMotor.getFalcon500(2)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** One NEO motor per drive side. */
|
2021-12-06 16:46:58 -06:00
|
|
|
kSingleNEOPerSide(DCMotor.getNEO(1)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Two NEO motors per drive side. */
|
2021-12-06 16:46:58 -06:00
|
|
|
kDoubleNEOPerSide(DCMotor.getNEO(2));
|
2020-09-20 09:39:52 -07:00
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/** KitbotMotor value. */
|
2020-09-20 09:39:52 -07:00
|
|
|
public final DCMotor value;
|
|
|
|
|
|
|
|
|
|
KitbotMotor(DCMotor i) {
|
|
|
|
|
this.value = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-11 21:55:45 -08:00
|
|
|
/** Represents common wheel sizes of the kit drivetrain. */
|
2020-09-20 09:39:52 -07:00
|
|
|
public enum KitbotWheelSize {
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Six inch diameter wheels. */
|
2021-05-01 14:09:23 +00:00
|
|
|
kSixInch(Units.inchesToMeters(6)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Eight inch diameter wheels. */
|
2021-05-01 14:09:23 +00:00
|
|
|
kEightInch(Units.inchesToMeters(8)),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Ten inch diameter wheels. */
|
2022-05-04 20:37:27 -07:00
|
|
|
kTenInch(Units.inchesToMeters(10));
|
2020-09-20 09:39:52 -07:00
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/** KitbotWheelSize value. */
|
2020-09-20 09:39:52 -07:00
|
|
|
public final double value;
|
|
|
|
|
|
|
|
|
|
KitbotWheelSize(double i) {
|
|
|
|
|
this.value = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a sim for the standard FRC kitbot.
|
|
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param motor The motors installed in the bot.
|
|
|
|
|
* @param gearing The gearing reduction used.
|
2020-09-20 09:39:52 -07:00
|
|
|
* @param wheelSize The wheel size.
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
|
2021-07-29 22:42:43 -07:00
|
|
|
* left velocity, right velocity, left distance, right distance]ᵀ. Can be null if no noise is
|
2020-12-29 22:45:16 -08:00
|
|
|
* desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
|
|
|
|
|
* m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
|
|
|
|
|
* point.
|
2021-06-10 20:46:47 -07:00
|
|
|
* @return A sim for the standard FRC kitbot.
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
2020-12-29 22:45:16 -08:00
|
|
|
public static DifferentialDrivetrainSim createKitbotSim(
|
|
|
|
|
KitbotMotor motor,
|
|
|
|
|
KitbotGearing gearing,
|
|
|
|
|
KitbotWheelSize wheelSize,
|
|
|
|
|
Matrix<N7, N1> measurementStdDevs) {
|
2022-05-20 15:16:56 -07:00
|
|
|
// MOI estimation -- note that I = mr² for point masses
|
2020-09-20 09:39:52 -07:00
|
|
|
var batteryMoi = 12.5 / 2.2 * Math.pow(Units.inchesToMeters(10), 2);
|
2020-12-29 22:45:16 -08:00
|
|
|
var gearboxMoi =
|
|
|
|
|
(2.8 /* CIM motor */ * 2 / 2.2 + 2.0 /* Toughbox Mini- ish */)
|
|
|
|
|
* Math.pow(Units.inchesToMeters(26.0 / 2.0), 2);
|
2020-09-20 09:39:52 -07:00
|
|
|
|
2020-12-04 18:46:50 -08:00
|
|
|
return createKitbotSim(motor, gearing, wheelSize, batteryMoi + gearboxMoi, measurementStdDevs);
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a sim for the standard FRC kitbot.
|
|
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param motor The motors installed in the bot.
|
|
|
|
|
* @param gearing The gearing reduction used.
|
|
|
|
|
* @param wheelSize The wheel size.
|
2025-02-10 07:23:04 -08:00
|
|
|
* @param j The moment of inertia of the drivebase in kg-m². This can be calculated using SysId.
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
|
2021-07-29 22:42:43 -07:00
|
|
|
* left velocity, right velocity, left distance, right distance]ᵀ. Can be null if no noise is
|
2020-12-29 22:45:16 -08:00
|
|
|
* desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
|
|
|
|
|
* m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
|
|
|
|
|
* point.
|
2021-06-10 20:46:47 -07:00
|
|
|
* @return A sim for the standard FRC kitbot.
|
2020-09-20 09:39:52 -07:00
|
|
|
*/
|
2020-12-29 22:45:16 -08:00
|
|
|
public static DifferentialDrivetrainSim createKitbotSim(
|
|
|
|
|
KitbotMotor motor,
|
|
|
|
|
KitbotGearing gearing,
|
|
|
|
|
KitbotWheelSize wheelSize,
|
2025-02-10 07:23:04 -08:00
|
|
|
double j,
|
2020-12-29 22:45:16 -08:00
|
|
|
Matrix<N7, N1> measurementStdDevs) {
|
|
|
|
|
return new DifferentialDrivetrainSim(
|
|
|
|
|
motor.value,
|
|
|
|
|
gearing.value,
|
2025-02-10 07:23:04 -08:00
|
|
|
j,
|
2021-03-08 01:54:40 -05:00
|
|
|
Units.lbsToKilograms(60),
|
2020-12-29 22:45:16 -08:00
|
|
|
wheelSize.value / 2.0,
|
|
|
|
|
Units.inchesToMeters(26),
|
|
|
|
|
measurementStdDevs);
|
2020-09-20 09:39:52 -07:00
|
|
|
}
|
|
|
|
|
}
|