Pinball Key controller
Part of my Pinball project: Key Controller.
I am making a pinball game based on 46″ screen. I am running Pinball fx2 or Ultra Pinball.
To control the flips I made a small button interface using an Arduino due. We the Due one can easily create a USB keyboard interface using the USB host library.
Here is the program and some photos of the hardware wiring.
Word Clock
This is a project I started a while ago and not yet completed. Just posting part of the design
- First Part of the Project: The front
The spaces between letters are 31.25mm (pitch of my led stripes). Font: Varsity Regular
Here is a photo of the real things made from plastic sheets black and white. It is made by a local supplier (advertising display shop). Not bad.
2. Second Part of the Project: The back
Drawing of the laser cut back (layer 1)
Since I am limited by the cutting area of my laser cutter, I had to divide the area in 4 pieces.
Laser Cutting…
Actually I need a thicker layer, the led are going to be too close to the front.
I am going to change to thick foam board. I will do the same design but CNC cut.
Foam board and CNC:
Result…
The result is OK, I still have to CNC three more pieces to complete the back.
Will finish that during the WE.
Soldering the stripes now.
Today is December 4th, I haven’t touch the thing for a while.
Here, the latest progress. All stripes are done and connected. Just need to think about the final look…
Don’t know how I am going to control them yet?
Today, December 15th.
I have decided to make the clock running with an Arduino Nano + RTC DS3231.
I started with the code from Javelin Word Clock (google Javelin Word Clock) but changed it a bit!
Have a look and play with it. The code only runs the clock, there are no fanzy things yet…
#include <Adafruit_NeoPixel.h> #include <Time.h> #include <Wire.h> #include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t #include <avr/pgmspace.h> #define N_LEDS 110 #define BRIGHTNESSDAY 200 // full on #define BRIGHTNESSNIGHT 55 // half on #define RGBLEDPIN 6 #define TIME_HEADER "T" typedef const unsigned char prog_uchar; Adafruit_NeoPixel grid = Adafruit_NeoPixel(N_LEDS, RGBLEDPIN, NEO_GRB + NEO_KHZ800); int intBrightness = BRIGHTNESSDAY; // the brightness of the clock (0 = off and 255 = 100%) int intTestMode; // set when both buttons are held down String strTime = ""; // used to detect if word time has changed int intTimeUpdated = 0; // used to tell if we need to turn on the brightness again when words change unsigned long previousMillis = 0; const long interval = 10000; uint32_t colorWhite = grid.Color(255, 255, 255); uint32_t colorBlack = grid.Color(0, 0, 0); uint32_t colorRed = grid.Color(255, 0, 0); uint32_t colorGreen = grid.Color(0, 255, 0); uint32_t colorBlue = grid.Color(0, 0, 255); uint32_t colorJGreen = grid.Color(50, 179, 30); #define arrIT {2,0,19} #define arrIS {2,39,40} #define arrAQUARTER {8,80,18,21,38,41,58,61,78} #define arrHALF {4,3,16,23,36} #define arrPAST {4,4,15,24,35} #define arrOCLOCK {6,49,69,70,89,90,109} #define arrTO {2,96,103} #define arrONE {3,5,14,25} #define arrTWO {3,34,45,54} #define arrTHREE {5,65,74,85,94,105} #define arrFOUR {4,6,13,26,33} #define arrFIVE {4,46,53,66,73} #define arrSIX {3,86,93,106} #define arrSEVEN {5,55,64,75,84,95} #define arrEIGHT {5,8,11,28,31,48} #define arrNINE {4,7,12,27,32} #define arrTEN {3,9,10,29} #define arrELEVEN {6,51,68,71,88,91,108} #define arrTWELVE {6,52,67,72,87,92,107} #define arrTWENTY {6,2,17,22,37,42,57} #define arrTWENTYFIVE {10,2,17,22,37,42,57,77,82,97,102} #define arrMFIVE {4,77,82,97,102} #define arrMTEN {3,56,63,76} prog_uchar words[23][11] PROGMEM ={arrIT, arrIS, arrAQUARTER, arrMFIVE, arrMTEN, arrTWENTY, arrTWENTYFIVE, arrHALF, arrTO, arrPAST, arrONE, arrTWO, arrTHREE, arrFOUR, arrFIVE, arrSIX, arrSEVEN, arrEIGHT, arrNINE, arrTEN, arrELEVEN, arrTWELVE, arrOCLOCK}; prog_uchar m[12][2] PROGMEM ={{0,22},{5,3},{10,4},{15,2},{20,5},{25,6},{30,7},{35,6},{40,5}, {45,2},{50,4},{55,3}}; prog_uchar h_a[13] PROGMEM ={0,10,11,12,13,14,15,16,17,18,19,20,21}; prog_uchar h_b[13] PROGMEM ={0,11,12,13,14,15,16,17,18,19,20,21,10}; void setup() { Serial.begin(9600); setSyncProvider(RTC.get); // the function to get the time from the RTC setSyncInterval(60); // sync the time every 60 seconds (1 minutes) if(timeStatus() != timeSet){ Serial.println("Unable to sync"); RTC.set(1481781666); // set the RTC to Thu, 15 Dec 2016 06:01:06 +00:00 setTime(1481781666); } // setup the LED strip grid.begin(); grid.show(); // set the brightness of the strip grid.setBrightness(intBrightness); } void loop(){ unsigned long currentMillis = millis(); // if there is a serial connection lets see if we need to set the time if (Serial.available()) { time_t t = processSyncMessage(); if (t != 0) { Serial.print("Time set via connection to: "); Serial.print(t); Serial.println(); RTC.set(t); // set the RTC and the system time to the received value setTime(t); } } // check to see if the time has been set if (timeStatus() == timeSet){ // time is set lets show the time if((hour() < 7) | (hour() >= 19)){ intBrightness = BRIGHTNESSNIGHT; }else{ intBrightness = BRIGHTNESSDAY; } grid.setBrightness(intBrightness); } if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; for (byte z =0; z<110; z++){ grid.setPixelColor(z,colorBlack); } pushtime(); grid.show(); } } unsigned long processSyncMessage() { unsigned long pctime = 0L; const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 if(Serial.find(TIME_HEADER)) { pctime = Serial.parseInt(); pctime = pctime + 28800; // + 8 hours - winter asia time return pctime; if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013) pctime = 0L; // return 0 to indicate that the time is not valid } Serial.println("Set"); } return pctime; } void pushtime(){ int Minute = minute(); int Hour = hourFormat12(); boolean past = true; Minute = Minute - (Minute % 5); if((minute()>34) && (minute()<= 59)) { past = false; } Serial.print (hourFormat12()); Serial.print (" : "); Serial.println (Minute); // push IT for(int i = 1; i <= pgm_read_byte ( & words [0][0]); i++){ Serial.println( pgm_read_byte ( & words [0][i]) ); grid.setPixelColor(pgm_read_byte ( & words [0][i]),colorWhite); } // push IS for(int i = 1; i <= pgm_read_byte ( & words [1][0]); i++){ Serial.println( pgm_read_byte ( & words [1][i]) ); grid.setPixelColor(pgm_read_byte ( & words [1][i]),colorWhite); } // push minute byte a; for (byte i=0; i<12; i++) { if (pgm_read_byte ( & m [i][0]) == Minute) { a = pgm_read_byte ( & m [i][1]); break; } } for(int i = 1; i <= pgm_read_byte ( & words [a][0]); i++){ Serial.println( pgm_read_byte ( & words [a][i])); grid.setPixelColor(pgm_read_byte ( & words [a][i]),colorWhite); } //push to or past if (Minute > 0){ if (past == true) { for(int i = 1; i <= pgm_read_byte ( & words [9][0]); i++){ Serial.println( pgm_read_byte ( & words [9][i]) ); grid.setPixelColor(pgm_read_byte ( & words [9][i]),colorWhite); } } if (past == false) { for(int i = 1; i <= pgm_read_byte ( & words [8][0]); i++){ Serial.println( pgm_read_byte ( & words [8][i]) ); grid.setPixelColor(pgm_read_byte ( & words [8][i]),colorWhite); } } } //push hour if (past == true){ byte a = pgm_read_byte ( & h_a [Hour]); for(int i = 1; i <= pgm_read_byte ( & words [a][0]); i++){ Serial.println( pgm_read_byte ( & words [a][i])); grid.setPixelColor(pgm_read_byte ( & words [a][i]),colorWhite); } } if (past == false){ byte a = pgm_read_byte ( & h_b [Hour]); for(int i = 1; i <= pgm_read_byte ( & words [a][0]); i++){ Serial.println( pgm_read_byte ( & words [a][i])); grid.setPixelColor(pgm_read_byte ( & words [a][i]),colorWhite); } } }
Back and finally the clock is ticking…
Here is the last code. I used FastLed library and other nice stuff like PaletteKnife for FastLED. Really cool.
#include "FastLED.h" #include <Time.h> #include <Wire.h> #include <DS1307RTC.h> #include <avr/pgmspace.h> #include <IRremote.h> #define N_LEDS 110 #define DATA_PIN 6 #define LED_TYPE WS2812 #define BRIGHTNESS 255 #define UPDATES_PER_SECOND 50 #define TIME_HEADER "T" typedef const unsigned char prog_uchar; CRGB leds[N_LEDS]; unsigned long previousMillis = 0; const long interval = 5000; int RECV_PIN = 11; boolean IR = false; byte bb = 100; #define arrIT {2,0,19} #define arrIS {2,39,40} #define arrAQUARTER {8,80,18,21,38,41,58,61,78} #define arrHALF {4,3,16,23,36} #define arrPAST {4,4,15,24,35} #define arrOCLOCK {6,49,69,70,89,90,109} #define arrTO {2,96,103} #define arrONE {3,5,14,25} #define arrTWO {3,34,45,54} #define arrTHREE {5,65,74,85,94,105} #define arrFOUR {4,6,13,26,33} #define arrFIVE {4,46,53,66,73} #define arrSIX {3,86,93,106} #define arrSEVEN {5,55,64,75,84,95} #define arrEIGHT {5,8,11,28,31,48} #define arrNINE {4,7,12,27,32} #define arrTEN {3,9,10,29} #define arrELEVEN {6,51,68,71,88,91,108} #define arrTWELVE {6,52,67,72,87,92,107} #define arrTWENTY {6,2,17,22,37,42,57} #define arrTWENTYFIVE {10,2,17,22,37,42,57,77,82,97,102} #define arrMFIVE {4,77,82,97,102} #define arrMTEN {3,56,63,76} #define IR_ON 0xFFA25D #define IR_AUTO 0xFF629D #define IR_OFF 0xFFE21D #define IR_SUP 0xFF22DD #define IR_MUP 0xFF02FD #define IR_BUP 0xFFC23D #define IR_SDN 0xFFE0AF #define IR_MDN 0xFFA857 #define IR_BDN 0xFF906F #define IR_RED 0xFF6897 #define IR_GREEN 0xFF9867 #define IR_BLUE 0xFFB04F #define IR_LIGHTYELLOW 0xFF30CF #define IR_YELLOW 0xFF18E7 #define IR_LIGHTORANGE 0xFF7A85 #define IR_ORANGE 0xFF10EF #define IR_GREY 0xFF38C7 #define IR_LIGHTBLUE 0xFF5AA5 #define IR_PINK 0xFF42BD #define IR_LIGHTGREEN 0xFF4AB5 #define IR_WHITE 0xFF52AD prog_uchar words[23][11] PROGMEM ={arrIT, arrIS, arrAQUARTER, arrMFIVE, arrMTEN, arrTWENTY, arrTWENTYFIVE, arrHALF, arrTO, arrPAST, arrONE, arrTWO, arrTHREE, arrFOUR, arrFIVE, arrSIX, arrSEVEN, arrEIGHT, arrNINE, arrTEN, arrELEVEN, arrTWELVE, arrOCLOCK}; prog_uchar m[12][2] PROGMEM ={{0,22},{5,3},{10,4},{15,2},{20,5},{25,6},{30,7},{35,6},{40,5}, {45,2},{50,4},{55,3}}; prog_uchar h_a[13] PROGMEM ={0,10,11,12,13,14,15,16,17,18,19,20,21}; prog_uchar h_b[13] PROGMEM ={0,11,12,13,14,15,16,17,18,19,20,21,10}; DEFINE_GRADIENT_PALETTE( p_orange ) { 0, 9, 5, 1, 48, 25, 9, 1, 76, 137, 27, 1, 96, 98, 42, 1, 124, 144, 79, 1, 153, 98, 42, 1, 178, 137, 27, 1, 211, 23, 9, 1, 255, 9, 5, 1}; DEFINE_GRADIENT_PALETTE( p_green ) { 0, 1, 22, 1, 130, 1,168, 2, 255, 1, 22, 1}; DEFINE_GRADIENT_PALETTE( p_red ) { 0, 14, 2, 5, 63, 40, 1, 7, 130, 182, 1, 1, 188, 40, 1, 7, 255, 14, 2, 5}; DEFINE_GRADIENT_PALETTE( p_blue ) { 0, 0, 0, 8, 45, 0, 0, 45, 79, 7, 12,255, 119, 42, 55,255, 158, 7, 12,255, 209, 0, 0, 45, 255, 0, 0, 8}; DEFINE_GRADIENT_PALETTE( p_yellow ) { 0, 208,186, 19, 53, 232,215, 42, 84, 255,255, 45, 127, 255,255,125, 165, 255,255, 45, 196, 232,215, 42, 247, 208,186, 19, 255, 208,186, 19}; DEFINE_GRADIENT_PALETTE( p_lightyellow ) { 0, 159,142, 27, 51, 192,180, 82, 127, 255,255,255, 201, 192,180, 82, 255, 159,142, 27}; DEFINE_GRADIENT_PALETTE( p_lightorange ) { 0, 47, 28, 2, 76, 229, 73, 1, 163, 255,255, 0, 255, 229, 73, 1}; DEFINE_GRADIENT_PALETTE( p_grey ) { 0, 1, 2, 1, 51, 42, 55, 45, 89, 144,178,170, 130, 255,255,255, 146, 194,215,210, 175, 144,178,170, 255, 1, 2, 1}; DEFINE_GRADIENT_PALETTE( p_lightblue ) { 0, 1, 10, 19, 132, 126,201,255, 255, 1, 10, 19}; DEFINE_GRADIENT_PALETTE( p_pink ) { 0, 2, 1, 8, 94, 79, 2,212, 140, 110, 11,197, 255, 2, 1, 8}; DEFINE_GRADIENT_PALETTE( p_lightgreen ) { 0, 30,186, 72, 81, 77,255,105, 127, 184,250,186, 175, 77,255,105, 255, 30,186, 72}; DEFINE_GRADIENT_PALETTE( p_white ) { 0, 121,136,125, 38, 173,180,172, 107, 255,255,255, 140, 255,255,255, 219, 173,180,172, 255, 121,136,125}; CRGBPalette16 currentPalette; TBlendType currentBlending; extern CRGBPalette16 myRedWhiteBluePalette; extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { FastLED.addLeds<LED_TYPE, DATA_PIN, GRB>(leds, N_LEDS); FastLED.setBrightness( BRIGHTNESS ); currentPalette = p_orange; currentBlending = LINEARBLEND; Serial.begin(9600); setSyncProvider(RTC.get); // the function to get the time from the RTC setSyncInterval(60); // sync the time every 60 seconds (1 minutes) irrecv.enableIRIn(); // Start the receiver if(timeStatus() != timeSet){ Serial.println("Unable to sync"); RTC.set(1481781666); // set the RTC to Thu, 15 Dec 2016 06:01:06 +00:00 setTime(1481781666); } } void loop(){ if (irrecv.decode(&results)) { IR = true; previousMillis = millis(); // Serial.println(results.value, HEX); //if results.value == 0xFFE21D display time switch (results.value) { case IR_OFF: //exit IR Loop IR = false; break; case IR_GREEN: currentPalette = p_green; IR = false; break; case IR_RED: currentPalette = p_red; IR = false; break; case IR_BLUE: currentPalette = p_blue; IR = false; break; case IR_LIGHTYELLOW: currentPalette = p_lightyellow; IR = false; break; case IR_YELLOW: currentPalette = p_yellow; IR = false; break; case IR_LIGHTORANGE: currentPalette = p_lightorange; IR = false; break; case IR_ORANGE: currentPalette = p_orange; IR = false; break; case IR_GREY: currentPalette = p_grey; IR = false; break; case IR_LIGHTBLUE: currentPalette = p_lightblue; IR = false; break; case IR_PINK: currentPalette = p_pink; IR = false; break; case IR_LIGHTGREEN: currentPalette = p_lightgreen; IR = false; break; case IR_WHITE: currentPalette = p_white; IR = false; break; case IR_MUP: RTC.set(now() + 300); // set the RTC and the system time to the received value setTime(now() + 300); IR = false; break; case IR_MDN: RTC.set(now() - 300); // set the RTC and the system time to the received value setTime(now() - 300); IR = false; break; case IR_BUP: bb = bb + 10; IR = false; break; case IR_BDN: bb = bb - 10; IR = false; break; } irrecv.resume(); // Receive the next value } if (!IR) { unsigned long currentMillis = millis(); // if there is a serial connection lets see if we need to set the time if (Serial.available()) { time_t t = processSyncMessage(); if (t != 0) { Serial.print("Time set via connection to: "); Serial.print(t); Serial.println(); RTC.set(t); // set the RTC and the system time to the received value setTime(t); } } static uint8_t startIndex = 0; startIndex = startIndex + 1; /* motion speed */ FillLEDsFromPaletteColors( startIndex); pushtime(); FastLED.show(); FastLED.delay(1000 / UPDATES_PER_SECOND); } if (IR) { //unsigned long currentMillis = millis(); if ( millis() - previousMillis >= interval) { IR = false; } } } unsigned long processSyncMessage() { unsigned long pctime = 0L; const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 if(Serial.find(TIME_HEADER)) { pctime = Serial.parseInt(); pctime = pctime + 28800; // + 8 hours - winter asia time return pctime; if( pctime < DEFAULT_TIME) { pctime = 0L; // return 0 to indicate that the time is not valid } Serial.println("Set"); } return pctime; } void pushtime(){ int Minute = minute(); int Hour = hourFormat12(); boolean past = true; Minute = Minute - (Minute % 5); if((minute()>34) && (minute()<= 59)) { past = false; } // push IT for(int i = 1; i <= pgm_read_byte ( & words [0][0]); i++){ leds[pgm_read_byte ( & words [0][i])] = CRGB::White; } // push IS for(int i = 1; i <= pgm_read_byte ( & words [1][0]); i++){ leds[pgm_read_byte ( & words [1][i])] = CRGB::White; } // push Minute byte a; for (byte i=0; i<12; i++) { if (pgm_read_byte ( & m [i][0]) == Minute) { a = pgm_read_byte ( & m [i][1]); break; } } for(int i = 1; i <= pgm_read_byte ( & words [a][0]); i++){ leds[pgm_read_byte ( & words [a][i])] = CRGB::White; } //push to or past excepted 0 if ( Minute > 0){ if (past == true) { for(int i = 1; i <= pgm_read_byte ( & words [9][0]); i++){ leds[pgm_read_byte ( & words [9][i])] = CRGB::White; } } if (past == false) { for(int i = 1; i <= pgm_read_byte ( & words [8][0]); i++){ leds[pgm_read_byte ( & words [8][i])] = CRGB::White; } } } //push hour if (past == true){ byte a = pgm_read_byte ( & h_a [Hour]); for(int i = 1; i <= pgm_read_byte ( & words [a][0]); i++){ leds[pgm_read_byte ( & words [a][i])] = CRGB::White; } } if (past == false){ byte a = pgm_read_byte ( & h_b [Hour]); for(int i = 1; i <= pgm_read_byte ( & words [a][0]); i++){ leds[pgm_read_byte ( & words [a][i])] = CRGB::White; } } } void FillLEDsFromPaletteColors( uint8_t colorIndex) { for( int i = 0; i < N_LEDS; i++) { leds[i] = ColorFromPalette( currentPalette, colorIndex, bb, currentBlending); colorIndex += 3; } }
I added a IR remote to set the time, change the effect and brightness.
If you look at the program, I stopped the led refresh to be able to use the IR receiving. I check the millis once in the IR receiving mode and after 5 sec hte refresh starts again. Not as nice as I want it to be but it does the job.
Some photos…

