052817_1619_MusicMonday4.jpg

Music Monday – eDrum Trigger Pad to MIDI mit Arduino und Roland PD-8

Heute geht es darum ein eDrum Trigger Pad (das Roland PD-8) MIDI-fähig zu machen. Ich will für ein Projekt, von dem es bald mehr geben wird, einen einfachen und intuitiven Weg um on-the-fly Drumsounds in Cubase einzuspielen. Was kommt da besser als ein Drumpad mit einem Drumstick zu bearbeiten? Das Pad selbst hab ich mir vom Drummer meiner Band http://www.monkeyfly.de/ ausgeliehen. Im Netz ein wenig gesucht und diverse Anleitungen zum kompletten Eigenbau gefunden (wie auch im Artikel der aktuellen make gesehen, mehr dazu aber bei Andy direkt unter http://doktor-andy.de/wordpress//?s=drum).

Die Funktionsweise des Roland PD-8 ist prinzipiell genauso, also ein Piezo, der angeschlagen eine Spannung abgibt. Das lässt sich genauso mit dem Arduino auslesen und dann per MIDI weitergeben.

Da das auch mein erster MIDI Gehversuch mit dem Arduino ist, hab ich mir erstmal die grundlegende Funktionsweise von seriellem MIDI (ich hatte keine Lust und keine Teile mir ein richtiges MIDI-Gerät zu bauen, ist ja erstmal nur zum Testen). Dazu braucht es eigentlich nur einen Arduino, der per USB angeschlossen wird, hairless MIDI (Seriell zu MIDI Konverter) und ein virtuelles MIDI Device, für Windows ist hier wohl loopMIDI die beste Wahl.

Nach der Installation von loopMIDI einfach mit dem + einen Port hinzufügen.

hairless MIDI muss nichtmal installiert werden, sondern nur gestartet. Als seriellen Port wählt man dann einfach seinen Arduino aus (COM-Port bekommt man aus der Arduino IDE) und wählt im MIDI In/Out den loopMIDI Port aus. Unter Help -> Preferences wählt man noch die Baud-Rate aus, die man im Arduino Programm hinterlegt hat. Ich habe erstmal 9600 genommen.

Einstellungen in hairless MIDI

Wie man dann den Arduino dazu bringt MIDI-fähigen Output auszugeben steht sehr schön auf http://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/ beschrieben. Dort in Schritt 5 ist auch der Weg über hairless beschrieben. Das Programm aus Schritt ist sehr schön um das Setup zu testen. Es gibt einfach nacheinander in einer Schleife einige MIDI-Noten aus. Beachtet aber die Baud-Rate dort auf die MIDI-Rate (31250) eingestelt ist. Die muss mit der Rate in den Preferences von hairless übereinstimmen.

Die Noten sollte man dann im Debug Output von hairless sehen (vorher natürlich den Debug aktivieren).

Wenn das funktioniert kann man sich daran machen das Drum-Pad anzuschließen und auszulesen. Das ist eigentlich ganz einfach und wie immer hat auch sparkfun da ein Tutorial für die Grundlagen bereit: https://www.sparkfun.com/tutorials/330

Im Grunde schließt man das Pad einfach an GND und A0 des Arduino an. Dazwischen kommt noch ein 1 MOhm Widerstand und gut ist:

TriggerToMIDI
Anschlussdiagramm (R1 = 1 MOhm)

Das Roland PD-8 hat die Besodnerheit, dass es ein Dual Trigger ist. Das heißt, das Pad und das Rim haben einen eigenen Trigger. Deswegen sollte man ein Klinkenkabel mit TRS Anschluss (Tip-Ring-Sleeve oder einfach Stereo-Klinke) benutzen. Ich schließe aber nur das Hauptpad (Tip) an. Ich habe auch mit beidem experimentiert, aber der Rim-Trigger liefert bei mir nur sehr kleine Ausschläge und das Übersprechen des Hauptpads ist recht groß. Lässt sich sicher auch noch Software-seitig irgendwie lösen.

Wenn die Software von Sparkfun zum seriellen Auslesen funktioniert, kann man sich daran machen alles zu verbinden. Ich habe als Ausgangsbasis den Code von https://beammyselfintothefuture.wordpress.com/2015/01/28/sensing-hit-velocity-and-quick-subsequent-hits-of-a-piezo-with-an-arduino-teensy/ genutzt. Dort habe ich statt der Ausgabe für den Teensy einfach die Ausgabe aus dem MIDI Beispiel genutzt.

