Codes
Codes
Computer1 Processing:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import processing.serial.*;
import processing.sound.*;
SoundFile soundbg;
SoundFile soundreceive;
Serial serialPort;
String ip = "Your host";
String inputText = ""; // Text currently being typed
String[] submittedTexts = new String[3]; // Array to store up to three previous texts
boolean showMessage = false; // Tracks if "Message received!" is shown
boolean showButtonClicked = false; // Tracks if "Message sent!" should be shown
int buttonClickTime = 0; // Time when button was clicked
int messageStartTime = 0; // Time when "Message sent!" starts showing
int buttonX, buttonY, buttonWidth, buttonHeight; // Button dimensions
int fieldX, fieldY, fieldWidth, fieldHeight; // Input field dimensions
float squareY = 0; // Initial Y position of gradient squares
float squareSize; // Size of each square
int squareCount; // Number of squares in the gradient
int[] textShakeOffsets = new int[3]; // Offsets for shaking effect for each text
void setup() {
fullScreen(); // Set the canvas size to the screen
printArray(Serial.list()); // List available serial ports
serialPort = new Serial(this, "/dev/cu.usbmodem101", 9600); // Adjust the port name
calculateSizes(); // Calculate scaled dimensions based on screen size
squareSize = width / 20; // Size of each square
squareCount = height / (int)squareSize + 1; // Number of squares needed for vertical coverage
for (int i = 0; i < textShakeOffsets.length; i++) {
textShakeOffsets[i] = 0; // Initialize offsets
soundbg = new SoundFile(this, "bg.mp3");
soundreceive = new SoundFile(this, "receive.mp3");
soundbg.amp(0.3); // Set background music volume to 30%
soundreceive.amp(1.2); // Set "receive" sound volume to 150%
soundbg.loop();
}
}
void draw() {
drawGradientBackground(); // Draw moving gradient background
// Draw input field
fill(200);
rect(fieldX, fieldY, fieldWidth, fieldHeight);
// Draw the typed text in the input box
fill(0);
textSize(fieldHeight * 0.5); // Scale text size to fit the input box
text(inputText, fieldX + 660, fieldY + fieldHeight * 0.5);
// Draw button
fill(150);
rect(buttonX, buttonY, buttonWidth, buttonHeight);
fill(255);
textSize(buttonHeight * 0.5);
textAlign(CENTER, CENTER);
text("Submit", buttonX + buttonWidth / 2, buttonY + buttonHeight / 2);
// Display the last three submitted texts in full-width line boxes with shaking effect
textSize(height / 20); // Larger text size
textAlign(CENTER, CENTER);
for (int i = 0; i < submittedTexts.length; i++) {
if (submittedTexts[i] != null) {
// Calculate position
int boxY = 50 + i * (height / 10);
int boxHeight = height / 12;
// Draw the outline box
noFill();
stroke(30, 10, 255);
strokeWeight(2);
// Update and apply shaking effect
textShakeOffsets[i] = (int)random(-5, 5); // Random vertical offset for shake
fill(255);
text(submittedTexts[i], width / 2+30, boxY + boxHeight / 2 + textShakeOffsets[i]);
}
}
// Show "Message received!" if showMessage is true
if (showMessage) {
fill(0, 255, 0);
textSize(30);
textAlign(CENTER, CENTER);
fill(255, 0, 0);
rect(width / 4, height / 3, width / 2, height / 6);
fill(255);
textSize(30);
textAlign(CENTER, CENTER);
text("Message received!", width / 2, height / 3 + height / 12);
}
// Show "Message sent!" after 3 seconds for 2 seconds
if (buttonClickTime > 0 && millis() - buttonClickTime >= 2000) {
showButtonClicked = true; // Start showing the message
if (messageStartTime == 0) {
messageStartTime = millis(); // Record the start time of the message
}
}
if (showButtonClicked) {
soundreceive.play();
fill(0, 255, 0);
textSize(30);
textAlign(CENTER, CENTER);
fill(255, 0, 0);
rect(width / 4, height / 3, width / 2, height / 6);
fill(255);
textSize(30);
textAlign(CENTER, CENTER);
text("Message sent!", width / 2, height / 3 + height / 12);
// Hide the message after 2 seconds
if (millis() - messageStartTime >= 2000) {
showButtonClicked = false; // Stop showing the message
buttonClickTime = 0; // Reset the button click time
messageStartTime = 0; // Reset the message start time
}
}
}
void mousePressed() {
// Check if the button was clicked
if (mouseX > buttonX && mouseX < buttonX + buttonWidth && mouseY > buttonY && mouseY < buttonY + buttonHeight) {
// Save the current inputText in the history
saveSubmittedText(inputText);
sendInputText();
inputText = ""; // Clear the input field
serialPort.write("L");
// Record the button click time
buttonClickTime = millis();
}
}
void keyPressed() {
// If the space bar is pressed, show "Message received!"
//if (key == ' ') {
// showMessage = true; // Trigger the dialog
// return; // Skip processing other keys
//}
// Capture the input text
if (keyCode != BACKSPACE && keyCode != ENTER) {
inputText += (char)key;
} else if (keyCode == BACKSPACE && inputText.length() > 0) {
inputText = inputText.substring(0, inputText.length() - 1);
}
}
void saveSubmittedText(String newText) {
// Shift the array to make room for the new text
for (int i = submittedTexts.length - 1; i > 0; i--) {
submittedTexts[i] = submittedTexts[i - 1];
}
// Save the new text at the start
submittedTexts[0] = newText;
}
void calculateSizes() {
// Calculate scaled dimensions based on the screen size
int margin = width / 20;
fieldX = margin;
fieldY = height / 2 - height / 10;
fieldWidth = width - 2 * margin;
fieldHeight = height / 15;
buttonWidth = width / 6;
buttonHeight = height / 15;
buttonX = width / 2 - buttonWidth / 2;
buttonY = fieldY + fieldHeight + margin;
}
void drawGradientBackground() {
squareY -= 2; // Move squares upwards
if (squareY <= -squareSize) {
squareY = 0; // Reset position when squares leave the top
}
for (int i = 0; i < squareCount; i++) {
for (int j = 0; j < width / squareSize; j++) {
float yPos = squareY + i * squareSize;
float gradient = map(yPos, 0, height, 50, 200); // Adjust gradient shades
fill(0, 0, gradient); // Gradient blue color
rect(j * squareSize, yPos, squareSize, squareSize);
}
}
}
void sendInputText() {
try {
// Create HttpClient instance
HttpClient client = HttpClient.newHttpClient();
// Build request
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://" + ip + ":3000/api/send?text=" + inputText))
.GET()
.build();
// Send request and get response
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// Print response status code
System.out.println("Response Code: " + response.statusCode());
// Print response body
System.out.println("Response: " + response.body());
}
catch (Exception e) {
e.printStackTrace();
}
}
Computer1 Arduino:
#include <FastLED.h>
#include <Servo.h>
// LED Setup for Strip 1
#define NUM_LEDS 60 // Number of LEDs
#define DATA_PIN 3 // Pin connected to the first NeoPixel strip
CRGB leds[NUM_LEDS];
bool pulseActive = false; // Whether the pulse effect is active
// LED Setup for Strip 2
#define STRIP2_PIN 5 // Pin connected to the second NeoPixel strip
CRGB leds2[NUM_LEDS];
bool strip2Active = false; // Whether the second strip is active
int led2Index = 0; // Current index for lighting up LEDs on strip 2
// Timing variables for LED effects
static unsigned long previousMillis1 = 0; // 上一次更新第一条灯带亮度的时间戳
static int brightness1 = 0; // 当前亮度
static int fadeAmount1 = 5; // 每次调整的亮度变化量
static unsigned long interval1 = 30; // 第一条灯带亮度变化的间隔时间
const unsigned long initialInterval = 30; // 第一条灯带初始亮度变化间隔时间
static unsigned long previousMillisStrip2 = 0; // 上一次更新第二条灯带的时间戳
const int interval2 = 50; // 第二条灯带点亮间隔时间(毫秒)
void setup() {
// Initialize LEDs
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
FastLED.addLeds<NEOPIXEL, STRIP2_PIN>(leds2, NUM_LEDS);
FastLED.clear();
FastLED.show();
// Initialize Serial communication for LED control
Serial.begin(9600);
}
void loop() {
// 检查是否有串口命令
if (Serial.available()) {
char command = Serial.read();
if (command == 'L') {
// Reset both LED strips
pulseActive = true; // 启动第一条灯带
interval1 = initialInterval; // 重置第一条灯带的闪烁速度
strip2Active = true; // 启动第二条灯带效果
led2Index = 0; // 重置第二条灯带的索引
FastLED.clear(); // 清空所有灯带
} else if (command == 'S') {
pulseActive = false; // 停止第一条灯带
strip2Active = false; // 停止第二条灯带
FastLED.clear(); // 关闭所有LED
FastLED.show();
}
}
// 控制第一条灯带(闪烁效果)
if (pulseActive) {
unsigned long currentMillis1 = millis();
if (currentMillis1 - previousMillis1 >= interval1) {
previousMillis1 = currentMillis1; // 更新上一次亮度变化的时间
// 更新亮度值
brightness1 += fadeAmount1;
if (brightness1 <= 0 || brightness1 >= 255) {
fadeAmount1 = -fadeAmount1; // 反转亮度变化方向
// 每次亮度反转时,加快亮度变化速度
if (interval1 > 30) { // 限制最小间隔时间
interval1 -= 1; // 减少间隔时间
}
}
// 更新第一条灯带亮度
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(0, 255, brightness1); // 设置 LED 的颜色和亮度
}
FastLED.show();
}
}
// 控制第二条灯带(逐个点亮效果)
if (strip2Active) {
unsigned long currentMillis2 = millis();
if (currentMillis2 - previousMillisStrip2 >= interval2) {
previousMillisStrip2 = currentMillis2; // 更新上一次更新时间
if (led2Index < NUM_LEDS) {
leds2[led2Index] = CRGB::Blue; // 设置当前LED为蓝色
FastLED.show(); // 显示更新
led2Index++; // 移动到下一个LED
} else {
strip2Active = false; // 当所有LED点亮后,停止效果
}
}
}
}
Computer2 Processing:
import processing.serial.*;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
Serial myPort;
String ip = "Your host";
int delayTime = 5; //
int sandWidth = 1; // 控制生成沙子宽度的初始值
String textToDisplay = "Sand Simulation";
PFont font;
int cols, rows;
int[][] grid;
int w = 4; // 每个方块大小
int hueValue = 200;
int matrix = 5; // 初始沙子的区域大小
String inputText = "";
Boolean isDown = false;
float downY = 0;
void setup() {
size(400, 600);
colorMode(HSB, 360, 255, 255);
font = createFont("Arial", 24);
cols = width / w;
rows = height / w;
reset();
// 初始化串口连接
myPort = new Serial(this, "/dev/cu.usbmodem101", 9600);
background(32);
}
void reset() {
grid = make2DArray(cols, rows);
addSand();
}
void draw() {
delay(delayTime);
// 背景
fill(32, 5);
noStroke();
rect(-5, -5, width + 10, height + 10);
// 文字
fill(255);
textAlign(CENTER, CENTER);
textFont(font);
text(textToDisplay, width / 2, height - 50); // 居中显示文字
push();
if (isDown) {
downY += 5;
if (downY >= height) {
downY = 0;
isDown = false;
reset();
}
}
translate(0, downY);
// 绘制沙子
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
if (grid[i][j] > 0) {
fill(grid[i][j], 100, 255);
rect(i * w, j * w, w, w);
}
}
}
pop();
// 更新沙子状态
int[][] nextGrid = make2DArray(cols, rows);
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
int state = grid[i][j];
if (state > 0) {
if (withinRows(j + 1) && grid[i][j + 1] == 0) {
nextGrid[i][j + 1] = state;
} else if (withinRows(j + 1)) {
int dir = (random(1) < 0.5) ? 1 : -1;
if (withinCols(i + dir) && grid[i + dir][j + 1] == 0) {
nextGrid[i + dir][j + 1] = state;
} else {
nextGrid[i][j] = state;
}
} else {
nextGrid[i][j] = state;
}
}
}
}
// 新沙子
int newSandStartCol = floor(cols / 2.0) - floor(sandWidth / 2.0);
for (int i = 0; i < sandWidth; i++) {
int col = newSandStartCol + i;
if (withinCols(col)) {
nextGrid[col][0] = hueValue;
}
}
grid = nextGrid;
hueValue = (hueValue + 1) % 360;
fill(255);
text(inputText, width / 2, height / 2);
if (frameCount % 30 == 0) {
getInputText();
}
}
void serialEvent(Serial myPort) {
String inString = myPort.readStringUntil('\n'); // 读取串口数据
if (inString != null) {
inString = trim(inString); // 去掉多余空格
int inData = int(inString); // 转换为整数
// 使用map函数来决定沙子宽度
sandWidth = int(map(inData, 0, 1023, 0, 50));
}
}
boolean withinCols(int i) {
return i >= 0 && i < cols;
}
boolean withinRows(int j) {
return j >= 0 && j < rows;
}
int[][] make2DArray(int cols, int rows) {
int[][] arr = new int[cols][rows];
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
arr[i][j] = 0;
}
}
return arr;
}
void addSand() {
int startCol = cols / 2;
int extent = floor(matrix / 2);
for (int i = -extent; i <= extent; i++) {
for (int j = -extent; j <= extent; j++) {
if (random(1) < 0.75) {
int col = startCol + i;
int row = 0 + j;
if (withinCols(col) && withinRows(row)) {
grid[col][row] = hueValue;
}
}
}
}
}
void getInputText() {
try {
// 创建 HttpClient
HttpClient client = HttpClient.newHttpClient();
// 构建请求
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://" + ip + ":3000/api/data?name=2"))
.GET()
.build();
// 发送请求并获取响应
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String res = response.body().trim();
if (res.length() != 0) {
inputText = res;
isDown = true;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
Computer2 Arduino:
#include <AccelStepper.h>
#include <FastLED.h>
#define NUM_LEDS 60 // Number of LEDs
#define DATA_PIN 7 // Pin connected to the NeoPixel strip
#define WAVE_LENGTH 10 // Length of each wave
#define WAVE_SPACING 5 // Spacing between waves
#define MAX_BRIGHTNESS 255 // Maximum brightness of the first LED in a wave
CRGB leds[NUM_LEDS];
//motor
int DIR_PIN2 = 9;
int STEP_PIN2 = 10;
int EN_PIN2 = 11;
AccelStepper stepper2(AccelStepper::DRIVER, STEP_PIN2, DIR_PIN2);
int ledPin = 13;
const int potentiometerPin = A0;
long previousMillis = 0; // 上次更新时间
bool allLedsOn = false; // 是否已点亮所有 LED
int x=0;
// 用于存储电位器读取值
int potentiometerValue = 0;
int sandKey = 0; // Sand value
unsigned long sandStartTime = 0; // Time sandKey was > 0
bool fullLEDMode = false;
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
FastLED.clear();
FastLED.show();
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
// 前20个LED
// for (int i = 0; i < 20; i++) {
// leds[i] = CRGB::Blue;
// }
// FastLED.show();
//motor
pinMode(EN_PIN2, OUTPUT);
digitalWrite(EN_PIN2, LOW); // LOW enables the stepper driver
stepper2.setMaxSpeed(400.0); // Increased speed
stepper2.setAcceleration(200.0); // Increased acceleration
//stepper2.moveTo(1000000);
stepper2.setSpeed(1200);
}
void loop() {
potentiometerValue = analogRead(potentiometerPin);
// send
int mappedValue = map(potentiometerValue, 0, 1023, 0, 500);
Serial.println(mappedValue);
sandKey = analogRead(potentiometerPin);
// Check if sandKey is > 0
if (sandKey > 0) {
if (sandStartTime == 0) {
sandStartTime = millis(); // Start the timer
}
if (millis() - sandStartTime > 10000) {
fullLEDMode = true; // Enable full LED mode after 8 seconds
// Serial.println("fullLED!!!!!");
}
} else {
sandStartTime = 0; // Reset the timer if sandKey is 0
fullLEDMode = false; // Revert to 20 LEDs
}
// Determine active LED range
int activeLEDs;
if (fullLEDMode) {
activeLEDs = NUM_LEDS;
digitalWrite(ledPin, HIGH);
motorRun();
} else {
activeLEDs = 20;
digitalWrite(ledPin, LOW);
}
// Clear the LED strip
FastLED.clear();
// // Draw the wave within the active range
for (int start = x; start < activeLEDs; start += (WAVE_LENGTH + WAVE_SPACING)) {
for (int i = 0; i < WAVE_LENGTH; i++) {
int ledIndex = (start + i) % NUM_LEDS; // Ensure index stays within bounds
if (ledIndex < activeLEDs) { // Only light up within the active range
int brightness = MAX_BRIGHTNESS * (1.0 - (float)i / WAVE_LENGTH); // Smooth brightness
leds[ledIndex] = CHSV(0, 255, brightness); // Set red wave
}
}
}
FastLED.show(); // Update the LED display
// Move the wave forward
x++;
if (x >= (WAVE_LENGTH + WAVE_SPACING)) {
x = 0; // Reset wave starting point after a full cycle
}
delay(50);
}
void motorRun(){
stepper2.runSpeed(); // This line is crucial! It needs to be in the loop
}
Computer3 Processing:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
String ip = "Your host";
import processing.serial.*;
PImage p;
ParticleSystem system;
Serial myPort;
color bg = color(0);
boolean trails = true;
int startX = 0, endX = -1;
int startY = 0, endY = -1;
int xSkip = 3;
int ySkip = 3;
int docCount =100;
float particleSize = 1;
boolean showText = false; // Indicates if text is to be shown
boolean recording = false;
boolean imageColour = false;
color particleColour = color(255);
float lastTextTime = -4000; // Last time the text appeared
PVector randomStartPoint; // Random start point for particles
void setup() {
fullScreen();
noStroke();
background(bg);
p = generateTextImage("test", 240);
system = new ParticleSystem(p);
// Initialize random start point
randomStartPoint = new PVector(width / 2, height / 2);
// Set up serial communication
myPort = new Serial(this, "/dev/cu.usbmodem101", 9600);
}
void draw() {
// Check if data is available from Arduino
if (myPort.available() > 0) {
String value = trim(myPort.readStringUntil('\n'));
if (value != null && value.length() > 0) {
int magVal = int(value);
// Set showText based on magnet detection
showText = (magVal == 1);
}
}
// Clear or fade background based on trails boolean
if (trails) {
noStroke();
fill(bg, 20);
rect(0, 0, width, height);
} else {
background(bg);
}
// Handle particle animation when magnet is detected
if (showText) {
// Display text every X seconds (currently set to 10 seconds)
if (millis() - lastTextTime >= 10000) {
lastTextTime = millis();
randomStartPoint.set(random(width), random(height));
system.resetParticles(randomStartPoint.x, randomStartPoint.y);
}
// Update and draw particle system
for (Particle particle : system.particles) {
particle.update(1f / 50);
particle.draw();
}
docCount = 0;
if (frameCount % 30 == 0) {
getInputText();
}
} else {
// Animate white dots when no magnet is detected
noStroke();
for (int i = 0; i < docCount; i++) {
float x = noise(frameCount * 0.01 + i) * width;
float y = noise(frameCount * 0.01 + i + 100) * height;
fill(255);
ellipse(x, y, 2, 2);
}
docCount=100;
}
}
PImage generateTextImage(String text, float textSize) {
PGraphics g = createGraphics(width, 400);
g.beginDraw();
g.fill(255);
g.textSize(textSize);
g.textAlign(CENTER, CENTER);
g.background(0);
g.text(text, g.width / 2, g.height / 2);
g.endDraw();
return g.get();
}
class Particle {
PVector start, anchor, end, current = new PVector();
float f = 0, size, duration;
color c;
Particle(float ex, float ey, float size, float d, color c) {
this.start = new PVector(width / 2, height / 2);
float a = random(TWO_PI);
this.anchor = new PVector(cos(a) * random(100, 800) + width / 2, sin(a) * random(100, 800) + height / 2);
this.end = new PVector(ex, ey);
this.size = size;
this.duration = d * 0.5; // Adjust duration
this.c = c;
}
void update(float delta) {
if (f >= 1) return;
f += delta / duration; // Smooth transition over time
b();
}
void b() {
float fi = 1 - pow(1 - f, 2); // Easing function for smooth transition
float x = lerp(lerp(start.x, anchor.x, fi), lerp(anchor.x, end.x, fi), fi);
float y = lerp(lerp(start.y, anchor.y, fi), lerp(anchor.y, end.y, fi), fi);
current.set(x, y);
}
void draw() {
stroke(c);
strokeWeight(size);
point(current.x, current.y);
}
}
class ParticleSystem {
ArrayList<Particle> particles = new ArrayList();
ParticleSystem(PImage p) {
addParticles(p);
}
void addParticles(PImage p) {
for (int x = startX; x < p.width; x += xSkip) {
for (int y = startY; y < p.height; y += ySkip) {
if (p.get(x, y) != bg) {
particles.add(new Particle(width / 2 + x - p.width / 2, height / 2 + y - p.height / 2, particleSize, random(0.5, 3), particleColour));
}
}
}
}
void resetParticles(float newX, float newY) {
for (Particle p : particles) {
p.f = 0;
p.start.set(newX, newY);
}
}
}
void getInputText() {
try {
// 创建 HttpClient
HttpClient client = HttpClient.newHttpClient();
// 构建请求
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://" + ip + ":3000/api/data?name=1"))
.GET()
.build();
// 发送请求并获取响应
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String res = response.body().trim();
if (res.length() != 0) {
p = generateTextImage(res, 120);
system = new ParticleSystem(p);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
Computer3 Arduino(stepper is commented out):
#include <AccelStepper.h>
#include <FastLED.h>
#include <Wire.h>
#include <SeeedOLED.h>
int acledPin = 6;
int magledPin = 7;
// Define stepper1 pins
// int DIR_PIN1 = 13;
// int STEP_PIN1 = 12;
// int EN_PIN1 = 11;
// AccelStepper stepper1(AccelStepper::DRIVER, STEP_PIN1, DIR_PIN1);
// unsigned long stepper1StartTime = 0;
// bool stepper1Running = false;
// bool stepper1Rotated = false;
// Define stepper2 pins
int DIR_PIN2 = 10;
int STEP_PIN2 = 9;
int EN_PIN2 = 8;
AccelStepper stepper2(AccelStepper::DRIVER, STEP_PIN2, DIR_PIN2);
unsigned long stepper2StartTime = 0;
bool stepper2Running = false;
bool stepper2Rotated = false;
// Constants for the first NeoPixel LED strip (Magnetic Sensor)
#define NUM_LEDS_1 60
#define DATA_PIN_1 3
#define WAVE_LENGTH_1 10 // Length of each wave
#define WAVE_SPACING_1 5 // Gap between waves
#define MAX_BRIGHTNESS_1 255 // Brightness of the first LED in the wave
CRGB leds1[NUM_LEDS_1]; // Array to store LED state for the first strip
int x1 = 0; // Starting point of the wave for the first strip
int magSensor = 2; // Reed Switch input pin
int magVal = 0; // Magnetic sensor state
// Constants for the second NeoPixel LED strip (Accelerometer)
#define NUM_LEDS_2 60
#define DATA_PIN_2 5
#define WAVE_LENGTH_2 10 // Length of each wave
#define WAVE_SPACING_2 5 // Gap between waves
#define MAX_BRIGHTNESS_2 255 // Brightness of the first LED in the wave
CRGB leds2[NUM_LEDS_2]; // Array to store LED state for the second strip
int x2 = 0; // Starting point of the wave for the second strip
// Accelerometer Variables
int xValue, yValue, zValue;
int mapMin = 0;
int mapMax = 1023;
void setup() {
//Enable the stepper2 driver
pinMode(EN_PIN2, OUTPUT);
digitalWrite(EN_PIN2, LOW);
// Setup for Magnetic Sensor
pinMode(magSensor, INPUT);
Serial.begin(9600);
// Add these stepper motor settings
// stepper1.setMaxSpeed(1000.0); // Steps per second
// stepper1.setAcceleration(500.0);
// stepper1.setSpeed(1000);
stepper2.setMaxSpeed(1000.0); // Steps per second
stepper2.setAcceleration(500.0);
stepper2.setSpeed(1000);
// Initialize the first NeoPixel LED strip
FastLED.addLeds<NEOPIXEL, DATA_PIN_1>(leds1, NUM_LEDS_1);
FastLED.clear();
FastLED.show();
// Initialize the second NeoPixel LED strip
FastLED.addLeds<NEOPIXEL, DATA_PIN_2>(leds2, NUM_LEDS_2);
FastLED.clear();
FastLED.show();
Wire.begin();
SeeedOled.init(); //initialze SEEED OLED display
SeeedOled.clearDisplay(); //clear the screen and set start position to top left corner
SeeedOled.setNormalDisplay(); //Set display to normal mode (i.e non-inverse mode)
SeeedOled.setPageMode();
}
void loop() {
// ---- Magnetic Sensor Logic (First LED Strip) ----
magVal = digitalRead(magSensor);
int activeLEDs1;
if (magVal == LOW) {
activeLEDs1 = 20; // Only first 20 LEDs are active
Serial.println("No Magnetic field detected!");
digitalWrite(magledPin, LOW);
} else {
activeLEDs1 = NUM_LEDS_1; // All LEDs active
Serial.println("Magnetic field detected!");
digitalWrite(magledPin, HIGH);
}
Serial.print(magVal);
Serial.println();
// Clear the first LED strip
FastLED.clear();
// Draw wave on the first LED strip
for (int start = x1; start < activeLEDs1; start += (WAVE_LENGTH_1 + WAVE_SPACING_1)) {
for (int i = 0; i < WAVE_LENGTH_1; i++) {
int ledIndex = (start + i) % activeLEDs1; // Ensure index stays within range
int brightness = MAX_BRIGHTNESS_1 * (((float)i / WAVE_LENGTH_1) - 1);
leds1[ledIndex] = CHSV(0, 0, brightness); // 设置为白色波浪
}
}
FastLED.show();
x1++;
if (x1 >= (WAVE_LENGTH_1 + WAVE_SPACING_1)) x1 = 0;
// ---- Accelerometer Logic (Second LED Strip) ----
xValue = analogRead(A0);
yValue = analogRead(A1);
zValue = analogRead(A2);
yValue = constrain(map(yValue, 210, 290, mapMin, mapMax), mapMin, mapMax);
int activeLEDs2;
if (yValue > 250) {
activeLEDs2 = NUM_LEDS_2; // Full LEDs active
digitalWrite(acledPin, HIGH);
} else {
activeLEDs2 = 30; // Only first 30 LEDs active
digitalWrite(acledPin, LOW);
}
// Clear the second LED strip
//FastLED.clear();
// Draw wave on the second LED strip
for (int start = x2; start < activeLEDs2; start += (WAVE_LENGTH_2 + WAVE_SPACING_2)) {
for (int i = 0; i < WAVE_LENGTH_2; i++) {
int ledIndex = (start + i) % NUM_LEDS_2; // Ensure index stays within bounds
if (ledIndex < activeLEDs2) {
// 奇偶交替设置红色和蓝色
if (ledIndex % 2 == 0) {
leds2[ledIndex] = CHSV(0, 255, MAX_BRIGHTNESS_2 * (((float)i / WAVE_LENGTH_2) - 1)); // Red
} else {
leds2[ledIndex] = CHSV(160, 255, MAX_BRIGHTNESS_2 * (((float)i / WAVE_LENGTH_2) - 1)); // Blue
}
}
}
}
FastLED.show();
x2++;
if (x2 >= (WAVE_LENGTH_2 + WAVE_SPACING_2)) x2 = 0;//?
// Print Accelerometer yValue
Serial.print("yValue: ");
Serial.println(yValue);
//stepper2.runSpeed();
delay(1); // Control animation speed for both strips
if (yValue > 250) {
//activeLEDs2 = NUM_LEDS_2; // Full LEDs active
//SeeedOled.clearDisplay();
SeeedOled.setTextXY(0, 0); // Set the cursor to Xth Page, Yth Column
SeeedOled.putString("TEXT LOADING...");
SeeedOled.setTextXY(1, 0); // Move the cursor to the next line
SeeedOled.putString(" "); // Print the second part of the string
} else {
//activeLEDs2 = 20; // Only first 20 LEDs active
SeeedOled.setTextXY(0, 0); // Set the cursor to Xth Page, Yth Column
SeeedOled.putString("I AM WAITING"); // Print the first part of the string
SeeedOled.setTextXY(1, 0); // Move the cursor to the next line
SeeedOled.putString("FOR YOUR TEXT"); // Print the second part of the string
}
//stepper2
if (yValue > 250) {
if (!stepper2Running && !stepper2Rotated) {
//stepper2.setCurrentPosition(0); // Reset position
//stepper2.moveTo(1000000);
//stepper2.setSpeed(10000); // Arbitrary large value to keep running
stepper2StartTime = millis(); // Record start time
stepper2Running = true; // Indicate the stepper is running
}
if (stepper2Running) {
// Run stepper motor
stepper2.runSpeed();
// Stop stepper after 3 seconds
if (millis() - stepper2StartTime >= 6000) {
stepper2.stop(); // Smoothly stop the stepper
stepper2Running = false; // Reset the running flag
stepper2Rotated = true; // Mark stepper as rotated for this `yValue`
}
}
} else {
stepper2Rotated = false; // Reset flag to allow next rotation when `yValue` returns to 1023
}
}
//stepper1
// if (magVal == LOW) {
// stepper1Rotated = false; // Reset flag to allow next rotation when magnetic field is detected
// } else {
// if (!stepper1Running && !stepper1Rotated) {
// // stepper1.setCurrentPosition(0); // Reset position
// // stepper1.moveTo(1000000);
// // stepper1.setSpeed(1000); // Set speed
// stepper1StartTime = millis(); // Record start time
// stepper1Running = true; // Indicate the stepper is running
// }
// if (stepper1Running) {
// // Run stepper motor
// stepper1.runSpeed();
// // Stop stepper after 3 seconds
// if (millis() - stepper1StartTime >= 3000) {
// stepper1.stop(); // Smoothly stop the stepper
// stepper1Running = false; // Reset the running flag
// stepper1Rotated = true; // Mark stepper as rotated for this `yValue`
// }
// }
// }
// }