Moved to Team 9.

Fork of LineScan by Nicholas Gan

LineScan.cpp

Committer:
ng3600
Date:
2015-04-18
Revision:
16:aaac67b2bce4
Parent:
15:4bd1c1d2cf94
Child:
17:4ba196fe78ea

File content as of revision 16:aaac67b2bce4:

/*
AnalogIn cam1(CAM1_IN);
DigitalOut camSi(CAM_SI);
DigitalOut camClk(CAM_CLK); // Definining camera pins. These are actually defined in Main... 
*/
#include "LineScan.h"

#define THRESH 5000 //may need adjusting

#define MEAN_REF 20000      //ideal mean we should see
#define CAM_CTRL_GAIN 0.0009 //should be small

#define NEUTRAL 0
#define FIND_PEAK 1
#define FIND_TROUGH 2

//#define FRAMELEN NUM_PIX -  2 * SKIP

uint16_t read1Bit(AnalogIn cam, DigitalOut *camClk){
    uint16_t pixel;
    
    //read pixel n
    pixel = cam.read_u16();
    
    //clock pulse for next pixel n + 1
    *camClk = 1;
    *camClk = 0;
    
    return pixel;  //return result as an uint16_t (16 bit integer)
}

void startRead(DigitalOut *camSi, DigitalOut *camClk){
    //pulse first clock cycle and start integral pin
    *camSi = 1;
    *camClk = 1;
    *camSi = 0;
    *camClk = 0;
}

float processFn(uint16_t *array, int arraySz, int* exposure, telemetry::NumericArray<uint16_t, NUM_PIX -  2 * SKIP> &tele_linescan_diff){   //consider adding diff to telemetry
    const static int frameLen = NUM_PIX -  2 * SKIP;
    int avg[frameLen];
    int diff[frameLen];
    int highest = 0;
    int lowest = 0;
    int total = 0;
    int h_idx_ary[frameLen];
    int h_idx_pos = 0;
    int l_idx_ary[frameLen];
    int l_idx_pos = 0;
    int state = NEUTRAL;
    int *l_walker, *h_walker;
    int out_width = frameLen;
    float out = -1.0;
    
    //for AGC
    float exposureChange;
    
    memset (h_idx_ary, -1, frameLen);
    memset (l_idx_ary, -1, frameLen);
    
    if(array){    
        avg[0] = array[SKIP - 1]/2 + array[SKIP]/2;
        diff[0] = 0;
        tele_linescan_diff[0] = 0;
        
        total += avg[0];    //AGC
        
        for(int i = 1; i < frameLen; i++){
            avg[i] = array[i - 1 + SKIP]/2 + array[i + SKIP]/2;   //smoothing
            diff[i] = avg[i - 1] - avg[i];          //differential
            tele_linescan_diff[i] = diff[i];
            
            total += avg[i];    //AGC
            
            //Finite State Machine
            switch(state){
                case NEUTRAL:
                    if( diff[i] > THRESH ){
                        state = FIND_PEAK;
                        highest = diff[i];
                    }else if( diff[i] < -THRESH ){
                        state = FIND_TROUGH;
                        lowest = diff[i];
                    }
                    break;
                    
                case FIND_PEAK:
                    if( diff[i] <= THRESH )
                        state = NEUTRAL;
                    else if(diff[i] > highest){
                        highest = diff[i];
                        h_idx_ary[h_idx_pos] = i;  //insert to array
                        h_idx_pos++;
                    }
                    break;
                    
                case FIND_TROUGH:
                    if( diff[i] >= -THRESH )
                        state = NEUTRAL;
                    else if(diff[i] < lowest){
                        lowest = diff[i];
                        l_idx_ary[l_idx_pos] = i;  //insert to array
                        l_idx_pos++;
                    }
                    break;
                    
                default:
                    //exit case if exception happened
                    return out;
            }
        }
        //AGC, simple proportional controller
        total = total / frameLen;
        exposureChange = ((float)(MEAN_REF - total)) * CAM_CTRL_GAIN;    
        *exposure += (int)exposureChange;
        if(*exposure < 0)
            *exposure = 0;
        else if(*exposure > UPDATE_RATE)
            *exposure = UPDATE_RATE;
    }
    
    l_walker = l_idx_ary;
    h_walker = h_idx_ary;
    
    while(*l_walker != -1 && *h_walker != -1){
        //evaluate out and advance if line is white on black and returns center of smallest white band
        //if interval is black on white, advance the pointer for the peak array
        if(*h_walker > *l_walker && (*h_walker - *l_walker) < out_width){
            out_width = *h_walker - *l_walker;
            out = ((float)(*h_walker + *l_walker)) / (2.0 * (float)frameLen);    //0.5 is center
            l_walker++;
        }
        h_walker++;
    }
    
    return out;
}

//call after integration time is done, returns index of array line is expected to be at and new exposure time
float getLinePos(AnalogIn cam, 
                 DigitalOut *camSi, 
                 DigitalOut *camClk, 
                 int *exposure, 
                 telemetry::NumericArray<uint16_t, 128> &tele_linescan,
                 telemetry::NumericArray<uint16_t, NUM_PIX -  2 * SKIP> &tele_linescan_diff){
    uint16_t lineAry[NUM_PIX];
    float position;
    
    //read 
    startRead(camSi, camClk);
    for(int i = 0; i < NUM_PIX; i++){
        lineAry[i] = read1Bit(cam, camClk);
        tele_linescan[i] = lineAry[i];
    }
    
    //process line scan data
    position  = processFn(lineAry, NUM_PIX, exposure, tele_linescan_diff);
    
    return position;
}

/*
sample call (handler thread):

while(1){
   linePos  = getLinePos(cameraIn1, si, clk, &exposureTime);   //volatile linePos, replace with steering angle and read 2 cameras?
   Thread::wait(exposureTime);    //sleep for 14 us
}
*/