Hier gibt es den Source Code:

/*
 * Source www.boriswerner.eu 2017
 * Merged from https://beammyselfintothefuture.wordpress.com/2015/01/28/sensing-hit-velocity-and-quick-subsequent-hits-of-a-piezo-with-an-arduino-teensy/
 * and 
 * MIDI On/Off Messages
 * By Amanda Ghassaei
 * July 2012
 * https://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 */
#define triggerThreshold 10 // If this is set too low, hits on other pads will trigger a "hit" on this pad
#define initialHitReadDuration 500 // In microseconds. Shorter times will mean less latency, but less accuracy. 500 microseconds is nothing, anyway
#define midiVelocityScaleDownAmount 2 // Number of halvings that will be applied to MIDI velocity
#define inputPin A0
 
// Getting the ideal balance of these two constants will ensure that fast subsequent hits are perceived accurately, but false hits are not generated
#define subsequentHitThreshold 1.7
#define subsequentHitThresholdDecaySpeed 14
 
uint16_t highestYet;
uint32_t startReadingTime;
uint32_t highestValueTime;
boolean hitOccurredRecently = false;
 
int noteON = 144;//144 = 10010000 in binary, note on command
int noteOFF = 128;//128 = 10000000 in binary, note off command
int midiNote = 69;//MIDI Note A3

void setup() {
  Serial.begin(9600); //Set Baud Rate to 31250 for MIDI or other rate to use with serial-MIDI-converter
}
 
void loop() {
 
  // Assume the normal hit-threshold
  uint16_t thresholdNow = triggerThreshold;
 
  // But, if a hit occurred very recently, we need to set a higher threshold for triggering another hit, otherwise the dissipating vibrations
  // of the previous hit would trigger another one now
  if (hitOccurredRecently) {
 
      // Work out how high a reading we'd need to see right now in order to conclude that another hit has occurred
      uint16_t currentDynamicThreshold = (highestYet >> ((micros() - highestValueTime) >> subsequentHitThresholdDecaySpeed)) * subsequentHitThreshold;
 
      // If that calculated threshold is now as low as the regular threshold, we can go back to just waiting for a regular, isolated hit
      if (currentDynamicThreshold <= triggerThreshold) hitOccurredRecently = false; // Otherwise, do use this higher threshold else thresholdNow = currentDynamicThreshold; } // Read the piezo uint16_t value = analogRead(inputPin); // If we've breached the threshold, it means we've got a hit! if (value >= thresholdNow) {
    startReadingTime = micros();
    highestYet = 0;
 
    // For the next few milliseconds, look out for the highest "spike" in the reading from the piezo. Its height is representative of the hit's velocity
    do {
      if (value > highestYet) {
        highestYet = value;
        highestValueTime = micros();
      }
      value = analogRead(inputPin);
    } while (timeGreaterOrEqual(startReadingTime + initialHitReadDuration, micros()));
 
    // Send the MIDI note
    //usbMIDI.sendNoteOn(0, (highestYet >> midiVelocityScaleDownAmount) + 1, 1); // We add 1 onto the velocity so that the result is never 0, which would mean the same as a note-off
    MIDImessage(noteON, midiNote, (highestYet >> midiVelocityScaleDownAmount) + 1);//turn note on
    //Serial.println(highestYet); // Send the unscaled velocity value to the serial monitor too, for debugging / fine-tuning
    hitOccurredRecently = true;
  }
}
 
// Compares times without being prone to problems when the micros() counter overflows, every ~70 mins
boolean timeGreaterOrEqual(uint32_t lhs, uint32_t rhs) {
  return (((lhs - rhs) & 2147483648) == 0);
}

void MIDImessage(int command, int MIDInote, int MIDIvelocity) {
  Serial.write(command);//send note on or note off command 
  Serial.write(MIDInote);//send pitch data
  Serial.write(MIDIvelocity);//send velocity data
}

Nach dem Experiment auf dem Breadboard habe ich das Ganze direkt an der Klinkenbuchse zusammengelötet und gut ist.

Anschluss noch über das Breadboard
Und direkt an der Klinkenbuchse zusammengelötet

Hier noch ein kurzes Beispielvideo, dass die Steuerung von DrumMic’a in Cubase mit dem Triggerpad zeigt:

052117_1850_TinkeringTu1.jpg

