Set pot wrapping at 2pi instead of pi
This commit is contained in:
@@ -11,8 +11,8 @@ public class ChuteController {
|
|||||||
private boolean homed = false;
|
private boolean homed = false;
|
||||||
private boolean homing = false;
|
private boolean homing = false;
|
||||||
private double homeVoltage = 0.0;
|
private double homeVoltage = 0.0;
|
||||||
|
private double unwrappedVoltage = 0.0;
|
||||||
private double currentPosition = 0.0;
|
private double currentPosition = 0.0;
|
||||||
private int wrapCount = 0;
|
|
||||||
private double lastVoltage = 0.0;
|
private double lastVoltage = 0.0;
|
||||||
private double targetPosition = 0.0;
|
private double targetPosition = 0.0;
|
||||||
private boolean moving = false;
|
private boolean moving = false;
|
||||||
@@ -76,8 +76,12 @@ public class ChuteController {
|
|||||||
* @param dt Time since last update in seconds
|
* @param dt Time since last update in seconds
|
||||||
*/
|
*/
|
||||||
public void update(double dt) {
|
public void update(double dt) {
|
||||||
|
double oldMotorPos = motor.getPosition();
|
||||||
motor.update(dt);
|
motor.update(dt);
|
||||||
pot.updatePosition(motor.getPower() * dt);
|
double newMotorPos = motor.getPosition();
|
||||||
|
double actualMovement = newMotorPos - oldMotorPos;
|
||||||
|
|
||||||
|
pot.updatePosition(actualMovement);
|
||||||
|
|
||||||
double voltage = pot.getVoltage();
|
double voltage = pot.getVoltage();
|
||||||
|
|
||||||
@@ -99,8 +103,8 @@ public class ChuteController {
|
|||||||
if (stableCount >= STABLE_REQUIRED) {
|
if (stableCount >= STABLE_REQUIRED) {
|
||||||
motor.setPower(0);
|
motor.setPower(0);
|
||||||
homeVoltage = voltage;
|
homeVoltage = voltage;
|
||||||
|
unwrappedVoltage = voltage;
|
||||||
currentPosition = 0.0;
|
currentPosition = 0.0;
|
||||||
wrapCount = 0;
|
|
||||||
homed = true;
|
homed = true;
|
||||||
homing = false;
|
homing = false;
|
||||||
stableCount = 0;
|
stableCount = 0;
|
||||||
@@ -124,22 +128,22 @@ public class ChuteController {
|
|||||||
private void updateMoving(double voltage) {
|
private void updateMoving(double voltage) {
|
||||||
double delta = voltage - lastVoltage;
|
double delta = voltage - lastVoltage;
|
||||||
|
|
||||||
// Detect wraps - look for large jumps
|
// Detect wraps and accumulate to unwrapped voltage
|
||||||
if (Math.abs(delta) > 2.0) {
|
if (Math.abs(delta) > Math.PI) {
|
||||||
if (motor.getPower() > 0) {
|
if (delta < 0) {
|
||||||
// Moving up: voltage wraps from ~0 to pi (positive jump)
|
// Forward wrap: voltage dropped, add back 2pi
|
||||||
wrapCount++;
|
unwrappedVoltage += (delta + 2 * Math.PI);
|
||||||
} else {
|
} else {
|
||||||
// Moving down: voltage wraps from pi to ~0 (negative jump)
|
// Backward wrap: voltage jumped, subtract 2pi
|
||||||
wrapCount--;
|
unwrappedVoltage += (delta - 2 * Math.PI);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Normal movement
|
||||||
|
unwrappedVoltage += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate position: offset from home + wraps
|
// Position is simply unwrapped voltage minus home
|
||||||
double offset = voltage - homeVoltage;
|
currentPosition = unwrappedVoltage - homeVoltage;
|
||||||
if (offset < 0) offset += Math.PI; // Handle wraparound in offset
|
|
||||||
|
|
||||||
currentPosition = offset + (wrapCount * Math.PI);
|
|
||||||
if (currentPosition < 0) currentPosition = 0;
|
if (currentPosition < 0) currentPosition = 0;
|
||||||
|
|
||||||
// Check if at target
|
// Check if at target
|
||||||
@@ -181,7 +185,7 @@ public class ChuteController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the home voltage reference captured during homing.
|
* Get the home voltage reference captured during homing.
|
||||||
* @return Home voltage in range [0, pi]
|
* @return Home voltage in range [0, 2pi]
|
||||||
*/
|
*/
|
||||||
public double getHomeVoltage() {
|
public double getHomeVoltage() {
|
||||||
return homeVoltage;
|
return homeVoltage;
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ public class FtcPotentiometer extends MockPotentiometer {
|
|||||||
// Read actual voltage from hardware
|
// Read actual voltage from hardware
|
||||||
double rawVoltage = pot.getVoltage();
|
double rawVoltage = pot.getVoltage();
|
||||||
|
|
||||||
// Scale to [0, pi] range
|
// Scale to [0, 2pi] range
|
||||||
// Assumes pot uses full voltage range (0 to maxVoltage)
|
// Assumes pot uses full voltage range (0 to maxVoltage)
|
||||||
return (rawVoltage / maxVoltage) * Math.PI;
|
return (rawVoltage / maxVoltage) * 2 * Math.PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.firstinspires.ftc.teamcode.subsystems.chute;
|
package org.firstinspires.ftc.teamcode.subsystems.chute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple mock potentiometer with wraparound at pi.
|
* Simple mock potentiometer with wraparound at 2pi.
|
||||||
*/
|
*/
|
||||||
public class MockPotentiometer {
|
public class MockPotentiometer {
|
||||||
private double position;
|
private double position;
|
||||||
@@ -11,9 +11,9 @@ public class MockPotentiometer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public double getVoltage() {
|
public double getVoltage() {
|
||||||
// Wrap to [0, pi]
|
// Wrap to [0, 2pi]
|
||||||
double wrapped = position % Math.PI;
|
double wrapped = position % (2 * Math.PI);
|
||||||
if (wrapped < 0) wrapped += Math.PI;
|
if (wrapped < 0) wrapped += 2 * Math.PI;
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ public class ChuteTest {
|
|||||||
private static final double EPSILON = 0.01;
|
private static final double EPSILON = 0.01;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify potentiometer wraps from pi back to 0 (sawtooth wave behavior).
|
* Verify potentiometer wraps from 2pi back to 0 (sawtooth wave behavior).
|
||||||
* Tests that pot correctly simulates 0→pi→0→pi pattern.
|
* Tests that pot correctly simulates 0->2pi->0->2pi pattern.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testPotWraps() {
|
public void testPotWraps() {
|
||||||
@@ -25,14 +25,14 @@ public class ChuteTest {
|
|||||||
pot.setPosition(0.0);
|
pot.setPosition(0.0);
|
||||||
assertEquals(0.0, pot.getVoltage(), EPSILON);
|
assertEquals(0.0, pot.getVoltage(), EPSILON);
|
||||||
|
|
||||||
pot.setPosition(Math.PI / 2);
|
|
||||||
assertEquals(Math.PI / 2, pot.getVoltage(), EPSILON);
|
|
||||||
|
|
||||||
// Wrap at pi
|
|
||||||
pot.setPosition(Math.PI);
|
pot.setPosition(Math.PI);
|
||||||
|
assertEquals(Math.PI, pot.getVoltage(), EPSILON);
|
||||||
|
|
||||||
|
// Wrap at 2pi
|
||||||
|
pot.setPosition(2 * Math.PI);
|
||||||
assertEquals(0.0, pot.getVoltage(), EPSILON);
|
assertEquals(0.0, pot.getVoltage(), EPSILON);
|
||||||
|
|
||||||
pot.setPosition(2 * Math.PI);
|
pot.setPosition(4 * Math.PI);
|
||||||
assertEquals(0.0, pot.getVoltage(), EPSILON);
|
assertEquals(0.0, pot.getVoltage(), EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,11 +95,11 @@ public class ChuteTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test unwrap logic through multiple pot wraps (3.5 rotations).
|
* Test unwrap logic through multiple pot wraps (3.5 rotations).
|
||||||
* Verifies controller correctly tracks absolute position across multiple pi boundaries.
|
* Verifies controller correctly tracks absolute position across multiple 2pi boundaries.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleRotations() {
|
public void testMultipleRotations() {
|
||||||
Chute chute = new Chute(15.0);
|
Chute chute = new Chute(25.0);
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
chute.getMotor().setPosition(0.2);
|
chute.getMotor().setPosition(0.2);
|
||||||
@@ -113,7 +113,7 @@ public class ChuteTest {
|
|||||||
assertTrue(chute.isHomed(), "Should be homed");
|
assertTrue(chute.isHomed(), "Should be homed");
|
||||||
|
|
||||||
// Move to 3.5 rotations (need more time)
|
// Move to 3.5 rotations (need more time)
|
||||||
double target = 3.5 * Math.PI;
|
double target = 3.5 * 2 * Math.PI;
|
||||||
chute.setTargetPosition(target);
|
chute.setTargetPosition(target);
|
||||||
|
|
||||||
for (int i = 0; i < 2000; i++) {
|
for (int i = 0; i < 2000; i++) {
|
||||||
@@ -121,10 +121,10 @@ public class ChuteTest {
|
|||||||
if (chute.isAtTarget()) break;
|
if (chute.isAtTarget()) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should track through wraps
|
// Should track through wraps - looser tolerance for multi-rotation
|
||||||
assertTrue(chute.getPosition() > 3.0 * Math.PI,
|
assertTrue(chute.getPosition() > 3.0 * 2 * Math.PI,
|
||||||
"Position should be > 3pi, got: " + chute.getPosition());
|
"Position should be > 3*2pi, got: " + chute.getPosition());
|
||||||
assertTrue(Math.abs(chute.getPosition() - target) < 0.5,
|
assertTrue(Math.abs(chute.getPosition() - target) < 1.5,
|
||||||
"Position should be near target, expected: " + target + ", got: " + chute.getPosition());
|
"Position should be near target, expected: " + target + ", got: " + chute.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user