@@ -394,15 +394,15 @@ an independent frame rate depending on particular complexity at the moment).
394394void loop () {
395395 if (++eyeNum >= NUM_EYES) eyeNum = 0 ; // Cycle through eyes...
396396
397- uint8_t x = eye[eyeNum].colNum ;
397+ uint8_t x = eye[eyeNum].colNum ;
398+ uint32_t t = micros ();
398399
399400 // If next column for this eye is not yet rendered...
400401 if (!eye[eyeNum].column_ready ) {
401402 if (!x) { // If it's the first column...
402403
403404 // ONCE-PER-FRAME EYE ANIMATION LOGIC HAPPENS HERE -------------------
404405
405- uint32_t t = micros ();
406406 float eyeX, eyeY;
407407 // Eye movement
408408 int32_t dt = t - eyeMoveStartTime; // uS elapsed since last eye event
@@ -445,58 +445,11 @@ void loop() {
445445 eye[eyeNum].eyeX = eyeX;
446446 eye[eyeNum].eyeY = eyeY;
447447
448- // Handle pupil scaling
449- if (lightSensorPin >= 0 ) {
450- // Read light sensor, but not too often (Seesaw hates that)
451- #define LIGHT_INTERVAL (1000000 / 8 ) // 8 Hz, don't poll Seesaw too often
452- if ((t - lastLightReadTime) >= LIGHT_INTERVAL) {
453- // Fun fact: eyes have a "consensual response" to light -- both
454- // pupils will react even if the opposite eye is stimulated.
455- // Meaning we can get away with using a single light sensor for
456- // both eyes. This comment has nothing to do with the code.
457- uint16_t rawReading = (lightSensorPin >= 100 ) ?
458- seesaw.analogRead (lightSensorPin - 100 ) : analogRead (lightSensorPin);
459- if (rawReading <= 1023 ) {
460- if (rawReading < lightSensorMin) rawReading = lightSensorMin; // Clamp light sensor range
461- else if (rawReading > lightSensorMax) rawReading = lightSensorMax; // to within usable range
462- float v = (float )(rawReading - lightSensorMin) / (float )(lightSensorMax - lightSensorMin); // 0.0 to 1.0
463- v = pow (v, lightSensorCurve);
464- lastLightValue = irisMin + v * irisRange;
465- lastLightReadTime = t;
466- lightSensorFailCount = 0 ;
467- } else { // I2C error
468- if (++lightSensorFailCount >= 50 ) { // If repeated errors in succession...
469- lightSensorPin = -1 ; // Stop trying to use the light sensor
470- } else {
471- lastLightReadTime = t - LIGHT_INTERVAL + 40000 ; // Try again in 40 ms
472- }
473- }
474- }
475- irisValue = (irisValue * 0.97 ) + (lastLightValue * 0.03 ); // Filter response for smooth reaction
476- } else {
477- // Not light responsive. Use autonomous iris w/fractal subdivision
478- float n, sum = 0.5 ;
479- for (uint16_t i=0 ; i<IRIS_LEVELS; i++) { // 0,1,2,3,...
480- uint16_t iexp = 1 << (i+1 ); // 2,4,8,16,...
481- uint16_t imask = (iexp - 1 ); // 2^i-1 (1,3,7,15,...)
482- uint16_t ibits = iris_frame & imask; // 0 to mask
483- if (ibits) {
484- float weight = (float )ibits / (float )iexp; // 0.0 to <1.0
485- n = iris_prev[i] * (1.0 - weight) + iris_next[i] * weight;
486- } else {
487- n = iris_next[i];
488- iris_prev[i] = iris_next[i];
489- iris_next[i] = -0.5 + ((float )random (1000 ) / 999.0 ); // -0.5 to +0.5
490- }
491- iexp = 1 << (IRIS_LEVELS - i); // ...8,4,2,1
492- sum += n / (float )iexp;
493- }
494- irisValue = irisMin + (sum * irisRange); // 0.0-1.0 -> iris min/max
495- if ((++iris_frame) >= (1 << IRIS_LEVELS)) iris_frame = 0 ;
496- }
497-
498448 // pupilFactor? irisValue? TO DO: pick a name and stick with it
499449 eye[eyeNum].pupilFactor = irisValue;
450+ // Also note - irisValue is calculated at the END of this function
451+ // for the next frame (because the sensor must be read when there's
452+ // no SPI traffic to the left eye)
500453
501454 // Similar to the autonomous eye movement above -- blink start times
502455 // and durations are random (within ranges).
@@ -821,6 +774,57 @@ void loop() {
821774 eye[eyeNum].display ->setAddrWindow (0 , 0 , 240 , 240 );
822775 delayMicroseconds (1 );
823776 digitalWrite (eye[eyeNum].dc , HIGH); // Data mode
777+ if (eyeNum == (NUM_EYES-1 )) {
778+ // Handle pupil scaling
779+ if (lightSensorPin >= 0 ) {
780+ // Read light sensor, but not too often (Seesaw hates that)
781+ #define LIGHT_INTERVAL (1000000 / 10 ) // 10 Hz, don't poll Seesaw too often
782+ if ((t - lastLightReadTime) >= LIGHT_INTERVAL) {
783+ // Fun fact: eyes have a "consensual response" to light -- both
784+ // pupils will react even if the opposite eye is stimulated.
785+ // Meaning we can get away with using a single light sensor for
786+ // both eyes. This comment has nothing to do with the code.
787+ uint16_t rawReading = (lightSensorPin >= 100 ) ?
788+ seesaw.analogRead (lightSensorPin - 100 ) : analogRead (lightSensorPin);
789+ if (rawReading <= 1023 ) {
790+ if (rawReading < lightSensorMin) rawReading = lightSensorMin; // Clamp light sensor range
791+ else if (rawReading > lightSensorMax) rawReading = lightSensorMax; // to within usable range
792+ float v = (float )(rawReading - lightSensorMin) / (float )(lightSensorMax - lightSensorMin); // 0.0 to 1.0
793+ v = pow (v, lightSensorCurve);
794+ lastLightValue = irisMin + v * irisRange;
795+ lastLightReadTime = t;
796+ lightSensorFailCount = 0 ;
797+ } else { // I2C error
798+ if (++lightSensorFailCount >= 25 ) { // If repeated errors in succession...
799+ lightSensorPin = -1 ; // Stop trying to use the light sensor
800+ } else {
801+ lastLightReadTime = t - LIGHT_INTERVAL + 30000 ; // Try again in 30 ms
802+ }
803+ }
804+ }
805+ irisValue = (irisValue * 0.97 ) + (lastLightValue * 0.03 ); // Filter response for smooth reaction
806+ } else {
807+ // Not light responsive. Use autonomous iris w/fractal subdivision
808+ float n, sum = 0.5 ;
809+ for (uint16_t i=0 ; i<IRIS_LEVELS; i++) { // 0,1,2,3,...
810+ uint16_t iexp = 1 << (i+1 ); // 2,4,8,16,...
811+ uint16_t imask = (iexp - 1 ); // 2^i-1 (1,3,7,15,...)
812+ uint16_t ibits = iris_frame & imask; // 0 to mask
813+ if (ibits) {
814+ float weight = (float )ibits / (float )iexp; // 0.0 to <1.0
815+ n = iris_prev[i] * (1.0 - weight) + iris_next[i] * weight;
816+ } else {
817+ n = iris_next[i];
818+ iris_prev[i] = iris_next[i];
819+ iris_next[i] = -0.5 + ((float )random (1000 ) / 999.0 ); // -0.5 to +0.5
820+ }
821+ iexp = 1 << (IRIS_LEVELS - i); // ...8,4,2,1
822+ sum += n / (float )iexp;
823+ }
824+ irisValue = irisMin + (sum * irisRange); // 0.0-1.0 -> iris min/max
825+ if ((++iris_frame) >= (1 << IRIS_LEVELS)) iris_frame = 0 ;
826+ }
827+ }
824828 } // end first-column check
825829
826830 // MUST read the booper when there’s no SPI traffic across the nose!
0 commit comments