Tinkering Tuesday – HUEify – JN5169 Xiaomi Smart Button – Part 1 – Making a connection

This is a side project to the original HUEify series on connecting a custom light to the HUE ecosystem. On the site http://faire-ca-soi-meme.fr/ there are some articles about what’s inside the Smart Home Gadgets of Xiaomi (at the end of this I provide all the links currently available). Every single piece is taken apart and detailed pictures were taken describing all the identifiable parts. With my little bit french from school even I can read through it. But maybe Google Translator may help others.

I decided to order two pieces because they were very cheap at Gearbest at that time and they would make a perfect match to the nightpanel lights I am currently building and replace the currently used Amazon Dash button. And because they just arrived and I am waiting for PeeVeeOne to publish his solution for the Multiple Endpoint RGB lights on the JN5168, I will now try my luck with the Xiaomi button to see whether I can get it to communicate with Hue.

On faire-ca-soi-meme there are several detailed images of the button and also the pinout from the test pins. Unfortunately these are pogo pins and my tries to solder a wire to them were not very successful. I was successful though with using jumper wires to connect 3.3V and GND to the battery connector, hot-glueing two jumper wires together in the right spacing and forcing it to the pogo pin connectors for RX and TX with a soldering hand. The fifth pin that is required is only temporary and is the SPIMISO pin next to RX/TX. Just shortly connect a ground wire to it when connecting the power (even with my shaky hand that works).

If that is done right you can open the Device Info in NXP Beyond Studio (use 1000000 Baud and the correct COM Port):

I then compiled the Controller_OnOffSensor Demo app from NXP although in the documentation it is only described to work with the JN5168 demo hardware. I used the compile flag for the JN5169 and it compiled successfully. There is an error when flashing the firmware with the flash utility from BeyondStudio but this is only the validation after flashing. The reason is that the chip was read-protected from Xiaomi in order to make reengineering their firmware impossible (or not-so-easy). So the flashing was successful which can be seen from the serial monitor after rebooting:

APP: Switch Power Up...........................(several dots more)
Heap size at step 1 is 11412 bytes (start=04003fe4 end=04006c78)
APP: Watchdog timer has reset device!
Heap size at step 2a is 11412 bytes (start=04003fe4 end=04006c78)
Heap size at step 3 is 11412 bytes (start=04003fe4 end=04006c78)
Heap size at step 4 is 11412 bytes (start=04003fe4 end=04006c78)
Heap size at step 5 is 8216 bytes (start=04004c60 end=04006c78)
Heap size at step 6 is 8216 bytes (start=04004c60 end=04006c78)
Starting Touch Interface...

This ouput is repeated from the timer resetting the device. There seems to be something wrong. The last output message can be found and after that the drivers eTouchInit method is called. I added some debug output and commented out the first for loop (is this a delay or what is that for?):

This results in the following output (the BWE was added because I wanted to be sure I have the correct call):

APP: Switch Power Up...........................(several dots more)
Heap size at step 1 is 11428 bytes (start=04003fd4 end=04006c78)
APP: Watchdog timer has reset device!
Heap size at step 2a is 11428 bytes (start=04003fd4 end=04006c78)
Heap size at step 3 is 11428 bytes (start=04003fd4 end=04006c78)
Heap size at step 4 is 11428 bytes (start=04003fd4 end=04006c78)
Heap size at step 5 is 8232 bytes (start=04004c50 end=04006c78)
Heap size at step 6 is 8232 bytes (start=04004c50 end=04006c78)
Starting Touch Interface...BWE
Starting vTouchInitHardware
Stoping vTouchInitHardware

So there seems to be something wrong with the for-loop. Maybe it tries to read from a wrong pin (because it was made for the JN5168). I will have to take a closer look at the driver and see what I can do. I think I have to understand how it is working first (it is build for a remote control with several buttons so I guess a more simple solution has to be found). I also have to see which DIO pin the buttons are connected to…

In parallel there are also some comments from lucac81 on peeveeone.com about using the JN5169 and Peter also wrote that he ordered some, so maybe the master is faster than me 😀 lucac81 had trouble even installing the light firmware compiled for the JN5169 so maybe I will even try flashing that on the chip to see what happens with the button (just to see if it works, of course I will not use a button to make a light…). I also remember a comment asking about using the chip as a switch for HUE. So maybe someone else is also making progress on this end. I am open for any discussion/help/input.

To be continued sooner or later.

UPDATE

