blob: a194961377bf292cd8f7a53202bdac1aac5f4650 [file] [log] [blame]
James Kuszmaul4b81d302019-12-14 20:53:14 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2019 FIRST. All Rights Reserved. */
3/* 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/AnalogEncoder.h"
9
10#include "frc/AnalogInput.h"
11#include "frc/Counter.h"
12#include "frc/DriverStation.h"
13#include "frc/smartdashboard/SendableBuilder.h"
14
15using namespace frc;
16
17AnalogEncoder::AnalogEncoder(AnalogInput& analogInput)
18 : m_analogInput{&analogInput, NullDeleter<AnalogInput>{}},
19 m_analogTrigger{m_analogInput.get()},
20 m_counter{} {
21 Init();
22}
23
24AnalogEncoder::AnalogEncoder(AnalogInput* analogInput)
25 : m_analogInput{analogInput, NullDeleter<AnalogInput>{}},
26 m_analogTrigger{m_analogInput.get()},
27 m_counter{} {
28 Init();
29}
30
31AnalogEncoder::AnalogEncoder(std::shared_ptr<AnalogInput> analogInput)
32 : m_analogInput{std::move(analogInput)},
33 m_analogTrigger{m_analogInput.get()},
34 m_counter{} {
35 Init();
36}
37
38void AnalogEncoder::Init() {
39 m_simDevice = hal::SimDevice{"AnalogEncoder", m_analogInput->GetChannel()};
40
41 if (m_simDevice) {
42 m_simPosition = m_simDevice.CreateDouble("Position", false, 0.0);
43 }
44
45 m_analogTrigger.SetLimitsVoltage(1.25, 3.75);
46 m_counter.SetUpSource(
47 m_analogTrigger.CreateOutput(AnalogTriggerType::kRisingPulse));
48 m_counter.SetDownSource(
49 m_analogTrigger.CreateOutput(AnalogTriggerType::kFallingPulse));
50
51 SendableRegistry::GetInstance().AddLW(this, "DutyCycle Encoder",
52 m_analogInput->GetChannel());
53}
54
55units::turn_t AnalogEncoder::Get() const {
56 if (m_simPosition) return units::turn_t{m_simPosition.Get()};
57
58 // As the values are not atomic, keep trying until we get 2 reads of the same
59 // value If we don't within 10 attempts, error
60 for (int i = 0; i < 10; i++) {
61 auto counter = m_counter.Get();
62 auto pos = m_analogInput->GetVoltage();
63 auto counter2 = m_counter.Get();
64 auto pos2 = m_analogInput->GetVoltage();
65 if (counter == counter2 && pos == pos2) {
66 units::turn_t turns{counter + pos - m_positionOffset};
67 m_lastPosition = turns;
68 return turns;
69 }
70 }
71
72 frc::DriverStation::GetInstance().ReportWarning(
73 "Failed to read Analog Encoder. Potential Speed Overrun. Returning last "
74 "value");
75 return m_lastPosition;
76}
77
78double AnalogEncoder::GetPositionOffset() const { return m_positionOffset; }
79
80void AnalogEncoder::SetDistancePerRotation(double distancePerRotation) {
81 m_distancePerRotation = distancePerRotation;
82}
83
84double AnalogEncoder::GetDistancePerRotation() const {
85 return m_distancePerRotation;
86}
87
88double AnalogEncoder::GetDistance() const {
89 return Get().to<double>() * GetDistancePerRotation();
90}
91
92void AnalogEncoder::Reset() {
93 m_counter.Reset();
94 m_positionOffset = m_analogInput->GetVoltage();
95}
96
97void AnalogEncoder::InitSendable(SendableBuilder& builder) {
98 builder.SetSmartDashboardType("AbsoluteEncoder");
99 builder.AddDoubleProperty("Distance", [this] { return this->GetDistance(); },
100 nullptr);
101 builder.AddDoubleProperty("Distance Per Rotation",
102 [this] { return this->GetDistancePerRotation(); },
103 nullptr);
104}