Another Jinx Led Matrix Control Remote
Since I had the dashboard node installed, I wanted to test a UI remote for Jinx.
- In Jinx, enable the remote
- Select Device Type: Art-Net
- Addressing: Set Net to: 2
- Other option unchanged
- In Node-Red (need version0.14 or newer and node-red-dashboard installed)
- Copy the flow
[{"id":"f264ee64.0c53c8","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":2,"width":"2","height":"2","label":"2","color":"","icon":"","payload":"2","payloadType":"num","topic":"","x":57,"y":156.25,"wires":[["cd532d39.cf3778"]]},{"id":"b3f22389.2b6a18","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":1,"width":"2","height":"2","label":"Black","color":"","icon":"","payload":"1","payloadType":"num","topic":"","x":82,"y":92.25,"wires":[["cd532d39.cf3778"]]},{"id":"a155b275.37d848","type":"ui_slider","z":"d8e38fe3.54c4a","group":"f2202e5b.62751","order":17,"width":"8","height":"1","name":"","label":"","topic":"master","min":0,"max":"255","x":87,"y":718.75,"wires":[["ade5845c.d2f3b8"]]},{"id":"ff98fe8f.e4a4a","type":"udp out","z":"d8e38fe3.54c4a","name":"","addr":"192.168.1.108","iface":"","port":"6454","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":703.75,"y":892.75,"wires":[]},{"id":"fa673c45.a29b28","type":"inject","z":"d8e38fe3.54c4a","name":"reset","topic":"","payload":"Reset","payloadType":"str","repeat":"","crontab":"","once":true,"x":97.25,"y":779.75,"wires":[["fa95cbd.1a7c938"]]},{"id":"30659925.52ad2e","type":"debug","z":"d8e38fe3.54c4a","name":"Debug","active":true,"console":"false","complete":"payload","x":533.25,"y":777.25,"wires":[]},{"id":"fa95cbd.1a7c938","type":"function","z":"d8e38fe3.54c4a","name":"Rest General Variable","func":"// initialise data\nflow.set('scener',0);\nflow.set('scenel',0);\nflow.set('chase',0);\nflow.set('mode',0);\nflow.set('cross',0);\nflow.set('stobe',0);\nflow.set('master',0);\nreturn msg;\n","outputs":1,"noerr":0,"x":300.75,"y":778.25,"wires":[["30659925.52ad2e"]]},{"id":"694bee14.421ba8","type":"function","z":"d8e38fe3.54c4a","name":"","func":"msg.payload = new Buffer([65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 2, 7,0,\nflow.get('scenel'), //scene left\nflow.get('scener'), //scene right\nflow.get('chase'), //chase select\nflow.get('mode'), //crossfade mode\nflow.get('cross'), //crossfade\nflow.get('strobe'), //strobe\nflow.get('master')]); //master\nreturn msg;","outputs":1,"noerr":0,"x":475.75,"y":890.75,"wires":[["ff98fe8f.e4a4a","e8f04232.d92818"]]},{"id":"ade5845c.d2f3b8","type":"function","z":"d8e38fe3.54c4a","name":"","func":"flow.set('master',msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":271,"y":718.5,"wires":[[]]},{"id":"5efedb9a.aa4824","type":"link in","z":"d8e38fe3.54c4a","name":"send","links":["fb1b4.29fa264d","f37e9b71.b9971","5241bb21.4d20dc","ccb4bc0c.b05fc8","cbf08263.553e"],"x":109,"y":899.25,"wires":[["98493a85.c2a5a8"]]},{"id":"cd532d39.cf3778","type":"function","z":"d8e38fe3.54c4a","name":"","func":"flow.set('scenel',msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":482,"y":86.5,"wires":[["f37e9b71.b9971"]]},{"id":"f37e9b71.b9971","type":"link out","z":"d8e38fe3.54c4a","name":"","links":["5efedb9a.aa4824"],"x":602,"y":87.5,"wires":[]},{"id":"98493a85.c2a5a8","type":"delay","z":"d8e38fe3.54c4a","name":"","pauseType":"timed","timeout":"5","timeoutUnits":"seconds","rate":"11","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":307.75,"y":889.5,"wires":[["694bee14.421ba8"]]},{"id":"b3585d74.89d69","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":18,"width":"8","height":"2","label":"Set","color":"","icon":"","payload":"1","payloadType":"num","topic":"","x":150.75,"y":1046.25,"wires":[["ccb4bc0c.b05fc8"]]},{"id":"ccb4bc0c.b05fc8","type":"link out","z":"d8e38fe3.54c4a","name":"","links":["5efedb9a.aa4824"],"x":321.75,"y":1050.25,"wires":[]},{"id":"dc513104.f3d9e8","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":3,"width":"2","height":"2","label":"3","color":"","icon":"","payload":"3","payloadType":"num","topic":"","x":58.75,"y":223.75,"wires":[["cd532d39.cf3778"]]},{"id":"44e8bf8a.9d8d38","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":4,"width":"2","height":"2","label":"4","color":"","icon":"","payload":"4","payloadType":"num","topic":"","x":58.75,"y":302.75,"wires":[["cd532d39.cf3778"]]},{"id":"e47bccae.aec548","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":5,"width":"2","height":"2","label":"5","color":"","icon":"","payload":"5","payloadType":"num","topic":"","x":55,"y":381.75,"wires":[["cd532d39.cf3778"]]},{"id":"61a6eb08.247934","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":6,"width":"2","height":"2","label":"6","color":"","icon":"","payload":"6","payloadType":"num","topic":"","x":59.75,"y":451.75,"wires":[["cd532d39.cf3778"]]},{"id":"e8f04232.d92818","type":"function","z":"d8e38fe3.54c4a","name":"Rest General Variable","func":"// initialise data\nflow.set('scener',0);\nflow.set('scenel',0);\nflow.set('chase',0);\nflow.set('mode',0);\nflow.set('cross',0);\nflow.set('stobe',0);\nreturn msg;\n","outputs":1,"noerr":0,"x":700,"y":972.5,"wires":[[]]},{"id":"6ff7f13e.ed2288","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":7,"width":"2","height":"2","label":"7","color":"","icon":"","payload":"7","payloadType":"num","topic":"","x":55.75,"y":506.75,"wires":[["cd532d39.cf3778"]]},{"id":"65706999.795398","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":8,"width":"2","height":"2","label":"8","color":"","icon":"","payload":"8","payloadType":"num","topic":"","x":55,"y":558.75,"wires":[["cd532d39.cf3778"]]},{"id":"9471f773.0461a","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":9,"width":"2","height":"2","label":"9","color":"","icon":"","payload":"9","payloadType":"num","topic":"","x":55.75,"y":608.75,"wires":[["cd532d39.cf3778"]]},{"id":"6dbdf78f.8ec2a8","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":10,"width":"2","height":"2","label":"10","color":"","icon":"","payload":"10","payloadType":"num","topic":"","x":462.75,"y":199.75,"wires":[["cd532d39.cf3778"]]},{"id":"8fc02d80.773ed","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":11,"width":"2","height":"2","label":"11","color":"","icon":"","payload":"11","payloadType":"num","topic":"","x":463.75,"y":251.75,"wires":[["cd532d39.cf3778"]]},{"id":"59cfb183.f4bc5","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":12,"width":"2","height":"2","label":"12","color":"","icon":"","payload":"12","payloadType":"num","topic":"","x":462.75,"y":316.75,"wires":[["cd532d39.cf3778"]]},{"id":"cd2dccb.78414b","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":13,"width":"2","height":"2","label":"13","color":"","icon":"","payload":"13","payloadType":"num","topic":"","x":463.75,"y":384.75,"wires":[["cd532d39.cf3778"]]},{"id":"71222766.c451d8","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":14,"width":"2","height":"2","label":"14","color":"","icon":"","payload":"14","payloadType":"num","topic":"","x":463.75,"y":453.75,"wires":[["cd532d39.cf3778"]]},{"id":"fe97a913.adf248","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":15,"width":"2","height":"2","label":"15","color":"","icon":"","payload":"15","payloadType":"num","topic":"","x":460.75,"y":513.75,"wires":[["cd532d39.cf3778"]]},{"id":"59323177.facad8","type":"ui_button","z":"d8e38fe3.54c4a","name":"","group":"f2202e5b.62751","order":15,"width":"2","height":"2","label":"16","color":"","icon":"","payload":"16","payloadType":"num","topic":"","x":460.75,"y":582.5,"wires":[["cd532d39.cf3778"]]},{"id":"f2202e5b.62751","type":"ui_group","z":"","name":"Main","tab":"24e26b6f.f52bd4","order":2,"disp":false,"width":"8"},{"id":"24e26b6f.f52bd4","type":"ui_tab","z":"","name":"Remote","icon":"dashboard","order":4}]
Raspbian Jessie – Enable ttyAMA0
I spent a bit of time trying to find out how to enable the gpio port /dev/ttyAMA0.
- In terminal
sudo raspi-config
- Select 9 Advanced Options
- Select A7 Serial
- Select No for: Would you like a login shell to be accessible over serial?
- reboot
- Enable uart in /boot/config.txt
- reboot
- Done
to check tty:
dmesg | grep tty
Use command-line gpio util to check state of all pins
gpio readall
Node-Red Dashboard (Raspberry Pi)
To setup Node-Red Dashboard, I started from a fresh install of Raspbian (Raspbian Jessie, May 2016)
- Once Raspbian is loaded, expend file system
- Open terminal and do an update
sudo apt-get update
- reinstall Node-Red
sudo apt-get install nodered
- install npm
sudo apt-get install npm sudo npm i -g npm@2.x
- install dashboard node
cd ~/.node-red sudo npm install node-red-dashboard
- Done
Temperature dry-well block calibrator
The latest ongoing project: A block calibrator.
Since I needed something to generate cold and hot in order to calibrate my sensors (NTC), I decided to go ahead into this project. (I tried to keep the cost as low as possible)
- Material
- Peltier Module
- Aduino Mega
- ADC converter (ADS1115)
- Aluminium Profile 2020
- AMD or Intel CPU cooler (I used a water cooled system)
- PC Power Supply
- Aluminium for the dry-well
- Software
- Frame Designer (www.framexpert.com)
- Inkscape
- Arduino IDE
- VB or similar for user interface
- Development
I started to make a sketch of frame on paper adding dimensions of parts and positioning (for complicated things usually I use Frame Designer). I ended up with something like 42 cm x 19 cm x 30 cm. Everything after cutting and assembling should fit into the frame.
The next step was to build the Power Supply and water cooler. I designed quickly the part using Inkscape and cut the thing in MDF using a laser cutter. Following, the design in pdf
To be continued…
Some leak checking after installing the pump…
The project is still on-hold, I got problem with the quality of the cooling tank. The acrylic completely cracked!! Need to find a replacement.
Done, the new one is on the way. I will start again to work on this next week.
Touch OSC – Node-red – Jinx
This time, I am going to use my ipad to control Jinx (Matrix Led Controller) with the tools I have available.
No idea yet if it is the best solution!
The full idea: Ipad with touch OSC sends message to raspberry pi / node-red sends artnet control to Jinx running on an Intel Z3736F Win10 box.
- Raspberry
- Use latest Raspbian-Jessie
- install npm
sudo apt-get install npm
- update npm
sudo npm i -g npm@2.x
- install node-red-contrib-osc
cd $HOME/.node-red npm install node-red-contrib-osc
- Copy the following flow to get started with Node-Red
[{"id":"53e93d80.8fa17c","type":"osc in","z":"a896c6ba.33dbc","name":"OSC Remote","addr":"127.0.0.1","port":"8888","x":99.5,"y":122.5,"wires":[["2e5a1f18.0780d"]]},{"id":"f004a737.24a56","type":"udp out","z":"a896c6ba.33dbc","name":"","addr":"192.168.1.115","iface":"","port":"6454","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":1046.5,"y":473,"wires":[]},{"id":"433f44a5.73f2fc","type":"function","z":"a896c6ba.33dbc","name":"Set Master","func":"flow.set('master',Number((msg.payload).toFixed(0)));\nreturn msg;","outputs":1,"noerr":0,"x":555.5,"y":116.5,"wires":[["61ebd424.dcfb84"]]},{"id":"2e5a1f18.0780d","type":"switch","z":"a896c6ba.33dbc","name":"Route OSC Message","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"Master","vt":"str"},{"t":"cont","v":"Scene Left","vt":"str"},{"t":"cont","v":"Scene Right","vt":"str"}],"checkall":"true","outputs":3,"x":308.5,"y":131.5,"wires":[["433f44a5.73f2fc"],["36341715.745cc8"],["50eae3a9.f8f4f4"]]},{"id":"36341715.745cc8","type":"function","z":"a896c6ba.33dbc","name":"Set Scene Left","func":"msg.topic = msg.topic.replace(\"/1/Scene Left/\",\"\");\nmsg.payload = msg.topic;\nreturn msg;","outputs":1,"noerr":0,"x":545.5,"y":188.5,"wires":[["f1053883.2d8508"]]},{"id":"cb95dbe.5976228","type":"function","z":"a896c6ba.33dbc","name":"","func":"flow.set('scenel',(msg.payload.Row - 1) * 5 + msg.payload.Column);\n//msg.payload = (msg.payload.Row - 1) * 5 + msg.payload.Column;\nmsg.scene = flow.get('scenel');\nreturn msg;","outputs":1,"noerr":0,"x":888.5,"y":187.5,"wires":[["857d701.f184e9"]]},{"id":"4c3cd0aa.c150d8","type":"inject","z":"a896c6ba.33dbc","name":"reset","topic":"","payload":"Reset","payloadType":"str","repeat":"","crontab":"","once":true,"x":107.5,"y":49.5,"wires":[["3f12f8ae.c301f"]]},{"id":"4eee2b21.e740ec","type":"debug","z":"a896c6ba.33dbc","name":"Debug","active":true,"console":"false","complete":"payload","x":543.5,"y":47,"wires":[]},{"id":"3f12f8ae.c301f","type":"function","z":"a896c6ba.33dbc","name":"Rest General Variable","func":"// initialise data\nflow.set('scener',0);\nflow.set('scenel',0);\nflow.set('chase',1);\nflow.set('mode',1);\nflow.set('cross',1);\nflow.set('stobe',0);\nflow.set('master',0);\nreturn msg;\n","outputs":1,"noerr":0,"x":311,"y":48,"wires":[["4eee2b21.e740ec"]]},{"id":"61ebd424.dcfb84","type":"function","z":"a896c6ba.33dbc","name":"","func":"msg.payload = new Buffer([65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 0, 7,0,\nflow.get('scenel'), //scene left\nflow.get('scener'), //scene right\nflow.get('chase'), //chase select\nflow.get('mode'), //crossfade mode\nflow.get('cross'), //crossfade\nflow.get('strobe'), //strobe\nflow.get('master')]); //master\nreturn msg;","outputs":1,"noerr":0,"x":892,"y":115,"wires":[["dd06deed.949b98"]]},{"id":"f1053883.2d8508","type":"csv","z":"a896c6ba.33dbc","name":"","sep":"/","hdrin":"","hdrout":true,"multi":"one","ret":"\\n","temp":"Row,Column","x":733.5,"y":190.5,"wires":[["cb95dbe.5976228"]]},{"id":"50eae3a9.f8f4f4","type":"function","z":"a896c6ba.33dbc","name":"Set Scene Right","func":"msg.topic = msg.topic.replace(\"/1/Scene Right/\",\"\");\nmsg.payload = msg.topic;\nreturn msg;","outputs":1,"noerr":0,"x":544,"y":242,"wires":[["fce93063.7fdf9"]]},{"id":"fce93063.7fdf9","type":"csv","z":"a896c6ba.33dbc","name":"","sep":"/","hdrin":"","hdrout":true,"multi":"one","ret":"\\n","temp":"Row,Column","x":734,"y":243,"wires":[["e042d2ed.0a25f"]]},{"id":"e042d2ed.0a25f","type":"function","z":"a896c6ba.33dbc","name":"","func":"flow.set('scener',(msg.payload.Row - 1) * 5 + msg.payload.Column);\n//msg.payload = (msg.payload.Row - 1) * 5 + msg.payload.Column;\nmsg.scene = flow.get('scener');\nreturn msg;","outputs":1,"noerr":0,"x":891,"y":240,"wires":[["857d701.f184e9"]]},{"id":"f06b7e55.e9286","type":"function","z":"a896c6ba.33dbc","name":"","func":"msg.payload = new Buffer([65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 0, 7,0,\nflow.get('scenel'), //scene left\nflow.get('scener'), //scene right\nflow.get('chase'), //chase select\nflow.get('mode'), //crossfade mode\nflow.get('cross'), //crossfade\nflow.get('strobe'), //strobe\nflow.get('master')]); //master\nreturn msg;","outputs":1,"noerr":0,"x":1019,"y":379,"wires":[["f004a737.24a56"]]},{"id":"dd06deed.949b98","type":"delay","z":"a896c6ba.33dbc","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":1070.5,"y":114.5,"wires":[["f06b7e55.e9286"]]},{"id":"857d701.f184e9","type":"delay","z":"a896c6ba.33dbc","name":"","pauseType":"queue","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1077.5,"y":204.5,"wires":[["f06b7e55.e9286"]]}]
- Jinx setting
- enable remote control in Setup/Remote Control
- set to Art-Net
- Don’t change the default addressing
- Touch OSC interface design
- Download Jinx_remote
- Rename the downlaoaded file to jinx_remote.touchosc (got problem to uplaod the file)
Test
It is basically working except a bug sometime when sending too many command. I added some delay in the flow in order to limit them.
If anyone has any idea or better solution please let me know.
ESP8266: Artnet receiver
The other I was playing with a matrix of led. The matrix is made of a stripe of WS2801.
So, here is what I have done.
- I flash a new lua based firmware in the ESP8266 using Marcel’s NodeMCU custom build cloud service.
Add WS2801 and / or WS2812 modules - Wait and download the compiled firmware
- Flash it using the tool ESPtool
- I use ESPlorer to program the ESP
- Create a new ini.lua
- Copy the following lines of code.
This is for a matrix 10×10 “snakelines”wifi.setmode(wifi.STATION) wifi.sta.config("******","******",1) tmr.delay(5000000) -- wait 1,000,000 us = 1 second ws2801.init(0, 2) tmr.delay(1000000) ws2801.write(string.char(0,0,0):rep(100)) s=net.createServer(net.UDP) s:on("receive",function(s,c) ws2801.write(string.sub (c, 19, 318)) end) s:listen(6454)
- Use Jinx or Glediator (I prefer Jinx) to drive the matrix and send the Artnet commands to the ESP8266
It works very well.
The code is simple and works well. I haven’t tried on large matrix but I think for larger matrix a fast wifi connection would be needed.
Fast Install Lamp on Ubuntu 15.10
To install Lamp in Ubuntu make the use of tasksel. It is quick and easy.
sudo apt-get update sudo apt-get install tasksel sudo tasksel
- select with “space” bar the required options
- keep the option “desktop”
- when requested enter admin password
- confirm admin password
Install phpmyadmin
- sudo apt-get install phpmyadmin
- select with “space” bar the option “apache2”
- when requested, select “no” to Configure database for phpmyadmin with dbconfig-common
Node-Red
How to install Node-Red on Ubuntu 15.10
Follow this instructions:
In terminal, run following commands
sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm
sudo ln -s /usr/bin/nodejs /usr/bin/node
sudo npm install -g --unsafe-perm node-red
cd $HOME/.node-red
sudo npm install node-red-node-serialport@0.0.5
To install other nodes, do it from the same directory /.node-red and using the command 7.
To run node-red, in terminal, launch it with the command
sudo node-red
I am using sudo because I need the root access to serial port.
- ← Previous
- 1
- 2
- 3