Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite DutyCycleEncoder and AnalogEncoder #6398

Merged
merged 33 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7c248d3
Deprecate AbsoluteEncoder classes, Replace DCE with DutyCyclePotentio…
ThadHouse Feb 25, 2024
d048b86
Keep with AnalogEncoder and DutyCycleEncoder
ThadHouse Feb 26, 2024
797eb84
Add inversion
ThadHouse Feb 26, 2024
5a4d3fd
Fix up example
ThadHouse Feb 29, 2024
dd2332d
Fixup C++
ThadHouse Feb 29, 2024
1e02bbb
Fix unused variable
ThadHouse Mar 2, 2024
d33ba3c
Add rollover support
ThadHouse Mar 2, 2024
85adf21
Formatting fixes
github-actions[bot] Mar 2, 2024
413b945
Analog Encoder Destructor
ThadHouse Mar 3, 2024
bdceac9
Docs
ThadHouse Mar 3, 2024
88298ee
Docs and format
ThadHouse Mar 3, 2024
cff871a
More format
ThadHouse Mar 3, 2024
ed0c807
Formatting
ThadHouse Mar 3, 2024
b5e681c
Format
ThadHouse Mar 3, 2024
0c6b352
Completely remove rollover
ThadHouse Mar 8, 2024
0889fec
Deprecate AbsoluteEncoder classes, Replace DCE with DutyCyclePotentio…
ThadHouse Feb 25, 2024
2ee6216
Keep with AnalogEncoder and DutyCycleEncoder
ThadHouse Feb 26, 2024
0c4b9c7
Add inversion
ThadHouse Feb 26, 2024
85469db
Fix up example
ThadHouse Feb 29, 2024
071b62c
Fixup C++
ThadHouse Feb 29, 2024
f48c093
Fix unused variable
ThadHouse Mar 2, 2024
a9a353f
Add rollover support
ThadHouse Mar 2, 2024
1d71776
Formatting fixes
github-actions[bot] Mar 2, 2024
e9a0339
Analog Encoder Destructor
ThadHouse Mar 3, 2024
45da00d
Docs
ThadHouse Mar 3, 2024
202a9e8
Docs and format
ThadHouse Mar 3, 2024
8d9c427
More format
ThadHouse Mar 3, 2024
af23048
Formatting
ThadHouse Mar 3, 2024
3622c01
Format
ThadHouse Mar 3, 2024
0b1e8a8
Completely remove rollover
ThadHouse Mar 8, 2024
879c396
Merge branch 'absencoderreplace' of https://github.com/thadhouse/allw…
ThadHouse Apr 29, 2024
07e4f0f
Merge remote-tracking branch 'wpilibsuite/main' into absencoderreplace
ThadHouse May 5, 2024
ee36569
Merge remote-tracking branch 'wpilibsuite/main' into absencoderreplace
ThadHouse May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions myRobot/src/main/java/frc/robot/MyRobot.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@

package frc.robot;

import edu.wpi.first.wpilibj.DutyCyclePotentiometer;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;

