Skip to content

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.

  1. Onboard Logic: You tell the sensor “If proximity is < 0.2 and Hue is between 0.1 and 0.2, trip the trigger.”
  2. Immediate Update: The sensor monitors this at 200Hz. As soon as the condition is met, it sends a CAN frame.
  3. Low Utilization: When no game piece is present, the sensor stays quiet, saving CAN bus bandwidth.
  1. 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 trips
    settings.setDigoutFrameTrigger(m_sensor.digout1().channelIndex(),
    DigoutFrameTrigger.kRisingAndFalling);
    m_sensor.setSettings(settings);
  2. 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 Notes
    m_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)
    );
  3. Read the Trigger
    In your code, you no longer need to check getProximity() or getHue(). 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();
    }
    }

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.

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();
}
}
}