Tutorial: Zero Latency Sensing
In FRC, every millisecond counts. Standard CAN sensors send data to the RoboRIO, which then processes it in your code. This introduces “latency” (delay).
The Canandcolor can perform detection onboard the sensor itself. When it sees a game piece, it can send a special “trigger” message immediately, or even toggle a physical pin to your RoboRIO or motor controller.
How it Works
Section titled “How it Works”- Onboard Logic: You tell the sensor “If proximity is < 0.2 and Hue is between 0.1 and 0.2, trip the trigger.”
- Immediate Update: The sensor monitors this at 200Hz. As soon as the condition is met, it sends a CAN frame.
- Low Utilization: When no game piece is present, the sensor stays quiet, saving CAN bus bandwidth.
Implementation
Section titled “Implementation”-
Configure Settings
We need to tell the sensor to trigger a CAN update whenever the “Digital Output” state changes.Canandcolor m_sensor = new Canandcolor(1);CanandcolorSettings settings = new CanandcolorSettings();// Slow down regular updates to save CAN bus (e.g., 0.5s)settings.setProximityFramePeriod(0.5);settings.setColorFramePeriod(0.5);// Tell the sensor to send a frame IMMEDIATELY when the logic tripssettings.setDigoutFrameTrigger(m_sensor.digout1().channelIndex(),DigoutFrameTrigger.kRisingAndFalling);m_sensor.setSettings(settings); -
Define the “Game Piece” Logic
Now we define what the sensor should look for. This happens inside the sensor’s firmware.import com.reduxrobotics.sensors.canandcolor.HSVDigoutConfig;// Define a "Slot" that triggers on yellow Notesm_sensor.digout1().configureSlots(new HSVDigoutConfig().setMinProximity(0.0).setMaxProximity(0.25) // Trigger when closer than 0.25.setMinHue(0.10) // Yellow hue range.setMaxHue(0.18)); -
Read the Trigger
In your code, you no longer need to checkgetProximity()orgetHue(). Just check the trigger state.public void teleopPeriodic() {if (m_sensor.digout1().getValue()) {// GAME PIECE DETECTED!// This value is updated instantly by the sensor.m_intake.stop();}}
Summary
Section titled “Summary”By offloading the detection logic to the Canandcolor, you get:
- Faster Response: No waiting for the next 20ms robot loop.
- Cleaner CAN Bus: Less traffic when nothing is happening.
- Simpler Code: Your robot code just checks a single boolean.
Full Subsystem Example
Section titled “Full Subsystem Example”Here is a complete intake subsystem that uses zero-latency sensing to stop the motor when a game piece is detected:
import com.reduxrobotics.sensors.canandcolor.Canandcolor;import com.reduxrobotics.sensors.canandcolor.CanandcolorSettings;import com.reduxrobotics.sensors.canandcolor.DigoutFrameTrigger;import com.reduxrobotics.sensors.canandcolor.HSVDigoutConfig;
import edu.wpi.first.wpilibj.motorcontrol.PWMMotorController;import edu.wpi.first.wpilibj2.command.SubsystemBase;
public class IntakeSubsystem extends SubsystemBase { private final Canandcolor m_sensor = new Canandcolor(1); private final PWMMotorController m_motor;
public IntakeSubsystem(PWMMotorController motor) { m_motor = motor;
CanandcolorSettings settings = new CanandcolorSettings(); settings.setProximityFramePeriod(0.5); settings.setColorFramePeriod(0.5); settings.setDigoutFrameTrigger(m_sensor.digout1().channelIndex(), DigoutFrameTrigger.kRisingAndFalling); m_sensor.setSettings(settings);
m_sensor.digout1().configureSlots(new HSVDigoutConfig() .setMinProximity(0.0) .setMaxProximity(0.25) .setMinHue(0.10) .setMaxHue(0.18));
m_sensor.setLampLEDBrightness(1.0); }
public void run(double speed) { m_motor.set(speed); }
public void stop() { m_motor.stopMotor(); }
public boolean hasGamePiece() { return m_sensor.digout1().getValue(); }
@Override public void periodic() { if (hasGamePiece()) { stop(); } }}