diff options
Diffstat (limited to 'src/main/java/frc/robot/util')
-rw-r--r-- | src/main/java/frc/robot/util/IMUGyro.java | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/main/java/frc/robot/util/IMUGyro.java b/src/main/java/frc/robot/util/IMUGyro.java new file mode 100644 index 0000000..1ea1983 --- /dev/null +++ b/src/main/java/frc/robot/util/IMUGyro.java @@ -0,0 +1,192 @@ +package frc.robot.util; + +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj.I2C; +import edu.wpi.first.wpilibj.Timer; + +public class IMUGyro +{ + public I2C mpu; + + public double pitch; + public double roll; + public double yaw; + + private double gyroOffsets[] = new double[3]; + + // for deltatime + private double prev_time = Timer.getFPGATimestamp(); + + private final int PWR_MGMT_1 = 0x6B; + private final int CONFIG_ADDR = 0x1A; + private final int SMPLRT_DIV = 0x19; + + private final int GYRO_ADDR = 0x43; + private final int GYRO_CONFIG = 0x1B; + + private final int ACCL_ADDR = 0x3B; + private final int ACCL_CONFIG = 0x1C; + + private final double SCALE_GYRO = (Math.PI/(180*16.384)); + private final double SCALE_ACCL = (1/16.384); + + public IMUGyro(I2C gyro) + { + mpu = gyro; + reset(); + + mpu.write(CONFIG_ADDR, 0b00000110); + mpu.write(SMPLRT_DIV, 0b00010011); + mpu.write(GYRO_CONFIG, 0b00001000); + mpu.write(ACCL_CONFIG, 0b00000000); + } + + public void reset() + { + mpu.write(PWR_MGMT_1, 0b10001000); + + pitch = 0; + roll = 0; + yaw = 0; + } + + public void update() + { + double cur_time = Timer.getFPGATimestamp(); + double dt = cur_time - prev_time; + prev_time = cur_time; + + // double[] gRates = gyroRates(); + + // roll = gRates[0] * dt; + // pitch = gRates[1] * dt; + // yaw = gRates[2] * dt; + + double[] gRates = gyroRates(); + double[] aRates = acclRates(); + + mahony(30, 0, gRates, aRates, dt); + double[] angles = fromQuaternion(q); + + roll = angles[0]; + pitch = angles[1]; + yaw = angles[2]; + } + + public Rotation2d toRotation2d() + { + return new Rotation2d(yaw % 360); + } + + public void calibrateGyro(int iter) + { + gyroOffsets = new double[3]; + + double x = 0, y = 0, z = 0; + for(int i = 0; i < iter; i++) + { + double[] rates = gyroRates(); + x += rates[0]; + y += rates[1]; + z += rates[2]; + } + + gyroOffsets[0] = x/iter; + gyroOffsets[1] = y/iter; + gyroOffsets[2] = z/iter; + } + + private double[] gyroRates() + { + return scaledRates(GYRO_ADDR, SCALE_GYRO); + } + + private double[] acclRates() + { + return scaledRates(ACCL_ADDR, SCALE_ACCL); + } + + private double[] scaledRates(int addr, double scale) + { + byte[] buffer = new byte[6]; + mpu.read(addr, 6, buffer); + double dx = decode(buffer[0], buffer[1]) * scale - gyroOffsets[0]; + double dy = decode(buffer[2], buffer[3]) * scale - gyroOffsets[1]; + double dz = decode(buffer[4], buffer[5]) * scale - gyroOffsets[2]; + return new double[] {dx, dy, dz}; + } + + private double decode(byte first, byte second) + { + return ((first << 8) | second); + } + + // mahony quaternion + private double[] q = {1.0, 0.0, 0.0, 0.0}; + // mahony integral term + private double[] i = new double[3]; + + private double[] fromQuaternion(double[] q) + { + return new double[] { + Math.atan2((q[0] * q[1] + q[2] * q[3]), 0.5 - (q[1] * q[1] + q[2] * q[2])), + Math.asin(2.0 * (q[0] * q[2] - q[1] * q[3])), + -Math.atan2((q[1] * q[2] + q[0] * q[3]), 0.5 - (q[2] * q[2] + q[3] * q[3])) + }; + } + + private void mahony(double Ki, double Kp, double[] gRates, double[] aRates, double dt) + { + double gx = gRates[0], gy = gRates[1], gz = gRates[2]; + double ax = aRates[0], ay = aRates[1], az = aRates[2]; + + double tmp = ax * ax + ay * ay + az * az; + if(tmp > 0.0) + { + tmp = Math.sqrt(tmp); + ax /= tmp; ay /= tmp; az /= tmp; + + // estimated direction of gravity in the body frame + double vx = q[1] * q[3] - q[0] * q[2]; + double vy = q[0] * q[1] + q[2] * q[3]; + double vz = q[0] * q[0] - 0.5f + q[3] * q[3]; + + // error is cross product + double ex = (ay * vz - az * vy); + double ey = (az * vx - ax * vz); + double ez = (ax * vy - ay * vx); + + // integral feedback + if(Ki > 0.0) { + i[0] += Ki * ex * dt; + i[1] += Ki * ey * dt; + i[2] += Ki * ez * dt; + gx += i[0]; + gy += i[1]; + gz += i[2]; + } + + gx += Kp * ex; + gy += Kp * ey; + gz += Kp * ez; + } + + // integrate quaternion + dt /= 2; // ?? + gx *= dt; gy *= dt; gz *= dt; + + double qa = q[0], qb = q[1], qc = q[2], qd = q[3]; + q[0] += (-qb * gx - qc * gy - qd * gz); + q[1] += (qa * gx + qc * gz - qd * gy); + q[2] += (qa * gy - qb * gz + qd * gx); + q[3] += (qa * gz + qb * gy - qc * gx); + + // renormalize + double qnorm_factor = Math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); + q[0] /= qnorm_factor; + q[1] /= qnorm_factor; + q[2] /= qnorm_factor; + q[3] /= qnorm_factor; + } +} + |