001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) 2008-2018 FIRST. 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.smartdashboard.SendableBuilder; 015 016/** 017 * Class implements the PWM generation in the FPGA. 018 * 019 * <p>The values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped to 020 * the hardware dependent values, in this case 0-2000 for the FPGA. Changes are immediately sent to 021 * the FPGA, and the update occurs at the next FPGA cycle (5.005ms). There is no delay. 022 * 023 * <p>As of revision 0.1.10 of the FPGA, the FPGA interprets the 0-2000 values as follows: - 2000 = 024 * maximum pulse width - 1999 to 1001 = linear scaling from "full forward" to "center" - 1000 = 025 * center value - 999 to 2 = linear scaling from "center" to "full reverse" - 1 = minimum pulse 026 * width (currently .5ms) - 0 = disabled (i.e. PWM output is held low) 027 */ 028public class PWM extends SendableBase implements Sendable { 029 /** 030 * Represents the amount to multiply the minimum servo-pulse pwm period by. 031 */ 032 public enum PeriodMultiplier { 033 /** 034 * Period Multiplier: don't skip pulses. PWM pulses occur every 5.005 ms 035 */ 036 k1X, 037 /** 038 * Period Multiplier: skip every other pulse. PWM pulses occur every 10.010 ms 039 */ 040 k2X, 041 /** 042 * Period Multiplier: skip three out of four pulses. PWM pulses occur every 20.020 ms 043 */ 044 k4X 045 } 046 047 private int m_channel; 048 private int m_handle; 049 050 /** 051 * Allocate a PWM given a channel. 052 * 053 * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port 054 */ 055 public PWM(final int channel) { 056 SensorBase.checkPWMChannel(channel); 057 m_channel = channel; 058 059 m_handle = PWMJNI.initializePWMPort(DIOJNI.getPort((byte) channel)); 060 061 setDisabled(); 062 063 PWMJNI.setPWMEliminateDeadband(m_handle, false); 064 065 HAL.report(tResourceType.kResourceType_PWM, channel); 066 setName("PWM", channel); 067 } 068 069 /** 070 * Free the PWM channel. 071 * 072 * <p>Free the resource associated with the PWM channel and set the value to 0. 073 */ 074 @Override 075 public void free() { 076 super.free(); 077 if (m_handle == 0) { 078 return; 079 } 080 setDisabled(); 081 PWMJNI.freePWMPort(m_handle); 082 m_handle = 0; 083 } 084 085 /** 086 * Optionally eliminate the deadband from a speed controller. 087 * 088 * @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate the deadband 089 * in the middle of the range. Otherwise, keep the full range without 090 * modifying any values. 091 */ 092 public void enableDeadbandElimination(boolean eliminateDeadband) { 093 PWMJNI.setPWMEliminateDeadband(m_handle, eliminateDeadband); 094 } 095 096 /** 097 * Set the bounds on the PWM pulse widths. This sets the bounds on the PWM values for a particular 098 * type of controller. The values determine the upper and lower speeds as well as the deadband 099 * bracket. 100 * 101 * @param max The max PWM pulse width in ms 102 * @param deadbandMax The high end of the deadband range pulse width in ms 103 * @param center The center (off) pulse width in ms 104 * @param deadbandMin The low end of the deadband pulse width in ms 105 * @param min The minimum pulse width in ms 106 */ 107 public void setBounds(double max, double deadbandMax, double center, double deadbandMin, 108 double min) { 109 PWMJNI.setPWMConfig(m_handle, max, deadbandMax, center, deadbandMin, min); 110 } 111 112 /** 113 * Gets the bounds on the PWM pulse widths. This Gets the bounds on the PWM values for a 114 * particular type of controller. The values determine the upper and lower speeds as well 115 * as the deadband bracket. 116 */ 117 public PWMConfigDataResult getRawBounds() { 118 return PWMJNI.getPWMConfigRaw(m_handle); 119 } 120 121 /** 122 * Gets the channel number associated with the PWM Object. 123 * 124 * @return The channel number. 125 */ 126 public int getChannel() { 127 return m_channel; 128 } 129 130 /** 131 * Set the PWM value based on a position. 132 * 133 * <p>This is intended to be used by servos. 134 * 135 * @param pos The position to set the servo between 0.0 and 1.0. 136 * @pre SetMaxPositivePwm() called. 137 * @pre SetMinNegativePwm() called. 138 */ 139 public void setPosition(double pos) { 140 PWMJNI.setPWMPosition(m_handle, pos); 141 } 142 143 /** 144 * Get the PWM value in terms of a position. 145 * 146 * <p>This is intended to be used by servos. 147 * 148 * @return The position the servo is set to between 0.0 and 1.0. 149 * @pre SetMaxPositivePwm() called. 150 * @pre SetMinNegativePwm() called. 151 */ 152 public double getPosition() { 153 return PWMJNI.getPWMPosition(m_handle); 154 } 155 156 /** 157 * Set the PWM value based on a speed. 158 * 159 * <p>This is intended to be used by speed controllers. 160 * 161 * @param speed The speed to set the speed controller between -1.0 and 1.0. 162 * @pre SetMaxPositivePwm() called. 163 * @pre SetMinPositivePwm() called. 164 * @pre SetCenterPwm() called. 165 * @pre SetMaxNegativePwm() called. 166 * @pre SetMinNegativePwm() called. 167 */ 168 public void setSpeed(double speed) { 169 PWMJNI.setPWMSpeed(m_handle, speed); 170 } 171 172 /** 173 * Get the PWM value in terms of speed. 174 * 175 * <p>This is intended to be used by speed controllers. 176 * 177 * @return The most recently set speed between -1.0 and 1.0. 178 * @pre SetMaxPositivePwm() called. 179 * @pre SetMinPositivePwm() called. 180 * @pre SetMaxNegativePwm() called. 181 * @pre SetMinNegativePwm() called. 182 */ 183 public double getSpeed() { 184 return PWMJNI.getPWMSpeed(m_handle); 185 } 186 187 /** 188 * Set the PWM value directly to the hardware. 189 * 190 * <p>Write a raw value to a PWM channel. 191 * 192 * @param value Raw PWM value. Range 0 - 255. 193 */ 194 public void setRaw(int value) { 195 PWMJNI.setPWMRaw(m_handle, (short) value); 196 } 197 198 /** 199 * Get the PWM value directly from the hardware. 200 * 201 * <p>Read a raw value from a PWM channel. 202 * 203 * @return Raw PWM control value. Range: 0 - 255. 204 */ 205 public int getRaw() { 206 return PWMJNI.getPWMRaw(m_handle); 207 } 208 209 /** 210 * Temporarily disables the PWM output. The next set call will reenable 211 * the output. 212 */ 213 public void setDisabled() { 214 PWMJNI.setPWMDisabled(m_handle); 215 } 216 217 /** 218 * Slow down the PWM signal for old devices. 219 * 220 * @param mult The period multiplier to apply to this channel 221 */ 222 public void setPeriodMultiplier(PeriodMultiplier mult) { 223 switch (mult) { 224 case k4X: 225 // Squelch 3 out of 4 outputs 226 PWMJNI.setPWMPeriodScale(m_handle, 3); 227 break; 228 case k2X: 229 // Squelch 1 out of 2 outputs 230 PWMJNI.setPWMPeriodScale(m_handle, 1); 231 break; 232 case k1X: 233 // Don't squelch any outputs 234 PWMJNI.setPWMPeriodScale(m_handle, 0); 235 break; 236 default: 237 // Cannot hit this, limited by PeriodMultiplier enum 238 } 239 } 240 241 protected void setZeroLatch() { 242 PWMJNI.latchPWMZero(m_handle); 243 } 244 245 @Override 246 public void initSendable(SendableBuilder builder) { 247 builder.setSmartDashboardType("Speed Controller"); 248 builder.setSafeState(this::setDisabled); 249 builder.addDoubleProperty("Value", this::getSpeed, this::setSpeed); 250 } 251}