Ironman Arc Reactor MARK I
Posted on 2023-12-21 in fun-project
Beim stundenlangen Surfen auf https://printables.com bin ich irgendwann auf das Model des Ironman Arc Reactors gestoßen. Wer wollte nicht auch schon immer mal einen eigenen Arc Reactor haben...
Der Druck erwieß sich als "nicht ganz so einfach", da man so gut wie jedes Teil auf eine bestimmte Größe skalieren muss. Zudem besteht das ganze Model aus fast 30 Teilen, welche in unterschiedlichen Farben gedruckt werden.
Oben auf dem Reactor sitzt der weiße Ring in den man laut Anleitung 10 weiße LEDs einbauen kann. Das war mir dann doch etwas zu langweilig und ich habe als Beleuchtung einen 24 LED Neopixel Ring genommen
Neopixel Ring mit Microcontroller steuern
Der Neopixel Ring wird mit einem Microcontroller gesteuert. Ich hatte noch einen billig ESP32 in einer Kiste gefunden der vergleichbar mit dem Arduino Nano ist. Da der dafür eigentlich immernoch overkill ist, habe ich noch einen kapazitiven Touch-Sensor realisiert. Fasst man die blank liegenden Kupferdrähte an, färbt sich der Ring rot, was eine Fehlfunktion / Überhizung signalisieren soll. Nach einer vorgegebenen Zeit (10 Runden) kehrt er wieder in den normalzustand zurück.
Arduino Code
/*
* Neopixel ring with 24 LED's for 3d printed Ironman Arc Reactor MK I
*/
#include <Adafruit_NeoPixel.h>
#define LED_PIN 13
#define LED_COUNT 24
#define CRITICAL_DURATION 10
#define MAX_BRIGHTNESS 100
#define WHITE strip.Color(255, 255, 255)
#define CAPACITY_OUT 4 // cpacity sensor
#define CAPACITY_IN 2 // capacity sensor
const int buttonPin = 3;
int buttonState = 0;
int manipulationCounter = 0; // indicated how long the critical state is active
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// the setup function runs once when you press reset or power the board
void setup() {
pinMode(buttonPin, INPUT);
strip.begin();
strip.show();
strip.setBrightness(10);
//reactorInitialization();
// initialize cpacity sensor
pinMode(CAPACITY_OUT, OUTPUT);
pinMode(CAPACITY_IN, INPUT);
Serial.begin(9600);
}
// this is the main loop that runs continiously
void loop() {
if(manipulationCounter > 0) {
reactorCritical();
} else {
reactorOperate();
}
}
// -> Custom Functions <-
// check for manipulation (aka someone touched me)
void temperDetection() {
// check capacity sensor
digitalWrite(CAPACITY_OUT, LOW);
delay(10);
long startTime = micros();
digitalWrite(CAPACITY_OUT, HIGH);
while(digitalRead(CAPACITY_IN) == LOW);
long sensVal = micros() - startTime;
Serial.println(sensVal);
if (sensVal > 40) {
if(manipulationCounter == 0) {
// set manipulation counter to default duration
manipulationCounter = CRITICAL_DURATION;
reactorExplode();
} else {
manipulationCounter = CRITICAL_DURATION;
}
}
}
// reactor is beeing initiated
void reactorInitialization() {
// initialize all reactor cores (pixels)
for(uint16_t j=0; j< strip.numPixels(); j++) {
if(strip.getBrightness() < MAX_BRIGHTNESS) {
strip.setBrightness(10 + (MAX_BRIGHTNESS/strip.numPixels()) );
}
for(uint16_t i=0; i< strip.numPixels(); i++) {
for(uint16_t s=0; s< j; s++) {
strip.setPixelColor((s+i) % strip.numPixels(), WHITE);
};
strip.show();
temperDetection();
delay(300 - (j*20));
for(uint16_t s=0; s< j; s++) {
strip.setPixelColor(s+i, 0);
};
}
}
}
// reactor runs under normal conditions
void reactorOperate() {
for(int i=0; i< strip.numPixels(); i++) {
strip.setPixelColor((i-1) % strip.numPixels(), strip.Color(127, 127, 180));
strip.setPixelColor((i-2) % strip.numPixels(), strip.Color(127, 127, 180));
strip.setPixelColor(i, strip.Color(80, 80, 255));
strip.setPixelColor(i-1, strip.Color(80,80, 200));
strip.setPixelColor(i-2 % strip.numPixels(), strip.Color(127, 127, 180));
strip.setPixelColor(i-3 % strip.numPixels(), strip.Color(127, 127, 180));
strip.setPixelColor(i-4 % strip.numPixels(), strip.Color(127, 127, 180));
strip.setPixelColor(i-5 % strip.numPixels(), strip.Color(127, 127, 180));
strip.show();
temperDetection();
if(i <= strip.numPixels()/2) {
delay(70);
} else {
delay(180);
};
};
}
// reactor runs in critical state
void reactorCritical() {
for(uint16_t i=0; i< strip.numPixels(); i++) {
strip.setPixelColor((i-1) % strip.numPixels(), strip.Color(150 + (manipulationCounter * 5), 127 - (manipulationCounter * 10), 100 - (manipulationCounter * 8)));
strip.setPixelColor((i-2) % strip.numPixels(), strip.Color(150 + (manipulationCounter * 5), 127 - (manipulationCounter * 10), 100 - (manipulationCounter * 8)));
strip.setPixelColor(i, strip.Color(205 + (manipulationCounter * 5), 0, 0,50));
strip.setPixelColor(i-1, strip.Color(150 + (manipulationCounter * 5), 0, 0,150));
strip.setPixelColor(i-2 % strip.numPixels(), strip.Color(150 + (manipulationCounter * 5), 127 - (manipulationCounter * 10), 100 - (manipulationCounter * 8)));
strip.setPixelColor(i-3 % strip.numPixels(), strip.Color(150 + (manipulationCounter * 5), 127 - (manipulationCounter * 10), 100 - (manipulationCounter * 8)));
strip.setPixelColor(i-4 % strip.numPixels(), strip.Color(150 + (manipulationCounter * 5), 127 - (manipulationCounter * 10), 100 - (manipulationCounter * 8)));
strip.setPixelColor(i-5 % strip.numPixels(), strip.Color(150 + (manipulationCounter * 5), 127 - (manipulationCounter * 10), 100 - (manipulationCounter * 8)));
strip.show();
temperDetection();
delay(80 + (manipulationCounter * 10));
};
manipulationCounter = manipulationCounter - 1;
}
// Reactor explodes on touch
void reactorExplode() {
for(uint16_t j=0; j< 5; j++) {
for(uint16_t i=0; i< strip.numPixels(); i++) {
strip.setPixelColor((i-1) % strip.numPixels(), strip.Color(127, 127 -(127/5*j), 180 -(180/5*j)));
strip.setPixelColor((i-2) % strip.numPixels(), strip.Color(127, 127 -(127/5*j), 180 -(180/5*j)));
strip.setPixelColor(i, strip.Color(0 +(205/5*j), 0, 200 -(200/5*j),50));
strip.setPixelColor(i-1, strip.Color(0 +(150/5*j), 0, 150 -(150/5*j),150));
strip.setPixelColor(i-2 % strip.numPixels(), strip.Color(127, 127 -(127/5*j), 180 -(180/5*j)));
strip.setPixelColor(i-3 % strip.numPixels(), strip.Color(127, 127 -(127/5*j), 180 -(180/5*j)));
strip.setPixelColor(i-4 % strip.numPixels(), strip.Color(127, 127 -(127/5*j), 180 -(180/5*j)));
strip.setPixelColor(i-5 % strip.numPixels(), strip.Color(127, 127 -(127/5*j), 180 -(180/5*j)));
strip.show();
temperDetection();
if(i <= strip.numPixels()/2) {
delay(180);
} else {
delay(230);
};
}
}
}
Kapazitiver Sensor (Touch-Sensor)
Für den Touch-Sensor habe ich mich an folgende Anleitung gehalten: Arduino Tutorial Touch and Capacity Sensing. Damit das ganze zuverlässig funktioniert, braucht man einen 1M Ohm Wiederstand. Ohne geht es garnicht! Ich hatte Anfangs nur einen 4k Wiederstand mit dem gab es keine zuverlässigen Werte und es hat nicht wirklich gut funktioniert.