CalibratedLineSensor takes an analog line sensor and turns it into a DigitalSensor by finding a threshold between light and dark. The getValue() method will return true if the sensor sees a line. Note: the act method must be called every loop to update the sensor values for averaging. This class is used in DoubleLineSensor.

ftc/evlib/hardware/sensors/CalibratedLineSensor.java

package ftc.evlib.hardware.sensors;

/**
 * This file was made by the electronVolts, FTC team 7393
 * Date Created: 3/8/16
 * 
 * manages threshold calculation for the line sensor
 *
 * @see AnalogSensor
 */
public class CalibratedLineSensor implements DigitalSensor {
    private boolean ready = true;
    private final AnalogSensor lineSensor;
    private static final int NUM_CALIBRATIONS = 100;
    private int numReadings;
    private double average, deviation, threshold = 80;
    private final double readings[] = new double[NUM_CALIBRATIONS];
    private boolean seeingLine = false;
    private double value;

    /**
     * @param lineSensor the raw line sensor
     */
    public CalibratedLineSensor(AnalogSensor lineSensor) {
        this.lineSensor = lineSensor;
    }

    /**
     * start calibrating the sensor
     */
    public void calibrate() {
        ready = false;
        average = 0;
        numReadings = 0;
        deviation = 0;
    }

    /**
     * @return true when done calibrating
     */
    public boolean isReady() {
        return ready;
    }

    /**
     * @return true if the sensor is over the line
     */
    @Override
    public Boolean getValue() {
        return seeingLine;
    }

    /**
     * read the sensor value and use it to calibrate/update the average
     */
    public void act() {
        value = lineSensor.getValue();
        if (!ready) {
            if (numReadings < NUM_CALIBRATIONS) {
                //add a value
                readings[numReadings] = value;
                numReadings++;

                //update the average
                average = (average * (numReadings - 1) + value) / (numReadings);

            } else {
                //find deviation
                for (double reading : readings) {
                    deviation += (reading - average) * (reading - average);
                }
                deviation /= Math.sqrt(numReadings);

                threshold = (average - deviation) * (average - deviation) / average;
                ready = true;
            }
        }
        seeingLine = value < threshold;
    }

    /**
     * @return the raw value of the line sensor
     */
    public double getRawValue() {
        return value;
    }
}