diff --git a/wpilibc/src/main/native/cpp/NidecBrushless.cpp b/wpilibc/src/main/native/cpp/NidecBrushless.cpp new file mode 100644 index 0000000000..d27540feb8 --- /dev/null +++ b/wpilibc/src/main/native/cpp/NidecBrushless.cpp @@ -0,0 +1,170 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2017 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "NidecBrushless.h" + +#include + +#include "LiveWindow/LiveWindow.h" + +using namespace frc; + +/** + * Constructor. + * + * @param pwmChannel The PWM channel that the Nidec Brushless controller is + * attached to. 0-9 are on-board, 10-19 are on the MXP port + * @param dioChannel The DIO channel that the Nidec Brushless controller is + * attached to. 0-9 are on-board, 10-25 are on the MXP port + */ +NidecBrushless::NidecBrushless(int pwmChannel, int dioChannel) + : m_safetyHelper(this), m_dio(dioChannel), m_pwm(pwmChannel) { + m_safetyHelper.SetExpiration(0.0); + m_safetyHelper.SetSafetyEnabled(false); + + // the dio controls the output (in PWM mode) + m_dio.SetPWMRate(15625); + m_dio.EnablePWM(0.5); + + // the pwm enables the controller + m_pwm.SetRaw(0xffff); + + LiveWindow::GetInstance()->AddActuator("Nidec Brushless", pwmChannel, this); + HAL_Report(HALUsageReporting::kResourceType_NidecBrushless, pwmChannel); +} + +/** + * Set the PWM value. + * + *

