001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */ 003/* Open Source Software - may be modified and shared by FRC teams. The code */ 004/* must be accompanied by the FIRST BSD license file in the root directory of */ 005/* the project. */ 006/*----------------------------------------------------------------------------*/ 007 008package edu.wpi.first.wpilibj; 009 010import edu.wpi.first.wpilibj.hal.DIOJNI; 011import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType; 012import edu.wpi.first.wpilibj.hal.HAL; 013import edu.wpi.first.wpilibj.hal.PWMJNI; 014import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable; 015import edu.wpi.first.wpilibj.tables.ITable; 016import edu.wpi.first.wpilibj.tables.ITableListener; 017 018/** 019 * Class implements the PWM generation in the FPGA. 020 * 021 * <p>The values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped to 022 * the hardware dependent values, in this case 0-2000 for the FPGA. Changes are immediately sent to 023 * the FPGA, and the update occurs at the next FPGA cycle. There is no delay. 024 * 025 * <p>As of revision 0.1.10 of the FPGA, the FPGA interprets the 0-2000 values as follows: - 2000 = 026 * maximum pulse width - 1999 to 1001 = linear scaling from "full forward" to "center" - 1000 = 027 * center value - 999 to 2 = linear scaling from "center" to "full reverse" - 1 = minimum pulse 028 * width (currently .5ms) - 0 = disabled (i.e. PWM output is held low) 029 */ 030public class PWM extends SensorBase implements LiveWindowSendable { 031 /** 032 * Represents the amount to multiply the minimum servo-pulse pwm period by. 033 */ 034 public enum PeriodMultiplier { 035 /** 036 * Period Multiplier: don't skip pulses. 037 */ 038 k1X, 039 /** 040 * Period Multiplier: skip every other pulse. 041 */ 042 k2X, 043 /** 044 * Period Multiplier: skip three out of four pulses. 045 */ 046 k4X 047 } 048 049 private int m_channel; 050 private int m_handle; 051 052 /** 053 * Allocate a PWM given a channel. 054 * 055 * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port 056 */ 057 public PWM(final int channel) { 058 checkPWMChannel(channel); 059 m_channel = channel; 060 061 m_handle = PWMJNI.initializePWMPort(DIOJNI.getPort((byte) channel)); 062 063 setDisabled(); 064 065 PWMJNI.setPWMEliminateDeadband(m_handle, false); 066 067 HAL.report(tResourceType.kResourceType_PWM, channel); 068 } 069 070 /** 071 * Free the PWM channel. 072 * 073 * <p>Free the resource associated with the PWM channel and set the value to 0. 074 */ 075 public void free() { 076 if (m_handle == 0) { 077 return; 078 } 079 setDisabled(); 080 PWMJNI.freePWMPort(m_handle); 081 m_handle = 0; 082 } 083 084 /** 085 * Optionally eliminate the deadband from a speed controller. 086 * 087 * @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate the deadband 088 * in the middle of the range. Otherwise, keep the full range without 089 * modifying any values. 090 */ 091 public void enableDeadbandElimination(boolean eliminateDeadband) { 092 PWMJNI.setPWMEliminateDeadband(m_handle, eliminateDeadband); 093 } 094 095 /** 096 * Set the bounds on the PWM values. This sets the bounds on the PWM values for a particular each 097 * type of controller. The values determine the upper and lower speeds as well as the deadband 098 * bracket. 099 * 100 * @param max The Minimum pwm value 101 * @param deadbandMax The high end of the deadband range 102 * @param center The center speed (off) 103 * @param deadbandMin The low end of the deadband range 104 * @param min The minimum pwm value 105 * @deprecated Recommended to set bounds in ms using {@link #setBounds(double, double, double, 106 * double, double)} 107 */ 108 @Deprecated 109 public void setRawBounds(final int max, final int deadbandMax, final int center, 110 final int deadbandMin, final int min) { 111 PWMJNI.setPWMConfigRaw(m_handle, max, deadbandMax, center, deadbandMin, min); 112 } 113 114 /** 115 * Set the bounds on the PWM pulse widths. This sets the bounds on the PWM values for a particular 116 * type of controller. The values determine the upper and lower speeds as well as the deadband 117 * bracket. 118 * 119 * @param max The max PWM pulse width in ms 120 * @param deadbandMax The high end of the deadband range pulse width in ms 121 * @param center The center (off) pulse width in ms 122 * @param deadbandMin The low end of the deadband pulse width in ms 123 * @param min The minimum pulse width in ms 124 */ 125 public void setBounds(double max, double deadbandMax, double center, double deadbandMin, 126 double min) { 127 PWMJNI.setPWMConfig(m_handle, max, deadbandMax, center, deadbandMin, min); 128 } 129 130 /** 131 * Gets the bounds on the PWM pulse widths. This Gets the bounds on the PWM values for a 132 * particular type of controller. The values determine the upper and lower speeds as well 133 * as the deadband bracket. 134 */ 135 public PWMConfigDataResult getRawBounds() { 136 return PWMJNI.getPWMConfigRaw(m_handle); 137 } 138 139 /** 140 * Gets the channel number associated with the PWM Object. 141 * 142 * @return The channel number. 143 */ 144 public int getChannel() { 145 return m_channel; 146 } 147 148 /** 149 * Set the PWM value based on a position. 150 * 151 * <p>This is intended to be used by servos. 152 * 153 * @param pos The position to set the servo between 0.0 and 1.0. 154 * @pre SetMaxPositivePwm() called. 155 * @pre SetMinNegativePwm() called. 156 */ 157 public void setPosition(double pos) { 158 PWMJNI.setPWMPosition(m_handle, pos); 159 } 160 161 /** 162 * Get the PWM value in terms of a position. 163 * 164 * <p>This is intended to be used by servos. 165 * 166 * @return The position the servo is set to between 0.0 and 1.0. 167 * @pre SetMaxPositivePwm() called. 168 * @pre SetMinNegativePwm() called. 169 */ 170 public double getPosition() { 171 return PWMJNI.getPWMPosition(m_handle); 172 } 173 174 /** 175 * Set the PWM value based on a speed. 176 * 177 * <p>This is intended to be used by speed controllers. 178 * 179 * @param speed The speed to set the speed controller between -1.0 and 1.0. 180 * @pre SetMaxPositivePwm() called. 181 * @pre SetMinPositivePwm() called. 182 * @pre SetCenterPwm() called. 183 * @pre SetMaxNegativePwm() called. 184 * @pre SetMinNegativePwm() called. 185 */ 186 public void setSpeed(double speed) { 187 PWMJNI.setPWMSpeed(m_handle, speed); 188 } 189 190 /** 191 * Get the PWM value in terms of speed. 192 * 193 * <p>This is intended to be used by speed controllers. 194 * 195 * @return The most recently set speed between -1.0 and 1.0. 196 * @pre SetMaxPositivePwm() called. 197 * @pre SetMinPositivePwm() called. 198 * @pre SetMaxNegativePwm() called. 199 * @pre SetMinNegativePwm() called. 200 */ 201 public double getSpeed() { 202 return PWMJNI.getPWMSpeed(m_handle); 203 } 204 205 /** 206 * Set the PWM value directly to the hardware. 207 * 208 * <p>Write a raw value to a PWM channel. 209 * 210 * @param value Raw PWM value. Range 0 - 255. 211 */ 212 public void setRaw(int value) { 213 PWMJNI.setPWMRaw(m_handle, (short) value); 214 } 215 216 /** 217 * Get the PWM value directly from the hardware. 218 * 219 * <p>Read a raw value from a PWM channel. 220 * 221 * @return Raw PWM control value. Range: 0 - 255. 222 */ 223 public int getRaw() { 224 return PWMJNI.getPWMRaw(m_handle); 225 } 226 227 /** 228 * Temporarily disables the PWM output. The next set call will reenable 229 * the output. 230 */ 231 public void setDisabled() { 232 PWMJNI.setPWMDisabled(m_handle); 233 } 234 235 /** 236 * Slow down the PWM signal for old devices. 237 * 238 * @param mult The period multiplier to apply to this channel 239 */ 240 public void setPeriodMultiplier(PeriodMultiplier mult) { 241 switch (mult) { 242 case k4X: 243 // Squelch 3 out of 4 outputs 244 PWMJNI.setPWMPeriodScale(m_handle, 3); 245 break; 246 case k2X: 247 // Squelch 1 out of 2 outputs 248 PWMJNI.setPWMPeriodScale(m_handle, 1); 249 break; 250 case k1X: 251 // Don't squelch any outputs 252 PWMJNI.setPWMPeriodScale(m_handle, 0); 253 break; 254 default: 255 // Cannot hit this, limited by PeriodMultiplier enum 256 } 257 } 258 259 protected void setZeroLatch() { 260 PWMJNI.latchPWMZero(m_handle); 261 } 262 263 /* 264 * Live Window code, only does anything if live window is activated. 265 */ 266 @Override 267 public String getSmartDashboardType() { 268 return "Speed Controller"; 269 } 270 271 private ITable m_table; 272 private ITableListener m_tableListener; 273 274 @Override 275 public void initTable(ITable subtable) { 276 m_table = subtable; 277 updateTable(); 278 } 279 280 @Override 281 public void updateTable() { 282 if (m_table != null) { 283 m_table.putNumber("Value", getSpeed()); 284 } 285 } 286 287 @Override 288 public ITable getTable() { 289 return m_table; 290 } 291 292 @Override 293 public void startLiveWindowMode() { 294 setSpeed(0); // Stop for safety 295 m_tableListener = new ITableListener() { 296 public void valueChanged(ITable itable, String key, Object value, boolean bln) { 297 setSpeed((Double) value); 298 } 299 }; 300 m_table.addTableListener("Value", m_tableListener, true); 301 } 302 303 @Override 304 public void stopLiveWindowMode() { 305 setSpeed(0); // Stop for safety 306 // TODO: Broken, should only remove the listener from "Value" only. 307 m_table.removeTableListener(m_tableListener); 308 } 309}