Moved to Team 9.

Fork of LineScan by Nicholas Gan

Revision:
14:928254a609cb
Parent:
13:c17cf029d899
Child:
15:4bd1c1d2cf94
--- a/LineScan.cpp	Fri Apr 10 00:38:31 2015 +0000
+++ b/LineScan.cpp	Sat Apr 18 00:19:59 2015 +0000
@@ -5,10 +5,16 @@
 */
 #include "LineScan.h"
 
-#define THRESH 5000
+#define THRESH 5000 //may need adjusting
 
 #define MEAN_REF 20000      //ideal mean we should see
-#define CAM_CTRL_GAIN 0.0005 //should be small
+#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;
@@ -18,7 +24,7 @@
     
     //clock pulse for next pixel n + 1
     *camClk = 1;
-    *camClk = 0;    // Apparently there is no need for any delay. It may be desireable to flatten this, or perhaps the compiler does it. 
+    *camClk = 0;
     
     return pixel;  //return result as an uint16_t (16 bit integer)
 }
@@ -31,59 +37,112 @@
     *camClk = 0;
 }
 
-float processFn(uint16_t *array, int arraySz, int* exposure){
-    const static int frameLen = NUM_PIX -  2 * SKIP;
-    int avg[frameLen];
-    int diff[frameLen];
+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 = frameLen/2;
-    int l_idx = frameLen/2;
+    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;
     
-    //Just finds line center, does not track crossings (needs this feature)
     if(array){ 
+        memset (h_idx_ary, -1, FRAMELEN);
+        memset (l_idx_ary, -1, FRAMELEN);
+    
         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++){
+        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
             
-            if(diff[i] > highest){
-                highest = diff[i];
-                h_idx = i;
-            }
-            else if(diff[i] < lowest){
-                lowest = diff[i];
-                l_idx = i;
+            //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;
+        total = total / FRAMELEN;
         exposureChange = ((float)(MEAN_REF - total)) * CAM_CTRL_GAIN;    
         *exposure += (int)exposureChange;
-        if(*exposure < 1)
-            *exposure = 1;
-        else if(*exposure > 30)
-            *exposure = 30;
+        if(*exposure < 0)
+            *exposure = 0;
+        else if(*exposure > UPDATE_RATE)
+            *exposure = UPDATE_RATE;
     }
-    //valid if white line on black and not blinded
-    if(h_idx > l_idx && (highest - lowest) > THRESH)
-        return ((float)(h_idx + l_idx)) / (2.0 * (float)frameLen);    //0.5 is center
-    else
-        return -1.0;  //invalid read
+    
+    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){
+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;
     
@@ -95,7 +154,7 @@
     }
     
     //process line scan data
-    position  = processFn(lineAry, NUM_PIX, exposure);
+    position  = processFn(lineAry, NUM_PIX, exposure, tele_linescan_diff);
     
     return position;
 }