Skip to content

Commit 9fe2e59

Browse files
authored
Merge pull request #1 from darkgrue/master
Fixes to wiichuck support and upstream compilation checks.
2 parents c461360 + 4d9bf4c commit 9fe2e59

17 files changed

+200
-108
lines changed

M4_Eyes/HeatSensor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ void HeatSensor::setup()
2222

2323
// default settings
2424
status = amg.begin();
25-
if (!status) {
25+
if(!status) {
2626
Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
2727
while (1);
2828
}
@@ -77,7 +77,7 @@ void HeatSensor::find_focus()
7777
for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++) {
7878
int val = min(5, round(max(0, pixels[i-1] - 20) / 2));
7979
Serial.print(charPixels[val]);
80-
if (i % 8 == 0)
80+
if(i % 8 == 0)
8181
Serial.println();
8282
}
8383
Serial.println();

M4_Eyes/M4_Eyes.ino

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ int iPupilFactor = 42;
5959
uint32_t boopSum = 0,
6060
boopSumFiltered = 0;
6161
bool booped = false;
62+
bool eyelidsClosed = false;
63+
bool eyelidsWide = false;
6264
int fixate = 7;
6365
uint8_t lightSensorFailCount = 0;
6466

@@ -135,34 +137,52 @@ uint32_t availableRAM(void) {
135137

136138
// USER CALLABLE FUNCTIONS
137139

138-
// set the booped flag
139-
void eyesWide(bool t) {
140-
booped = t;
140+
// Start a blink.
141+
void eyesBlink() {
142+
Serial.println("eyesBlink()");
143+
timeToNextBlink = 0;
141144
}
142145

143-
// start a blink
144-
void eyesBlink() {
145-
timeToNextBlink = 0;
146+
// Force the booped flag to be set true.
147+
void eyesBoop() {
148+
Serial.println("eyesBoop()");
149+
boopSum = 99999;
150+
}
151+
152+
// Close eyelids.
153+
void eyesClose() {
154+
Serial.println("eyesClose()");
155+
eyelidsClosed = true;
146156
}
147157

148-
// force the eyes to a position on the screen
158+
// Return the eyes to normal random movement.
159+
void eyesNormal() {
160+
// Serial.println("eyesNormal()");
161+
moveEyesRandomly = true;
162+
}
163+
164+
// Open eyelids wide.
165+
void eyesWide() {
166+
Serial.println("eyesWide()");
167+
eyelidsWide = true;
168+
}
169+
170+
// Force the eyes to a position on the screen.
149171
void eyesToCorner(float x, float y, bool immediate) {
172+
// Serial.println("eyesToCorner(" + String(x) + ", " + String(-y) + ", " + (immediate ? "TRUE" : "FALSE") + ")");
150173
moveEyesRandomly = false;
151174
eyeTargetX = x;
152175
eyeTargetY = y;
153-
if (immediate)
176+
if(immediate)
154177
eyeMoveDuration = 0;
155178
}
156179

157-
// return the eyes to normal random movement
158-
void eyesNormal() {
159-
moveEyesRandomly = true;
160-
}
161-
162180

163181
// SETUP FUNCTION - CALLED ONCE AT PROGRAM START ---------------------------
164182

165183
void setup() {
184+
Serial.println("SETUP BEGINS");
185+
166186
if(!arcada.arcadaBegin()) fatal("Arcada init fail!", 100);
167187
#if defined(USE_TINYUSB)
168188
if(!arcada.filesysBeginMSD()) fatal("No filesystem found!", 250);
@@ -214,10 +234,10 @@ void setup() {
214234
#endif
215235

216236
yield();
217-
if (showSplashScreen) {
218-
if (arcada.drawBMP((char *)"/splash.bmp", 0, 0, (eye[0].display)) == IMAGE_SUCCESS) {
237+
if(showSplashScreen) {
238+
if(arcada.drawBMP((char *)"/splash.bmp", 0, 0, (eye[0].display)) == IMAGE_SUCCESS) {
219239
Serial.println("Splashing");
220-
if (NUM_EYES > 1) { // other eye
240+
if(NUM_EYES > 1) { // other eye
221241
yield();
222242
arcada.drawBMP((char *)"/splash.bmp", 0, 0, (eye[1].display));
223243
}
@@ -448,10 +468,11 @@ void setup() {
448468
}
449469

450470
lastLightReadTime = micros() + 2000000; // Delay initial light reading
471+
472+
Serial.println("END OF SETUP");
451473
}
452474

453475

454-
455476
// LOOP FUNCTION - CALLED REPEATEDLY UNTIL POWER-OFF -----------------------
456477

457478
/*
@@ -502,29 +523,29 @@ void loop() {
502523
// Eye movement
503524
int32_t dt = t - eyeMoveStartTime; // uS elapsed since last eye event
504525
if(eyeInMotion) { // Currently moving?
505-
if(dt >= eyeMoveDuration) { // Time up? Destination reached.
506-
eyeInMotion = false; // Stop moving
507-
if (moveEyesRandomly) {
508-
eyeMoveDuration = random(10000, 3000000); // 0.01-3 sec stop
509-
eyeMoveStartTime = t; // Save initial time of stop
526+
if(dt >= eyeMoveDuration) { // Time up? Destination reached.
527+
eyeInMotion = false; // Stop moving
528+
if(moveEyesRandomly) {
529+
eyeMoveDuration = random(10000, 3000000); // 0.01-3 sec stop
530+
eyeMoveStartTime = t; // Save initial time of stop
510531
}
511532
eyeX = eyeOldX = eyeNewX; // Save position
512533
eyeY = eyeOldY = eyeNewY;
513534
} else { // Move time's not yet fully elapsed -- interpolate position
514535
float e = (float)dt / float(eyeMoveDuration); // 0.0 to 1.0 during move
515536
e = 3 * e * e - 2 * e * e * e; // Easing function: 3*e^2-2*e^3 0.0 to 1.0
516-
eyeX = eyeOldX + (eyeNewX - eyeOldX) * e; // Interp X
517-
eyeY = eyeOldY + (eyeNewY - eyeOldY) * e; // and Y
537+
eyeX = eyeOldX + (eyeNewX - eyeOldX) * e; // Interp X
538+
eyeY = eyeOldY + (eyeNewY - eyeOldY) * e; // and Y
518539
}
519-
} else { // Eye stopped
540+
} else { // Eye stopped
520541
eyeX = eyeOldX;
521542
eyeY = eyeOldY;
522-
if(dt > eyeMoveDuration) { // Time up? Begin new move.
543+
if(dt > eyeMoveDuration) { // Time up? Begin new move.
523544
// r is the radius in X and Y that the eye can go, from (0,0) in the center.
524545
float r = (float)mapDiameter - (float)DISPLAY_SIZE * M_PI_2; // radius of motion
525546
r *= 0.6; // calibration constant
526547

527-
if (moveEyesRandomly) {
548+
if(moveEyesRandomly) {
528549
eyeNewX = random(-r, r);
529550
float h = sqrt(r * r - x * x);
530551
eyeNewY = random(-h, h);
@@ -537,9 +558,9 @@ void loop() {
537558
eyeNewY += mapRadius;
538559

539560
// Set the duration for this move, and start it going.
540-
eyeMoveDuration = random(83000, 166000); // ~1/12 - ~1/6 sec
541-
eyeMoveStartTime = t; // Save initial time of move
542-
eyeInMotion = true; // Start move on next frame
561+
eyeMoveDuration = random(83000, 166000); // ~1/12 - ~1/6 sec
562+
eyeMoveStartTime = t; // Save initial time of move
563+
eyeInMotion = true; // Start move on next frame
543564
}
544565
}
545566

@@ -581,24 +602,31 @@ void loop() {
581602
iy = (int)map2screen(mapRadius - eye[eyeNum].eyeY) + (DISPLAY_SIZE/2); // on screen
582603
iy += irisRadius * trackFactor;
583604
if(eyeNum & 1) ix = DISPLAY_SIZE - 1 - ix; // Flip for right eye
584-
if(iy > upperOpen[ix]) {
605+
if(eyelidsWide) {
585606
uq = 1.0;
586-
} else if(iy < upperClosed[ix]) {
587-
uq = 0.0;
588-
} else {
589-
uq = (float)(iy - upperClosed[ix]) / (float)(upperOpen[ix] - upperClosed[ix]);
590-
}
591-
if(booped) {
607+
lq = 1.0;
608+
} else if(booped) {
592609
uq = 0.9;
593610
lq = 0.7;
594611
} else {
612+
if(iy > upperOpen[ix]) {
613+
uq = 1.0;
614+
} else if(iy < upperClosed[ix]) {
615+
uq = 0.0;
616+
} else {
617+
uq = (float)(iy - upperClosed[ix]) / (float)(upperOpen[ix] - upperClosed[ix]);
618+
}
595619
lq = 1.0 - uq;
596620
}
597621
} else {
598622
// If no tracking, eye is FULLY OPEN when not blinking
599623
uq = 1.0;
600624
lq = 1.0;
601625
}
626+
if(eyelidsClosed) {
627+
uq = 0.0;
628+
lq = 0.0;
629+
}
602630
// Dampen eyelid movements slightly
603631
// SAVE upper & lower lid factors per eye,
604632
// they need to stay consistent across frame
@@ -629,13 +657,14 @@ void loop() {
629657
// of both screens is about 1/2 this.
630658
frames++;
631659
if(((t - lastFrameRateReportTime) >= 1000000) && t) { // Once per sec.
632-
Serial.println((frames * 1000) / (t / 1000));
660+
Serial.printf("Frame rate: %d\n", (frames * 1000) / (t / 1000));
633661
lastFrameRateReportTime = t;
634662
}
635663

636664
// Once per frame (of eye #0), reset boopSum...
637665
if((eyeNum == 0) && (boopPin >= 0)) {
638666
boopSumFiltered = ((boopSumFiltered * 3) + boopSum) / 4;
667+
// Serial.printf("boopSum: %d, boopSumFiltered: %d, boopThreshold: %d, booped: %s\n", boopSum, boopSumFiltered, boopThreshold, (booped ? "true" : "false"));
639668
if(boopSumFiltered > boopThreshold) {
640669
if(!booped) {
641670
Serial.println("BOOP!");
@@ -647,6 +676,12 @@ void loop() {
647676
boopSum = 0;
648677
}
649678

679+
// Once per frame (of eye #1), reset eyelid states...
680+
if(eyeNum == 1) {
681+
eyelidsClosed = false;
682+
eyelidsWide = false;
683+
}
684+
650685
float mins = (float)millis() / 60000.0;
651686
if(eye[eyeNum].iris.iSpin) {
652687
// Spin works in fixed amount per frame (eyes may lose sync, but "wagon wheel" tricks work)

M4_Eyes/eyes/eagle/config.eye

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"boopThreshold" : 17500, // lower is more sensitive
3+
"eyeRadius" : 125, // radius, in pixels
4+
"irisRadius" : 120, // radius, in pixels
5+
"slitPupilRadius" : 0, // height, in pixels; 0 is round pupil
6+
7+
"irisTexture" : "eagle/iris.bmp",
8+
// "scleraTexture" : "eagle/sclera.bmp",
9+
"scleraColor" : [ 64, 24, 22 ],
10+
"pupilColor" : [ 0, 0, 0 ],
11+
"backColor" : [ 140, 40, 20 ], // covers the outermost/backmost part of the eye where the sclera texture map (or color) doesn’t reach
12+
"eyelidIndex" : "0x00", // 8-bit value; from table learn.adafruit.com/assets/61921
13+
14+
// independent irisTexture, scleraTexture, irisColor, scleraColor,
15+
// pupilColor, backColor, irisAngle, scleraAngle, irisSpin, scleraSpin,
16+
// irisMirror, scleraMirror, and rotate can be specified
17+
"left" : {
18+
},
19+
"right" : {
20+
},
21+
22+
"upperEyelid" : "eagle/upper.bmp",
23+
"lowerEyelid" : "eagle/lower.bmp",
24+
"tracking" : true,
25+
"squint" : 0.5, // offsets eyelid center point vertically
26+
27+
"lightSensor" : 102, // light sensor pin; 102 is MONSTER M4SK, 21 is HalloWing M4
28+
"pupilMin" : 0.05, // smallest pupil size as a fraction of iris size; from 0.0 to 1.0
29+
"pupilMax" : 0.3, // largest pupil size as a fraction of iris size; from 0.0 to 1.0
30+
31+
"voice" : false,
32+
"pitch" : 1.0,
33+
"gain" : 1.0, // microphone gain (sensitivity)
34+
// "waveform" : "sine" // "square", "sine", "tri" and "saw" are supported
35+
// "modulate" : 30 // waveform modulation, in Hz
36+
37+
"wiichuck" : {
38+
"min" : 28,
39+
"max" : 229
40+
}
41+
}

M4_Eyes/eyes/eagle/eyelid.psd

44.7 KB
Binary file not shown.

M4_Eyes/eyes/eagle/iris.bmp

192 KB
Binary file not shown.

M4_Eyes/eyes/eagle/iris.psd

408 KB
Binary file not shown.

M4_Eyes/eyes/eagle/lower.bmp

7.56 KB
Binary file not shown.

M4_Eyes/eyes/eagle/sclera.bmp

234 KB
Binary file not shown.

M4_Eyes/eyes/eagle/upper.bmp

7.56 KB
Binary file not shown.

M4_Eyes/file.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//34567890123456789012345678901234567890123456789012345678901234567890123456
22

3-
#define ARDUINOJSON_ENABLE_COMMENTS 1
4-
#include <ArduinoJson.h> // JSON config file functions
3+
#define ARDUINOJSON_ENABLE_COMMENTS 1 // ARDUINOJSON_ENABLE_COMMENTS must be set to 1 before including the library.
4+
// The same value of ARDUINOJSON_ENABLE_COMMENTS must be set in each compilation unit.
5+
#include <ArduinoJson.h> // JSON config file functions
56
#include "globals.h"
67

78
extern Adafruit_Arcada arcada;
@@ -89,7 +90,7 @@ void loadConfig(char *filename) {
8990
DeserializationError error = deserializeJson(doc, file);
9091
yield();
9192
if(error) {
92-
Serial.println("Config file error, using default settings");
93+
Serial.println("Config file error, using default settings.");
9394
Serial.println(error.c_str());
9495
} else {
9596
uint8_t e;
@@ -286,7 +287,7 @@ void loadConfig(char *filename) {
286287
file.close();
287288
user_setup(doc);
288289
} else {
289-
Serial.println("Can't open config file, using default settings");
290+
Serial.println("Can't open config file, using default settings.");
290291
}
291292

292293
// INITIALIZE DEFAULT VALUES if config file missing or in error ----------
@@ -330,7 +331,7 @@ ImageReturnCode loadEyelid(char *filename,
330331
Adafruit_ImageReader *reader;
331332

332333
reader = arcada.getImageReader();
333-
if (!reader) {
334+
if(!reader) {
334335
return IMAGE_ERR_FILE_NOT_FOUND;
335336
}
336337

@@ -340,7 +341,7 @@ ImageReturnCode loadEyelid(char *filename,
340341
// This is the "booster seat" described in m4eyes.ino
341342
if(reader->bmpDimensions(filename, &w, &h) == IMAGE_SUCCESS) {
342343
tempBytes = ((w + 7) / 8) * h; // Bitmap size in bytes
343-
if (maxRam > tempBytes) {
344+
if(maxRam > tempBytes) {
344345
if((tempPtr = (uint8_t *)malloc(maxRam - tempBytes)) != NULL) {
345346
// Make SOME tempPtr reference, or optimizer removes the alloc!
346347
tempPtr[0] = 0;
@@ -416,14 +417,14 @@ ImageReturnCode loadTexture(char *filename, uint16_t **data,
416417
Adafruit_ImageReader *reader;
417418

418419
reader = arcada.getImageReader();
419-
if (!reader) {
420+
if(!reader) {
420421
return IMAGE_ERR_FILE_NOT_FOUND;
421422
}
422423

423424
// This is the "booster seat" described in m4eyes.ino
424425
if(reader->bmpDimensions(filename, &w, &h) == IMAGE_SUCCESS) {
425426
tempBytes = w * h * 2; // Image size in bytes (converted to 16bpp)
426-
if (maxRam > tempBytes) {
427+
if(maxRam > tempBytes) {
427428
if((tempPtr = (uint8_t *)malloc(maxRam - tempBytes)) != NULL) {
428429
// Make SOME tempPtr reference, or optimizer removes the alloc!
429430
tempPtr[0] = 0;

0 commit comments

Comments
 (0)