blob: efdaae74a3ba1f8860d380f39cd2de34312bbd29 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. 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 "PWM.h"
9
10#include <sstream>
11
12#include "Utility.h"
13#include "WPIErrors.h"
14
15using namespace frc;
16
17const double PWM::kDefaultPwmPeriod = 5.05;
18const double PWM::kDefaultPwmCenter = 1.5;
19const int PWM::kDefaultPwmStepsDown = 1000;
20const int PWM::kPwmDisabled = 0;
21
22/**
23 * Allocate a PWM given a channel number.
24 *
25 * Checks channel value range and allocates the appropriate channel.
26 * The allocation is only done to help users ensure that they don't double
27 * assign channels.
28 *
29 * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP
30 * port
31 */
32PWM::PWM(int channel) {
33 std::stringstream ss;
34
35 if (!CheckPWMChannel(channel)) {
36 ss << "PWM Channel " << channel;
37 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, ss.str());
38 return;
39 }
40
41 ss << "pwm/" << channel;
42 impl = new SimContinuousOutput(ss.str());
43 m_channel = channel;
44 m_eliminateDeadband = false;
45
46 m_centerPwm = kPwmDisabled; // In simulation, the same thing.
47}
48
49PWM::~PWM() {
50 if (m_table != nullptr) m_table->RemoveTableListener(this);
51}
52
53/**
54 * Optionally eliminate the deadband from a speed controller.
55 *
56 * @param eliminateDeadband If true, set the motor curve on the Jaguar to
57 * eliminate the deadband in the middle of the range.
58 * Otherwise, keep the full range without modifying
59 * any values.
60 */
61void PWM::EnableDeadbandElimination(bool eliminateDeadband) {
62 m_eliminateDeadband = eliminateDeadband;
63}
64
65/**
66 * Set the bounds on the PWM values.
67 *
68 * This sets the bounds on the PWM values for a particular each type of
69 * controller. The values determine the upper and lower speeds as well as the
70 * deadband bracket.
71 *
72 * @param max The Minimum pwm value
73 * @param deadbandMax The high end of the deadband range
74 * @param center The center speed (off)
75 * @param deadbandMin The low end of the deadband range
76 * @param min The minimum pwm value
77 */
78void PWM::SetBounds(int max, int deadbandMax, int center, int deadbandMin,
79 int min) {
80 // Nothing to do in simulation.
81}
82
83/**
84 * Set the bounds on the PWM pulse widths.
85 *
86 * This sets the bounds on the PWM values for a particular type of controller.
87 * The values determine the upper and lower speeds as well as the deadband
88 * bracket.
89 *
90 * @param max The max PWM pulse width in ms
91 * @param deadbandMax The high end of the deadband range pulse width in ms
92 * @param center The center (off) pulse width in ms
93 * @param deadbandMin The low end of the deadband pulse width in ms
94 * @param min The minimum pulse width in ms
95 */
96void PWM::SetBounds(double max, double deadbandMax, double center,
97 double deadbandMin, double min) {
98 // Nothing to do in simulation.
99}
100
101/**
102 * Set the PWM value based on a position.
103 *
104 * This is intended to be used by servos.
105 *
106 * @pre SetMaxPositivePwm() called.
107 * @pre SetMinNegativePwm() called.
108 *
109 * @param pos The position to set the servo between 0.0 and 1.0.
110 */
111void PWM::SetPosition(double pos) {
112 if (pos < 0.0) {
113 pos = 0.0;
114 } else if (pos > 1.0) {
115 pos = 1.0;
116 }
117
118 impl->Set(pos);
119}
120
121/**
122 * Get the PWM value in terms of a position.
123 *
124 * This is intended to be used by servos.
125 *
126 * @pre SetMaxPositivePwm() called.
127 * @pre SetMinNegativePwm() called.
128 *
129 * @return The position the servo is set to between 0.0 and 1.0.
130 */
131double PWM::GetPosition() const {
132 double value = impl->Get();
133 if (value < 0.0) {
134 return 0.0;
135 } else if (value > 1.0) {
136 return 1.0;
137 } else {
138 return value;
139 }
140}
141
142/**
143 * Set the PWM value based on a speed.
144 *
145 * This is intended to be used by speed controllers.
146 *
147 * @pre SetMaxPositivePwm() called.
148 * @pre SetMinPositivePwm() called.
149 * @pre SetCenterPwm() called.
150 * @pre SetMaxNegativePwm() called.
151 * @pre SetMinNegativePwm() called.
152 *
153 * @param speed The speed to set the speed controller between -1.0 and 1.0.
154 */
155void PWM::SetSpeed(double speed) {
156 // clamp speed to be in the range 1.0 >= speed >= -1.0
157 if (speed < -1.0) {
158 speed = -1.0;
159 } else if (speed > 1.0) {
160 speed = 1.0;
161 }
162
163 impl->Set(speed);
164}
165
166/**
167 * Get the PWM value in terms of speed.
168 *
169 * This is intended to be used by speed controllers.
170 *
171 * @pre SetMaxPositivePwm() called.
172 * @pre SetMinPositivePwm() called.
173 * @pre SetMaxNegativePwm() called.
174 * @pre SetMinNegativePwm() called.
175 *
176 * @return The most recently set speed between -1.0 and 1.0.
177 */
178double PWM::GetSpeed() const {
179 double value = impl->Get();
180 if (value > 1.0) {
181 return 1.0;
182 } else if (value < -1.0) {
183 return -1.0;
184 } else {
185 return value;
186 }
187}
188
189/**
190 * Set the PWM value directly to the hardware.
191 *
192 * Write a raw value to a PWM channel.
193 *
194 * @param value Raw PWM value.
195 */
196void PWM::SetRaw(uint16_t value) {
197 wpi_assert(value == kPwmDisabled);
198 impl->Set(0);
199}
200
201/**
202 * Slow down the PWM signal for old devices.
203 *
204 * @param mult The period multiplier to apply to this channel
205 */
206void PWM::SetPeriodMultiplier(PeriodMultiplier mult) {
207 // Do nothing in simulation.
208}
209
210void PWM::ValueChanged(ITable* source, llvm::StringRef key,
211 std::shared_ptr<nt::Value> value, bool isNew) {
212 if (!value->IsDouble()) return;
213 SetSpeed(value->GetDouble());
214}
215
216void PWM::UpdateTable() {
217 if (m_table != nullptr) {
218 m_table->PutNumber("Value", GetSpeed());
219 }
220}
221
222void PWM::StartLiveWindowMode() {
223 SetSpeed(0);
224 if (m_table != nullptr) {
225 m_table->AddTableListener("Value", this, true);
226 }
227}
228
229void PWM::StopLiveWindowMode() {
230 SetSpeed(0);
231 if (m_table != nullptr) {
232 m_table->RemoveTableListener(this);
233 }
234}
235
236std::string PWM::GetSmartDashboardType() const { return "Speed Controller"; }
237
238void PWM::InitTable(std::shared_ptr<ITable> subTable) {
239 m_table = subTable;
240 UpdateTable();
241}
242
243std::shared_ptr<ITable> PWM::GetTable() const { return m_table; }