blob: 4fc5457b54c474ba5f7ff5e4c4e9d8d9a154c6da [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
Brian Silverman8fce7482020-01-05 13:18:21 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "frc/DutyCycleEncoder.h"
9
Austin Schuh1e69f942020-11-14 15:06:14 -080010#include "frc/Base.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080011#include "frc/Counter.h"
12#include "frc/DigitalInput.h"
13#include "frc/DigitalSource.h"
14#include "frc/DriverStation.h"
15#include "frc/DutyCycle.h"
16#include "frc/smartdashboard/SendableBuilder.h"
17
18using namespace frc;
19
20DutyCycleEncoder::DutyCycleEncoder(int channel)
21 : m_dutyCycle{std::make_shared<DutyCycle>(
Austin Schuh1e69f942020-11-14 15:06:14 -080022 std::make_shared<DigitalInput>(channel))} {
Brian Silverman8fce7482020-01-05 13:18:21 -080023 Init();
24}
25
26DutyCycleEncoder::DutyCycleEncoder(DutyCycle& dutyCycle)
Austin Schuh1e69f942020-11-14 15:06:14 -080027 : m_dutyCycle{&dutyCycle, NullDeleter<DutyCycle>{}} {
Brian Silverman8fce7482020-01-05 13:18:21 -080028 Init();
29}
30
31DutyCycleEncoder::DutyCycleEncoder(DutyCycle* dutyCycle)
Austin Schuh1e69f942020-11-14 15:06:14 -080032 : m_dutyCycle{dutyCycle, NullDeleter<DutyCycle>{}} {
Brian Silverman8fce7482020-01-05 13:18:21 -080033 Init();
34}
35
36DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle)
Austin Schuh1e69f942020-11-14 15:06:14 -080037 : m_dutyCycle{std::move(dutyCycle)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080038 Init();
39}
40
41DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource)
Austin Schuh1e69f942020-11-14 15:06:14 -080042 : m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080043 Init();
44}
45
46DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource)
Austin Schuh1e69f942020-11-14 15:06:14 -080047 : m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080048 Init();
49}
50
51DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource)
Austin Schuh1e69f942020-11-14 15:06:14 -080052 : m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080053 Init();
54}
55
56void DutyCycleEncoder::Init() {
57 m_simDevice = hal::SimDevice{"DutyCycleEncoder", m_dutyCycle->GetFPGAIndex()};
58
59 if (m_simDevice) {
60 m_simPosition = m_simDevice.CreateDouble("Position", false, 0.0);
Austin Schuh1e69f942020-11-14 15:06:14 -080061 m_simDistancePerRotation =
62 m_simDevice.CreateDouble("DistancePerRotation", false, 1.0);
Brian Silverman8fce7482020-01-05 13:18:21 -080063 m_simIsConnected = m_simDevice.CreateBoolean("Connected", false, true);
Austin Schuh1e69f942020-11-14 15:06:14 -080064 } else {
65 m_analogTrigger = std::make_unique<AnalogTrigger>(m_dutyCycle.get());
66 m_analogTrigger->SetLimitsDutyCycle(0.25, 0.75);
67 m_counter = std::make_unique<Counter>();
68 m_counter->SetUpSource(
69 m_analogTrigger->CreateOutput(AnalogTriggerType::kRisingPulse));
70 m_counter->SetDownSource(
71 m_analogTrigger->CreateOutput(AnalogTriggerType::kFallingPulse));
Brian Silverman8fce7482020-01-05 13:18:21 -080072 }
73
Brian Silverman8fce7482020-01-05 13:18:21 -080074 SendableRegistry::GetInstance().AddLW(this, "DutyCycle Encoder",
75 m_dutyCycle->GetSourceChannel());
76}
77
78units::turn_t DutyCycleEncoder::Get() const {
79 if (m_simPosition) return units::turn_t{m_simPosition.Get()};
80
81 // As the values are not atomic, keep trying until we get 2 reads of the same
82 // value If we don't within 10 attempts, error
83 for (int i = 0; i < 10; i++) {
Austin Schuh1e69f942020-11-14 15:06:14 -080084 auto counter = m_counter->Get();
Brian Silverman8fce7482020-01-05 13:18:21 -080085 auto pos = m_dutyCycle->GetOutput();
Austin Schuh1e69f942020-11-14 15:06:14 -080086 auto counter2 = m_counter->Get();
Brian Silverman8fce7482020-01-05 13:18:21 -080087 auto pos2 = m_dutyCycle->GetOutput();
88 if (counter == counter2 && pos == pos2) {
89 units::turn_t turns{counter + pos - m_positionOffset};
90 m_lastPosition = turns;
91 return turns;
92 }
93 }
94
95 frc::DriverStation::GetInstance().ReportWarning(
96 "Failed to read DutyCycle Encoder. Potential Speed Overrun. Returning "
97 "last value");
98 return m_lastPosition;
99}
100
101void DutyCycleEncoder::SetDistancePerRotation(double distancePerRotation) {
102 m_distancePerRotation = distancePerRotation;
Austin Schuh1e69f942020-11-14 15:06:14 -0800103 m_simDistancePerRotation.Set(distancePerRotation);
Brian Silverman8fce7482020-01-05 13:18:21 -0800104}
105
106double DutyCycleEncoder::GetDistancePerRotation() const {
107 return m_distancePerRotation;
108}
109
110double DutyCycleEncoder::GetDistance() const {
111 return Get().to<double>() * GetDistancePerRotation();
112}
113
114int DutyCycleEncoder::GetFrequency() const {
115 return m_dutyCycle->GetFrequency();
116}
117
118void DutyCycleEncoder::Reset() {
Austin Schuh1e69f942020-11-14 15:06:14 -0800119 if (m_counter) m_counter->Reset();
Brian Silverman8fce7482020-01-05 13:18:21 -0800120 m_positionOffset = m_dutyCycle->GetOutput();
121}
122
123bool DutyCycleEncoder::IsConnected() const {
124 if (m_simIsConnected) return m_simIsConnected.Get();
125 return GetFrequency() > m_frequencyThreshold;
126}
127
128void DutyCycleEncoder::SetConnectedFrequencyThreshold(int frequency) {
129 if (frequency < 0) {
130 frequency = 0;
131 }
132 m_frequencyThreshold = frequency;
133}
134
Austin Schuh1e69f942020-11-14 15:06:14 -0800135int DutyCycleEncoder::GetFPGAIndex() const {
136 return m_dutyCycle->GetFPGAIndex();
137}
138
139int DutyCycleEncoder::GetSourceChannel() const {
140 return m_dutyCycle->GetSourceChannel();
141}
142
Brian Silverman8fce7482020-01-05 13:18:21 -0800143void DutyCycleEncoder::InitSendable(SendableBuilder& builder) {
144 builder.SetSmartDashboardType("AbsoluteEncoder");
Austin Schuh1e69f942020-11-14 15:06:14 -0800145 builder.AddDoubleProperty(
146 "Distance", [this] { return this->GetDistance(); }, nullptr);
147 builder.AddDoubleProperty(
148 "Distance Per Rotation",
149 [this] { return this->GetDistancePerRotation(); }, nullptr);
150 builder.AddDoubleProperty(
151 "Is Connected", [this] { return this->IsConnected(); }, nullptr);
Brian Silverman8fce7482020-01-05 13:18:21 -0800152}