Pinscape Controller version 1 fork. This is a fork to allow for ongoing bug fixes to the original controller version, from before the major changes for the expansion board project.
Dependencies: FastIO FastPWM SimpleDMA mbed
Fork of Pinscape_Controller by
ccdSensor.h
00001 // CCD plunger sensor 00002 // 00003 // This file implements our generic plunger sensor interface for the 00004 // TAOS TSL1410R CCD array sensor. 00005 00006 00007 00008 // Number of pixels we read from the CCD on each frame. Use the 00009 // sample size from config.h. 00010 const int npix = CCD_NPIXELS_SAMPLED; 00011 00012 // PlungerSensor interface implementation for the CCD 00013 class PlungerSensor 00014 { 00015 public: 00016 PlungerSensor() : ccd(CCD_SO_PIN) 00017 { 00018 } 00019 00020 // initialize 00021 void init() 00022 { 00023 // flush any random power-on values from the CCD's integration 00024 // capacitors, and start the first integration cycle 00025 ccd.clear(); 00026 } 00027 00028 // Perform a low-res scan of the sensor. 00029 int lowResScan() 00030 { 00031 // read the pixels at low resolution 00032 const int nlpix = 32; 00033 uint16_t pix[nlpix]; 00034 ccd.read(pix, nlpix); 00035 00036 // determine which end is brighter 00037 uint16_t p1 = pix[0]; 00038 uint16_t p2 = pix[nlpix-1]; 00039 int si = 0, di = 1; 00040 if (p1 < p2) 00041 si = nlpix - 1, di = -1; 00042 00043 // figure the shadow edge threshold - just use the midpoint 00044 // of the levels at the bright and dark ends 00045 uint16_t shadow = uint16_t((long(p1) + long(p2))/2); 00046 00047 // find the current tip position 00048 for (int n = 0 ; n < nlpix ; ++n, si += di) 00049 { 00050 // check to see if we found the shadow 00051 if (pix[si] <= shadow) 00052 { 00053 // got it - normalize it to normal 'npix' resolution and 00054 // return the result 00055 return n*npix/nlpix; 00056 } 00057 } 00058 00059 // didn't find a shadow - assume the whole array is in shadow (so 00060 // the edge is at the zero pixel point) 00061 return 0; 00062 } 00063 00064 // Perform a high-res scan of the sensor. 00065 bool highResScan(int &pos) 00066 { 00067 // read the array 00068 ccd.read(pix, npix); 00069 00070 // get the brightness at each end of the sensor 00071 long b1 = pix[0]; 00072 long b2 = pix[npix-1]; 00073 00074 // Work from the bright end to the dark end. VP interprets the 00075 // Z axis value as the amount the plunger is pulled: zero is the 00076 // rest position, and the axis maximum is fully pulled. So we 00077 // essentially want to report how much of the sensor is lit, 00078 // since this increases as the plunger is pulled back. 00079 int si = 0, di = 1; 00080 long hi = b1; 00081 if (b1 < b2) 00082 si = npix - 1, di = -1, hi = b2; 00083 00084 // Figure the shadow threshold. In practice, the portion of the 00085 // sensor that's not in shadow has all pixels consistently near 00086 // saturation; the first drop in brightness is pretty reliably the 00087 // start of the shadow. So set the threshold level to be closer 00088 // to the bright end's brightness level, so that we detect the leading 00089 // edge if the shadow isn't perfectly sharp. Use the point 1/3 of 00090 // the way down from the high top the low side, so: 00091 // 00092 // threshold = lo + (hi - lo)*2/3 00093 // = lo + hi*2/3 - lo*2/3 00094 // = lo - lo*2/3 + hi*2/3 00095 // = lo*1/3 + hi*2/3 00096 // = (lo + hi*2)/3 00097 // 00098 // Now, 'lo' is always one of b1 or b2, and 'hi' is the other 00099 // one, so we can rewrite this as: 00100 long midpt = (b1 + b2 + hi)/3; 00101 00102 // If we have enough contrast, proceed with the scan. 00103 // 00104 // If the bright end and dark end don't differ by enough, skip this 00105 // reading entirely. Either we have an overexposed or underexposed frame, 00106 // or the sensor is misaligned and is either fully in or out of shadow 00107 // (it's supposed to be mounted such that the edge of the shadow always 00108 // falls within the sensor, for any possible plunger position). 00109 if (labs(b1 - b2) > 0x1000) 00110 { 00111 uint16_t *pixp = pix + si; 00112 for (int n = 0 ; n < npix ; ++n, pixp += di) 00113 { 00114 // if we've crossed the midpoint, report this position 00115 if (long(*pixp) < midpt) 00116 { 00117 // note the new position 00118 pos = n; 00119 return true; 00120 } 00121 } 00122 } 00123 00124 // we didn't find a shadow - return no reading 00125 return false; 00126 } 00127 00128 // send an exposure report to the joystick interface 00129 void sendExposureReport(USBJoystick &js) 00130 { 00131 // send reports for all pixels 00132 int idx = 0; 00133 while (idx < npix) 00134 { 00135 js.updateExposure(idx, npix, pix); 00136 wait_ms(1); 00137 } 00138 00139 // The pixel dump requires many USB reports, since each report 00140 // can only send a few pixel values. An integration cycle has 00141 // been running all this time, since each read starts a new 00142 // cycle. Our timing is longer than usual on this round, so 00143 // the integration won't be comparable to a normal cycle. Throw 00144 // this one away by doing a read now, and throwing it away - that 00145 // will get the timing of the *next* cycle roughly back to normal. 00146 ccd.read(pix, npix); 00147 } 00148 00149 private: 00150 // pixel buffer 00151 uint16_t pix[npix]; 00152 00153 // the low-level interface to the CCD hardware 00154 TSL1410R<CCD_SI_PIN, CCD_CLOCK_PIN> ccd; 00155 };
Generated on Wed Jul 13 2022 23:56:13 by 1.7.2