// HEADLIGHT CODEint sensorPin = A1; // select the input pin for the LDRint ledPin1 =4; // select the pin for the Red LED pairint ledPin2 =0; // select the pin for the White LED pair 1int ledPin3 =1; // select the pin for the White LED pair 2int sensorValue =0; // variable to store the value coming from the sensorvoidsetup() {// declare the ledPins as an OUTPUT:pinMode(ledPin1, OUTPUT);pinMode(ledPin2, OUTPUT);pinMode(ledPin3, OUTPUT);}voidloop() {// read the value from the sensor:sensorValue =analogRead(sensorPin);if (sensorValue <=200) {// turn the ledPin ondigitalWrite(ledPin1, HIGH); //Turns leds on when darkdigitalWrite(ledPin2, HIGH);digitalWrite(ledPin3, HIGH);}else(100); {// turn the ledPin off:digitalWrite(ledPin1, LOW); //Turns leds off when there is sufficient lightdigitalWrite(ledPin2, LOW);digitalWrite(ledPin3, LOW);delay(100);}}
C++
Main Drive Code
#defineportOfPin(P)\ (((P)>=0&&(P)<8)?&PORTD:(((P)>7&&(P)<14)?&PORTB:&PORTC))#defineddrOfPin(P)\ (((P)>=0&&(P)<8)?&DDRD:(((P)>7&&(P)<14)?&DDRB:&DDRC))#definepinOfPin(P)\ (((P)>=0&&(P)<8)?&PIND:(((P)>7&&(P)<14)?&PINB:&PINC))#definepinIndex(P)((uint8_t)(P>13?P-14:P&7))#definepinMask(P)((uint8_t)(1<<pinIndex(P)))#definepinAsInput(P) *(ddrOfPin(P))&=~pinMask(P)#definepinAsInputPullUp(P) *(ddrOfPin(P))&=~pinMask(P);digitalHigh(P)#definepinAsOutput(P) *(ddrOfPin(P))|=pinMask(P)#definedigitalLow(P) *(portOfPin(P))&=~pinMask(P)#definedigitalHigh(P) *(portOfPin(P))|=pinMask(P)#defineisHigh(P)((*(pinOfPin(P))& pinMask(P))>0)#defineisLow(P)((*(pinOfPin(P))& pinMask(P))==0)#definedigitalState(P)((uint8_t)isHigh(P))#ifndefQTRSensors_h#defineQTRSensors_h#defineQTR_EMITTERS_OFF 0#defineQTR_EMITTERS_ON 1#defineQTR_EMITTERS_ON_AND_OFF 2#defineQTR_EMITTERS_ODD_EVEN 3#defineQTR_EMITTERS_ODD_EVEN_AND_OFF 4#defineQTR_EMITTERS_MANUAL 5#defineQTR_NO_EMITTER_PIN 255#defineQTR_BANK_ODD 1#defineQTR_BANK_EVEN 2#defineQTR_MAX_SENSORS 31// Base class: this class cannot be instantiated directly.// Instead, you should instantiate one of its derived classes.classQTRSensors{public: // Reads the sensor values into an array. There *MUST* be space // for as many values as there were sensors specified in the constructor. // Example usage: // unsigned int sensor_values[8]; // sensors.read(sensor_values); // The values returned are a measure of the reflectance in abstract units, // with higher values corresponding to lower reflectance (e.g. a black // surface or a void). // If measureOffAndOn is true, measures the values with the // emitters on AND off and returns on - (timeout - off). If this // value is less than zero, it returns zero. // This method will call the appropriate derived class's readPrivate(), // which is defined as a virtual function in the base class and // overridden by each derived class's own implementation.virtualvoidread(unsignedint*sensor_values, unsignedcharreadMode= QTR_EMITTERS_ON); // Turn the IR LEDs off and on. These are mainly for use by the read // method, and calling these functions before or after reading the sensors // will have no effect on the readings unless the readMode is // QTR_EMITTERS_MANUAL, but you may wish to use these for testing purposes.virtualvoidemittersOff();virtualvoidemittersOn(); // Reads the sensors for calibration. The sensor values are // not returned; instead, the maximum and minimum values found // over time are stored internally and used for the // readCalibrated() method.voidcalibrate(unsignedcharreadMode= QTR_EMITTERS_ON); // Resets all calibration that has been done.voidresetCalibration(); // Returns values calibrated to a value between 0 and 1000, where // 0 corresponds to the minimum value read by calibrate() and 1000 // corresponds to the maximum value. Calibration values are // stored separately for each sensor, so that differences in the // sensors are accounted for automatically.voidreadCalibrated(unsignedint*sensor_values, unsignedcharreadMode= QTR_EMITTERS_ON); // Operates the same as read calibrated, but also returns an // estimated position of the robot with respect to a line. The // estimate is made using a weighted average of the sensor indices // multiplied by 1000, so that a return value of 0 indicates that // the line is directly below sensor 0, a return value of 1000 // indicates that the line is directly below sensor 1, 2000 // indicates that it's below sensor 2000, etc. Intermediate // values indicate that the line is between two sensors. The // formula is: // // 0*value0 + 1000*value1 + 2000*value2 + ... // -------------------------------------------- // value0 + value1 + value2 + ... // // By default, this function assumes a dark line (high values) // surrounded by white (low values). If your line is light on // black, set the optional second argument white_line to true. In // this case, each sensor value will be replaced by (1000-value) // before the averaging.intreadLine(unsignedint*sensor_values, unsignedcharreadMode= QTR_EMITTERS_ON, unsignedcharwhite_line=0); // Calibrated minumum and maximum values. These start at 1000 and // 0, respectively, so that the very first sensor reading will // update both of them. // // The pointers are unallocated until calibrate() is called, and // then allocated to exactly the size required. Depending on the // readMode argument to calibrate, only the On or Off values may // be allocated, as required. // // These variables are made public so that you can use them for // your own calculations and do things like saving the values to // EEPROM, performing sanity checking, etc.unsignedint*calibratedMinimumOn;unsignedint*calibratedMaximumOn;unsignedint*calibratedMinimumOff;unsignedint*calibratedMaximumOff;~QTRSensors();protected:QTRSensors();virtualvoidinit(unsignedchar*pins, unsignedcharnumSensors, unsignedcharemitterPin);virtualvoidreadPrivate(unsignedint*sensor_values, unsignedcharstep=1, unsignedcharstart=0) =0;unsignedchar*_pins;unsignedchar _numSensors;unsignedchar _emitterPin;unsignedint _maxValue; // the maximum value returned by readPrivate()private: // Handles the actual calibration. calibratedMinimum and // calibratedMaximum are pointers to the requested calibration // arrays, which will be allocated if necessary.voidcalibrateOnOrOff(unsignedint**calibratedMinimum,unsignedint**calibratedMaximum,unsignedcharreadMode);int _lastValue;};// Base class for dimmable QTR sensors with support for odd/even emitter bank// control; derived from QTRSensors. This class also cannot be instantiated// directly, and you should instantiate one of its derived classes instead.classQTRDimmable : virtualpublicQTRSensors{public: // Read function for dimmable sensors with support for additional (odd/even) // readModes. The odd/even readModes only work if the object was initialized // with two emitter pins.voidread(unsignedint*sensor_values, unsignedcharreadMode= QTR_EMITTERS_ON) override; // Turns off emitters for dimmable sensors with one bank or combined banks.voidemittersOff() override; // Turns off emitters for selected bank on dimmable sensors with separate // banks. If wait = false, returns immediately without waiting for emitters // to actually turn off.voidemittersOff(unsignedcharbank, boolwait=true); // Turns on emitters for dimmable sensors with one bank or combined banks.voidemittersOn() override; // Turns on emitters for selected bank on dimmable sensors with separate // banks. If wait = false, returns immediately without waiting for emitters // to actually turn on.voidemittersOn(unsignedcharbank, boolwait=true); // Turns on the selected bank and turns off the other bank with optimized // timing (no unnecessary waits compared to calling emittersOff and // emittersOn separately, but still waits for both banks of emitters to be // in the right states before returning).voidemitterBankSelect(unsignedcharbank); // Sets and gets the dimming level (0-31). A dimming level of 0 corresponds // to full current and brightness, with higher dimming levels meaning lower // currents; see the product page for your sensor for details.voidsetDimmingLevel(unsignedchardimmingLevel);unsignedchargetDimmingLevel() {return _dimmingLevel; }protected:QTRDimmable() {} // empty constructorvoidinit(unsignedchar*pins, unsignedcharnumSensors,unsignedcharemitterPin) override;voidinit(unsignedchar*pins, unsignedcharnumSensors,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin);private:unsignedchar _evenEmitterPin; // odd pin is stored in _emitterPinunsignedchar _dimmingLevel;};// Object to be used for original (non-dimmable) QTR-xRC sensorsclassQTRSensorsRC : virtualpublicQTRSensors{public: // if this constructor is used, the user must call init() before using // the methods in this classQTRSensorsRC() {} // this constructor just calls init()QTRSensorsRC(unsignedchar*pins, unsignedcharnumSensors,unsignedinttimeout=2500, unsignedcharemitterPin= QTR_NO_EMITTER_PIN); // The array 'pins' contains the Arduino pin number for each sensor. // 'numSensors' specifies the length of the 'pins' array (i.e. the // number of QTR-RC sensors you are using). numSensors must be // no greater than 16. // 'timeout' specifies the length of time in microseconds beyond // which you consider the sensor reading completely black. That is to say, // if the pulse length for a pin exceeds 'timeout', pulse timing will stop // and the reading for that pin will be considered full black. // It is recommended that you set timeout to be between 1000 and // 3000 us, depending on things like the height of your sensors and // ambient lighting. Using timeout allows you to shorten the // duration of a sensor-reading cycle while still maintaining // useful analog measurements of reflectance // 'emitterPin' is the Arduino pin that controls the IR LEDs on the 8RC // modules. If you are using a 1RC (i.e. if there is no emitter pin), // or if you just want the emitters on all the time and don't want to // use an I/O pin to control it, use a value of 255 (QTR_NO_EMITTER_PIN).virtualvoidinit(unsignedchar*pins, unsignedcharnumSensors,unsignedinttimeout=2500, unsignedcharemitterPin= QTR_NO_EMITTER_PIN);private: // Reads the sensor values into an array. There *MUST* be space // for as many values as there were sensors specified in the constructor. // Example usage: // unsigned int sensor_values[8]; // sensors.read(sensor_values); // The values returned are a measure of the reflectance in microseconds. // A 'step' of n means that the first of every n sensors is read, starting // with 'start' (this is 0-indexed, so start = 0 means start with the first // sensor). For example, step = 2, start = 1 means read the *even-numbered* // sensors.voidreadPrivate(unsignedint*sensor_values, unsignedcharstep=1, unsignedcharstart=0) override;};// Object to be used for original (non-dimmable) QTR-xA sensorsclassQTRSensorsAnalog : virtualpublicQTRSensors{public: // if this constructor is used, the user must call init() before using // the methods in this classQTRSensorsAnalog() {} // this constructor just calls init()QTRSensorsAnalog(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor=4,unsignedcharemitterPin= QTR_NO_EMITTER_PIN); // the array 'pins' contains the Arduino analog pin assignment for each // sensor. For example, if pins is {0, 1, 7}, sensor 1 is on // Arduino analog input 0, sensor 2 is on Arduino analog input 1, // and sensor 3 is on Arduino analog input 7. // 'numSensors' specifies the length of the 'analogPins' array (i.e. the // number of QTR-A sensors you are using). numSensors must be // no greater than 16. // 'numSamplesPerSensor' indicates the number of 10-bit analog samples // to average per channel (i.e. per sensor) for each reading. The total // number of analog-to-digital conversions performed will be equal to // numSensors*numSamplesPerSensor. Note that it takes about 100 us to // perform a single analog-to-digital conversion, so: // if numSamplesPerSensor is 4 and numSensors is 6, it will take // 4 * 6 * 100 us = ~2.5 ms to perform a full readLine(). // Increasing this parameter increases noise suppression at the cost of // sample rate. The recommended value is 4. // 'emitterPin' is the Arduino pin that controls the IR LEDs on the 8RC // modules. If you are using a 1RC (i.e. if there is no emitter pin), // or if you just want the emitters on all the time and don't want to // use an I/O pin to control it, use a value of 255 (QTR_NO_EMITTER_PIN).virtualvoidinit(unsignedchar*analogPins, unsignedcharnumSensors,unsignedcharnumSamplesPerSensor=4, unsignedcharemitterPin= QTR_NO_EMITTER_PIN);protected:unsignedchar _numSamplesPerSensor;private: // Reads the sensor values into an array. There *MUST* be space // for as many values as there were sensors specified in the constructor. // Example usage: // unsigned int sensor_values[8]; // sensors.read(sensor_values); // The values returned are a measure of the reflectance in terms of a // 10-bit ADC average with higher values corresponding to lower // reflectance (e.g. a black surface or a void). // A 'step' of n means that the first of every n sensors is read, starting // with 'start' (this is 0-indexed, so start = 0 means start with the first // sensor). For example, step = 2, start = 1 means read the *even-numbered* // sensors.voidreadPrivate(unsignedint*sensor_values, unsignedcharstep=1, unsignedcharstart=0) override;};// Object to be used for dimmable QTR-xD-xRC and QTRX-xD-xRC sensorsclassQTRDimmableRC: publicQTRDimmable, publicQTRSensorsRC{public: // if this constructor is used, the user must call init() before using // the methods in this classQTRDimmableRC() {} // this constructor just calls init() (one bank or combined banks)QTRDimmableRC(unsignedchar*pins,unsignedcharnumSensors, unsignedinttimeout=2500,unsignedcharemitterPin= QTR_NO_EMITTER_PIN); // this constructor just calls init() (separate banks)QTRDimmableRC(unsignedchar*pins,unsignedcharnumSensors, unsignedinttimeout,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin);voidinit(unsignedchar*pins, unsignedcharnumSensors,unsignedinttimeout=2500, unsignedcharemitterPin= QTR_NO_EMITTER_PIN) override;voidinit(unsignedchar*pins,unsignedcharnumSensors, unsignedinttimeout,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin);};// Object to be used for dimmable QTR-xD-xA and QTRX-xD-xA sensorsclassQTRDimmableAnalog: publicQTRDimmable, publicQTRSensorsAnalog{public: // if this constructor is used, the user must call init() before using // the methods in this classQTRDimmableAnalog() {} // this constructor just calls init() (one bank or combined banks)QTRDimmableAnalog(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor=4,unsignedcharemitterPin= QTR_NO_EMITTER_PIN); // this constructor just calls init() (separate banks)QTRDimmableAnalog(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin);voidinit(unsignedchar*analogPins, unsignedcharnumSensors,unsignedcharnumSamplesPerSensor=4, unsignedcharemitterPin= QTR_NO_EMITTER_PIN) override;voidinit(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin);};#endif#include<stdlib.h>//#include "QTRSensors.h"#include<Arduino.h>// Base class constructorQTRSensors::QTRSensors() :calibratedMinimumOn(nullptr),calibratedMaximumOn(nullptr),calibratedMinimumOff(nullptr),calibratedMaximumOff(nullptr),_pins(nullptr){ // empty}// Base class data member initialization (called by derived class init())voidQTRSensors::init(unsignedchar*pins, unsignedcharnumSensors,unsignedcharemitterPin){ calibratedMinimumOn =nullptr; calibratedMaximumOn =nullptr; calibratedMinimumOff =nullptr; calibratedMaximumOff =nullptr; _lastValue =0; // assume initially that the line is left.if (numSensors > QTR_MAX_SENSORS) _numSensors = QTR_MAX_SENSORS;else _numSensors = numSensors;if (_pins ==nullptr) { _pins = (unsignedchar*)malloc(sizeof(unsignedchar) * _numSensors);if (_pins ==nullptr)return; }unsignedchar i;for (i =0; i < _numSensors; i++) {_pins[i] =pins[i]; } _emitterPin = emitterPin;}// Reads the sensor values into an array. There *MUST* be space// for as many values as there were sensors specified in the constructor.// Example usage:// unsigned int sensor_values[8];// sensors.read(sensor_values);// The values returned are a measure of the reflectance in abstract units,// with higher values corresponding to lower reflectance (e.g. a black// surface or a void).voidQTRSensors::read(unsignedint*sensor_values, unsignedcharreadMode){unsignedchar i;if (readMode == QTR_EMITTERS_ON || readMode == QTR_EMITTERS_ON_AND_OFF)emittersOn();elseif (readMode == QTR_EMITTERS_OFF)emittersOff();readPrivate(sensor_values);if (readMode != QTR_EMITTERS_MANUAL)emittersOff();if (readMode == QTR_EMITTERS_ON_AND_OFF) {unsignedintoff_values[QTR_MAX_SENSORS];readPrivate(off_values);for (i =0; i < _numSensors; i++) {sensor_values[i] += _maxValue -off_values[i]; } }}// Turn the IR LEDs off and on. These are mainly for use by the read// method, and calling these functions before or after reading the sensors// will have no effect on the readings unless the readMode is// QTR_EMITTERS_MANUAL, but you may wish to use these for testing purposes.voidQTRSensors::emittersOff(){if (_emitterPin == QTR_NO_EMITTER_PIN)return;pinMode(_emitterPin, OUTPUT);digitalWrite(_emitterPin, LOW);delayMicroseconds(200);}voidQTRSensors::emittersOn(){if (_emitterPin == QTR_NO_EMITTER_PIN)return;pinMode(_emitterPin, OUTPUT);digitalWrite(_emitterPin, HIGH);delayMicroseconds(200);}// Resets the calibration.voidQTRSensors::resetCalibration(){unsignedchar i;for (i =0; i < _numSensors; i++) {if (calibratedMinimumOn)calibratedMinimumOn[i] = _maxValue;if (calibratedMinimumOff)calibratedMinimumOff[i] = _maxValue;if (calibratedMaximumOn)calibratedMaximumOn[i] =0;if (calibratedMaximumOff)calibratedMaximumOff[i] =0; }}// Reads the sensors 10 times and uses the results for// calibration. The sensor values are not returned; instead, the// maximum and minimum values found over time are stored internally// and used for the readCalibrated() method.voidQTRSensors::calibrate(unsignedcharreadMode){if (readMode == QTR_EMITTERS_ON_AND_OFF || readMode == QTR_EMITTERS_ON) {calibrateOnOrOff(&calibratedMinimumOn,&calibratedMaximumOn, QTR_EMITTERS_ON); }if (readMode == QTR_EMITTERS_ON_AND_OFF || readMode == QTR_EMITTERS_OFF) {calibrateOnOrOff(&calibratedMinimumOff,&calibratedMaximumOff, QTR_EMITTERS_OFF); }}voidQTRSensors::calibrateOnOrOff(unsignedint**calibratedMinimum,unsignedint**calibratedMaximum,unsignedcharreadMode){int i;unsignedintsensor_values[16];unsignedintmax_sensor_values[16];unsignedintmin_sensor_values[16]; // Allocate the arrays if necessary.if (*calibratedMaximum ==0) {*calibratedMaximum = (unsignedint*)malloc(sizeof(unsignedint) * _numSensors); // If the malloc failed, don't continue.if (*calibratedMaximum ==0)return; // Initialize the max and min calibrated values to values that // will cause the first reading to update them.for (i =0; i < _numSensors; i++) (*calibratedMaximum)[i] =0; }if (*calibratedMinimum ==0) {*calibratedMinimum = (unsignedint*)malloc(sizeof(unsignedint) * _numSensors); // If the malloc failed, don't continue.if (*calibratedMinimum ==0)return;for (i =0; i < _numSensors; i++) (*calibratedMinimum)[i] = _maxValue; }int j;for (j =0; j <10; j++) {read(sensor_values, readMode);for (i =0; i < _numSensors; i++) { // set the max we found THIS timeif (j ==0||max_sensor_values[i] <sensor_values[i])max_sensor_values[i] =sensor_values[i]; // set the min we found THIS timeif (j ==0||min_sensor_values[i] >sensor_values[i])min_sensor_values[i] =sensor_values[i]; } } // record the min and max calibration valuesfor (i =0; i < _numSensors; i++) {if (min_sensor_values[i] > (*calibratedMaximum)[i]) (*calibratedMaximum)[i] =min_sensor_values[i];if (max_sensor_values[i] < (*calibratedMinimum)[i]) (*calibratedMinimum)[i] =max_sensor_values[i]; }}// Returns values calibrated to a value between 0 and 1000, where// 0 corresponds to the minimum value read by calibrate() and 1000// corresponds to the maximum value. Calibration values are// stored separately for each sensor, so that differences in the// sensors are accounted for automatically.voidQTRSensors::readCalibrated(unsignedint*sensor_values, unsignedcharreadMode){int i; // if not calibrated, do nothingif (readMode == QTR_EMITTERS_ON_AND_OFF || readMode == QTR_EMITTERS_OFF)if (!calibratedMinimumOff ||!calibratedMaximumOff)return;if (readMode == QTR_EMITTERS_ON_AND_OFF || readMode == QTR_EMITTERS_ON)if (!calibratedMinimumOn ||!calibratedMaximumOn)return; // read the needed valuesread(sensor_values, readMode);for (i =0; i < _numSensors; i++) {unsignedint calmin, calmax;unsignedint denominator; // find the correct calibrationif (readMode == QTR_EMITTERS_ON) { calmax =calibratedMaximumOn[i]; calmin =calibratedMinimumOn[i]; }elseif (readMode == QTR_EMITTERS_OFF) { calmax =calibratedMaximumOff[i]; calmin =calibratedMinimumOff[i]; }else // QTR_EMITTERS_ON_AND_OFF {if (calibratedMinimumOff[i] <calibratedMinimumOn[i]) // no meaningful signal calmin = _maxValue;else calmin =calibratedMinimumOn[i] + _maxValue -calibratedMinimumOff[i]; // this won't go past _maxValueif (calibratedMaximumOff[i] <calibratedMaximumOn[i]) // no meaningful signal calmax = _maxValue;else calmax =calibratedMaximumOn[i] + _maxValue -calibratedMaximumOff[i]; // this won't go past _maxValue } denominator = calmax - calmin;signedint x =0;if (denominator !=0) x = (((signedlong)sensor_values[i]) - calmin)*1000/ denominator;if (x <0) x =0;elseif (x >1000) x =1000;sensor_values[i] = x; }}// Operates the same as read calibrated, but also returns an// estimated position of the robot with respect to a line. The// estimate is made using a weighted average of the sensor indices// multiplied by 1000, so that a return value of 0 indicates that// the line is directly below sensor 0, a return value of 1000// indicates that the line is directly below sensor 1, 2000// indicates that it's below sensor 2000, etc. Intermediate// values indicate that the line is between two sensors. The// formula is://// 0*value0 + 1000*value1 + 2000*value2 + ...// --------------------------------------------// value0 + value1 + value2 + ...//// By default, this function assumes a dark line (high values)// surrounded by white (low values). If your line is light on// black, set the optional second argument white_line to true. In// this case, each sensor value will be replaced by (1000-value)// before the averaging.intQTRSensors::readLine(unsignedint*sensor_values,unsignedcharreadMode, unsignedcharwhite_line){unsignedchar i, on_line =0;unsignedlong avg; // this is for the weighted total, which is long // before divisionunsignedint sum; // this is for the denominator which is <= 64000readCalibrated(sensor_values, readMode); avg =0; sum =0;for (i =0; i < _numSensors; i++) {int value =sensor_values[i];if (white_line) value =1000- value; // keep track of whether we see the line at allif (value >200) { on_line =1; } // only average in values that are above a noise thresholdif (value >50) { avg += (long)(value) * (i *1000); sum += value; } }if (!on_line) { // If it last read to the left of center, return 0.if (_lastValue < (_numSensors -1) *1000/2)return0; // If it last read to the right of center, return the max.elsereturn (_numSensors -1) *1000; } _lastValue = avg / sum;return _lastValue;}// Dimmable base class initialization for one bank or combined banks// (1 emitter control pin) (called by derived class init())// (overrides QTRSensors::init)voidQTRDimmable::init(unsignedchar*pins, unsignedcharnumSensors,unsignedcharemitterPin){ QTRSensors::init(pins, numSensors, emitterPin); _evenEmitterPin = QTR_NO_EMITTER_PIN;}// Dimmable base class initialization for separate banks// (2 emitter control pins) (called by derived class init())voidQTRDimmable::init(unsignedchar*pins, unsignedcharnumSensors,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin){ QTRSensors::init(pins, numSensors, oddEmitterPin); _evenEmitterPin = evenEmitterPin;}// Read function for dimmable sensors with support for additional (odd/even)// readModes. The odd/even readModes only work if the object was initialized// with two emitter pins.// (overrides QTRSensors::read)voidQTRDimmable::read(unsignedint*sensor_values, unsignedcharreadMode){if (readMode == QTR_EMITTERS_ODD_EVEN || readMode == QTR_EMITTERS_ODD_EVEN_AND_OFF) {emitterBankSelect(QTR_BANK_ODD); // Read the odd-numbered sensors. // (readPrivate takes a 0-based array index, so start = 0 to start with // the first sensor)readPrivate(sensor_values, 2, 0);emitterBankSelect(QTR_BANK_EVEN); // Read the even-numbered sensors. // (readPrivate takes a 0-based array index, so start = 1 to start with // the second sensor)readPrivate(sensor_values, 2, 1); }else {if (readMode == QTR_EMITTERS_ON || readMode == QTR_EMITTERS_ON_AND_OFF)emittersOn();elseif (readMode == QTR_EMITTERS_OFF)emittersOff();readPrivate(sensor_values); }if (readMode != QTR_EMITTERS_MANUAL)emittersOff();if (readMode == QTR_EMITTERS_ON_AND_OFF || readMode == QTR_EMITTERS_ODD_EVEN_AND_OFF) {unsignedchar i;unsignedintoff_values[QTR_MAX_SENSORS];readPrivate(off_values);for (i =0; i < _numSensors; i++) {sensor_values[i] += _maxValue -off_values[i]; } }}// Turns off emitters for dimmable sensors with one bank or combined banks.// (overrides QTRSensors::emittersOff)voidQTRDimmable::emittersOff(){if (_evenEmitterPin != QTR_NO_EMITTER_PIN) { // Stop driving even emitter ctrl pin // and let odd pin control all emitterspinMode (_evenEmitterPin, INPUT); }emittersOff(QTR_BANK_ODD);}// Turns off emitters for selected bank on dimmable sensors with separate// banks. If wait = false, returns immediately without waiting for emitters// to actually turn off.voidQTRDimmable::emittersOff(unsignedcharbank, boolwait){unsignedchar ePin;if (bank == QTR_BANK_ODD) { ePin = _emitterPin; }else // bank == QTR_BANK_EVEN { ePin = _evenEmitterPin; }if (ePin == QTR_NO_EMITTER_PIN)return;pinMode(ePin, OUTPUT);digitalWrite(ePin, LOW);if (wait) { // Wait for emitters to turn off. (minimum 1 ms; add some margin)delayMicroseconds(1200); }}// Turns on emitters for dimmable sensors with one bank or combined banks.// (overrides QTRSensors::emittersOn)voidQTRDimmable::emittersOn(){if (_evenEmitterPin != QTR_NO_EMITTER_PIN) { // Stop driving even emitter pin and let odd pin control all emitters.pinMode (_evenEmitterPin, INPUT); }emittersOn(QTR_BANK_ODD);}// Turns on emitters for selected bank on dimmable sensors with separate// banks. If wait = false, returns immediately without waiting for emitters// to actually turn on.voidQTRDimmable::emittersOn(unsignedcharbank, boolwait){unsignedchar ePin;if (bank == QTR_BANK_ODD) { ePin = _emitterPin; }else // bank == QTR_BANK_EVEN { ePin = _evenEmitterPin; }if (ePin == QTR_NO_EMITTER_PIN)return;pinMode(ePin, OUTPUT);digitalWrite(ePin, HIGH);unsignedint turnOnStart =micros();noInterrupts();for (unsignedchar i =0; i < _dimmingLevel; i++) {delayMicroseconds(1);digitalWrite(ePin, LOW);delayMicroseconds(1);digitalWrite(ePin, HIGH); }interrupts();if (wait) { // Wait for emitters to turn on: make sure it's been at least 300 us // since the emitter pin first went high before returning. // (minimum 250 us; add some margin)while ((unsignedint)(micros() - turnOnStart) <300) {delayMicroseconds(10); } }}// Turns on the selected bank and turns off the other bank with optimized// timing (no unnecessary waits compared to calling emittersOff and// emittersOn separately, but still waits for both banks of emitters to be// in the right states before returning).voidQTRDimmable::emitterBankSelect(unsignedcharbank){unsignedchar offBank;if (bank == QTR_BANK_ODD) { offBank = QTR_BANK_EVEN; }else // bank == QTR_BANK_EVEN { offBank = QTR_BANK_ODD; } // Turn off the off-bank; don't wait before proceeding, but record the time.emittersOff(offBank, false);unsignedint turnOffStart =micros(); // Turn on the on-bank.emittersOn(bank); // Finish waiting for the off-bank emitters to turn off: make sure it's been // at least 1200 us since the off-bank was turned off before returning. // (minimum 1 ms; add some margin)while ((unsignedint)(micros() - turnOffStart) <1200) {delayMicroseconds(10); }}// Sets the dimming level (0-31). A dimming level of 0 corresponds// to full current and brightness, with higher dimming levels meaning lower// currents; see the product page for your sensor for details.voidQTRDimmable::setDimmingLevel(unsignedchardimmingLevel){if (dimmingLevel >31) { dimmingLevel =31; } _dimmingLevel = dimmingLevel;}// Derived RC class constructorQTRSensorsRC::QTRSensorsRC(unsignedchar* pins,unsignedchar numSensors, unsignedint timeout, unsignedchar emitterPin){init(pins, numSensors, timeout, emitterPin);}// The array 'pins' contains the Arduino pin number for each sensor.// 'numSensors' specifies the length of the 'pins' array (i.e. the// number of QTR-RC sensors you are using). numSensors must be// no greater than 16.// 'timeout' specifies the length of time in microseconds beyond// which you consider the sensor reading completely black. That is to say,// if the pulse length for a pin exceeds 'timeout', pulse timing will stop// and the reading for that pin will be considered full black.// It is recommended that you set timeout to be between 1000 and// 3000 us, depending on things like the height of your sensors and// ambient lighting. Using timeout allows you to shorten the// duration of a sensor-reading cycle while still maintaining// useful analog measurements of reflectance// 'emitterPin' is the Arduino pin that controls the IR LEDs on the 8RC// modules. If you are using a 1RC (i.e. if there is no emitter pin),// or if you just want the emitters on all the time and don't want to// use an I/O pin to control it, use a value of 255 (QTR_NO_EMITTER_PIN).voidQTRSensorsRC::init(unsignedchar*pins,unsignedcharnumSensors, unsignedinttimeout, unsignedcharemitterPin){ QTRSensors::init(pins, numSensors, emitterPin); _maxValue = timeout;}// Reads the sensor values into an array. There *MUST* be space// for as many values as there were sensors specified in the constructor.// Example usage:// unsigned int sensor_values[8];// sensors.read(sensor_values);// ...// The values returned are in microseconds and range from 0 to// timeout (as specified in the constructor).// A 'step' of n means that the first of every n sensors is read, starting// with 'start' (this is 0-indexed, so start = 0 means start with the first// sensor). For example, step = 2, start = 1 means read the *even-numbered*// sensors.voidQTRSensorsRC::readPrivate(unsignedint*sensor_values, unsignedcharstep, unsignedcharstart){unsignedchar i;if (_pins ==0)return;for (i = start; i < _numSensors; i += step) {sensor_values[i] = _maxValue;pinAsOutput(_pins[i]); // make sensor line an output (drives low briefly, but doesn't matter)digitalHigh(_pins[i]); // drive sensor line high }delayMicroseconds(10); // charge lines for 10 usfor (i = start; i < _numSensors; i += step) {pinAsInput(_pins[i]); // make sensor line an inputdigitalLow(_pins[i]); // important: disable internal pull-up! }unsignedlong startTime =micros();while (micros() - startTime < _maxValue) {unsignedint time =micros() - startTime;for (i = start; i < _numSensors; i += step) {if (isLow(_pins[i]) && time <sensor_values[i])sensor_values[i] = time; } }}// Derived Analog class constructorQTRSensorsAnalog::QTRSensorsAnalog(unsignedchar* analogPins,unsignedchar numSensors, unsignedchar numSamplesPerSensor,unsignedchar emitterPin){init(analogPins, numSensors, numSamplesPerSensor, emitterPin);}// the array 'pins' contains the Arduino analog pin assignment for each// sensor. For example, if pins is {0, 1, 7}, sensor 1 is on// Arduino analog input 0, sensor 2 is on Arduino analog input 1,// and sensor 3 is on Arduino analog input 7.// 'numSensors' specifies the length of the 'analogPins' array (i.e. the// number of QTR-A sensors you are using). numSensors must be// no greater than 16.// 'numSamplesPerSensor' indicates the number of 10-bit analog samples// to average per channel (i.e. per sensor) for each reading. The total// number of analog-to-digital conversions performed will be equal to// numSensors*numSamplesPerSensor. Note that it takes about 100 us to// perform a single analog-to-digital conversion, so:// if numSamplesPerSensor is 4 and numSensors is 6, it will take// 4 * 6 * 100 us = ~2.5 ms to perform a full readLine().// Increasing this parameter increases noise suppression at the cost of// sample rate. The recommended value is 4.// 'emitterPin' is the Arduino pin that controls the IR LEDs on the 8RC// modules. If you are using a 1RC (i.e. if there is no emitter pin),// or if you just want the emitters on all the time and don't want to// use an I/O pin to control it, use a value of 255 (QTR_NO_EMITTER_PIN).voidQTRSensorsAnalog::init(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor,unsignedcharemitterPin){ QTRSensors::init(analogPins, numSensors, emitterPin); _numSamplesPerSensor = numSamplesPerSensor; _maxValue =1023; // this is the maximum returned by the A/D conversion}// Reads the sensor values into an array. There *MUST* be space// for as many values as there were sensors specified in the constructor.// Example usage:// unsigned int sensor_values[8];// sensors.read(sensor_values);// The values returned are a measure of the reflectance in terms of a// 10-bit ADC average with higher values corresponding to lower// reflectance (e.g. a black surface or a void).// A 'step' of n means that the first of every n sensors is read, starting// with 'start' (this is 0-indexed, so start = 0 means start with the first// sensor). For example, step = 2, start = 1 means read the *even-numbered*// sensors.voidQTRSensorsAnalog::readPrivate(unsignedint*sensor_values, unsignedcharstep, unsignedcharstart){unsignedchar i, j;if (_pins ==0)return; // reset the valuesfor (i = start; i < _numSensors; i += step)sensor_values[i] =0;for (j =0; j < _numSamplesPerSensor; j++) {for (i = start; i < _numSensors; i += step) {sensor_values[i] +=analogRead(_pins[i]); // add the conversion result } } // get the rounded average of the readings for each sensorfor (i = start; i < _numSensors; i += step)sensor_values[i] = (sensor_values[i] + (_numSamplesPerSensor >>1)) / _numSamplesPerSensor;}// Derived Dimmable RC class constructor (one bank or combined banks)QTRDimmableRC::QTRDimmableRC(unsignedchar* pins,unsignedchar numSensors, unsignedint timeout,unsignedchar emitterPin){init(pins, numSensors, timeout, emitterPin);}// Derived Dimmable RC class constructor (separate banks)QTRDimmableRC::QTRDimmableRC(unsignedchar* pins,unsignedchar numSensors, unsignedint timeout,unsignedchar oddEmitterPin, unsignedchar evenEmitterPin){init(pins, numSensors, timeout, oddEmitterPin, evenEmitterPin);}// initialization for dimmable RC sensors with one bank or combined banks// (1 emitter control pin)// (overrides QTRSensorsAnalog::init)voidQTRDimmableRC::init(unsignedchar*pins,unsignedcharnumSensors, unsignedinttimeout, unsignedcharemitterPin){ QTRDimmable::init(pins, numSensors, emitterPin); _maxValue = timeout;}// initialization for dimmable RC sensors with separate banks// (2 emitter control pins)voidQTRDimmableRC::init(unsignedchar*pins,unsignedcharnumSensors, unsignedinttimeout,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin){ QTRDimmable::init(pins, numSensors, oddEmitterPin, evenEmitterPin); _maxValue = timeout;}// Derived Dimmable Analog class constructor (one bank or combined banks)QTRDimmableAnalog::QTRDimmableAnalog(unsignedchar* analogPins,unsignedchar numSensors, unsignedchar numSamplesPerSensor,unsignedchar emitterPin){init(analogPins, numSensors, numSamplesPerSensor, emitterPin);}// Derived Dimmable Analog class constructor (separate banks)QTRDimmableAnalog::QTRDimmableAnalog(unsignedchar* analogPins,unsignedchar numSensors, unsignedchar numSamplesPerSensor,unsignedchar oddEmitterPin, unsignedchar evenEmitterPin){init(analogPins, numSensors, numSamplesPerSensor, oddEmitterPin, evenEmitterPin);}// initialization for dimmable analog sensors with one bank or combined banks// (1 emitter control pin)// (overrides QTRSensorsAnalog::init)voidQTRDimmableAnalog::init(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor,unsignedcharemitterPin){ QTRDimmable::init(analogPins, numSensors, emitterPin); _numSamplesPerSensor = numSamplesPerSensor; _maxValue =1023; // this is the maximum returned by the A/D conversion}// initialization for dimmable analog sensors with separate banks// (2 emitter control pins)voidQTRDimmableAnalog::init(unsignedchar*analogPins,unsignedcharnumSensors, unsignedcharnumSamplesPerSensor,unsignedcharoddEmitterPin, unsignedcharevenEmitterPin){ QTRDimmable::init(analogPins, numSensors, oddEmitterPin, evenEmitterPin); _numSamplesPerSensor = numSamplesPerSensor; _maxValue =1023; // this is the maximum returned by the A/D conversion}// the destructor frees up allocated memoryQTRSensors::~QTRSensors(){if (_pins)free(_pins);if (calibratedMaximumOn)free(calibratedMaximumOn);if (calibratedMaximumOff)free(calibratedMaximumOff);if (calibratedMinimumOn)free(calibratedMinimumOn);if (calibratedMinimumOff)free(calibratedMinimumOff);}#defineKp 0.1#defineKd 2#defineKi .01// experiment to determine this, slowly increase the speeds and adjust this value. ( Note: Kp < Kd) #defineMaxSpeed 200// max speed of the robot#defineBaseSpeed 350 // this is the speed at which the motors should spin when the robot is perfectly on the line#defineNUM_SENSORS 7 // number of sensors used#defineTIMEOUT 2500 // waits for 2500 microseconds for sensor outputs to go low#defineEMITTER_PIN QTR_NO_EMITTER_PIN#definerightMotor1 A0#definerightMotor2 A1#definerightMotorPWM 10#defineleftMotor1 A4#defineleftMotor2 A3#defineleftMotorPWM 9#definemotorPower A2 QTRSensorsRCqtrrc((unsignedchar[]) {8,7,6,5,4,3,2} , NUM_SENSORS, 2500, QTR_NO_EMITTER_PIN);unsignedintsensorValues[NUM_SENSORS];float line_position;float lastError =0;unsignedintsensors[7];voidsetup(){pinAsOutput(rightMotor1);pinAsOutput(rightMotor2);pinAsOutput(rightMotorPWM);pinAsOutput(leftMotor1);pinAsOutput(leftMotor2);pinAsOutput(leftMotorPWM);pinAsOutput(motorPower); //pinAsOutput(led);digitalHigh(motorPower);for (int i =0; i <=200; i++) // begin calibration cycle to last about 2.5 seconds (100*25ms/call) {digitalLow( rightMotor1 );digitalHigh( rightMotor2 );digitalLow( leftMotor1 );digitalHigh( leftMotor2 );analogWrite(rightMotorPWM, 70);analogWrite(leftMotorPWM, 70);qtrrc.calibrate(); // reads all sensors with the define set 2500 microseconds (25 milliseconds) for sensor outputs to go low. }analogWrite(rightMotorPWM, 0);analogWrite(leftMotorPWM, 0);delay(3000);digitalLow( rightMotor2 );digitalHigh( rightMotor1 );digitalLow( leftMotor1 );digitalHigh( leftMotor2 ); }voidloop(){ line_position =qtrrc.readLine(sensorValues);int error = line_position -3000;int error1 = error - lastError;int error2 = (2.0/3.0) * error2 + error ;int motorSpeed = Kp * error + Kd * error1 + Ki * error2;int rightMotorSpeed = BaseSpeed - motorSpeed;int leftMotorSpeed = BaseSpeed + motorSpeed;if (rightMotorSpeed > MaxSpeed ) rightMotorSpeed = MaxSpeed; // prevent the motor from going beyond max speedif (leftMotorSpeed > MaxSpeed ) leftMotorSpeed = MaxSpeed; // prevent the motor from going beyond max speedif (rightMotorSpeed <0)rightMotorSpeed =0;if (leftMotorSpeed <0)leftMotorSpeed =0;analogWrite(rightMotorPWM, rightMotorSpeed);analogWrite(leftMotorPWM, leftMotorSpeed); lastError = error;}