I flashed the JN5169 binary provided by Peter on the Xiaomi SmartHome button but it didn’t join. Unfortunately the debug output on that build doesn’t provide much information.
I build a new one from the demo application with all debugs enabled and the keys in place as I did with the JN5168 but I am getting the same output I had when not correctly putting the keys in place the first time with the JN5168 (see my post http://www.boriswerner.eu/tinkering-tuesday-hueify-making-the-custom-binary-and-the-demo-app-work-on-the-jn5168/):

Try To join 6a075d40c86781e on Ch 11
Try join status 00
Join failed ad

I already researched the error code „ad“ before:

ZPS_APL_APS_E_SECURITY_FAIL: An APSDE-DATA.request requesting security has resulted in an error during the corresponding security processing.

Which definitely hints to a key problem. So the general function is there and it even tries to connect to the bridge but get’s a bad response. That can’t be everything here 😉

 

Links

http://faire-ca-soi-meme.fr/domotique/2017/05/09/test-xiaomi-power-socket/

http://faire-ca-soi-meme.fr/hack/2017/04/24/hack-xiaomi-mi-smarthome-decouverte-de-clef/

http://faire-ca-soi-meme.fr/domotique/2017/04/15/test-xiaomi-mijia-6-in-1-smart-home/

http://faire-ca-soi-meme.fr/domotique/2017/04/04/detournement-capteur-de-mouvement-xiaomi/

http://faire-ca-soi-meme.fr/domotique/2017/03/13/hack-xiaomi-mi-smarthome-zigbee-sniffer/

http://faire-ca-soi-meme.fr/domotique/2017/02/27/hack-xiaomi-mi-smart-temperature-and-humidity-sensor/

JN5169 discussion on https://peeveeone.com/?p=187&

050317_1802_TinkeringTu1.jpg

Tinkering Tuesday – HUEify – PWM to RGB LED strip driver Board

Today I want to show you the board that I created in order to drive 4 RGB LED strips from 16 PWM outputs of the Arduino Mega. It is not the best design as this is my first board and I began without really knowing how to connect the strips in the end 😉 This board connected to the Arduino Mega controlled by the output of the JN5168 will then be the final solution to integrate light in to our nightstands.

I built the design in fritzing so let’s have a look at it:

  • J3, J5, J7, J9 are the connectors (male pin headers) for the PWM pins from the Arduino Mega
  • J2, J4, J6, J8 are also male pin headers to connect the RGB strips
  • J1 ist the input for the external power source (5V in my case) also as male pin headers
  • J22 are additional ground pins to connect the ground from the Arduino (I connected three because you never know…)
  • Q1 – Q12 are MOSFETs, in my case BUZ11

On the board I put all ground connections to the second PCB side (orange) so the connections are clear.

When I had already started soldering the board I thought about how I wanted to connect the RGB strips in the final setup and I decided to go with commonly available 4 wire RGB strip cable (can be found on ebay) and connect it via screw terminals. I was not able to change the design I already started so I just added another board (in the end I had enough space on the same board) which had four 4-pin headers again directly connected to four 4-output (okay, it’s eight 2-output) screw terminals:

I did not put much effort in making the fritzing pretty so the schematic view is a real mess and in the breadboard view I just used perfboard without any wire connections. So essentially just use the PCB view. It should be obvious. Anyway I would modify the board to make direct connections to the screw terminals if you want to use it. But it is working now and it is my first completely self designed and soldered board J

You can download the fritzing file here: 16PWMIn_4RGBOut

This is the progress with the first working module (I already showed a work in progress version in the previous post):

This is the final board including all terminals and pin headers. I even have space to include the logic level converter (LLC) that I need for the JN5168. This way I can directly connect the grounds all on this board. This is not yet soldered because I ran out of solder wire.

This is the board connected to the Arduino and currently directly from the pin headers to the RGB strips.

I put together a small sketch that activates the colors one after the other on all 4 strips. You can download it here: Arduino_Mega_4_RGB_Strip_Color_Test

This is a video of the Arduino Mega controlling all 4 strips via PWM signals from 16 pins:

Next task is to solder the LLC and reconnect the JN5168. Then I have to prepare the wires to connect from the screw terminals to the RGB strip (needs a little soldering and heat shrink tubing). This will then suffice to control all 4 strips with the same setting (one endpoint) but the final piece will then be to create 4 endpoints on the JN5168 to control the 4 strips independently.