This code goes along with my lengthy post on line trackers. The code below is written in RobotC, but has instructions for easyC users at each step so that this code is applicable to you, too. Enduring thanks to Griffin Tabor for this code; it’s pretty clever, and covers an angle I hadn’t thought of previously.

#pragma config(Sensor, in1,  Left,    sensorLineFollower)
#pragma config(Sensor, in2,  Center,  sensorLineFollower)
#pragma config(Sensor, in3,  Right,   sensorLineFollower)
//*!!Code automatically generated by 'ROBOTC' configuration wizard  !!*//
#pragma platform(VEX2)
#pragma competitionControl(Competition)
#include "Vex_Competition_Includes.c"

/* ————————————————————————————————————————————————————————— 
/*  Code courtesy of Griffin Tabor
/*  Line-follower code for
/*  (a) capturing the min & max of your sensors on the field
/*  to account for current lighting conditions; this takes
/*  place in the pre-autonomous/Initialize section of the
/*  program, and
/*  (b) converting sensor values to a % as auton is
/*  running so that your code references a 1-to-100 scale 
/*  instead of raw sensor values; allows the program’s 
/*  status-checking along the line to be unaffected by the
/*  new min & max
/* —————————————————————————————————————————————————————— */

// set the starting min and max global variables to the
// opposite ends of the sensor’s complete range
// easyC users: this is 0 to 1023 for your program
int leftMin = 4095;
int leftMax = 0;

int rightMin = 4095;
int rightMax = 0;

int centerMin = 4095;
int centerMax = 0;

// easyC users: Tasks in RobotC run simultaneously
// with other code; there is no easyC equivalent. 
// See comment below in pre-autonomous section

task Calibrator() {


      // put the robot down on the field; push it to the 
      // side until each sensor has spent time on both grey
      // field tiles and white tape. This code will overwrite 
      // each sensor’s min & max from above with your
      // real-world values

      if(SensorValue[Left] > leftMax)
         leftMax = SensorValue[Left];
      if(SensorValue[Left] < leftMin)
         leftMin = SensorValue[Left];

      if(SensorValue[Center] > centerMax)
         centerMax = SensorValue[Center];
      if(SensorValue[Center] < centerMin)
         centerMin = SensorValue[Center];

      if(SensorValue[Right] > rightMax)
         rightMax = SensorValue[Right];
      if(SensorValue[Right] < rightMin)
         rightMin = SensorValue[Right];


void pre_auton() {

   // runs the task above endlessly while in pre-auton.

   // easyC users: you’d have all of your code here, in 
   // this section, inside the following loop:
   // while( ! IsEnabled() ) {  above code goes here  }
   // the “! IsEnabled()” part makes it run in a continuous 
   // loop while the field is in disabled mode (not enabled) 
   // when auton starts, it will automatically break the loop


// create function used by auton that converts incoming sensor
// data to a 0-to-100 scale so you’re using %s instead of raw
// numbers
int getSensorPercent(int value, int min, int max) {
   int return_val = (value - min)/(max - min) * 100;

   // Checks to see if for some reason the % value is 
   // negative or > 100 if so, cap it at 0 or 100 and sends 
   // that back to the auton code
   // Accounts for pre-auton calibration being slightly off
   // from true min & max

   if(return_val < 0)
      return 0;
   if(return_val > 100)
      return 100;

   // otherwise send the return_val calculated above back to
   // the auton routine
   return return_val;

task autonomous() {

   // easyC users do not need this line

   // converts incoming sensor data to a 1-100 scale; 
   // your PID would be written to reference percentages instead 
   // of numerical values when deciding if the robot is 
   // veering off the line

   int leftValue = getSensorPercent(SensorValue[Left], leftMin, leftMax);
   int rightValue = getSensorPercent(SensorValue[Right], rightMin, rightMax);
   int centerValue = getSensorPercent(SensorValue[Center], centerMin, centerMax);

   // Rest of line-following code goes here


task usercontrol() {
   while (true) {
      // Joystick/driver-control code goes here