blob: 5f26e87fb9c52cddab8bb77d87341960bfdbb1c5 [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "frc/AnalogEncoder.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <wpi/NullDeleter.h>
8#include <wpi/sendable/SendableBuilder.h>
9
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include "frc/AnalogInput.h"
11#include "frc/Counter.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070012#include "frc/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080013
14using namespace frc;
15
Austin Schuh812d0d12021-11-04 20:16:48 -070016AnalogEncoder::AnalogEncoder(int channel)
17 : AnalogEncoder(std::make_shared<AnalogInput>(channel)) {}
18
Brian Silverman8fce7482020-01-05 13:18:21 -080019AnalogEncoder::AnalogEncoder(AnalogInput& analogInput)
Austin Schuh812d0d12021-11-04 20:16:48 -070020 : m_analogInput{&analogInput, wpi::NullDeleter<AnalogInput>{}},
Brian Silverman8fce7482020-01-05 13:18:21 -080021 m_analogTrigger{m_analogInput.get()},
22 m_counter{} {
23 Init();
24}
25
26AnalogEncoder::AnalogEncoder(AnalogInput* analogInput)
Austin Schuh812d0d12021-11-04 20:16:48 -070027 : m_analogInput{analogInput, wpi::NullDeleter<AnalogInput>{}},
Brian Silverman8fce7482020-01-05 13:18:21 -080028 m_analogTrigger{m_analogInput.get()},
29 m_counter{} {
30 Init();
31}
32
33AnalogEncoder::AnalogEncoder(std::shared_ptr<AnalogInput> analogInput)
34 : m_analogInput{std::move(analogInput)},
35 m_analogTrigger{m_analogInput.get()},
36 m_counter{} {
37 Init();
38}
39
40void AnalogEncoder::Init() {
41 m_simDevice = hal::SimDevice{"AnalogEncoder", m_analogInput->GetChannel()};
42
43 if (m_simDevice) {
44 m_simPosition = m_simDevice.CreateDouble("Position", false, 0.0);
45 }
46
47 m_analogTrigger.SetLimitsVoltage(1.25, 3.75);
48 m_counter.SetUpSource(
49 m_analogTrigger.CreateOutput(AnalogTriggerType::kRisingPulse));
50 m_counter.SetDownSource(
51 m_analogTrigger.CreateOutput(AnalogTriggerType::kFallingPulse));
52
Austin Schuh812d0d12021-11-04 20:16:48 -070053 wpi::SendableRegistry::AddLW(this, "DutyCycle Encoder",
54 m_analogInput->GetChannel());
Brian Silverman8fce7482020-01-05 13:18:21 -080055}
56
57units::turn_t AnalogEncoder::Get() const {
Austin Schuh812d0d12021-11-04 20:16:48 -070058 if (m_simPosition) {
59 return units::turn_t{m_simPosition.Get()};
60 }
Brian Silverman8fce7482020-01-05 13:18:21 -080061
62 // As the values are not atomic, keep trying until we get 2 reads of the same
63 // value If we don't within 10 attempts, error
64 for (int i = 0; i < 10; i++) {
65 auto counter = m_counter.Get();
66 auto pos = m_analogInput->GetVoltage();
67 auto counter2 = m_counter.Get();
68 auto pos2 = m_analogInput->GetVoltage();
69 if (counter == counter2 && pos == pos2) {
70 units::turn_t turns{counter + pos - m_positionOffset};
71 m_lastPosition = turns;
72 return turns;
73 }
74 }
75
Austin Schuh812d0d12021-11-04 20:16:48 -070076 FRC_ReportError(
77 warn::Warning, "{}",
Brian Silverman8fce7482020-01-05 13:18:21 -080078 "Failed to read Analog Encoder. Potential Speed Overrun. Returning last "
79 "value");
80 return m_lastPosition;
81}
82
Austin Schuh812d0d12021-11-04 20:16:48 -070083double AnalogEncoder::GetPositionOffset() const {
84 return m_positionOffset;
85}
Brian Silverman8fce7482020-01-05 13:18:21 -080086
87void AnalogEncoder::SetDistancePerRotation(double distancePerRotation) {
88 m_distancePerRotation = distancePerRotation;
89}
90
91double AnalogEncoder::GetDistancePerRotation() const {
92 return m_distancePerRotation;
93}
94
95double AnalogEncoder::GetDistance() const {
Austin Schuh812d0d12021-11-04 20:16:48 -070096 return Get().value() * GetDistancePerRotation();
Brian Silverman8fce7482020-01-05 13:18:21 -080097}
98
99void AnalogEncoder::Reset() {
100 m_counter.Reset();
101 m_positionOffset = m_analogInput->GetVoltage();
102}
103
Austin Schuh812d0d12021-11-04 20:16:48 -0700104int AnalogEncoder::GetChannel() const {
105 return m_analogInput->GetChannel();
106}
Austin Schuh1e69f942020-11-14 15:06:14 -0800107
Austin Schuh812d0d12021-11-04 20:16:48 -0700108void AnalogEncoder::InitSendable(wpi::SendableBuilder& builder) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800109 builder.SetSmartDashboardType("AbsoluteEncoder");
Austin Schuh1e69f942020-11-14 15:06:14 -0800110 builder.AddDoubleProperty(
111 "Distance", [this] { return this->GetDistance(); }, nullptr);
112 builder.AddDoubleProperty(
113 "Distance Per Rotation",
114 [this] { return this->GetDistancePerRotation(); }, nullptr);
Brian Silverman8fce7482020-01-05 13:18:21 -0800115}