
Living Rock
Worldbuilding and interactive design through touch and light.
Dates
October 2024
Role
Individual
Skills
Fabrication: 3D Printing, Electronics, Coding, Paper Mache, Painting
Design: Onshape, Arduino, Worldbuilding
Interaction
Touch sensors and fiber optics are embedded in each moss section. When the moss is touched, that section flickers and dances.
Prototyping & Development
Features
- Chicken wire structure
- Paper mache form
- Paint
- Moss
- 6x Piezoelectric touch sensors
- 1x Adafruit Neopixel LED ring
- 1x Adafruit Metro Mini
#include <Adafruit_NeoPixel.h>
#define PixelPIN 3 // Pin where NeoPixels are connected
#define NUMPIXELS 12 // Total number of NeoPixels to be used
#define SIXTHPIXELS (NUMPIXELS / 6) // One-sixth of the total pixels (2 LEDs per sensor)
Adafruit_NeoPixel pixels(NUMPIXELS, PixelPIN, NEO_RGBW + NEO_KHZ800);
// Sensor pins
const int sensor1 = A0;
const int sensor2 = A1;
const int sensor3 = A2;
const int sensor4 = A4;
const int sensor5 = A3;
const int sensor6 = A5;
// Individual threshold values for each sensor
const int thresholds[6] = {20, 30, 15, 20, 40, 15};
// Flicker timing variables
unsigned long flickerDuration = 2000; // Duration to flicker
unsigned long flickerStartTime[6]; // Start time of flickering for each sensor
bool isFlickering[6] = {false, false, false, false, false, false}; // Flickering state for sensors
void setup() {
Serial.begin(9600);
pixels.begin(); // Initialize the NeoPixel strip
pixels.clear();
pixels.show();
}
void loop() {
// Reading sensors
int sensorReadings[6] = {
analogRead(sensor1),
analogRead(sensor2),
analogRead(sensor3),
analogRead(sensor4),
analogRead(sensor5),
analogRead(sensor6)
};
// Check if any sensor is triggered and start flickering
for (int i = 0; i < 6; i++) {
if (sensorReadings[i] >= thresholds[i] && !isFlickering[i]) {
isFlickering[i] = true;
flickerStartTime[i] = millis(); // Record the start time for the sensor
}
}
// Handle flickering for each sensor section
for (int i = 0; i < 6; i++) {
if (isFlickering[i]) {
flickerLights(i); // Call flicker function for the section
if (millis() - flickerStartTime[i] >= flickerDuration) {
pixels.clear(); // Clear the pixels after flickering
pixels.show();
isFlickering[i] = false; // Stop flickering for that section
}
}
}
// Print sensor readings to serial monitor
for (int i = 0; i < 6; i++) {
Serial.print("Sensor "); Serial.print(i + 1); Serial.print(": ");
Serial.print(sensorReadings[i]);
if (i < 5) Serial.print(" | ");
}
Serial.println();
}
// Non-blocking flicker function
void flickerLights(int sensorNumber) {
static unsigned long lastFlickerTime[6] = {0, 0, 0, 0, 0, 0}; // Last time a flicker occurred for each section
const int flickerInterval = random(20, 100); // Random interval for flicker
// Check if it's time to flicker again for this section
if (millis() - lastFlickerTime[sensorNumber] >= flickerInterval) {
lastFlickerTime[sensorNumber] = millis(); // Update the last flicker time
// Determine which sixth of the pixels to flicker
int startPixel = sensorNumber * SIXTHPIXELS;
int endPixel = startPixel + SIXTHPIXELS;
// Flicker the pixels in the specified range
for (int i = startPixel; i < endPixel; i++) {
// Randomly decide to turn the pixel on or off
if (random(2) == 0) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0, 100)); // Turn on white
} else {
pixels.setPixelColor(i, pixels.Color(0, 0, 0, 0)); // Turn off
}
}
pixels.show(); // Update the pixels after flickering
}
}








