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