diff --git a/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp b/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp index 8e994e9baa..452f5cd729 100644 --- a/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp +++ b/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp @@ -89,6 +89,14 @@ units::turn_t DutyCycleEncoder::Get() const { auto counter2 = m_counter->Get(); auto pos2 = m_dutyCycle->GetOutput(); if (counter == counter2 && pos == pos2) { + // map sensor range + if (pos < m_sensorMin) { + pos = m_sensorMin; + } + if (pos > m_sensorMax) { + pos = m_sensorMax; + } + pos = (pos - m_sensorMin) / (m_sensorMax - m_sensorMin); units::turn_t turns{counter + pos - m_positionOffset}; m_lastPosition = turns; return turns; @@ -102,6 +110,11 @@ units::turn_t DutyCycleEncoder::Get() const { return m_lastPosition; } +void DutyCycleEncoder::SetDutyCycleRange(double min, double max) { + m_sensorMin = std::clamp(min, 0.0, 1.0); + m_sensorMax = std::clamp(max, 0.0, 1.0); +} + void DutyCycleEncoder::SetDistancePerRotation(double distancePerRotation) { m_distancePerRotation = distancePerRotation; m_simDistancePerRotation.Set(distancePerRotation); diff --git a/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h b/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h index ccf56adffd..ab7ded9d3f 100644 --- a/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h +++ b/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h @@ -121,6 +121,21 @@ class DutyCycleEncoder : public wpi::Sendable, */ units::turn_t Get() const; + /** + * Set the encoder duty cycle range. As the encoder needs to maintain a duty + * cycle, the duty cycle cannot go all the way to 0% or all the way to 100%. + * For example, an encoder with a 4096 us period might have a minimum duty + * cycle of 1 us / 4096 us and a maximum duty cycle of 4095 / 4096 us. Setting + * the range will result in an encoder duty cycle less than or equal to the + * minimum being output as 0 rotation, the duty cycle greater than or equal to + * the maximum being output as 1 rotation, and values in between linearly + * scaled from 0 to 1. + * + * @param min minimum duty cycle (0-1 range) + * @param max maximum duty cycle (0-1 range) + */ + void SetDutyCycleRange(double min, double max); + /** * Set the distance per rotation of the encoder. This sets the multiplier used * to determine the distance driven based on the rotation value from the @@ -175,6 +190,8 @@ class DutyCycleEncoder : public wpi::Sendable, double m_positionOffset = 0; double m_distancePerRotation = 1.0; mutable units::turn_t m_lastPosition{0.0}; + double m_sensorMin = 0; + double m_sensorMax = 1; hal::SimDevice m_simDevice; hal::SimDouble m_simPosition; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java index ce5b684a56..c8d5bc9fc8 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java @@ -7,6 +7,7 @@ package edu.wpi.first.wpilibj; import edu.wpi.first.hal.SimBoolean; import edu.wpi.first.hal.SimDevice; import edu.wpi.first.hal.SimDouble; +import edu.wpi.first.math.MathUtil; import edu.wpi.first.util.sendable.Sendable; import edu.wpi.first.util.sendable.SendableBuilder; import edu.wpi.first.util.sendable.SendableRegistry; @@ -26,6 +27,8 @@ public class DutyCycleEncoder implements Sendable, AutoCloseable { private double m_positionOffset; private double m_distancePerRotation = 1.0; private double m_lastPosition; + private double m_sensorMin; + private double m_sensorMax = 1.0; protected SimDevice m_simDevice; protected SimDouble m_simPosition; @@ -105,6 +108,14 @@ public class DutyCycleEncoder implements Sendable, AutoCloseable { double counter2 = m_counter.get(); double pos2 = m_dutyCycle.getOutput(); if (counter == counter2 && pos == pos2) { + // map sensor range + if (pos < m_sensorMin) { + pos = m_sensorMin; + } + if (pos > m_sensorMax) { + pos = m_sensorMax; + } + pos = (pos - m_sensorMin) / (m_sensorMax - m_sensorMin); double position = counter + pos - m_positionOffset; m_lastPosition = position; return position; @@ -129,6 +140,22 @@ public class DutyCycleEncoder implements Sendable, AutoCloseable { return m_positionOffset; } + /** + * Set the encoder duty cycle range. As the encoder needs to maintain a duty cycle, the duty cycle + * cannot go all the way to 0% or all the way to 100%. For example, an encoder with a 4096 us + * period might have a minimum duty cycle of 1 us / 4096 us and a maximum duty cycle of 4095 / + * 4096 us. Setting the range will result in an encoder duty cycle less than or equal to the + * minimum being output as 0 rotation, the duty cycle greater than or equal to the maximum being + * output as 1 rotation, and values in between linearly scaled from 0 to 1. + * + * @param min minimum duty cycle (0-1 range) + * @param max maximum duty cycle (0-1 range) + */ + public void setDutyCycleRange(double min, double max) { + m_sensorMin = MathUtil.clamp(min, 0.0, 1.0); + m_sensorMax = MathUtil.clamp(max, 0.0, 1.0); + } + /** * Set the distance per rotation of the encoder. This sets the multiplier used to determine the * distance driven based on the rotation value from the encoder. Set this value based on the how