The PWM value is set using a range of -1.0 to 1.0, appropriately scaling + * the value for the FPGA. + * + * @param speed The speed value between -1.0 and 1.0 to set. + */ +void NidecBrushless::Set(double speed) { + m_speed = speed; + m_dio.UpdateDutyCycle(0.5 + 0.5 * (m_isInverted ? -speed : speed)); + m_safetyHelper.Feed(); +} + +/** + * Get the recently set value of the PWM. + * + * @return The most recently set value for the PWM between -1.0 and 1.0. + */ +double NidecBrushless::Get() const { return m_speed; } + +void NidecBrushless::SetInverted(bool isInverted) { m_isInverted = isInverted; } + +bool NidecBrushless::GetInverted() const { return m_isInverted; } + +/** + * Write out the PID value as seen in the PIDOutput base object. + * + * @param output Write out the PWM value as was found in the PIDController + */ +void NidecBrushless::PIDWrite(double output) { Set(output); } + +/** + * Set the safety expiration time. + * + * @param timeout The timeout (in seconds) for this motor object + */ +void NidecBrushless::SetExpiration(double timeout) { + m_safetyHelper.SetExpiration(timeout); +} + +/** + * Return the safety expiration time. + * + * @return The expiration time value. + */ +double NidecBrushless::GetExpiration() const { + return m_safetyHelper.GetExpiration(); +} + +/** + * Check if the motor is currently alive or stopped due to a timeout. + * + * @return a bool value that is true if the motor has NOT timed out and should + * still be running. + */ +bool NidecBrushless::IsAlive() const { return m_safetyHelper.IsAlive(); } + +/** + * Stop the motor. This is called by the MotorSafetyHelper object + * when it has a timeout for this PWM and needs to stop it from running. + */ +void NidecBrushless::StopMotor() { Disable(); } + +/** + * Check if motor safety is enabled. + * + * @return True if motor safety is enforced for this object + */ +bool NidecBrushless::IsSafetyEnabled() const { + return m_safetyHelper.IsSafetyEnabled(); +} + +void NidecBrushless::SetSafetyEnabled(bool enabled) { + m_safetyHelper.SetSafetyEnabled(enabled); +} + +void NidecBrushless::GetDescription(llvm::raw_ostream& desc) const { + desc << "Nidec " << GetChannel(); +} + +void NidecBrushless::Disable() { m_dio.UpdateDutyCycle(0.5); } + +/** + * Gets the channel number associated with the object. + * + * @return The channel number. + */ +int NidecBrushless::GetChannel() const { return m_pwm.GetChannel(); } + +/* + * Live Window code, only does anything if live window is activated. + */ +std::string NidecBrushless::GetSmartDashboardType() const { + return "Nidec Brushless"; +} + +void NidecBrushless::InitTable(std::shared_ptr subtable) { + if (subtable) { + m_valueEntry = subtable->GetEntry("Value"); + UpdateTable(); + } else { + m_valueEntry = nt::NetworkTableEntry(); + } +} + +void NidecBrushless::UpdateTable() { + if (m_valueEntry) { + m_valueEntry.SetDouble(Get()); + } +} + +void NidecBrushless::StartLiveWindowMode() { + Set(0); // Stop for safety + if (m_valueEntry) { + m_valueListener = m_valueEntry.AddListener( + [=](const nt::EntryNotification& event) { + if (!event.value->IsDouble()) return; + Set(event.value->GetDouble()); + }, + NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE); + } +} + +void NidecBrushless::StopLiveWindowMode() { + Set(0); // Stop for safety + if (m_valueListener != 0) { + m_valueEntry.RemoveListener(m_valueListener); + m_valueListener = 0; + } +} diff --git a/wpilibc/src/main/native/include/NidecBrushless.h b/wpilibc/src/main/native/include/NidecBrushless.h new file mode 100644 index 0000000000..b6dcd82242 --- /dev/null +++ b/wpilibc/src/main/native/include/NidecBrushless.h @@ -0,0 +1,73 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2017 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +#include "DigitalOutput.h" +#include "LiveWindow/LiveWindowSendable.h" +#include "MotorSafety.h" +#include "MotorSafetyHelper.h" +#include "PWM.h" +#include "SpeedController.h" +#include "networktables/NetworkTableEntry.h" + +namespace frc { + +/** + * Nidec Brushless Motor. + */ +class NidecBrushless : public SpeedController, + public MotorSafety, + public LiveWindowSendable { + public: + NidecBrushless(int pwmChannel, int dioChannel); + ~NidecBrushless() = default; + + // SpeedController interface + void Set(double speed) override; + double Get() const override; + void SetInverted(bool isInverted) override; + bool GetInverted() const override; + void Disable() override; + void StopMotor() override; + + // PIDOutput interface + void PIDWrite(double output) override; + + // MotorSafety interface + void SetExpiration(double timeout) override; + double GetExpiration() const override; + bool IsAlive() const override; + void SetSafetyEnabled(bool enabled) override; + bool IsSafetyEnabled() const override; + void GetDescription(llvm::raw_ostream& desc) const override; + + int GetChannel() const; + + // Sendable interface + void InitTable(std::shared_ptr subtable) override; + std::string GetSmartDashboardType() const override; + + // LiveWindowSendable interface + void UpdateTable() override; + void StartLiveWindowMode() override; + void StopLiveWindowMode() override; + + private: + MotorSafetyHelper m_safetyHelper; + bool m_isInverted = false; + DigitalOutput m_dio; + PWM m_pwm; + double m_speed = 0.0; + nt::NetworkTableEntry m_valueEntry; + int m_valueListener; +}; + +} // namespace frc diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java new file mode 100644 index 0000000000..98980b1330 --- /dev/null +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java @@ -0,0 +1,213 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2017 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj; + +import edu.wpi.first.networktables.EntryListenerFlags; +import edu.wpi.first.networktables.NetworkTable; +import edu.wpi.first.networktables.NetworkTableEntry; +import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType; +import edu.wpi.first.wpilibj.hal.HAL; +import edu.wpi.first.wpilibj.livewindow.LiveWindow; +import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable; + +/** + * Nidec Brushless Motor. + */ +public class NidecBrushless implements SpeedController, MotorSafety, LiveWindowSendable { + private final MotorSafetyHelper m_safetyHelper; + private boolean m_isInverted = false; + private DigitalOutput m_dio; + private PWM m_pwm; + private volatile double m_speed = 0.0; + + /** + * Constructor. + * + * @param pwmChannel The PWM channel that the Nidec Brushless controller is attached to. + * 0-9 are on-board, 10-19 are on the MXP port + * @param dioChannel The DIO channel that the Nidec Brushless controller is attached to. + * 0-9 are on-board, 10-25 are on the MXP port + */ + public NidecBrushless(final int pwmChannel, final int dioChannel) { + m_safetyHelper = new MotorSafetyHelper(this); + m_safetyHelper.setExpiration(0.0); + m_safetyHelper.setSafetyEnabled(false); + + // the dio controls the output (in PWM mode) + m_dio = new DigitalOutput(dioChannel); + m_dio.setPWMRate(15625); + m_dio.enablePWM(0.5); + + // the pwm enables the controller + m_pwm = new PWM(pwmChannel); + m_pwm.setRaw(0xffff); + + LiveWindow.addActuator("Nidec Brushless", pwmChannel, this); + HAL.report(tResourceType.kResourceType_NidecBrushless, pwmChannel); + } + + /** + * Set the PWM value. + * + *

The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the + * FPGA. + * + * @param speed The speed value between -1.0 and 1.0 to set. + */ + @Override + public void set(double speed) { + m_speed = speed; + m_dio.updateDutyCycle(0.5 + 0.5 * (m_isInverted ? -speed : speed)); + m_safetyHelper.feed(); + } + + /** + * Get the recently set value of the PWM. + * + * @return The most recently set value for the PWM between -1.0 and 1.0. + */ + @Override + public double get() { + return m_speed; + } + + @Override + public void setInverted(boolean isInverted) { + m_isInverted = isInverted; + } + + @Override + public boolean getInverted() { + return m_isInverted; + } + + /** + * Write out the PID value as seen in the PIDOutput base object. + * + * @param output Write out the PWM value as was found in the PIDController + */ + @Override + public void pidWrite(double output) { + set(output); + } + + /** + * Set the safety expiration time. + * + * @param timeout The timeout (in seconds) for this motor object + */ + @Override + public void setExpiration(double timeout) { + m_safetyHelper.setExpiration(timeout); + } + + /** + * Return the safety expiration time. + * + * @return The expiration time value. + */ + @Override + public double getExpiration() { + return m_safetyHelper.getExpiration(); + } + + /** + * Check if the motor is currently alive or stopped due to a timeout. + * + * @return a bool value that is true if the motor has NOT timed out and should still be running. + */ + @Override + public boolean isAlive() { + return m_safetyHelper.isAlive(); + } + + /** + * Stop the motor. This is called by the MotorSafetyHelper object + * when it has a timeout for this PWM and needs to stop it from running. + */ + @Override + public void stopMotor() { + disable(); + } + + /** + * Check if motor safety is enabled. + * + * @return True if motor safety is enforced for this object + */ + @Override + public boolean isSafetyEnabled() { + return m_safetyHelper.isSafetyEnabled(); + } + + @Override + public void setSafetyEnabled(boolean enabled) { + m_safetyHelper.setSafetyEnabled(enabled); + } + + @Override + public String getDescription() { + return "Nidec " + getChannel(); + } + + @Override + public void disable() { + m_dio.updateDutyCycle(0.5); + } + + /** + * Gets the channel number associated with the object. + * + * @return The channel number. + */ + public int getChannel() { + return m_pwm.getChannel(); + } + + /* + * Live Window code, only does anything if live window is activated. + */ + @Override + public String getSmartDashboardType() { + return "Nidec Brushless"; + } + + private NetworkTableEntry m_valueEntry; + private int m_valueListener; + + @Override + public void initTable(NetworkTable subtable) { + if (subtable != null) { + m_valueEntry = subtable.getEntry("Value"); + updateTable(); + } else { + m_valueEntry = null; + } + } + + @Override + public void updateTable() { + if (m_valueEntry != null) { + m_valueEntry.setDouble(get()); + } + } + + @Override + public void startLiveWindowMode() { + set(0); // Stop for safety + m_valueListener = m_valueEntry.addListener((event) -> set(event.value.getDouble()), + EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate); + } + + @Override + public void stopLiveWindowMode() { + set(0); // Stop for safety + m_valueEntry.removeListener(m_valueListener); + m_valueListener = 0; + } +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java index 226d21e11b..4bce91d6dc 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/FRCNetComm.java @@ -107,6 +107,7 @@ public class FRCNetComm extends JNIWrapper { int kResourceType_PDP = 59; int kResourceType_PCM = 60; int kResourceType_PigeonIMU = 61; + int kResourceType_NidecBrushless = 62; } /**