[wpilib] Rewrite DutyCycleEncoder and AnalogEncoder (#6398)

This commit is contained in:
Thad House
2024-05-24 11:53:56 -07:00
committed by GitHub
parent 294c9946ae
commit d05c7c125b
18 changed files with 638 additions and 883 deletions

View File

@@ -8,130 +8,117 @@
#include <wpi/sendable/SendableBuilder.h>
#include "frc/AnalogInput.h"
#include "frc/Counter.h"
#include "frc/Errors.h"
#include "frc/MathUtil.h"
#include "frc/RobotController.h"
using namespace frc;
AnalogEncoder::~AnalogEncoder() {}
AnalogEncoder::AnalogEncoder(int channel)
: AnalogEncoder(std::make_shared<AnalogInput>(channel)) {}
AnalogEncoder::AnalogEncoder(AnalogInput& analogInput)
: m_analogInput{&analogInput, wpi::NullDeleter<AnalogInput>{}},
m_analogTrigger{m_analogInput.get()},
m_counter{} {
Init();
: m_analogInput{&analogInput, wpi::NullDeleter<AnalogInput>{}} {
Init(1.0, 0.0);
}
AnalogEncoder::AnalogEncoder(AnalogInput* analogInput)
: m_analogInput{analogInput, wpi::NullDeleter<AnalogInput>{}},
m_analogTrigger{m_analogInput.get()},
m_counter{} {
Init();
: m_analogInput{analogInput, wpi::NullDeleter<AnalogInput>{}} {
Init(1.0, 0.0);
}
AnalogEncoder::AnalogEncoder(std::shared_ptr<AnalogInput> analogInput)
: m_analogInput{std::move(analogInput)},
m_analogTrigger{m_analogInput.get()},
m_counter{} {
Init();
: m_analogInput{std::move(analogInput)} {
Init(1.0, 0.0);
}
void AnalogEncoder::Init() {
AnalogEncoder::AnalogEncoder(int channel, double fullRange, double expectedZero)
: AnalogEncoder(std::make_shared<AnalogInput>(channel), fullRange,
expectedZero) {}
AnalogEncoder::AnalogEncoder(AnalogInput& analogInput, double fullRange,
double expectedZero)
: m_analogInput{&analogInput, wpi::NullDeleter<AnalogInput>{}} {
Init(fullRange, expectedZero);
}
AnalogEncoder::AnalogEncoder(AnalogInput* analogInput, double fullRange,
double expectedZero)
: m_analogInput{analogInput, wpi::NullDeleter<AnalogInput>{}} {
Init(fullRange, expectedZero);
}
AnalogEncoder::AnalogEncoder(std::shared_ptr<AnalogInput> analogInput,
double fullRange, double expectedZero)
: m_analogInput{std::move(analogInput)} {
Init(fullRange, expectedZero);
}
void AnalogEncoder::Init(double fullRange, double expectedZero) {
m_simDevice = hal::SimDevice{"AnalogEncoder", m_analogInput->GetChannel()};
if (m_simDevice) {
m_simPosition = m_simDevice.CreateDouble("Position", false, 0.0);
m_simAbsolutePosition =
m_simDevice.CreateDouble("absPosition", hal::SimDevice::kInput, 0.0);
}
m_analogTrigger.SetLimitsVoltage(1.25, 3.75);
m_counter.SetUpSource(
m_analogTrigger.CreateOutput(AnalogTriggerType::kRisingPulse));
m_counter.SetDownSource(
m_analogTrigger.CreateOutput(AnalogTriggerType::kFallingPulse));
m_fullRange = fullRange;
m_expectedZero = expectedZero;
wpi::SendableRegistry::AddLW(this, "DutyCycle Encoder",
wpi::SendableRegistry::AddLW(this, "Analog Encoder",
m_analogInput->GetChannel());
}
static bool DoubleEquals(double a, double b) {
constexpr double epsilon = 0.00001;
return std::abs(a - b) < epsilon;
}
units::turn_t AnalogEncoder::Get() const {
double AnalogEncoder::Get() const {
if (m_simPosition) {
return units::turn_t{m_simPosition.Get()};
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, error
for (int i = 0; i < 10; i++) {
auto counter = m_counter.Get();
auto pos = m_analogInput->GetVoltage();
auto counter2 = m_counter.Get();
auto pos2 = m_analogInput->GetVoltage();
if (counter == counter2 && DoubleEquals(pos, pos2)) {
pos = pos / frc::RobotController::GetVoltage5V();
units::turn_t turns{counter + pos - m_positionOffset};
m_lastPosition = turns;
return turns;
}
double analog = m_analogInput->GetVoltage();
double pos = analog / RobotController::GetVoltage5V();
// Map sensor range if range isn't full
pos = MapSensorRange(pos);
// Compute full range and offset
pos = pos * m_fullRange - m_expectedZero;
// Map from 0 - Full Range
double result = InputModulus(pos, 0.0, m_fullRange);
// Invert if necessary
if (m_isInverted) {
return m_fullRange - result;
}
FRC_ReportError(
warn::Warning,
"Failed to read Analog Encoder. Potential Speed Overrun. Returning last "
"value");
return m_lastPosition;
return result;
}
double AnalogEncoder::GetAbsolutePosition() const {
if (m_simAbsolutePosition) {
return m_simAbsolutePosition.Get();
}
return m_analogInput->GetVoltage() / frc::RobotController::GetVoltage5V();
void AnalogEncoder::SetVoltagePercentageRange(double min, double max) {
m_sensorMin = std::clamp(min, 0.0, 1.0);
m_sensorMax = std::clamp(max, 0.0, 1.0);
}
double AnalogEncoder::GetPositionOffset() const {
return m_positionOffset;
}
void AnalogEncoder::SetPositionOffset(double offset) {
m_positionOffset = std::clamp(offset, 0.0, 1.0);
}
void AnalogEncoder::SetDistancePerRotation(double distancePerRotation) {
m_distancePerRotation = distancePerRotation;
}
double AnalogEncoder::GetDistancePerRotation() const {
return m_distancePerRotation;
}
double AnalogEncoder::GetDistance() const {
return Get().value() * GetDistancePerRotation();
}
void AnalogEncoder::Reset() {
m_counter.Reset();
m_positionOffset =
m_analogInput->GetVoltage() / frc::RobotController::GetVoltage5V();
void AnalogEncoder::SetInverted(bool inverted) {
m_isInverted = inverted;
}
int AnalogEncoder::GetChannel() const {
return m_analogInput->GetChannel();
}
double AnalogEncoder::MapSensorRange(double pos) const {
if (pos < m_sensorMin) {
pos = m_sensorMin;
}
if (pos > m_sensorMax) {
pos = m_sensorMax;
}
pos = (pos - m_sensorMin) / (m_sensorMax - m_sensorMin);
return pos;
}
void AnalogEncoder::InitSendable(wpi::SendableBuilder& builder) {
builder.SetSmartDashboardType("AbsoluteEncoder");
builder.AddDoubleProperty(
"Distance", [this] { return this->GetDistance(); }, nullptr);
builder.AddDoubleProperty(
"Distance Per Rotation",
[this] { return this->GetDistancePerRotation(); }, nullptr);
"Position", [this] { return this->Get(); }, nullptr);
}

View File

@@ -7,108 +7,137 @@
#include <wpi/NullDeleter.h>
#include <wpi/sendable/SendableBuilder.h>
#include "frc/Counter.h"
#include "frc/DigitalInput.h"
#include "frc/DigitalSource.h"
#include "frc/DutyCycle.h"
#include "frc/Errors.h"
#include "frc/MathUtil.h"
using namespace frc;
DutyCycleEncoder::DutyCycleEncoder(int channel)
: m_dutyCycle{std::make_shared<DutyCycle>(
std::make_shared<DigitalInput>(channel))} {
Init();
Init(1.0, 0.0);
}
DutyCycleEncoder::DutyCycleEncoder(DutyCycle& dutyCycle)
: m_dutyCycle{&dutyCycle, wpi::NullDeleter<DutyCycle>{}} {
Init();
Init(1.0, 0.0);
}
DutyCycleEncoder::DutyCycleEncoder(DutyCycle* dutyCycle)
: m_dutyCycle{dutyCycle, wpi::NullDeleter<DutyCycle>{}} {
Init();
Init(1.0, 0.0);
}
DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle)
: m_dutyCycle{std::move(dutyCycle)} {
Init();
Init(1.0, 0.0);
}
DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init();
Init(1.0, 0.0);
}
DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init();
Init(1.0, 0.0);
}
DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init();
Init(1.0, 0.0);
}
void DutyCycleEncoder::Init() {
DutyCycleEncoder::DutyCycleEncoder(int channel, double fullRange,
double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(
std::make_shared<DigitalInput>(channel))} {
Init(fullRange, expectedZero);
}
DutyCycleEncoder::DutyCycleEncoder(DutyCycle& dutyCycle, double fullRange,
double expectedZero)
: m_dutyCycle{&dutyCycle, wpi::NullDeleter<DutyCycle>{}} {
Init(fullRange, expectedZero);
}
DutyCycleEncoder::DutyCycleEncoder(DutyCycle* dutyCycle, double fullRange,
double expectedZero)
: m_dutyCycle{dutyCycle, wpi::NullDeleter<DutyCycle>{}} {
Init(fullRange, expectedZero);
}
DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle,
double fullRange, double expectedZero)
: m_dutyCycle{std::move(dutyCycle)} {
Init(fullRange, expectedZero);
}
DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource,
double fullRange, double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(fullRange, expectedZero);
}
DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource,
double fullRange, double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(fullRange, expectedZero);
}
DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource,
double fullRange, double expectedZero)
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Init(fullRange, expectedZero);
}
void DutyCycleEncoder::Init(double fullRange, double expectedZero) {
m_simDevice = hal::SimDevice{"DutyCycle:DutyCycleEncoder",
m_dutyCycle->GetSourceChannel()};
if (m_simDevice) {
m_simPosition =
m_simDevice.CreateDouble("position", hal::SimDevice::kInput, 0.0);
m_simDistancePerRotation = m_simDevice.CreateDouble(
"distance_per_rot", hal::SimDevice::kOutput, 1.0);
m_simAbsolutePosition =
m_simDevice.CreateDouble("absPosition", hal::SimDevice::kInput, 0.0);
m_simPosition = m_simDevice.CreateDouble("Position", false, 0.0);
m_simIsConnected =
m_simDevice.CreateBoolean("connected", hal::SimDevice::kInput, true);
} else {
m_analogTrigger = std::make_unique<AnalogTrigger>(m_dutyCycle.get());
m_analogTrigger->SetLimitsDutyCycle(0.25, 0.75);
m_counter = std::make_unique<Counter>();
m_counter->SetUpSource(
m_analogTrigger->CreateOutput(AnalogTriggerType::kRisingPulse));
m_counter->SetDownSource(
m_analogTrigger->CreateOutput(AnalogTriggerType::kFallingPulse));
m_simDevice.CreateBoolean("Connected", hal::SimDevice::kInput, true);
}
m_fullRange = fullRange;
m_expectedZero = expectedZero;
wpi::SendableRegistry::AddLW(this, "DutyCycle Encoder",
m_dutyCycle->GetSourceChannel());
}
static bool DoubleEquals(double a, double b) {
constexpr double epsilon = 0.00001;
return std::abs(a - b) < epsilon;
}
units::turn_t DutyCycleEncoder::Get() const {
double DutyCycleEncoder::Get() const {
if (m_simPosition) {
return units::turn_t{m_simPosition.Get()};
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, error
for (int i = 0; i < 10; i++) {
auto counter = m_counter->Get();
auto pos = m_dutyCycle->GetOutput();
auto counter2 = m_counter->Get();
auto pos2 = m_dutyCycle->GetOutput();
if (counter == counter2 && DoubleEquals(pos, pos2)) {
// map sensor range
pos = MapSensorRange(pos);
units::turn_t turns{counter + pos - m_positionOffset};
m_lastPosition = turns;
return turns;
}
double pos;
// Compute output percentage (0-1)
if (m_period.value() == 0.0) {
pos = m_dutyCycle->GetOutput();
} else {
auto highTime = m_dutyCycle->GetHighTime();
pos = highTime / m_period;
}
FRC_ReportError(
warn::Warning,
"Failed to read DutyCycle Encoder. Potential Speed Overrun. Returning "
"last value");
return m_lastPosition;
// Map sensor range if range isn't full
pos = MapSensorRange(pos);
// Compute full range and offset
pos = pos * m_fullRange - m_expectedZero;
// Map from 0 - Full Range
double result = InputModulus(pos, 0.0, m_fullRange);
// Invert if necessary
if (m_isInverted) {
return m_fullRange - result;
}
return result;
}
double DutyCycleEncoder::MapSensorRange(double pos) const {
@@ -122,54 +151,15 @@ double DutyCycleEncoder::MapSensorRange(double pos) const {
return pos;
}
double DutyCycleEncoder::GetAbsolutePosition() const {
if (m_simAbsolutePosition) {
return m_simAbsolutePosition.Get();
}
return MapSensorRange(m_dutyCycle->GetOutput());
}
double DutyCycleEncoder::GetPositionOffset() const {
return m_positionOffset;
}
void DutyCycleEncoder::SetPositionOffset(double offset) {
m_positionOffset = std::clamp(offset, 0.0, 1.0);
}
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);
}
double DutyCycleEncoder::GetDistancePerRotation() const {
return m_distancePerRotation;
}
double DutyCycleEncoder::GetDistance() const {
return Get().value() * GetDistancePerRotation();
}
int DutyCycleEncoder::GetFrequency() const {
return m_dutyCycle->GetFrequency();
}
void DutyCycleEncoder::Reset() {
if (m_counter) {
m_counter->Reset();
}
if (m_simPosition) {
m_simPosition.Set(0);
}
m_positionOffset = GetAbsolutePosition();
}
bool DutyCycleEncoder::IsConnected() const {
if (m_simIsConnected) {
return m_simIsConnected.Get();
@@ -184,6 +174,18 @@ void DutyCycleEncoder::SetConnectedFrequencyThreshold(int frequency) {
m_frequencyThreshold = frequency;
}
void DutyCycleEncoder::SetInverted(bool inverted) {
m_isInverted = inverted;
}
void DutyCycleEncoder::SetAssumedFrequency(units::hertz_t frequency) {
if (frequency.value() == 0) {
m_period = 0_s;
} else {
m_period = 1.0 / frequency;
}
}
int DutyCycleEncoder::GetFPGAIndex() const {
return m_dutyCycle->GetFPGAIndex();
}
@@ -195,10 +197,7 @@ int DutyCycleEncoder::GetSourceChannel() const {
void DutyCycleEncoder::InitSendable(wpi::SendableBuilder& builder) {
builder.SetSmartDashboardType("AbsoluteEncoder");
builder.AddDoubleProperty(
"Distance", [this] { return this->GetDistance(); }, nullptr);
builder.AddDoubleProperty(
"Distance Per Rotation",
[this] { return this->GetDistancePerRotation(); }, nullptr);
"Position", [this] { return this->Get(); }, nullptr);
builder.AddDoubleProperty(
"Is Connected", [this] { return this->IsConnected(); }, nullptr);
}

View File

@@ -14,18 +14,10 @@ AnalogEncoderSim::AnalogEncoderSim(const frc::AnalogEncoder& encoder) {
m_positionSim = deviceSim.GetDouble("Position");
}
void AnalogEncoderSim::SetPosition(frc::Rotation2d angle) {
SetTurns(angle.Degrees());
void AnalogEncoderSim::Set(double value) {
m_positionSim.Set(value);
}
void AnalogEncoderSim::SetTurns(units::turn_t turns) {
m_positionSim.Set(turns.value());
}
units::turn_t AnalogEncoderSim::GetTurns() {
return units::turn_t{m_positionSim.Get()};
}
frc::Rotation2d AnalogEncoderSim::GetPosition() {
return units::radian_t{GetTurns()};
double AnalogEncoderSim::Get() {
return m_positionSim.Get();
}

View File

@@ -14,38 +14,16 @@ DutyCycleEncoderSim::DutyCycleEncoderSim(const frc::DutyCycleEncoder& encoder)
DutyCycleEncoderSim::DutyCycleEncoderSim(int channel) {
frc::sim::SimDeviceSim deviceSim{"DutyCycle:DutyCycleEncoder", channel};
m_simPosition = deviceSim.GetDouble("position");
m_simDistancePerRotation = deviceSim.GetDouble("distance_per_rot");
m_simAbsolutePosition = deviceSim.GetDouble("absPosition");
m_simIsConnected = deviceSim.GetBoolean("connected");
m_simPosition = deviceSim.GetDouble("Position");
m_simIsConnected = deviceSim.GetBoolean("Connected");
}
double DutyCycleEncoderSim::Get() {
return m_simPosition.Get();
}
void DutyCycleEncoderSim::Set(units::turn_t turns) {
m_simPosition.Set(turns.value());
}
double DutyCycleEncoderSim::GetDistance() {
return m_simPosition.Get() * m_simDistancePerRotation.Get();
}
void DutyCycleEncoderSim::SetDistance(double distance) {
m_simPosition.Set(distance / m_simDistancePerRotation.Get());
}
double DutyCycleEncoderSim::GetAbsolutePosition() {
return m_simAbsolutePosition.Get();
}
void DutyCycleEncoderSim::SetAbsolutePosition(double position) {
m_simAbsolutePosition.Set(position);
}
double DutyCycleEncoderSim::GetDistancePerRotation() {
return m_simDistancePerRotation.Get();
void DutyCycleEncoderSim::Set(double value) {
m_simPosition.Set(value);
}
bool DutyCycleEncoderSim::IsConnected() {

View File

@@ -8,13 +8,9 @@
#include <hal/SimDevice.h>
#include <hal/Types.h>
#include <units/angle.h>
#include <wpi/sendable/Sendable.h>
#include <wpi/sendable/SendableHelper.h>
#include "frc/AnalogTrigger.h"
#include "frc/Counter.h"
namespace frc {
class AnalogInput;
@@ -27,6 +23,8 @@ class AnalogEncoder : public wpi::Sendable,
/**
* Construct a new AnalogEncoder attached to a specific AnalogIn channel.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param channel the analog input channel to attach to
*/
explicit AnalogEncoder(int channel);
@@ -34,6 +32,8 @@ class AnalogEncoder : public wpi::Sendable,
/**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param analogInput the analog input to attach to
*/
explicit AnalogEncoder(AnalogInput& analogInput);
@@ -41,6 +41,8 @@ class AnalogEncoder : public wpi::Sendable,
/**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param analogInput the analog input to attach to
*/
explicit AnalogEncoder(AnalogInput* analogInput);
@@ -48,90 +50,79 @@ class AnalogEncoder : public wpi::Sendable,
/**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param analogInput the analog input to attach to
*/
explicit AnalogEncoder(std::shared_ptr<AnalogInput> analogInput);
~AnalogEncoder() override = default;
/**
* Construct a new AnalogEncoder attached to a specific AnalogIn channel.
*
* @param channel the analog input channel to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
AnalogEncoder(int channel, double fullRange, double expectedZero);
/**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* @param analogInput the analog input to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
AnalogEncoder(AnalogInput& analogInput, double fullRange,
double expectedZero);
/**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* @param analogInput the analog input to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
AnalogEncoder(AnalogInput* analogInput, double fullRange,
double expectedZero);
/**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* @param analogInput the analog input to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
AnalogEncoder(std::shared_ptr<AnalogInput> analogInput, double fullRange,
double expectedZero);
~AnalogEncoder() override;
AnalogEncoder(AnalogEncoder&&) = default;
AnalogEncoder& operator=(AnalogEncoder&&) = default;
/**
* Reset the Encoder distance to zero.
* Get the encoder value.
*
* @return the encoder value scaled by the full range input
*/
void Reset();
double Get() const;
/**
* Get the encoder value since the last reset.
* Set the encoder voltage percentage range. Analog sensors are not always
* fully stable at the end of their travel ranges. Shrinking this range down
* can help mitigate issues with that.
*
* This is reported in rotations since the last reset.
*
* @return the encoder value in rotations
* @param min minimum voltage percentage (0-1 range)
* @param max maximum voltage percentage (0-1 range)
*/
units::turn_t Get() const;
void SetVoltagePercentageRange(double min, double max);
/**
* Get the absolute position of the analog encoder.
* Set if this encoder is inverted.
*
* <p>GetAbsolutePosition() - GetPositionOffset() will give an encoder
* absolute position relative to the last reset. This could potentially be
* negative, which needs to be accounted for.
*
* <p>This will not account for rollovers, and will always be just the raw
* absolute position.
*
* @return the absolute position
* @param inverted true to invert the encoder, false otherwise
*/
double GetAbsolutePosition() const;
/**
* Get the offset of position relative to the last reset.
*
* GetAbsolutePosition() - GetPositionOffset() will give an encoder absolute
* position relative to the last reset. This could potentially be negative,
* which needs to be accounted for.
*
* @return the position offset
*/
double GetPositionOffset() const;
/**
* Set the position offset.
*
* <p>This must be in the range of 0-1.
*
* @param offset the offset
*/
void SetPositionOffset(double offset);
/**
* 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 far the mechanism travels in 1
* rotation of the encoder, and factor in gearing reductions following the
* encoder shaft. This distance can be in any units you like, linear or
* angular.
*
* @param distancePerRotation the distance per rotation of the encoder
*/
void SetDistancePerRotation(double distancePerRotation);
/**
* Get the distance per rotation for this encoder.
*
* @return The scale factor that will be used to convert rotation to useful
* units.
*/
double GetDistancePerRotation() const;
/**
* Get the distance the sensor has driven since the last reset as scaled by
* the value from SetDistancePerRotation.
*
* @return The distance driven since the last reset
*/
double GetDistance() const;
void SetInverted(bool inverted);
/**
* Get the channel number.
@@ -143,17 +134,17 @@ class AnalogEncoder : public wpi::Sendable,
void InitSendable(wpi::SendableBuilder& builder) override;
private:
void Init();
void Init(double fullRange, double expectedZero);
double MapSensorRange(double pos) const;
std::shared_ptr<AnalogInput> m_analogInput;
AnalogTrigger m_analogTrigger;
Counter m_counter;
double m_positionOffset = 0;
double m_distancePerRotation = 1.0;
mutable units::turn_t m_lastPosition{0.0};
double m_fullRange;
double m_expectedZero;
double m_sensorMin{0.0};
double m_sensorMax{1.0};
bool m_isInverted{false};
hal::SimDevice m_simDevice;
hal::SimDouble m_simPosition;
hal::SimDouble m_simAbsolutePosition;
};
} // namespace frc

View File

@@ -8,13 +8,11 @@
#include <hal/SimDevice.h>
#include <hal/Types.h>
#include <units/angle.h>
#include <units/frequency.h>
#include <units/time.h>
#include <wpi/sendable/Sendable.h>
#include <wpi/sendable/SendableHelper.h>
#include "frc/AnalogTrigger.h"
#include "frc/Counter.h"
namespace frc {
class DutyCycle;
class DigitalSource;
@@ -30,6 +28,8 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder on a specific channel.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param channel the channel to attach to
*/
explicit DutyCycleEncoder(int channel);
@@ -37,6 +37,8 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder attached to an existing DutyCycle object.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param dutyCycle the duty cycle to attach to
*/
explicit DutyCycleEncoder(DutyCycle& dutyCycle);
@@ -44,6 +46,8 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder attached to an existing DutyCycle object.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param dutyCycle the duty cycle to attach to
*/
explicit DutyCycleEncoder(DutyCycle* dutyCycle);
@@ -51,6 +55,8 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder attached to an existing DutyCycle object.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param dutyCycle the duty cycle to attach to
*/
explicit DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle);
@@ -58,6 +64,8 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder attached to a DigitalSource object.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param digitalSource the digital source to attach to
*/
explicit DutyCycleEncoder(DigitalSource& digitalSource);
@@ -65,6 +73,8 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder attached to a DigitalSource object.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param digitalSource the digital source to attach to
*/
explicit DutyCycleEncoder(DigitalSource* digitalSource);
@@ -72,10 +82,79 @@ class DutyCycleEncoder : public wpi::Sendable,
/**
* Construct a new DutyCycleEncoder attached to a DigitalSource object.
*
* <p>This has a fullRange of 1 and an expectedZero of 0.
*
* @param digitalSource the digital source to attach to
*/
explicit DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource);
/**
* Construct a new DutyCycleEncoder on a specific channel.
*
* @param channel the channel to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(int channel, double fullRange, double expectedZero);
/**
* Construct a new DutyCycleEncoder attached to an existing DutyCycle object.
*
* @param dutyCycle the duty cycle to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(DutyCycle& dutyCycle, double fullRange, double expectedZero);
/**
* Construct a new DutyCycleEncoder attached to an existing DutyCycle object.
*
* @param dutyCycle the duty cycle to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(DutyCycle* dutyCycle, double fullRange, double expectedZero);
/**
* Construct a new DutyCycleEncoder attached to an existing DutyCycle object.
*
* @param dutyCycle the duty cycle to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle, double fullRange,
double expectedZero);
/**
* Construct a new DutyCycleEncoder attached to a DigitalSource object.
*
* @param digitalSource the digital source to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(DigitalSource& digitalSource, double fullRange,
double expectedZero);
/**
* Construct a new DutyCycleEncoder attached to a DigitalSource object.
*
* @param digitalSource the digital source to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(DigitalSource* digitalSource, double fullRange,
double expectedZero);
/**
* Construct a new DutyCycleEncoder attached to a DigitalSource object.
*
* @param digitalSource the digital source to attach to
* @param fullRange the value to report at maximum travel
* @param expectedZero the reading where you would expect a 0 from get()
*/
DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource,
double fullRange, double expectedZero);
~DutyCycleEncoder() override = default;
DutyCycleEncoder(DutyCycleEncoder&&) = default;
@@ -108,52 +187,11 @@ class DutyCycleEncoder : public wpi::Sendable,
void SetConnectedFrequencyThreshold(int frequency);
/**
* Reset the Encoder distance to zero.
* Get the encoder value.
*
* @return the encoder value scaled by the full range input
*/
void Reset();
/**
* Get the encoder value since the last reset.
*
* This is reported in rotations since the last reset.
*
* @return the encoder value in rotations
*/
units::turn_t Get() const;
/**
* Get the absolute position of the duty cycle encoder encoder.
*
* <p>GetAbsolutePosition() - GetPositionOffset() will give an encoder
* absolute position relative to the last reset. This could potentially be
* negative, which needs to be accounted for.
*
* <p>This will not account for rollovers, and will always be just the raw
* absolute position.
*
* @return the absolute position
*/
double GetAbsolutePosition() const;
/**
* Get the offset of position relative to the last reset.
*
* GetAbsolutePosition() - GetPositionOffset() will give an encoder absolute
* position relative to the last reset. This could potentially be negative,
* which needs to be accounted for.
*
* @return the position offset
*/
double GetPositionOffset() const;
/**
* Set the position offset.
*
* <p>This must be in the range of 0-1.
*
* @param offset the offset
*/
void SetPositionOffset(double offset);
double Get() const;
/**
* Set the encoder duty cycle range. As the encoder needs to maintain a duty
@@ -171,32 +209,24 @@ class DutyCycleEncoder : public wpi::Sendable,
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
* encoder. Set this value based on the how far the mechanism travels in 1
* rotation of the encoder, and factor in gearing reductions following the
* encoder shaft. This distance can be in any units you like, linear or
* angular.
* Sets the assumed frequency of the connected device.
*
* @param distancePerRotation the distance per rotation of the encoder
* <p>By default, the DutyCycle engine has to compute the frequency of the
* input signal. This can result in both delayed readings and jumpy readings.
* To solve this, you can pass the expected frequency of the sensor to this
* function. This will use that frequency to compute the DutyCycle percentage,
* rather than the computed frequency.
*
* @param frequency the assumed frequency of the sensor
*/
void SetDistancePerRotation(double distancePerRotation);
void SetAssumedFrequency(units::hertz_t frequency);
/**
* Get the distance per rotation for this encoder.
* Set if this encoder is inverted.
*
* @return The scale factor that will be used to convert rotation to useful
* units.
* @param inverted true to invert the encoder, false otherwise
*/
double GetDistancePerRotation() const;
/**
* Get the distance the sensor has driven since the last reset as scaled by
* the value from SetDistancePerRotation.
*
* @return The distance driven since the last reset
*/
double GetDistance() const;
void SetInverted(bool inverted);
/**
* Get the FPGA index for the DutyCycleEncoder.
@@ -215,23 +245,20 @@ class DutyCycleEncoder : public wpi::Sendable,
void InitSendable(wpi::SendableBuilder& builder) override;
private:
void Init();
void Init(double fullRange, double expectedZero);
double MapSensorRange(double pos) const;
std::shared_ptr<DutyCycle> m_dutyCycle;
std::unique_ptr<AnalogTrigger> m_analogTrigger;
std::unique_ptr<Counter> m_counter;
int m_frequencyThreshold = 100;
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;
double m_fullRange;
double m_expectedZero;
units::second_t m_period{0_s};
double m_sensorMin{0.0};
double m_sensorMax{1.0};
bool m_isInverted{false};
hal::SimDevice m_simDevice;
hal::SimDouble m_simPosition;
hal::SimDouble m_simAbsolutePosition;
hal::SimDouble m_simDistancePerRotation;
hal::SimBoolean m_simIsConnected;
};
} // namespace frc

View File

@@ -28,28 +28,16 @@ class AnalogEncoderSim {
explicit AnalogEncoderSim(const AnalogEncoder& encoder);
/**
* Set the position using an Rotation2d.
* Set the position.
*
* @param angle The angle.
* @param value The position.
*/
void SetPosition(Rotation2d angle);
/**
* Set the position of the encoder.
*
* @param turns The position.
*/
void SetTurns(units::turn_t turns);
void Set(double value);
/**
* Get the simulated position.
*/
units::turn_t GetTurns();
/**
* Get the position as a Rotation2d.
*/
Rotation2d GetPosition();
double Get();
private:
hal::SimDouble m_positionSim;

View File

@@ -33,55 +33,18 @@ class DutyCycleEncoderSim {
explicit DutyCycleEncoderSim(int channel);
/**
* Get the position in turns.
* Get the position.
*
* @return The position.
*/
double Get();
/**
* Set the position in turns.
* Set the position.
*
* @param turns The position.
* @param value The position.
*/
void Set(units::turn_t turns);
/**
* Get the distance.
*
* @return The distance.
*/
double GetDistance();
/**
* Set the distance.
*
* @param distance The distance.
*/
void SetDistance(double distance);
/**
* Get the absolute position.
*
* @return The absolute position
*/
double GetAbsolutePosition();
/**
* Set the absolute position.
*
* @param position The absolute position
*/
void SetAbsolutePosition(double position);
/**
* Get the distance per rotation for this encoder.
*
* @return The scale factor that will be used to convert rotation to useful
* units.
*/
double GetDistancePerRotation();
void Set(double value);
/**
* Get if the encoder is connected.
@@ -99,8 +62,6 @@ class DutyCycleEncoderSim {
private:
hal::SimDouble m_simPosition;
hal::SimDouble m_simDistancePerRotation;
hal::SimDouble m_simAbsolutePosition;
hal::SimBoolean m_simIsConnected;
};