Moved to Team 9.

Fork of LineScan by Nicholas Gan

LineScan.cpp

Committer:
ikrase
Date:
2015-05-21
Revision:
27:173b2f564143
Parent:
26:5e70edee216d

File content as of revision 27:173b2f564143:

#include "LineScan.h"
#include <string.h>

#define THRESH 1000

#define MEAN_REF 10000      //ideal mean we should see
#define CAM_CTRL_GAIN 0.002 //should be small

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

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> &tele_linescan_diff)
{
    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[10];
    int h_idx_pos = 0;
    int l_idx_ary[10];
    int l_idx_pos = 0;
    int state = NEUTRAL;
    int *l_walker, *h_walker;
    int out_width = frameLen;
    int i;
    float out = -1.0;
    int thinnest = 128;
    int linestart = -1;
    int linestop = -1;
    int tempstart = 0;

    //for AGC
    float exposureChange;

    h_idx_ary[0] = -1;
    l_idx_ary[0] = -1;

    if(array) {
        avg[0] = array[SKIP - 1]/2 + array[SKIP]/2;     // To cut off the (invalid) ends of the data. 
        diff[0] = 0;
        tele_linescan_diff[0] = diff[0];

        total += avg[0];    //AGC

        for(i = 1; i < frameLen; i++) {
            avg[i] = array[i - 1 + SKIP]/2 + array[i + SKIP]/2;   //smoothing
            if ((avg[i] - avg[i-1] >= THRESH) || (avg[i] - avg[i-1] <= -THRESH)) {
                diff[i] = avg[i] - avg[i-1];          //differential
            } else {
                diff[i] = 0;
            }
            if (diff [i] > 0) {
                tele_linescan_diff[i] = 10000;
            } else if (diff[i] < 0) {
                tele_linescan_diff[i] = 5000;
            } else {
                tele_linescan_diff[i] = 0;
            }

            total += avg[i];    //AGC


            //Finite State Machine
            //problem in this section, rewrite? find peaks and troughs
            switch(state) {
                case NEUTRAL:
                    //serial.printf("Neutral case in processFn\r\n");
                    if( diff[i] > THRESH ) {
                        state = FIND_PEAK;
                        highest = diff[i];
                        h_idx_ary[h_idx_pos] = i;
                        tempstart = i;
                    } /*else if( diff[i] < -THRESH ) {
                        state = FIND_TROUGH;
                        lowest = diff[i];
                        l_idx_ary[l_idx_pos] = i;
                        tempstart = i;
                    }*/
                    break;

                case FIND_PEAK:
                    //serial.printf("Peak case in processFn\r\n");
                    if( diff[i] <= -THRESH ) {
                        state = NEUTRAL;
                        h_idx_pos++;
                        h_idx_ary[h_idx_pos] = -1;  //last element is always -1
                        if ((i - tempstart > 4) && (i - tempstart < thinnest)) {
                            thinnest = i - tempstart;
                            linestart = tempstart;
                            linestop = i;
                        }
                    } else if(diff[i] > highest) {
                        highest = diff[i];
                        h_idx_ary[h_idx_pos] = i;  //insert to array, clobbers
                        tempstart = i;
                    }
                    break;

                case FIND_TROUGH:
                    //serial.printf("Trough case in processFn\r\n");
                    if( diff[i] >= THRESH ) {
                        state = NEUTRAL;
                        l_idx_pos++;
                        l_idx_ary[l_idx_pos] = -1;  //last element is always -1
                        if ((i - tempstart > 4) && (i - tempstart < thinnest)) {
                            thinnest = i - tempstart;
                            linestart = tempstart;
                            linestop = i;
                        }
                    } else if(diff[i] < lowest) {
                        lowest = diff[i];
                        l_idx_ary[l_idx_pos] = i;  //insert to array, clobbers
                        tempstart = i;
                    }
                    break;

                default:
                    //exit case if exception happened
                    serial.printf("Default case in processFn\r\n");
                    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
        //width needs to be larger than 4 pixels wide to be a good read.

        if(*h_walker > *l_walker && (*h_walker - *l_walker) < out_width && (*h_walker - *l_walker) > 3){
            out_width = *h_walker - *l_walker;
            out = ((float)(*h_walker + *l_walker)) / (2.0 * (float)frameLen);    //0.5 is center
            l_walker++;
        }
        h_walker++;

        //serial.printf("%d %d\r\n", *h_walker, *l_walker);
        //serial.printf("%.2f\r\n", out);
    }*/

    if (linestart != -1) {
        out = ((float)(linestart + linestop)) / (2.0 * (float)frameLen);
    } else {
        out = -1;
    }
    return out;
}

float processFn2(uint16_t *array, int arraySz, int* exposure)
{
    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[10];
    int h_idx_pos = 0;
    int l_idx_ary[10];
    int l_idx_pos = 0;
    int state = NEUTRAL;
    int *l_walker, *h_walker;
    int out_width = frameLen;
    int i;
    float out = -1.0;
    int thinnest = 128;
    int linestart = -1;
    int linestop = -1;
    int tempstart = 0;

    //for AGC
    float exposureChange;

    h_idx_ary[0] = -1;
    l_idx_ary[0] = -1;

    if(array) {
        avg[0] = array[SKIP - 1]/2 + array[SKIP]/2;
        diff[0] = 0;
        //tele_linescan_diff[0] = diff[0];

        total += avg[0];    //AGC

        for(i = 1; i < frameLen; i++) {
            avg[i] = array[i - 1 + SKIP]/2 + array[i + SKIP]/2;   //smoothing
            diff[i] = avg[i] - avg[i-1];          //differential
            //tele_linescan_diff[i] = diff[i];

            total += avg[i];    //AGC


            //Finite State Machine
            //problem in this section, rewrite? find peaks and troughs
            switch(state) {
                case NEUTRAL:
                    //serial.printf("Neutral case in processFn\r\n");
                    if( diff[i] > THRESH ) {
                        state = FIND_PEAK;
                        highest = diff[i];
                        h_idx_ary[h_idx_pos] = i;
                        tempstart = i;
                    } else if( diff[i] < -THRESH ) {
                        state = FIND_TROUGH;
                        lowest = diff[i];
                        l_idx_ary[l_idx_pos] = i;
                        tempstart = i;
                    }
                    break;

                case FIND_PEAK:
                    //serial.printf("Peak case in processFn\r\n");
                    if( diff[i] <= THRESH ) {
                        state = NEUTRAL;
                        h_idx_pos++;
                        h_idx_ary[h_idx_pos] = -1;  //last element is always -1
                        if ((i - tempstart > 4) && (i - tempstart < thinnest)) {
                            thinnest = i - tempstart;
                            linestart = tempstart;
                            linestop = i;
                        }
                    } else if(diff[i] > highest) {
                        highest = diff[i];
                        h_idx_ary[h_idx_pos] = i;  //insert to array, clobbers
                        tempstart = i;
                    }
                    break;

                case FIND_TROUGH:
                    //serial.printf("Trough case in processFn\r\n");
                    if( diff[i] >= -THRESH ) {
                        state = NEUTRAL;
                        l_idx_pos++;
                        l_idx_ary[l_idx_pos] = -1;  //last element is always -1
                        if ((i - tempstart > 4) && (i - tempstart < thinnest)) {
                            thinnest = i - tempstart;
                            linestart = tempstart;
                            linestop = i;
                        }
                    } else if(diff[i] < lowest) {
                        lowest = diff[i];
                        l_idx_ary[l_idx_pos] = i;  //insert to array, clobbers
                        tempstart = i;
                    }
                    break;

                default:
                    //exit case if exception happened
                    serial.printf("Default case in processFn\r\n");
                    return out;
            }
        }
        //AGC, simple proportional controller
        total = total / frameLen;
        exposureChange = ((float)(MEAN_REF - total)) * CAM_CTRL_GAIN;       // This is actually I control. 
        *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
        //width needs to be larger than 4 pixels wide to be a good read.

        if(*h_walker > *l_walker && (*h_walker - *l_walker) < out_width && (*h_walker - *l_walker) > 3){
            out_width = *h_walker - *l_walker;
            out = ((float)(*h_walker + *l_walker)) / (2.0 * (float)frameLen);    //0.5 is center
            l_walker++;
        }
        h_walker++;

        //serial.printf("%d %d\r\n", *h_walker, *l_walker);
        //serial.printf("%.2f\r\n", out);
    }*/

    if (linestart != -1) {
        out = ((float)(linestart + linestop)) / (2.0 * (float)frameLen);
    } else {
        out = -1;
    }
    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, NUM_PIX> &tele_linescan,
                 telemetry::NumericArray<uint16_t, NUM_PIX> &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;
}



float getLinePos2(AnalogIn cam,
                  DigitalOut *camSi,
                  DigitalOut *camClk,
                  int *exposure)            // Doesn't send telem. 
{
    uint16_t lineAry[NUM_PIX];
    float position;

    //read
    startRead(camSi, camClk);
    for(int i = 0; i < NUM_PIX; i++) {
        lineAry[i] = read1Bit(cam, camClk);
    }

    //process line scan data
    position  = processFn2(lineAry, NUM_PIX, exposure);

    return position;
}