Skip to content

Commit fcc0787

Browse files
Merge pull request #813 from adafruit/philb-branch
M4_Eyes: more stable boop reading
2 parents af5623b + 6f6e9d1 commit fcc0787

2 files changed

Lines changed: 48 additions & 43 deletions

File tree

M4_Eyes/M4_Eyes.ino

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ uint32_t lastLightReadTime = 0;
5656
float lastLightValue = 0.5;
5757
double irisValue = 0.5;
5858
int iPupilFactor = 42;
59-
uint32_t boopSum = 0;
59+
uint32_t boopSum = 0,
60+
boopSumFiltered = 0;
6061
bool booped = false;
6162
int fixate = 7;
6263
uint8_t lightSensorFailCount = 0;
@@ -106,6 +107,15 @@ SPISettings settings(DISPLAY_FREQ, MSBFIRST, SPI_MODE0);
106107
// the affected DMA channel (DMAbuddy::fix()).
107108
#define DMA_TIMEOUT ((240 * 16 * 4000) / (DISPLAY_FREQ / 1000))
108109

110+
static inline uint16_t readBoop(void) {
111+
uint16_t counter = 0;
112+
pinMode(boopPin, OUTPUT);
113+
digitalWrite(boopPin, HIGH);
114+
pinMode(boopPin, INPUT);
115+
while(digitalRead(boopPin) && (++counter < 1000));
116+
return counter;
117+
}
118+
109119
// Crude error handler. Prints message to Serial Monitor, blinks LED.
110120
void fatal(char *message, uint16_t blinkDelay) {
111121
Serial.println(message);
@@ -330,6 +340,14 @@ void setup() {
330340
calcDisplacement();
331341
Serial.printf("Free RAM: %d\n", availableRAM());
332342

343+
if(boopPin >= 0) {
344+
boopThreshold = 0;
345+
for(i=0; i<240; i++) {
346+
boopThreshold += readBoop();
347+
}
348+
boopThreshold = boopThreshold * 110 / 100; // 10% overhead
349+
}
350+
333351
randomSeed(SysTick->VAL + analogRead(A2));
334352
eyeOldX = eyeNewX = eyeOldY = eyeNewY = mapRadius; // Start in center
335353
for(e=0; e<NUM_EYES; e++) { // For each eye...
@@ -419,7 +437,7 @@ void loop() {
419437
}
420438

421439
// Eyes fixate (are slightly crossed) -- amount is filtered for boops
422-
int nufix = booped ? 150 : 7;
440+
int nufix = booped ? 90 : 7;
423441
fixate = ((fixate * 15) + nufix) / 16;
424442
// save eye position to this eye's struct so it's same throughout render
425443
if(eyeNum & 1) eyeX += fixate; // Eyes converge slightly toward center
@@ -500,37 +518,39 @@ void loop() {
500518
int ix = (int)map2screen(mapRadius - eye[eyeNum].eyeX) + 120, // Pupil position
501519
iy = (int)map2screen(mapRadius - eye[eyeNum].eyeY) + 120; // on screen
502520
iy += irisRadius / 2; // top edge of iris (ish) in screen pixels
503-
float qqq; // So many sloppy temp vars in here for now, sorry
521+
float uq, lq; // So many sloppy temp vars in here for now, sorry
504522
if(eyeNum & 1) ix = 239 - ix; // Flip for right eye
505523
if(iy > upperOpen[ix]) {
506-
qqq = 1.0;
524+
uq = 1.0;
507525
} else if(iy < upperClosed[ix]) {
508-
qqq = 0.0;
526+
uq = 0.0;
527+
} else {
528+
uq = (float)(iy - upperClosed[ix]) / (float)(upperOpen[ix] - upperClosed[ix]);
529+
}
530+
if(booped) {
531+
uq = 0.9;
532+
lq = 0.7;
509533
} else {
510-
qqq = (float)(iy - upperClosed[ix]) / (float)(upperOpen[ix] - upperClosed[ix]);
534+
lq = 1.0 - uq;
511535
}
512536
// Dampen eyelid movements slightly
513537
// SAVE upper & lower lid factors per eye,
514538
// they need to stay consistent across frame
515-
eye[eyeNum].upperLidFactor = (eye[eyeNum].upperLidFactor * 0.75) + (qqq * 0.25);
516-
eye[eyeNum].lowerLidFactor = 1.0 - eye[eyeNum].upperLidFactor;
539+
eye[eyeNum].upperLidFactor = (eye[eyeNum].upperLidFactor * 0.6) + (uq * 0.4);
540+
eye[eyeNum].lowerLidFactor = (eye[eyeNum].lowerLidFactor * 0.6) + (lq * 0.4);
541+
517542

518543
// Process blinks
519544
if(eye[eyeNum].blink.state) { // Eye currently blinking?
520545
// Check if current blink state time has elapsed
521546
if((t - eye[eyeNum].blink.startTime) >= eye[eyeNum].blink.duration) {
522-
if((eye[eyeNum].blink.state == ENBLINK) && booped) {
523-
// do nothing, don't advance blink state while booped
547+
if(++eye[eyeNum].blink.state > DEBLINK) { // Deblinking finished?
548+
eye[eyeNum].blink.state = NOBLINK; // No longer blinking
549+
eye[eyeNum].blinkFactor = 0.0;
550+
} else { // Advancing from ENBLINK to DEBLINK mode
551+
eye[eyeNum].blink.duration *= 2; // DEBLINK is 1/2 ENBLINK speed
552+
eye[eyeNum].blink.startTime = t;
524553
eye[eyeNum].blinkFactor = 1.0;
525-
} else {
526-
if(++eye[eyeNum].blink.state > DEBLINK) { // Deblinking finished?
527-
eye[eyeNum].blink.state = NOBLINK; // No longer blinking
528-
eye[eyeNum].blinkFactor = 0.0;
529-
} else { // Advancing from ENBLINK to DEBLINK mode
530-
eye[eyeNum].blink.duration *= 2; // DEBLINK is 1/2 ENBLINK speed
531-
eye[eyeNum].blink.startTime = t;
532-
eye[eyeNum].blinkFactor = 1.0;
533-
}
534554
}
535555
} else {
536556
eye[eyeNum].blinkFactor = (float)(t - eye[eyeNum].blink.startTime) / (float)eye[eyeNum].blink.duration;
@@ -549,21 +569,9 @@ void loop() {
549569

550570
// Once per frame (of eye #0), reset boopSum...
551571
if((eyeNum == 0) && (boopPin >= 0)) {
552-
if(boopSum > boopThreshold) {
572+
boopSumFiltered = ((boopSumFiltered * 3) + boopSum) / 4;
573+
if(boopSumFiltered > boopThreshold) {
553574
if(!booped) {
554-
timeOfLastBlink = t;
555-
// slow, intentional blink
556-
uint32_t blinkDuration = random(60000, 100000);
557-
// Set up durations for both eyes (if not already winking)
558-
for(uint8_t e=0; e<NUM_EYES; e++) {
559-
// if(eye[e].blink.state == NOBLINK) {
560-
if(1) {
561-
eye[e].blink.state = ENBLINK;
562-
eye[e].blink.startTime = t;
563-
eye[e].blink.duration = blinkDuration;
564-
}
565-
}
566-
timeToNextBlink = blinkDuration * 3 + random(4000000);
567575
Serial.println("BOOP!");
568576
}
569577
booped = true;
@@ -815,6 +823,11 @@ void loop() {
815823
digitalWrite(eye[eyeNum].dc, HIGH); // Data mode
816824
} // end first-column check
817825

826+
// MUST read the booper when there’s no SPI traffic across the nose!
827+
if((eyeNum == (NUM_EYES-1)) && (boopPin >= 0)) {
828+
boopSum += readBoop();
829+
}
830+
818831
memcpy(eye[eyeNum].dptr, &eye[eyeNum].column[eye[eyeNum].colIdx].descriptor[0], sizeof(DmacDescriptor));
819832
eye[eyeNum].dma_busy = true;
820833
eye[eyeNum].dma.startJob();
@@ -824,13 +837,4 @@ void loop() {
824837
}
825838
eye[eyeNum].colIdx ^= 1; // Alternate 0/1 line structs
826839
eye[eyeNum].column_ready = false; // OK to render next line
827-
828-
if((eyeNum == 0) && (boopPin >= 0)) {
829-
uint16_t counter = 0;
830-
pinMode(boopPin, OUTPUT);
831-
digitalWrite(boopPin, HIGH);
832-
pinMode(boopPin, INPUT);
833-
while(digitalRead(boopPin) && (++counter < 1000));
834-
boopSum += counter;
835-
}
836840
}

M4_Eyes/file.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ void loadConfig(char *filename) {
247247

248248
lightSensorPin = doc["lightSensor"] | lightSensorPin;
249249
boopPin = doc["boopSensor"] | boopPin;
250-
boopThreshold = doc["boopThreshold"] | boopThreshold;
250+
// Computed at startup, NOT from file now
251+
// boopThreshold = doc["boopThreshold"] | boopThreshold;
251252

252253
// Values that can be distinct per-eye but have a common default...
253254
uint16_t pupilColor = dwim(doc["pupilColor"] , eye[0].pupilColor),

0 commit comments

Comments
 (0)