Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/main/java/org/team2342/lib/leds/LedIO.java
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a function to set the entire strip (all it needs to do is call setFirst and setSecond, but a single function to do both would be nice)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using the Phoenix specific Animation type in the generic IO. You could make a custom class that extends Animation, or a class that can convert itself to a Phoenix Animation (eg. PIDFFConfigs).

Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,58 @@

package org.team2342.lib.leds;

public interface LedIO {}
public interface LedIO {

public enum Half {
FIRST,
SECOND,
ALL
}


public enum LedEffect {
SOLID,
FLASHING,
RAINBOW,
OFF
}

public static class LedColor {
public int red;
public int green;
public int blue;

public LedColor(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
}

public static LedColor off() {
return new LedColor(0, 0, 0);
}
}

public static class LedIOInputs {
public LedColor firstHalfColor = LedColor.off();
public LedColor secondHalfColor = LedColor.off();
public LedEffect firstHalfEffect = LedEffect.OFF;
public LedEffect secondHalfEffect = LedEffect.OFF;
}

public default void updateInputs(LedIOInputs inputs) {}

public default void setColor(Half half, LedColor color) {}

public default void setEffect(Half half, LedEffect effect, LedColor color) {}

public default void setAllColor(LedColor color) {
setColor(Half.FIRST, color);
setColor(Half.SECOND, color);
}

public default void setAllEffect(LedEffect effect, LedColor color) {
setEffect(Half.FIRST, effect, color);
setEffect(Half.SECOND, effect, color);
}
}
125 changes: 124 additions & 1 deletion src/main/java/org/team2342/lib/leds/LedIOCANdle.java
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember integers aren't always perfectly divisible by 2

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how hard it would be to implement, but it would be possible to also animate halves (eg. top half is the rainbow animation, bottom is the fire animation)? Not necessary though.

Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,127 @@

package org.team2342.lib.leds;

public class LedIOCANdle implements LedIO {}
import com.ctre.phoenix6.hardware.CANdle;
import com.ctre.phoenix6.configs.CANdleConfiguration;
import com.ctre.phoenix6.controls.SolidColor;
import com.ctre.phoenix6.controls.RainbowAnimation;
import com.ctre.phoenix6.signals.RGBWColor;
import com.ctre.phoenix6.signals.StripTypeValue;


public class LedIOCANdle implements LedIO {
private CANdle candle;
private int totalLeds;
private int firstHalfLength;
private int secondHalfLength;

private LedColor lastFirstColor = LedColor.off();
private LedColor lastSecondColor = LedColor.off();
private LedEffect lastFirstEffect = LedEffect.OFF;
private LedEffect lastSecondEffect = LedEffect.OFF;

public LedIOCANdle(int canID, int ledCount){
this.candle = new CANdle(canID);
this.totalLeds = ledCount;
this.firstHalfLength = totalLeds / 2;
this.secondHalfLength = totalLeds - firstHalfLength;

CANdleConfiguration config = new CANdleConfiguration();
config.LED.StripType = StripTypeValue.RGB;
candle.getConfigurator().apply(config);
}

@Override
public void updateInputs(LedIOInputs inputs){
inputs.firstHalfColor = lastFirstColor;
inputs.secondHalfColor = lastSecondColor;
inputs.firstHalfEffect = lastFirstEffect;
inputs.secondHalfEffect = lastSecondEffect;
}

@Override
public void setColor(Half half, LedColor color) {
switch (half) {
case FIRST:
sendSolidColor(0, firstHalfLength, color);
lastFirstColor = color;
lastFirstEffect = LedEffect.SOLID;
break;
case SECOND:
sendSolidColor(firstHalfLength, secondHalfLength, color);
lastSecondColor = color;
lastSecondEffect = LedEffect.SOLID;
break;
case ALL:
sendSolidColor(0, totalLeds, color);
lastFirstColor = color;
lastSecondColor = color;
lastFirstEffect = LedEffect.SOLID;
lastSecondEffect = LedEffect.SOLID;
break;
}

}

@Override
public void setEffect(Half half, LedEffect effect, LedColor color) {
if (color == null){
color = LedColor.off();
}

int start = 0;
int length = 0;

switch (half) {
case FIRST:
start = 0;
length = firstHalfLength;
lastFirstColor = color;
lastFirstEffect = effect;
break;
case SECOND:
start = firstHalfLength;
length = secondHalfLength;
lastSecondColor = color;
lastSecondEffect = effect;
break;
case ALL:
start = 0;
length = totalLeds;
lastFirstEffect = effect;
lastSecondEffect = effect;
lastFirstColor = color;
lastSecondColor = color;
break;
}

switch (effect) {
case SOLID:
sendSolidColor(start, length, color);
break;
case RAINBOW:
RainbowAnimation rainbow = new RainbowAnimation(start, length);
candle.setControl(rainbow);
break;
case FLASHING:
sendSolidColor(start, length, color);
break;
case OFF:
sendSolidColor(start, length, LedColor.off());
break;
}
}

private RGBWColor toCTRE(LedColor c) {
if (c == null){
return new RGBWColor(0,0,0,0);
}
return new RGBWColor(c.red, c.green, c.blue,0);
}

private void sendSolidColor(int start, int length, LedColor color) {
SolidColor request = new SolidColor(start, length);
request.withColor(toCTRE(color));
candle.setControl(request);
}
}
82 changes: 82 additions & 0 deletions src/main/java/org/team2342/lib/leds/LedIOSim.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) 2025 Team 2342
// https://github.com/FRCTeamPhoenix
//
// This source code is licensed under the MIT License.
// See the LICENSE file in the root directory of this project.

package org.team2342.lib.leds;

import org.littletonrobotics.junction.Logger;

