2019-11-14 22:51:33 -08:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2020-03-20 16:32:52 -05:00
|
|
|
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
2019-11-14 22:51:33 -08:00
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
#include "frc/DutyCycleEncoder.h"
|
|
|
|
|
|
2020-10-03 12:21:03 -04:00
|
|
|
#include "frc/Base.h"
|
2019-11-14 22:51:33 -08:00
|
|
|
#include "frc/Counter.h"
|
2019-12-06 20:58:04 -08:00
|
|
|
#include "frc/DigitalInput.h"
|
2019-11-14 22:51:33 -08:00
|
|
|
#include "frc/DigitalSource.h"
|
|
|
|
|
#include "frc/DriverStation.h"
|
|
|
|
|
#include "frc/DutyCycle.h"
|
|
|
|
|
#include "frc/smartdashboard/SendableBuilder.h"
|
|
|
|
|
|
|
|
|
|
using namespace frc;
|
|
|
|
|
|
2019-12-06 20:58:04 -08:00
|
|
|
DutyCycleEncoder::DutyCycleEncoder(int channel)
|
|
|
|
|
: m_dutyCycle{std::make_shared<DutyCycle>(
|
2020-03-20 16:32:52 -05:00
|
|
|
std::make_shared<DigitalInput>(channel))} {
|
2019-12-09 21:35:00 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
2019-12-06 20:58:04 -08:00
|
|
|
|
2019-11-14 22:51:33 -08:00
|
|
|
DutyCycleEncoder::DutyCycleEncoder(DutyCycle& dutyCycle)
|
2020-03-20 16:32:52 -05:00
|
|
|
: m_dutyCycle{&dutyCycle, NullDeleter<DutyCycle>{}} {
|
2019-11-14 22:51:33 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DutyCycleEncoder::DutyCycleEncoder(DutyCycle* dutyCycle)
|
2020-03-20 16:32:52 -05:00
|
|
|
: m_dutyCycle{dutyCycle, NullDeleter<DutyCycle>{}} {
|
2019-11-14 22:51:33 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle)
|
2020-03-20 16:32:52 -05:00
|
|
|
: m_dutyCycle{std::move(dutyCycle)} {
|
2019-11-14 22:51:33 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource)
|
2020-03-20 16:32:52 -05:00
|
|
|
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
|
2019-11-14 22:51:33 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource)
|
2020-03-20 16:32:52 -05:00
|
|
|
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
|
2019-11-14 22:51:33 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource)
|
2020-03-20 16:32:52 -05:00
|
|
|
: m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
|
2019-11-14 22:51:33 -08:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DutyCycleEncoder::Init() {
|
2020-12-23 15:54:11 -08:00
|
|
|
m_simDevice = hal::SimDevice{"DutyCycle:DutyCycleEncoder",
|
|
|
|
|
m_dutyCycle->GetSourceChannel()};
|
2019-11-14 22:51:33 -08:00
|
|
|
|
|
|
|
|
if (m_simDevice) {
|
2020-12-23 15:54:11 -08:00
|
|
|
m_simPosition =
|
|
|
|
|
m_simDevice.CreateDouble("position", hal::SimDevice::kInput, 0.0);
|
2020-12-24 12:23:38 -08:00
|
|
|
m_simDistancePerRotation = m_simDevice.CreateDouble(
|
|
|
|
|
"distance_per_rot", hal::SimDevice::kOutput, 1.0);
|
2020-12-23 15:54:11 -08:00
|
|
|
m_simIsConnected =
|
|
|
|
|
m_simDevice.CreateBoolean("connected", hal::SimDevice::kInput, true);
|
2020-03-20 16:32:52 -05:00
|
|
|
} 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));
|
2019-11-14 22:51:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SendableRegistry::GetInstance().AddLW(this, "DutyCycle Encoder",
|
|
|
|
|
m_dutyCycle->GetSourceChannel());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
units::turn_t DutyCycleEncoder::Get() const {
|
|
|
|
|
if (m_simPosition) return units::turn_t{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++) {
|
2020-03-20 16:32:52 -05:00
|
|
|
auto counter = m_counter->Get();
|
2019-11-14 22:51:33 -08:00
|
|
|
auto pos = m_dutyCycle->GetOutput();
|
2020-03-20 16:32:52 -05:00
|
|
|
auto counter2 = m_counter->Get();
|
2019-11-14 22:51:33 -08:00
|
|
|
auto pos2 = m_dutyCycle->GetOutput();
|
|
|
|
|
if (counter == counter2 && pos == pos2) {
|
|
|
|
|
units::turn_t turns{counter + pos - m_positionOffset};
|
|
|
|
|
m_lastPosition = turns;
|
|
|
|
|
return turns;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
frc::DriverStation::GetInstance().ReportWarning(
|
|
|
|
|
"Failed to read DutyCycle Encoder. Potential Speed Overrun. Returning "
|
|
|
|
|
"last value");
|
|
|
|
|
return m_lastPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DutyCycleEncoder::SetDistancePerRotation(double distancePerRotation) {
|
|
|
|
|
m_distancePerRotation = distancePerRotation;
|
2020-12-24 12:23:38 -08:00
|
|
|
m_simDistancePerRotation.Set(distancePerRotation);
|
2019-11-14 22:51:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double DutyCycleEncoder::GetDistancePerRotation() const {
|
|
|
|
|
return m_distancePerRotation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double DutyCycleEncoder::GetDistance() const {
|
|
|
|
|
return Get().to<double>() * GetDistancePerRotation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int DutyCycleEncoder::GetFrequency() const {
|
|
|
|
|
return m_dutyCycle->GetFrequency();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DutyCycleEncoder::Reset() {
|
2020-03-20 16:32:52 -05:00
|
|
|
if (m_counter) m_counter->Reset();
|
2019-11-14 22:51:33 -08:00
|
|
|
m_positionOffset = m_dutyCycle->GetOutput();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DutyCycleEncoder::IsConnected() const {
|
|
|
|
|
if (m_simIsConnected) return m_simIsConnected.Get();
|
|
|
|
|
return GetFrequency() > m_frequencyThreshold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DutyCycleEncoder::SetConnectedFrequencyThreshold(int frequency) {
|
|
|
|
|
if (frequency < 0) {
|
|
|
|
|
frequency = 0;
|
|
|
|
|
}
|
|
|
|
|
m_frequencyThreshold = frequency;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 20:18:58 -07:00
|
|
|
int DutyCycleEncoder::GetFPGAIndex() const {
|
|
|
|
|
return m_dutyCycle->GetFPGAIndex();
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-23 20:18:49 -07:00
|
|
|
int DutyCycleEncoder::GetSourceChannel() const {
|
|
|
|
|
return m_dutyCycle->GetSourceChannel();
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 22:51:33 -08:00
|
|
|
void DutyCycleEncoder::InitSendable(SendableBuilder& builder) {
|
|
|
|
|
builder.SetSmartDashboardType("AbsoluteEncoder");
|
2020-06-27 20:39:00 -07:00
|
|
|
builder.AddDoubleProperty(
|
|
|
|
|
"Distance", [this] { return this->GetDistance(); }, nullptr);
|
|
|
|
|
builder.AddDoubleProperty(
|
|
|
|
|
"Distance Per Rotation",
|
|
|
|
|
[this] { return this->GetDistancePerRotation(); }, nullptr);
|
|
|
|
|
builder.AddDoubleProperty(
|
|
|
|
|
"Is Connected", [this] { return this->IsConnected(); }, nullptr);
|
2019-11-14 22:51:33 -08:00
|
|
|
}
|