001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) 2017-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.FRCNetComm.tResourceType; 011import edu.wpi.first.wpilibj.hal.HAL; 012import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder; 013 014/** 015 * Nidec Brushless Motor. 016 */ 017public class NidecBrushless extends SendableBase implements SpeedController, MotorSafety, Sendable { 018 private final MotorSafetyHelper m_safetyHelper; 019 private boolean m_isInverted = false; 020 private DigitalOutput m_dio; 021 private PWM m_pwm; 022 private volatile double m_speed = 0.0; 023 private volatile boolean m_disabled = false; 024 025 /** 026 * Constructor. 027 * 028 * @param pwmChannel The PWM channel that the Nidec Brushless controller is attached to. 029 * 0-9 are on-board, 10-19 are on the MXP port 030 * @param dioChannel The DIO channel that the Nidec Brushless controller is attached to. 031 * 0-9 are on-board, 10-25 are on the MXP port 032 */ 033 public NidecBrushless(final int pwmChannel, final int dioChannel) { 034 m_safetyHelper = new MotorSafetyHelper(this); 035 m_safetyHelper.setExpiration(0.0); 036 m_safetyHelper.setSafetyEnabled(false); 037 038 // the dio controls the output (in PWM mode) 039 m_dio = new DigitalOutput(dioChannel); 040 addChild(m_dio); 041 m_dio.setPWMRate(15625); 042 m_dio.enablePWM(0.5); 043 044 // the pwm enables the controller 045 m_pwm = new PWM(pwmChannel); 046 addChild(m_pwm); 047 048 HAL.report(tResourceType.kResourceType_NidecBrushless, pwmChannel); 049 setName("Nidec Brushless", pwmChannel); 050 } 051 052 /** 053 * Free the resources used by this object. 054 */ 055 @Override 056 public void free() { 057 super.free(); 058 m_dio.free(); 059 m_pwm.free(); 060 } 061 062 /** 063 * Set the PWM value. 064 * 065 * <p>The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the 066 * FPGA. 067 * 068 * @param speed The speed value between -1.0 and 1.0 to set. 069 */ 070 @Override 071 public void set(double speed) { 072 if (!m_disabled) { 073 m_speed = speed; 074 m_dio.updateDutyCycle(0.5 + 0.5 * (m_isInverted ? -speed : speed)); 075 m_pwm.setRaw(0xffff); 076 } 077 m_safetyHelper.feed(); 078 } 079 080 /** 081 * Get the recently set value of the PWM. 082 * 083 * @return The most recently set value for the PWM between -1.0 and 1.0. 084 */ 085 @Override 086 public double get() { 087 return m_speed; 088 } 089 090 @Override 091 public void setInverted(boolean isInverted) { 092 m_isInverted = isInverted; 093 } 094 095 @Override 096 public boolean getInverted() { 097 return m_isInverted; 098 } 099 100 /** 101 * Write out the PID value as seen in the PIDOutput base object. 102 * 103 * @param output Write out the PWM value as was found in the PIDController 104 */ 105 @Override 106 public void pidWrite(double output) { 107 set(output); 108 } 109 110 /** 111 * Set the safety expiration time. 112 * 113 * @param timeout The timeout (in seconds) for this motor object 114 */ 115 @Override 116 public void setExpiration(double timeout) { 117 m_safetyHelper.setExpiration(timeout); 118 } 119 120 /** 121 * Return the safety expiration time. 122 * 123 * @return The expiration time value. 124 */ 125 @Override 126 public double getExpiration() { 127 return m_safetyHelper.getExpiration(); 128 } 129 130 /** 131 * Check if the motor is currently alive or stopped due to a timeout. 132 * 133 * @return a bool value that is true if the motor has NOT timed out and should still be running. 134 */ 135 @Override 136 public boolean isAlive() { 137 return m_safetyHelper.isAlive(); 138 } 139 140 /** 141 * Stop the motor. This is called by the MotorSafetyHelper object 142 * when it has a timeout for this PWM and needs to stop it from running. 143 * Calling set() will re-enable the motor. 144 */ 145 @Override 146 public void stopMotor() { 147 m_dio.updateDutyCycle(0.5); 148 m_pwm.setDisabled(); 149 } 150 151 /** 152 * Check if motor safety is enabled. 153 * 154 * @return True if motor safety is enforced for this object 155 */ 156 @Override 157 public boolean isSafetyEnabled() { 158 return m_safetyHelper.isSafetyEnabled(); 159 } 160 161 @Override 162 public void setSafetyEnabled(boolean enabled) { 163 m_safetyHelper.setSafetyEnabled(enabled); 164 } 165 166 @Override 167 public String getDescription() { 168 return "Nidec " + getChannel(); 169 } 170 171 /** 172 * Disable the motor. The enable() function must be called to re-enable 173 * the motor. 174 */ 175 @Override 176 public void disable() { 177 m_disabled = true; 178 m_dio.updateDutyCycle(0.5); 179 m_pwm.setDisabled(); 180 } 181 182 /** 183 * Re-enable the motor after disable() has been called. The set() 184 * function must be called to set a new motor speed. 185 */ 186 public void enable() { 187 m_disabled = false; 188 } 189 190 /** 191 * Gets the channel number associated with the object. 192 * 193 * @return The channel number. 194 */ 195 public int getChannel() { 196 return m_pwm.getChannel(); 197 } 198 199 @Override 200 public void initSendable(SendableBuilder builder) { 201 builder.setSmartDashboardType("Nidec Brushless"); 202 builder.setSafeState(this::stopMotor); 203 builder.addDoubleProperty("Value", this::get, this::set); 204 } 205}