Drumleds

From RevSpace
Revision as of 13:48, 25 May 2017 by Merethan (talk | contribs) (Arduino code)
Jump to navigation Jump to search
Project Drumleds
Drumleds merethan.jpg
Een project wat ik voor een bekende van mij gedaan heb, tevens mijn eerste project bij revspace. Het betreft een kastje wat leds laat flitsen wanneer de drummer de basskick intrapt. Die bekende van mij heeft dit kastje momenteel in gebruik op een drumstel wat hij geheel zelf gemaakt heeft.
Status Completed
Contact merethan
Last Update 2017-05-25

Project

Dit project is begonnen toen iemand die ik kende via een muzikantencentrum mij benaderde met de vraag of ik hem kon helpen. Hij was een eigen drumstel aan het bouwen en als show-element wilde hij een ledstrip met witte powerleds in de bassdrum laten knipperen op het ritme van de kick. Zelf had hij al een paar onderdelen (voeding, ledstrip, sensor). Aan mij de vraag of ik iets kon maken om het geheel aan elkaar te knopen.

Onderdelen

Behuizing

Een onderdeel waar je gemakkelijk overheen kijkt is de behuizing. Dat alles veilig zit opgeborgen is een must voor iets wat van optreden naar optreden gaat, daarom heb ik gekozen voor een project box van Hammond Manufacturing. Doet gewoon wat het moet doen. Gewoon goed.

Voedingen

De grote voeding (het witte blok) gaat van 230v naar 12v, met een vermogen van 2.5A (volgens mij). Genoeg prik om de powerleds van stroom te voorzien in elk geval. Diezelfde voeding wordt ook voor de schakel-elektronica gebruikt via een DC-DC converter (rode print), die van de 12v naar 5v gaat. Deze 5v voed het relais-board en de Arduino Pro mini.

Arduino

Tja wat anders. Een Arduino. In dit project heb ik een Arduino Pro mini 5v model gebruikt. Tamelijk klein model, maar meer was er niet nodig.

Relais-board

Voor dit project heb ik een print met twee relais gebruikt, ook al gebruik ik nu slecht een enkele relais. Ik voorzie dat de beste man binnenkort meer lampjes op zijn drumstel wil, vandaar dat die tweede er maar alvast zit. (En het was de kleinste print die ik had liggen.) De relais worden door een opto-coupler aangestuurd die van 3.3v (het voltage op de GPIO's van de Arduino) gelijk ook naar 5v gaan, en de relais activeren. De relais zouden tot 250v AC kunnen hebben, nu schakelen ze slechts 12v DC.

Sensor

Een RT-10K van Roland. Gewoon een goede drumtrigger, verder niets speciaals aan. Het zijn in feite microfoontjes met een andere spoelwikkeling waardoor ze een relatief hoog voltage genereren. Ook hebben ze geen membraam wat mee beweegt op de trilling in de lucht maar een schuimpje wat tegen het vel van een tom of kick moet zitten. Er zit ook een mooi beugeltje bij om het stevig aan een trommel vast te maken.

Werking

Nog te schrijven. WIP!

Verbeterpunten

Mosfets! Drumtrigger ging over de 5v (max meetbereik Pro mini is 5v).

Arduino code

/*
   Drumkit lights is a custom piece of code written
   to switch on/off a LED strip in a drumkit.
   Essentially, it is a simple system listening on
   analog inputs and switching digital ones accordingly.
   The analog inputs are to be wired to drumtriggers
   (those are basically very weird microphones) and
   the outputs to mosfets or relay boards, controlling LEDs.
   Currently it is written to run on a Pro mini board.
*/

void setup()
{
  // IO setup
  pinMode(2, OUTPUT); // First relay
  pinMode(3, OUTPUT); // Second relay
  pinMode(4, OUTPUT); // Third relay
  pinMode(5, OUTPUT); // Fourth relay
  pinMode(13, OUTPUT); // Arduino PCB LED

  // Initialize outputs
  digitalWrite(2, HIGH); // Open the first relay
  digitalWrite(3, HIGH); // Open the second relay
  digitalWrite(4, HIGH); // Open the third relay
  digitalWrite(5, HIGH); // Open the fourth relay
  digitalWrite(13, LOW); // Turn off the PCB LED
}

// Default values
const unsigned short flashduration = 42; // Duration, in miliseconds
const unsigned int calibrationinterval = 250; // Minimum interval in between threshold calibrations, in miliseconds

// Global vars
const unsigned short iocount = 4; // The number of drumtrigger input and led output pairs this piece of software has to process
unsigned short current[iocount] = {0, 0, 0, 0}; // The last measured value on an drumtrigger's analog in port
unsigned short peakvalue[iocount] = {0, 0, 0, 0}; // The highest current value seen so far on the drumtrigger's port
unsigned short threshold[iocount] = {0, 0, 0, 0}; // The analog input value we consider a strike for this port
unsigned long lasttrigger[iocount] = {0, 0, 0, 0}; // The last moment a strike was detected on this port (in miliseconds, counted since the start of the program)
unsigned long lastcalcycle = 0; // The last moment a threshold calibration cycle was performed (in miliseconds, counted since the start of the program)
const unsigned short smoothcount = 128; // The number of samples the smoothing algorithm operates with
unsigned short smoothiter[iocount] = {0, 0, 0, 0}; // The iterator for each input, used for cycling trough the history array used for smoothing each input
unsigned short currenthistory[iocount][smoothcount]; // A two-dimensional array holding a history for each analog input, where the history is $smoothcount in size

void loop()
{
  // Each input is processed in a sequential fashion
  for (int i = 0; i < iocount; i++) {
    // The first part is about establishing whether a piece of the drumkit was struck or not
    current[i] = analogRead(i); // Read the input on analog pin i. Goes from 0-1023, representing 0-5v for this model Arduino

    if (current[i] > threshold[i]) {
      lasttrigger[i] = millis(); // Write time of last trigger
    }

    // The second part is about turning lights on or off, depending on how long ago a hit was detected
    if ((millis() - lasttrigger[i]) < flashduration) {
      digitalWrite(i + 2, LOW); // Close the relay
      digitalWrite(13, HIGH); // Activate the LED
    } else {
      digitalWrite(i + 2, HIGH); // Open the relay
      digitalWrite(13, LOW); // Turn off the LED
    }

    // The third part is about self-calibrating threshold values
    if (current[i] > peakvalue[i]) {
      peakvalue[i] = current[i]; // Save the highest detected value so far
    }

    threshold[i] = peakvalue[i] / 1.2; // ~83% of the highest peak so far is considered the threshold

    // Lowering the threshold is based on current value. But since it is noise, smoothing is needed. Therefore, a history needs to be kept
    currenthistory[i][smoothiter[i]] = current[i];
    if (smoothiter[i] < (smoothcount - 1)) {
      smoothiter[i]++;
    } else {
      smoothiter[i] = 0;
    }

    unsigned long totalcurr = 0;
    for (int j = 0; j < smoothcount; j++) {
      totalcurr += currenthistory[i][j];
    }
    unsigned short smoothed = totalcurr / smoothcount;

    if ((millis() - lastcalcycle) > calibrationinterval) {
      lastcalcycle = millis(); // Write time of last threshold calibration

      if (smoothed < (peakvalue[i] / 2)) { // Only reduce the peakvalue if the noise level is less than 50% of the peakvalue
        peakvalue[i]--;
      }
    }
  }
}