public class LedIOSim implements LedIO {
private LedColor firstColor = LedColor.off();
private LedColor secondColor = LedColor.off();
private LedEffect firstEffect = LedEffect.OFF;
private LedEffect secondEffect = LedEffect.OFF;

@Override
public void setColor(Half half, LedColor color) {
if (color == null) {
color = LedColor.off();
}

switch (half) {
case FIRST:
firstColor = color;
firstEffect = LedEffect.SOLID;
break;
case SECOND:
secondColor = color;
secondEffect = LedEffect.SOLID;
break;
case ALL:
firstColor = color;
secondColor = color;
firstEffect = LedEffect.SOLID;
secondEffect = LedEffect.SOLID;
break;
}
}

@Override
public void setEffect(Half half, LedEffect effect, LedColor color){
if (color == null) {
color = LedColor.off();
}

switch (half) {
case FIRST:
firstColor = color;
firstEffect = effect;
break;
case SECOND:
secondColor = color;
secondEffect = effect;
break;
case ALL:
firstColor = color;
secondColor = color;
firstEffect = effect;
secondEffect = effect;
break;
}
}

@Override
public void updateInputs(LedIOInputs inputs){
inputs.firstHalfColor = firstColor;
inputs.secondHalfColor = secondColor;
inputs.firstHalfEffect = firstEffect;
inputs.secondHalfEffect = secondEffect;

Logger.recordOutput("LED/FirstHalf/Red", firstColor.red);
Logger.recordOutput("LED/FirstHalf/Green", firstColor.green);
Logger.recordOutput("LED/FirstHalf/Blue", firstColor.blue);
Logger.recordOutput("LED/FirstHalf/Effect", firstEffect.toString());

Logger.recordOutput("LED/SecondHalf/Red", secondColor.red);
Logger.recordOutput("LED/SecondHalf/Green", secondColor.green);
Logger.recordOutput("LED/SecondHalf/Blue", secondColor.blue);
Logger.recordOutput("LED/SecondHalf/Effect", secondEffect.toString());
}
}
68 changes: 68 additions & 0 deletions src/main/java/org/team2342/lib/leds/LedStrip.java
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using driver/operator naming, stick to the first/second naming.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments on the class are nice, but don't explain the functions in the class doc. Just a high-level explanation of what the class does.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are using a periodic() function, would it useful to have the class extend SubsystemBase so the periodic function gets called automatically? It would also let you use commands to set the LEDs, and let the CommandScheduler handle conflicts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default state for the LEDs should always be off, and not flashing white.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a better way to do flashing? If you already using animations, why not create a flashing animation?

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2025 Team 2342
// https://github.com/FRCTeamPhoenix
//
// This source code is licensed under the MIT License.
// See the LICENSE file in the root directory of this project.

package org.team2342.lib.leds;

import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.SubsystemBase;

public class LedStrip extends SubsystemBase {
private final LedIO io;
private LedIO.LedColor firstColor = LedIO.LedColor.off();
private LedIO.LedEffect firstEffect = LedIO.LedEffect.OFF;
private LedIO.LedColor secondColor = LedIO.LedColor.off();
private LedIO.LedEffect secondEffect = LedIO.LedEffect.OFF;

private boolean flashing = false;
private double lastFlashTime = 0.0;
private static final double FLASH_PERIOD_SEC = 0.5;

public LedStrip(LedIO io){
this.io = io;
}

public void setFirst(LedIO.LedEffect effect, LedIO.LedColor color){
firstEffect = effect;
firstColor = color;
}

public void setSecond(LedIO.LedEffect effect, LedIO.LedColor color){
secondEffect = effect;
secondColor = color;
}

@Override
public void periodic() {
updateFlashing();
applyEffect(LedIO.Half.FIRST, firstEffect, firstColor);
applyEffect(LedIO.Half.SECOND, secondEffect, secondColor);
}

private void updateFlashing() {
double now = Timer.getFPGATimestamp();
if (now - lastFlashTime >= FLASH_PERIOD_SEC) {
flashing = !flashing;
lastFlashTime = now;
}
}

private void applyEffect(LedIO.Half half, LedIO.LedEffect effect, LedIO.LedColor color){
switch (effect) {
case SOLID:
io.setColor(half, color);
break;
case FLASHING:
io.setColor(half, (flashing ? color : LedIO.LedColor.off()));
break;
case RAINBOW:
io.setEffect(half, LedIO.LedEffect.RAINBOW, color);
break;
case OFF:
io.setColor(half, LedIO.LedColor.off());
break;
}
}
}
20 changes: 20 additions & 0 deletions src/main/java/org/team2342/lib/motors/dumb/DumbMotorIO.java
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going forward, avoid changing stuff in other files not related to the task at hand. These are just comments, so I'll leave them, but if you want to edit something else, make another branch.

Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,35 @@

import org.littletonrobotics.junction.AutoLog;

/*
* Interface for dumb motor input/output
* Lets simulation, real hardware, and different motor types to use same structure
*/

public interface DumbMotorIO {
/**
* Container class for motor inputs - used for logging and data updates. The @AutoLog annotation
* automatically generates code for logging with the AdvantageKit framework.
*/
@AutoLog
public static class DumbMotorIOInputs {
public boolean connected = false;
public double appliedVolts = 0.0;
public double currentAmps = 0.0;
}

/**
* Called periodically to update the motor input data.
*
* @param inputs The object that stores motor readings to be logged or used somewhere else.
*/
public default void updateInputs(DumbMotorIOInputs inputs) {}

/**
* Runs the motor at a specified voltage. This method is intended to be overridden by
* implementations to control the motor.
*
* @param voltage The voltage to apply to the motor.
*/
public default void runVoltage(double voltage) {}
}
Loading