Skip to content

Commit

Permalink
Merge pull request #10 from Arctos6135/develop
Browse files Browse the repository at this point in the history
2020 Initial Release
  • Loading branch information
tylertian123 committed Jan 6, 2020
2 parents a8af3a0 + 41a128b commit 91a6bbf
Show file tree
Hide file tree
Showing 14 changed files with 646 additions and 16 deletions.
13 changes: 2 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies {
compile wpi.deps.wpilib()
compile wpi.deps.vendor.java()
compile files('lib/RobotLib-0.1.2.jar')
compile files('lib/RobotLib-0.2.0.jar')
nativeZip wpi.deps.vendor.jni(wpi.platforms.roborio)
nativeDesktopZip wpi.deps.vendor.jni(wpi.platforms.desktop)
Expand All @@ -31,13 +31,4 @@ dependencies {
## Documentation
All classes in the public API are documented with Javadocs. For every release, you can find the Javadocs as `RobotLib-Doc-<VERSION>.zip`.

## Thank You to Our Generous Sponsors:
<img src="https://dynamicmedia.zuza.com/zz/m/original_/3/a/3aae60b3-ff18-4be5-b2b1-e244943a85fb/TDSB_Gallery.png" alt="Toronto District School Board" height="200px"/>
<img src="https://developer.nordicsemi.com/.webresources/NordicS.jpg" alt="Nordic Semiconductors" height="170px"/>
<img src="https://upload.wikimedia.org/wikipedia/en/thumb/5/50/SNC-Lavalin_logo.svg/1280px-SNC-Lavalin_logo.svg.png" alt="SNC-Lavalin" height="170px"/>
<img src="https://user-images.githubusercontent.com/32781310/52970668-acd64780-3382-11e9-857f-85b829690e0c.png" alt="Scotia McLeod" height="200px"/>
<img src="https://kissmybutton.gr/wp-content/uploads/2017/09/ryver.png" alt="Ryver Inc." height="200px"/>
<img src="https://user-images.githubusercontent.com/32781310/52224389-eaf94480-2875-11e9-82ba-78ec58cd20cd.png" alt="The Maker Bean Cafe" height="200px"/>
<img src="http://connecttech.com/logo.jpg" alt="Connect Tech Inc." height="200px"/>
<img src="https://brafasco.com/media/wysiwyg/HDS_construction_industrial_BF_4C_pos.png" alt="HD Supply Brafasco" height="200px"/>
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqnEGnLesUirrtMQfhxLGUTZn2xkVWpbROlvmABI2Nk6HzhD1w" alt="Arbour Memorial" height="200px"/>
## 2020 Sponsors Coming Soon!
12 changes: 9 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id 'java-library'

// Use GradleRIO for the FRC libraries
id 'edu.wpi.first.GradleRIO' version '2019.3.2'
id 'edu.wpi.first.GradleRIO' version '2020.1.2'

// Checkstyle
id 'checkstyle'
Expand All @@ -13,7 +13,7 @@ plugins {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

project.version = "0.1.2"
project.version = "0.2.0"

// Needed to fix Javadoc search
// See comments below
Expand Down Expand Up @@ -75,7 +75,13 @@ repositories {

dependencies {
// Use WPILib API
api wpi.deps.wpilib()
implementation wpi.deps.wpilib()
nativeZip wpi.deps.wpilibJni(wpi.platforms.roborio)
nativeDesktopZip wpi.deps.wpilibJni(wpi.platforms.desktop)

implementation wpi.deps.vendor.java()
nativeZip wpi.deps.vendor.jni(wpi.platforms.roborio)
nativeDesktopZip wpi.deps.vendor.jni(wpi.platforms.desktop)

// Use JUnit test framework
testImplementation 'junit:junit:4.12'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.arctos6135.robotlib.newcommands.motors;

import com.arctos6135.robotlib.motors.Motor;
import com.arctos6135.robotlib.newcommands.triggers.CurrentMonitoringTrigger;

import edu.wpi.first.wpilibj.PowerDistributionPanel;

/**
* A motor with software overcurrent protection. The {@code ProtectedMotor} acts
* as a wrapper around a normal motor.
* <p>
* When the maximum current allowed for this motor is exceeded for a specified
* period of time, the motor becomes blacklisted. When a motor is blacklisted,
* it will be set to 0 and will not respond to any operations. Once blacklisted,
* a motor stays blacklisted unless it is overridden with
* {@link #clearBlacklist()}.
* </p>
*
* @author Tyler Tian
*/
public class ProtectedMotor {

private Motor motor;

// A motor is blacklisted when the current limit is exceeded for a set period of
// time
// After it is blacklisted, it will be set to 0 and will not respond to setting
// Blacklist status will stick around forever unless cleared
private boolean blacklisted = false;

// Whether the protection system is enabled
// If protection is not enabled, the motor will ignore overcurrent permanently
private boolean enabled = true;

/**
* Creates a new protected motor object.
*
* @param pdp The PDP to get current readings from
* @param channel The PDP channel to get current readings from
* @param motor The internal {@link Motor} object controlled
* @param currentLimit The current limit in amps
* @param overcurrentTime The time allowed to exceed the current limit before
* the motor is blacklisted
* @param callback A callback function to be run when the motor is
* blacklisted
*/
@SuppressWarnings("resource")
public ProtectedMotor(PowerDistributionPanel pdp, int channel, Motor motor, double currentLimit,
double overcurrentTime, Runnable callback) {
this.motor = motor;

new CurrentMonitoringTrigger(pdp, channel, currentLimit, overcurrentTime, () -> {
if (enabled) {
blacklisted = true;
motor.set(0);

if (callback != null) {
callback.run();
}
}
});
}

/**
* Creates a new protected motor object.
*
* @param pdp The PDP to get current readings from
* @param channel The PDP channel to get current readings from
* @param motor The internal {@link Motor} object controlled
* @param currentLimit The current limit in amps
* @param overcurrentTime The time allowed to exceed the current limit before
* the motor is blacklisted
*/
public ProtectedMotor(PowerDistributionPanel pdp, int channel, Motor motor, double currentLimit,
double overcurrentTime) {
this(pdp, channel, motor, currentLimit, overcurrentTime, null);
}

/**
* Sets the motor. If the motor is blacklisted, this method will set it to 0
* instead.
*
* @param value The value to set the motor to
*/
public void set(double value) {
if (!blacklisted || !enabled) {
motor.set(value);
} else {
motor.set(0);
}
}

/**
* Returns whether the motor is blacklisted.
*
* @return Whether the motor is blacklisted
*/
public boolean isBlacklisted() {
return blacklisted;
}

/**
* Overrides the blacklisted status of the motor. This is the only way to get
* rid of blacklisted status.
*/
public void clearBlacklist() {
blacklisted = false;
}

/**
* Manually sets the motor to be blacklisted.
*/
public void blacklist() {
blacklisted = true;
}

/**
* Returns whether overcurrent protection is on for the motor.
*
* <p>
* If overcurrent protection is off, the motor will never be blacklisted, and
* will still be controllable even if it is.
* </p>
*
* @return Whether overcurrent protection is on
*/
public boolean getProtectionState() {
return enabled;
}

/**
* Enables or disables the overcurrent protection.
*
* <p>
* If overcurrent protection is off, the motor will never be blacklisted, and
* will still be controllable even if it is.
* </p>
*
* @param enabled Whether overcurrent protection is on
*/
public void setProtectionState(boolean enabled) {
this.enabled = enabled;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* This package contains classes related to motors offered by RobotLib <b>with
* the new command-based framework</b>.
*/
package com.arctos6135.robotlib.newcommands.motors;
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.arctos6135.robotlib.newcommands.triggers;

import edu.wpi.first.wpilibj.GenericHID;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.button.Trigger;

/**
* The {@code AnalogTrigger} class is a {@link Trigger} that activates when the
* value of some analog axis on a joystick exceeds a given threshold.
*
* @author Tyler Tian
*/
public class AnalogTrigger extends Trigger {

private int axis;
private double threshold;
private GenericHID joystick;
private boolean reverse;

private double pressedAt = Double.NaN;
private double timeRequired = 0.1;

/**
* Creates a new {@link AnalogTrigger}.
*
* @param joystick The controller
* @param trigger The specific axis to read from
* @param threshold The threshold that needs to be reached for this trigger to
* activate
*/
public AnalogTrigger(GenericHID joystick, int trigger, double threshold) {
axis = trigger;
this.joystick = joystick;
this.threshold = threshold;
}

/**
* Creates a new {@link AnalogTrigger}.
*
* @param joystick The controller
* @param trigger The specific axis to read from
* @param threshold The threshold that needs to be reached for this trigger to
* activate
* @param reverse If true, the value must be less than the threshold for the
* trigger to activate
*/
public AnalogTrigger(GenericHID joystick, int trigger, double threshold, boolean reverse) {
axis = trigger;
this.joystick = joystick;
this.threshold = threshold;
this.reverse = reverse;
}

/**
* Sets the minimum amount of time the axis value is required to exceed the
* threshold for before this trigger activates.
*
* <p>
* This minimum time requirement is to prevent the trigger from being activated
* too many times due to an unstable analog reading.
* </p>
*
* @param required The minimum required time for activation, in seconds
*/
public void setMinTimeRequired(double required) {
timeRequired = required;
}

@Override
public boolean get() {
boolean exceeded = reverse ? joystick.getRawAxis(axis) <= threshold : joystick.getRawAxis(axis) >= threshold;
// If trigger is pressed down:
if (exceeded) {
// Pressed down since is NaN (trigger not pressed down before), set the value
if (Double.isNaN(pressedAt)) {
pressedAt = Timer.getFPGATimestamp();
}
// Return whether the trigger has been pressed for more than the specified
// duration
return Timer.getFPGATimestamp() - pressedAt >= timeRequired;
} else {
// If the trigger is not pressed, reset the last pressed down time
pressedAt = Double.NaN;
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.arctos6135.robotlib.newcommands.triggers;

import java.util.concurrent.atomic.AtomicBoolean;

import edu.wpi.first.wpilibj2.command.button.Trigger;

/**
* The {@code ConditionalTrigger} class is a wrapper around a normal
* {@link Trigger} that can only be activated when its "condition" evaluates to
* {@code true}.
*
* <p>
* The "condition" is passed in the form of an {@link AtomicBoolean}, so that it
* can be modified outside of this class.
* </p>
* <p>
* Example Usage:
*
* <pre>
* AtomicBoolean allowInput = new AtomicBoolean(true);
* Trigger b = new ConditionalTrigger(new JoystickButton(joystick, number), allowInput);
* b.whenActive(new SomeCommand()); // After this point, SomeCommand will run when the trigger is pressed
* // ...
* allowInput.set(false); // After this point, SomeCommand will not run, even if the trigger is pressed
* </pre>
* </p>
*
* @author Tyler Tian
*/
public class ConditionalTrigger extends Trigger {

private Trigger trigger;
private AtomicBoolean condition;
private boolean required = true;

/**
* Creates a new {@link ConditionalTrigger}.
*
* <p>
* This trigger can only be activated when {@code condition.get()} evaluates to
* {@code true}.
* </p>
*
* @param trigger The trigger to wrap around
* @param condition The condition for this trigger
*/
public ConditionalTrigger(Trigger trigger, AtomicBoolean condition) {
this.trigger = trigger;
this.condition = condition;
}

/**
* Create a new {@link ConditionalTrigger}.
*
* <p>
* This trigger can only be activated when {@code condition.get() == required}.
* </p>
*
* @param trigger The trigger to wrap around
* @param condition The condition for this trigger
* @param required The state the condition is required to be in for this
* trigger to activate
*/
public ConditionalTrigger(Trigger trigger, AtomicBoolean condition, boolean required) {
this(trigger, condition);
this.required = required;
}

@Override
public boolean get() {
return trigger.get() && (condition.get() == required);
}
}
Loading

0 comments on commit 91a6bbf

Please sign in to comment.