// Tactile Labyrinth - Interactive Mapping System // Uses serial commands to map LEDs on a sphere using polar coordinates #include #include #include "SphericalLEDMap.h" // Include our new library // Pin Definitions #define LED_PIN D6 #define PIN_BUTTON D10 // Constants #define NUM_LEDS SPHERE_NUM_LEDS #define BRIGHTNESS 64 #define LED_TYPE WS2812B #define COLOR_ORDER GRB #define BUTTON_PRESSED LOW #define BUILTIN_LED_ON LOW #define BUILTIN_LED_OFF HIGH // LED array CRGB leds[NUM_LEDS]; // Current active LED for mapping int currentLed = 0; int displayMode = 0; // Multiple display modes now unsigned long lastRotationTime = 0; float rotationAngle = 0.0; float animationParameter = 0.0; // For various animations // Define the number of display modes #define NUM_DISPLAY_MODES 5 // Display mode names const char* displayModeNames[NUM_DISPLAY_MODES] = { "Key Points", "Rotating Ring", "Latitude Circle", "Longitude Circle", "Hemisphere" }; // Set current LED index void setCurrentLed(int index) { if (index >= 0 && index < NUM_LEDS) { currentLed = index; Serial.print("Current LED set to: "); Serial.println(currentLed); // Call updateDisplay to refresh the visualization updateDisplay(); } else { Serial.println("Error: LED index out of range"); } } // Update display based on current mode void updateDisplay() { // Update rotation angle - complete a full circle in 10 seconds unsigned long currentTime = millis(); if (currentTime - lastRotationTime >= 10) { // Update every 10ms float angleIncrement = TWO_PI / (10.0 * 100.0); // 10 seconds * 100 updates per second rotationAngle += angleIncrement; if (rotationAngle >= TWO_PI) rotationAngle -= TWO_PI; // Update animation parameter (oscillates between 0 and PI) animationParameter = (sin(millis() / 5000.0) + 1.0) * 0.5 * PI; lastRotationTime = currentTime; } // Choose which animation to display based on mode switch (displayMode) { case 0: // Key Points sphereShowKeyPoints(leds, currentLed); break; case 1: // Rotating Ring sphereShowRotatingRing(leds, rotationAngle, 0.3); break; case 2: // Latitude Circle - changes with time sphereShowLatitude(leds, animationParameter, 0.3); break; case 3: // Longitude Circle - changes with time sphereShowLongitude(leds, rotationAngle, 0.3); break; case 4: // Hemisphere - rotates with time { // Create a moving direction vector float dirX = cos(rotationAngle); float dirY = sin(animationParameter / 3.0); // Slower up/down movement float dirZ = sin(rotationAngle); sphereShowHemisphere(leds, dirX, dirY, dirZ); } break; default: // If we somehow get an invalid mode, reset to mode 0 displayMode = 0; sphereShowKeyPoints(leds, currentLed); break; } } // Process serial commands void processSerialCommand() { if (Serial.available() > 0) { String command = Serial.readStringUntil('\n'); command.trim(); // Process the "led n" command if (command.startsWith("led")) { int index = command.substring(4).toInt(); setCurrentLed(index); } else { Serial.println("Only 'led n' command is supported"); } } } void setup() { Serial.begin(115200); Serial.println("Tactile Labyrinth - Interactive Mapping System"); // Initialize button with pull-up pinMode(PIN_BUTTON, INPUT_PULLUP); // Initialize built-in LEDs pinMode(PIN_LED_R, OUTPUT); pinMode(PIN_LED_G, OUTPUT); pinMode(PIN_LED_B, OUTPUT); digitalWrite(PIN_LED_R, BUILTIN_LED_OFF); digitalWrite(PIN_LED_G, BUILTIN_LED_OFF); digitalWrite(PIN_LED_B, BUILTIN_LED_OFF); // Initialize LED strip FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); FastLED.setBrightness(BRIGHTNESS); // Initialize the sphere mapping sphereInitialize(); // Print debug info spherePrintDebugInfo(); // Set current LED (but don't display yet) currentLed = 0; Serial.println("Interactive mapping system ready."); Serial.println("Button: Cycle through animation modes"); Serial.println("Serial command available: 'led n'"); // Initial display mode displayMode = 0; // Start with key points mode Serial.print("Initial display mode: "); Serial.println(displayModeNames[displayMode]); // Explicitly display the initial animation updateDisplay(); } void loop() { // Process serial commands processSerialCommand(); // Button will cycle through display modes if (digitalRead(PIN_BUTTON) == BUTTON_PRESSED) { static unsigned long lastPress = 0; if (millis() - lastPress > 300) { // Debounce lastPress = millis(); // Cycle to next display mode displayMode = (displayMode + 1) % NUM_DISPLAY_MODES; Serial.print("Changed to display mode: "); Serial.println(displayModeNames[displayMode]); // Update display immediately after mode change updateDisplay(); } } // Update the animation updateDisplay(); // Small delay for stability FastLED.delay(10); }