diff --git a/M4_Eyes/M4_Eyes.ino b/M4_Eyes/M4_Eyes.ino index f7910bdad..a2e08cc0a 100644 --- a/M4_Eyes/M4_Eyes.ino +++ b/M4_Eyes/M4_Eyes.ino @@ -59,6 +59,7 @@ int iPupilFactor = 42; uint32_t boopSum = 0; bool booped = false; int fixate = 7; +uint8_t lightSensorFailCount = 0; // For autonomous iris scaling #define IRIS_LEVELS 7 @@ -191,19 +192,21 @@ void setup() { eye[e].iris.startAngle = (e & 1) ? 512 : 0; // Rotate alternate eyes 180 degrees eye[e].iris.angle = eye[e].iris.startAngle; eye[e].iris.mirror = 0; - eye[e].iris.spin = 0; + eye[e].iris.spin = 0.0; + eye[e].iris.iSpin = 0; eye[e].sclera.color = 0xFFFF; eye[e].sclera.data = NULL; eye[e].sclera.filename = NULL; eye[e].sclera.startAngle = (e & 1) ? 512 : 0; // Rotate alternate eyes 180 degrees eye[e].sclera.angle = eye[e].sclera.startAngle; eye[e].sclera.mirror = 0; - eye[e].sclera.spin = 0; + eye[e].sclera.spin = 0.0; + eye[e].sclera.iSpin = 0; // Uncanny eyes carryover stuff for now, all messy: eye[e].blink.state = NOBLINK; - eye[e].eyeX = 512; - eye[e].eyeY = 512; +// eye[e].eyeX = 512; +// eye[e].eyeY = 512; eye[e].blinkFactor = 0.0; } @@ -328,6 +331,12 @@ void setup() { Serial.printf("Free RAM: %d\n", availableRAM()); randomSeed(SysTick->VAL + analogRead(A2)); + eyeOldX = eyeNewX = eyeOldY = eyeNewY = mapRadius; // Start in center + for(e=0; e= 100) ? seesaw.analogRead(lightSensorPin - 100) : analogRead(lightSensorPin); - if(rawReading < lightSensorMin) rawReading = lightSensorMin; // Clamp light sensor range - else if(rawReading > lightSensorMax) rawReading = lightSensorMax; // to within usable range - float v = (float)(rawReading - lightSensorMin) / (float)(lightSensorMax - lightSensorMin); // 0.0 to 1.0 - v = pow(v, lightSensorCurve); - lastLightValue = irisMin + v * irisRange; - lastLightReadTime = t; + if(rawReading <= 1023) { + if(rawReading < lightSensorMin) rawReading = lightSensorMin; // Clamp light sensor range + else if(rawReading > lightSensorMax) rawReading = lightSensorMax; // to within usable range + float v = (float)(rawReading - lightSensorMin) / (float)(lightSensorMax - lightSensorMin); // 0.0 to 1.0 + v = pow(v, lightSensorCurve); + lastLightValue = irisMin + v * irisRange; + lastLightReadTime = t; + lightSensorFailCount = 0; + } else { // I2C error + if(++lightSensorFailCount >= 50) { // If repeated errors in succession... + lightSensorPin = -1; // Stop trying to use the light sensor + } else { + lastLightReadTime = t - LIGHT_INTERVAL + 40000; // Try again in 40 ms + } + } } irisValue = (irisValue * 0.97) + (lastLightValue * 0.03); // Filter response for smooth reaction } else { @@ -556,8 +574,18 @@ void loop() { } float mins = (float)millis() / 60000.0; - eye[eyeNum].iris.angle = (int)((float)eye[eyeNum].iris.startAngle + eye[eyeNum].iris.spin * mins + 0.5); - eye[eyeNum].sclera.angle = (int)((float)eye[eyeNum].sclera.startAngle + eye[eyeNum].sclera.spin * mins + 0.5); + if(eye[eyeNum].iris.iSpin) { + // Spin works in fixed amount per frame (eyes may lose sync, but "wagon wheel" tricks work) + eye[eyeNum].iris.angle += eye[eyeNum].iris.iSpin; + } else { + // Keep consistent timing in spin animation (eyes stay in sync, no "wagon wheel" effects) + eye[eyeNum].iris.angle = (int)((float)eye[eyeNum].iris.startAngle + eye[eyeNum].iris.spin * mins + 0.5); + } + if(eye[eyeNum].sclera.iSpin) { + eye[eyeNum].sclera.angle += eye[eyeNum].sclera.iSpin; + } else { + eye[eyeNum].sclera.angle = (int)((float)eye[eyeNum].sclera.startAngle + eye[eyeNum].sclera.spin * mins + 0.5); + } // END ONCE-PER-FRAME EYE ANIMATION ---------------------------------- diff --git a/M4_Eyes/file.cpp b/M4_Eyes/file.cpp index 70a3e3378..ecde20b12 100644 --- a/M4_Eyes/file.cpp +++ b/M4_Eyes/file.cpp @@ -257,7 +257,9 @@ void loadConfig(char *filename) { irisMirror = 0, scleraMirror = 0, irisAngle = 0, - scleraAngle = 0; + scleraAngle = 0, + irisiSpin = 0, + scleraiSpin = 0; float irisSpin = 0.0, scleraSpin = 0.0; JsonVariant iristv = doc["irisTexture"], @@ -268,6 +270,10 @@ void loadConfig(char *filename) { if(v.is()) irisSpin = v.as() * -1024.0; v = doc["scleraSpin"]; if(v.is()) scleraSpin = v.as() * -1024.0; + v = doc["irisiSpin"]; + if(v.is()) irisiSpin = v.as(); + v = doc["scleraiSpin"]; + if(v.is()) scleraiSpin = v.as(); v = doc["irisMirror"]; if(v.is() || v.is()) irisMirror = v ? 1023 : 0; v = doc["scleraMirror"]; @@ -294,6 +300,8 @@ void loadConfig(char *filename) { eye[e].sclera.mirror = scleraMirror; eye[e].iris.spin = irisSpin; eye[e].sclera.spin = scleraSpin; + eye[e].iris.iSpin = irisiSpin; + eye[e].sclera.iSpin = scleraiSpin; // iris and sclera filenames are strdup'd for each eye rather than // sharing a common pointer, reason being that it gets really messy // below when overriding one or the other and trying to do the right @@ -325,6 +333,10 @@ void loadConfig(char *filename) { if(v.is()) eye[e].iris.spin = v.as() * -1024.0; v = doc[eye[e].name]["scleraSpin"]; if(v.is()) eye[e].sclera.spin = v.as() * -1024.0; + v = doc[eye[e].name]["irisiSpin"]; + if(v.is()) eye[e].iris.iSpin = v.as(); + v = doc[eye[e].name]["scleraiSpin"]; + if(v.is()) eye[e].sclera.iSpin = v.as(); v = doc[eye[e].name]["irisMirror"]; if(v.is() || v.is()) eye[e].iris.mirror = v ? 1023 : 0; v = doc[eye[e].name]["scleraMirror"]; diff --git a/M4_Eyes/globals.h b/M4_Eyes/globals.h index 8297ca79a..711d88f27 100644 --- a/M4_Eyes/globals.h +++ b/M4_Eyes/globals.h @@ -131,6 +131,7 @@ typedef struct { uint16_t startAngle; // INITIAL rotation 0-1023 CCW uint16_t angle; // CURRENT rotation 0-1023 CCW uint16_t mirror; // 0 = normal, 1023 = flip X axis + uint16_t iSpin; // Per-frame fixed integer spin, overrides 'spin' value } texture; // Each eye then uses the following structure. Each eye must be on its own diff --git a/Pylint_and_CircuitPython/.circuitpython.skip b/Pylint_and_CircuitPython/.circuitpython.skip new file mode 100644 index 000000000..e69de29bb diff --git a/Pylint_and_CircuitPython/pylint_example.py b/Pylint_and_CircuitPython/pylint_example.py new file mode 100644 index 000000000..4aa79b16e --- /dev/null +++ b/Pylint_and_CircuitPython/pylint_example.py @@ -0,0 +1,45 @@ +import board +import digitalio +import adafruit_lis3dh +import touchio +import time +import neopixel +import adafruit_thermistor + +pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.2) + +i2c = board.I2C() +int1 = digitalio.DigitalInOut(board.ACCELEROMETER_UNTERRUPT) +lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1) + +circuit_playground_temperature = adafruit_thermistor.Thermistor(board.TEMPERATURE, 10000, 10000, 25, 3950) + +touch_A1 = touchio.TouchIn(board.A1) +touch_A2 = touchio.TouchIn(board.A2) + +led = digitalio.DigitalInOut(board.D13) +led.direction = digitalio.Direction.OUTPUT + +button_A = digitalio.DigitalInOut(board.BUTTON_A) +button_A.direction = digitalio.Direction.INPUT +button_A.pull = digitalio.Pull.DOWN + +while True: + x, y, z = lis3dh.acceleration + + if button_A.value: + led.value = True + else: + led.value = False + + print("Temperature:", circuit_playground_temperature.temperature) + print("Acceleration:", x, y, z) + + if touch_A1.value: + pixels.fill((255, 0, 0)) + if touch_A2.value: + pixels.fill((0, 0, 255)) + else: + pixels.fill((0, 0, 0)) + + time.sleep(0.01)