Ironman Arc Reactor MARK I

Posted on 2023-12-21 in fun-project

Arc Reactor replik

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.

ironman arcreactor 3d printing instructions to build

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.

Microcontroller Nano

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.