Pot range is now dynamic
This commit is contained in:
@@ -22,6 +22,9 @@ public class ChuteOpMode extends LinearOpMode {
|
|||||||
|
|
||||||
private Chute chute;
|
private Chute chute;
|
||||||
|
|
||||||
|
// Pot configuration - change this if your pot has different range
|
||||||
|
private static final double POT_WRAP_AMOUNT = 2 * Math.PI;
|
||||||
|
|
||||||
// Position presets (in radians)
|
// Position presets (in radians)
|
||||||
private static final double HOME = 0.0;
|
private static final double HOME = 0.0;
|
||||||
private static final double LOW = Math.PI;
|
private static final double LOW = Math.PI;
|
||||||
@@ -37,13 +40,14 @@ public class ChuteOpMode extends LinearOpMode {
|
|||||||
|
|
||||||
// Create hardware adapters
|
// Create hardware adapters
|
||||||
FtcMotor motor = new FtcMotor(chuteMotor);
|
FtcMotor motor = new FtcMotor(chuteMotor);
|
||||||
FtcPotentiometer pot = new FtcPotentiometer(chutePot);
|
FtcPotentiometer pot = new FtcPotentiometer(chutePot, POT_WRAP_AMOUNT);
|
||||||
|
|
||||||
// Create chute controller with real hardware
|
// Create chute controller with real hardware
|
||||||
ChuteController controller = new ChuteController(motor, pot, MAX);
|
ChuteController controller = new ChuteController(motor, pot, MAX);
|
||||||
chute = new Chute(controller, motor, pot);
|
chute = new Chute(controller, motor, pot);
|
||||||
|
|
||||||
telemetry.addLine("Chute initialized");
|
telemetry.addLine("Chute initialized");
|
||||||
|
telemetry.addData("Pot wrap", "%.2f rad", POT_WRAP_AMOUNT);
|
||||||
telemetry.addLine("Press A to home");
|
telemetry.addLine("Press A to home");
|
||||||
telemetry.update();
|
telemetry.update();
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,21 @@ public class Chute {
|
|||||||
private final MockPotentiometer pot;
|
private final MockPotentiometer pot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create chute with mock hardware (for testing).
|
* Create chute with mock hardware (for testing) - default 2pi wraparound.
|
||||||
|
* @param maxExtension Maximum extension in radians
|
||||||
*/
|
*/
|
||||||
public Chute(double maxExtension) {
|
public Chute(double maxExtension) {
|
||||||
|
this(maxExtension, 2 * Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create chute with mock hardware (for testing) - custom wraparound.
|
||||||
|
* @param maxExtension Maximum extension in radians
|
||||||
|
* @param wrapAmount Potentiometer wrap amount in radians
|
||||||
|
*/
|
||||||
|
public Chute(double maxExtension, double wrapAmount) {
|
||||||
this.motor = new MockMotor();
|
this.motor = new MockMotor();
|
||||||
this.pot = new MockPotentiometer();
|
this.pot = new MockPotentiometer(wrapAmount);
|
||||||
this.controller = new ChuteController(motor, pot, maxExtension);
|
this.controller = new ChuteController(motor, pot, maxExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public class ChuteController {
|
|||||||
private final MockMotor motor;
|
private final MockMotor motor;
|
||||||
private final MockPotentiometer pot;
|
private final MockPotentiometer pot;
|
||||||
private final double maxExtension;
|
private final double maxExtension;
|
||||||
|
private final double wrapAmount;
|
||||||
|
|
||||||
private boolean homed = false;
|
private boolean homed = false;
|
||||||
private boolean homing = false;
|
private boolean homing = false;
|
||||||
@@ -32,6 +33,7 @@ public class ChuteController {
|
|||||||
this.motor = motor;
|
this.motor = motor;
|
||||||
this.pot = pot;
|
this.pot = pot;
|
||||||
this.maxExtension = maxExtension;
|
this.maxExtension = maxExtension;
|
||||||
|
this.wrapAmount = pot.getWrapAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,13 +131,14 @@ public class ChuteController {
|
|||||||
double delta = voltage - lastVoltage;
|
double delta = voltage - lastVoltage;
|
||||||
|
|
||||||
// Detect wraps and accumulate to unwrapped voltage
|
// Detect wraps and accumulate to unwrapped voltage
|
||||||
if (Math.abs(delta) > Math.PI) {
|
// Threshold is half the wrap amount
|
||||||
|
if (Math.abs(delta) > wrapAmount / 2) {
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
// Forward wrap: voltage dropped, add back 2pi
|
// Forward wrap: voltage dropped, add back wrap amount
|
||||||
unwrappedVoltage += (delta + 2 * Math.PI);
|
unwrappedVoltage += (delta + wrapAmount);
|
||||||
} else {
|
} else {
|
||||||
// Backward wrap: voltage jumped, subtract 2pi
|
// Backward wrap: voltage jumped, subtract wrap amount
|
||||||
unwrappedVoltage += (delta - 2 * Math.PI);
|
unwrappedVoltage += (delta - wrapAmount);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Normal movement
|
// Normal movement
|
||||||
@@ -185,12 +188,20 @@ 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, 2pi]
|
* @return Home voltage in range [0, wrapAmount]
|
||||||
*/
|
*/
|
||||||
public double getHomeVoltage() {
|
public double getHomeVoltage() {
|
||||||
return homeVoltage;
|
return homeVoltage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pot wraparound amount.
|
||||||
|
* @return Wrap amount in radians
|
||||||
|
*/
|
||||||
|
public double getWrapAmount() {
|
||||||
|
return wrapAmount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emergency stop - immediately stops motor and cancels movement.
|
* Emergency stop - immediately stops motor and cancels movement.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,11 +11,20 @@ public class FtcPotentiometer extends MockPotentiometer {
|
|||||||
private final double maxVoltage;
|
private final double maxVoltage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create potentiometer adapter.
|
* Create potentiometer adapter with default 2pi wraparound.
|
||||||
* @param pot The real FTC analog input from hardwareMap
|
* @param pot The real FTC analog input from hardwareMap
|
||||||
*/
|
*/
|
||||||
public FtcPotentiometer(AnalogInput pot) {
|
public FtcPotentiometer(AnalogInput pot) {
|
||||||
super();
|
this(pot, 2 * Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create potentiometer adapter with custom wraparound.
|
||||||
|
* @param pot The real FTC analog input from hardwareMap
|
||||||
|
* @param wrapAmount Voltage value at which pot wraps (in radians)
|
||||||
|
*/
|
||||||
|
public FtcPotentiometer(AnalogInput pot, double wrapAmount) {
|
||||||
|
super(wrapAmount);
|
||||||
this.pot = pot;
|
this.pot = pot;
|
||||||
this.maxVoltage = pot.getMaxVoltage(); // Usually 3.3V
|
this.maxVoltage = pot.getMaxVoltage(); // Usually 3.3V
|
||||||
}
|
}
|
||||||
@@ -25,9 +34,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, 2pi] range
|
// Scale to [0, wrapAmount] range
|
||||||
// Assumes pot uses full voltage range (0 to maxVoltage)
|
// Assumes pot uses full voltage range (0 to maxVoltage)
|
||||||
return (rawVoltage / maxVoltage) * 2 * Math.PI;
|
return (rawVoltage / maxVoltage) * getWrapAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,19 +1,32 @@
|
|||||||
package org.firstinspires.ftc.teamcode.subsystems.chute;
|
package org.firstinspires.ftc.teamcode.subsystems.chute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple mock potentiometer with wraparound at 2pi.
|
* Simple mock potentiometer with configurable wraparound.
|
||||||
*/
|
*/
|
||||||
public class MockPotentiometer {
|
public class MockPotentiometer {
|
||||||
private double position;
|
private double position;
|
||||||
|
private final double wrapAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create potentiometer with default 2pi wraparound.
|
||||||
|
*/
|
||||||
public MockPotentiometer() {
|
public MockPotentiometer() {
|
||||||
|
this(2 * Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create potentiometer with custom wraparound amount.
|
||||||
|
* @param wrapAmount Voltage at which pot wraps back to 0
|
||||||
|
*/
|
||||||
|
public MockPotentiometer(double wrapAmount) {
|
||||||
this.position = 0.0;
|
this.position = 0.0;
|
||||||
|
this.wrapAmount = wrapAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getVoltage() {
|
public double getVoltage() {
|
||||||
// Wrap to [0, 2pi]
|
// Wrap to [0, wrapAmount]
|
||||||
double wrapped = position % (2 * Math.PI);
|
double wrapped = position % wrapAmount;
|
||||||
if (wrapped < 0) wrapped += 2 * Math.PI;
|
if (wrapped < 0) wrapped += wrapAmount;
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,4 +37,8 @@ public class MockPotentiometer {
|
|||||||
public void updatePosition(double delta) {
|
public void updatePosition(double delta) {
|
||||||
this.position += delta;
|
this.position += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getWrapAmount() {
|
||||||
|
return wrapAmount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -226,4 +226,44 @@ public class ChuteTest {
|
|||||||
assertTrue(downPos < 1.5, "Should move back down");
|
assertTrue(downPos < 1.5, "Should move back down");
|
||||||
assertTrue(downPos < upPos, "Down position should be less than up");
|
assertTrue(downPos < upPos, "Down position should be less than up");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test custom wraparound amount (3.0 radians instead of 2pi).
|
||||||
|
* Verifies controller correctly handles non-standard pot configurations.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCustomWrapAmount() {
|
||||||
|
// Create chute with 3.0 radian wraparound (instead of default 2pi)
|
||||||
|
Chute chute = new Chute(20.0, 3.0);
|
||||||
|
|
||||||
|
// Home
|
||||||
|
chute.getMotor().setPosition(0.2);
|
||||||
|
chute.getPot().setPosition(0.2);
|
||||||
|
chute.home();
|
||||||
|
for (int i = 0; i < 200; i++) {
|
||||||
|
chute.update(DT);
|
||||||
|
if (chute.isHomed()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(chute.isHomed(), "Should be homed");
|
||||||
|
|
||||||
|
// Move to 2.5 wraps (2.5 * 3.0 = 7.5 radians)
|
||||||
|
double target = 2.5 * 3.0;
|
||||||
|
chute.setTargetPosition(target);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2000; i++) {
|
||||||
|
chute.update(DT);
|
||||||
|
if (chute.isAtTarget()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should track through wraps correctly
|
||||||
|
assertTrue(chute.getPosition() > 2.0 * 3.0,
|
||||||
|
"Position should be > 2 wraps (6.0), got: " + chute.getPosition());
|
||||||
|
assertTrue(Math.abs(chute.getPosition() - target) < 1.0,
|
||||||
|
"Position should be near target, expected: " + target + ", got: " + chute.getPosition());
|
||||||
|
|
||||||
|
// Verify pot actually wraps at 3.0
|
||||||
|
assertEquals(3.0, chute.getPot().getWrapAmount(), EPSILON,
|
||||||
|
"Pot should wrap at 3.0 radians");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user