public class MyRobot extends TimedRobot {
DutyCyclePotentiometer pot;
/**
* This function is run when the robot is first started up and should be used for any
* initialization code.
*/
@Override
public void robotInit() {}
public void robotInit() {
pot = new DutyCyclePotentiometer(0);
pot.setAssumedFrequency(967.77);
}

/** This function is run once each time the robot enters autonomous mode. */
@Override
Expand All @@ -36,5 +42,8 @@ public void testPeriodic() {}

/** This function is called periodically during all modes. */
@Override
public void robotPeriodic() {}
public void robotPeriodic() {
SmartDashboard.putNumber("DC", pot.get());
SmartDashboard.putNumber("Freq", pot.getFrequency());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@
import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;

/** Class for supporting continuous analog encoders, such as the US Digital MA3. */
/**
* Class for supporting continuous analog encoders, such as the US Digital MA3.
*
* @deprecated Use AnalogPotentiometer instead. If rollover support is necessary,
* use enableRolloverSupport() on AnalogPotentiometer.
*/
@Deprecated(since = "2025", forRemoval = true)
public class AnalogEncoder implements Sendable, AutoCloseable {
private final AnalogInput m_analogInput;
private AnalogTrigger m_analogTrigger;
Expand Down
174 changes: 142 additions & 32 deletions wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,63 @@

package edu.wpi.first.wpilibj;

import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimDevice.Direction;
import edu.wpi.first.util.sendable.Sendable;
import edu.wpi.first.util.sendable.SendableBuilder;
import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;

/**
* Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that
* corresponds to a position. The position is in whichever units you choose, by way of the scaling
* Class for reading analog potentiometers. Analog potentiometers read in an
* analog voltage that
* corresponds to a position. The position is in whichever units you choose, by
* way of the scaling
* and offset constants passed to the constructor.
*/
public class AnalogPotentiometer implements Sendable, AutoCloseable {
private AnalogInput m_analogInput;
private boolean m_initAnalogInput;
private double m_fullRange;
private double m_offset;
private AnalogTrigger m_rotationTrigger;
private Counter m_rotationCounter;
private double m_lastPosition;

private SimDevice m_simDevice;
private SimDouble m_simPosition;

private void init() {
m_simDevice = SimDevice.create("AnalogPotentiometer", m_analogInput.getChannel());

if (m_simDevice != null) {
m_simPosition = m_simDevice.createDouble("Position", Direction.kInput, 0.0);
}
}

/**
* AnalogPotentiometer constructor.
*
* <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
* have a 270 degree potentiometer, and you want the output to be degrees with the halfway point
* as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
* point after scaling is 135 degrees. This will calculate the result from the fullRange times the
* <p>
* Use the fullRange and offset values so that the output produces meaningful
* values. I.E: you
* have a 270 degree potentiometer, and you want the output to be degrees with
* the halfway point
* as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0
* since the halfway
* point after scaling is 135 degrees. This will calculate the result from the
* fullRange times the
* fraction of the supply voltage, plus the offset.
*
* @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board
* and 4-7 are on the MXP port.
* @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
* @param offset The offset to add to the scaled value for controlling the zero value
* @param channel The analog input channel this potentiometer is plugged into.
* 0-3 are on-board
* and 4-7 are on the MXP port.
* @param fullRange The scaling to multiply the fraction by to get a meaningful
* unit.
* @param offset The offset to add to the scaled value for controlling the
* zero value
*/
@SuppressWarnings("this-escape")
public AnalogPotentiometer(final int channel, double fullRange, double offset) {
Expand All @@ -43,37 +72,51 @@ public AnalogPotentiometer(final int channel, double fullRange, double offset) {
/**
* AnalogPotentiometer constructor.
*
* <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
* have a 270 degree potentiometer, and you want the output to be degrees with the halfway point
* as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
* point after scaling is 135 degrees. This will calculate the result from the fullRange times the
* <p>
* Use the fullRange and offset values so that the output produces meaningful
* values. I.E: you
* have a 270 degree potentiometer, and you want the output to be degrees with
* the halfway point
* as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0
* since the halfway
* point after scaling is 135 degrees. This will calculate the result from the
* fullRange times the
* fraction of the supply voltage, plus the offset.
*
* @param input The {@link AnalogInput} this potentiometer is plugged into.
* @param fullRange The angular value (in desired units) representing the full 0-5V range of the
* input.
* @param offset The angular value (in desired units) representing the angular output at 0V.
* @param input The {@link AnalogInput} this potentiometer is plugged into.
* @param fullRange The angular value (in desired units) representing the full
* 0-5V range of the
* input.
* @param offset The angular value (in desired units) representing the
* angular output at 0V.
*/
@SuppressWarnings("this-escape")
public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) {
SendableRegistry.addLW(this, "AnalogPotentiometer", input.getChannel());
m_analogInput = input;
m_analogInput = requireNonNullParam(input, "input", "AnalogPotentiometer");
m_initAnalogInput = false;

m_fullRange = fullRange;
m_offset = offset;

init();
}

/**
* AnalogPotentiometer constructor.
*
* <p>Use the scale value so that the output produces meaningful values. I.E: you have a 270
* degree potentiometer, and you want the output to be degrees with the starting point as 0
* <p>
* Use the scale value so that the output produces meaningful values. I.E: you
* have a 270
* degree potentiometer, and you want the output to be degrees with the starting
* point as 0
* degrees. The scale value is 270.0(degrees).
*
* @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board
* and 4-7 are on the MXP port.
* @param scale The scaling to multiply the voltage by to get a meaningful unit.
* @param channel The analog input channel this potentiometer is plugged into.
* 0-3 are on-board
* and 4-7 are on the MXP port.
* @param scale The scaling to multiply the voltage by to get a meaningful
* unit.
*/
public AnalogPotentiometer(final int channel, double scale) {
this(channel, scale, 0);
Expand All @@ -82,8 +125,11 @@ public AnalogPotentiometer(final int channel, double scale) {
/**
* AnalogPotentiometer constructor.
*
* <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
* have a 270 degree potentiometer, and you want the output to be degrees with the starting point
* <p>
* Use the fullRange and offset values so that the output produces meaningful
* values. I.E: you
* have a 270 degree potentiometer, and you want the output to be degrees with
* the starting point
* as 0 degrees. The scale value is 270.0(degrees).
*
* @param input The {@link AnalogInput} this potentiometer is plugged into.
Expand All @@ -96,10 +142,12 @@ public AnalogPotentiometer(final AnalogInput input, double scale) {
/**
* AnalogPotentiometer constructor.
*
* <p>The potentiometer will return a value between 0 and 1.0.
* <p>
* The potentiometer will return a value between 0 and 1.0.
*
* @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board
* and 4-7 are on the MXP port.
* @param channel The analog input channel this potentiometer is plugged into.
* 0-3 are on-board
* and 4-7 are on the MXP port.
*/
public AnalogPotentiometer(final int channel) {
this(channel, 1, 0);
Expand All @@ -108,27 +156,82 @@ public AnalogPotentiometer(final int channel) {
/**
* AnalogPotentiometer constructor.
*
* <p>The potentiometer will return a value between 0 and 1.0.
* <p>
* The potentiometer will return a value between 0 and 1.0.
*
* @param input The {@link AnalogInput} this potentiometer is plugged into.
*/
public AnalogPotentiometer(final AnalogInput input) {
this(input, 1, 0);
}

private boolean doubleEquals(double a, double b) {
double epsilon = 0.00001d;
return Math.abs(a - b) < epsilon;
}

private double getRollovers() {
if (m_simPosition != null) {
return m_simPosition.get();
}

// As the values are not atomic, keep trying until we get 2 reads of the same
// value. If we don't within 10 attempts, warn
for (int i = 0; i < 10; i++) {
double counter = m_rotationCounter.get();
double pos = m_analogInput.getVoltage();
double counter2 = m_rotationCounter.get();
double pos2 = m_analogInput.getVoltage();
if (counter == counter2 && doubleEquals(pos, pos2)) {
pos = pos / RobotController.getVoltage5V();
double position = (counter + pos) * m_fullRange + m_offset;
m_lastPosition = position;
return position;
}
}

DriverStation.reportWarning(
"Failed to read Analog Encoder. Potential Speed Overrun. Returning last value", false);
return m_lastPosition;
}

/**
* Get the current reading of the potentiometer.
*
* @return The current position of the potentiometer.
*/
public double get() {
if (m_analogInput == null) {
return m_offset;
if (m_simPosition != null) {
return m_simPosition.get();
}

if (m_rotationCounter != null) {
return getRollovers();
}

return (m_analogInput.getAverageVoltage() / RobotController.getVoltage5V()) * m_fullRange
+ m_offset;
}

public void enableRolloverSupport() {
if (m_rotationCounter != null) {
return;
}
m_rotationTrigger = new AnalogTrigger(m_analogInput);
m_rotationCounter = new Counter();

// Limits need to be 25% from each end
m_rotationTrigger.setLimitsVoltage(1.25, 3.75);
m_rotationCounter.setUpSource(m_rotationTrigger, AnalogTriggerType.kRisingPulse);
m_rotationCounter.setDownSource(m_rotationTrigger, AnalogTriggerType.kFallingPulse);
}

public void resetRollovers() {
if (m_rotationCounter != null) {
m_rotationCounter.reset();
}
}

@Override
public void initSendable(SendableBuilder builder) {
if (m_analogInput != null) {
Expand All @@ -140,10 +243,17 @@ public void initSendable(SendableBuilder builder) {
@Override
public void close() {
SendableRegistry.remove(this);
if (m_rotationCounter != null) {
m_rotationCounter.close();
m_rotationTrigger.close();
m_rotationCounter = null;
m_rotationTrigger = null;
}
if (m_initAnalogInput) {
m_analogInput.close();
m_analogInput = null;
m_initAnalogInput = false;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
/**
* Class for supporting duty cycle/PWM encoders, such as the US Digital MA3 with PWM Output, the
* CTRE Mag Encoder, the Rev Hex Encoder, and the AM Mag Encoder.
*
* @deprecated Use DutyCyclePotentiometer instead. Rollover support is not supported for
* duty cycle encoders, there is no reliable way to do so.
*/
@Deprecated(since = "2025", forRemoval = true)
public class DutyCycleEncoder implements Sendable, AutoCloseable {
private final DutyCycle m_dutyCycle;
private boolean m_ownsDutyCycle;
Expand Down
Loading
Loading