Pinball Key controller

Posted on Updated on

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.

arcade_controller_4

 

 

Word Clock

Posted on Updated on

This is a project I started a while ago and not yet completed. Just posting part of the design

  1. First Part of the Project: The front

The spaces between letters are 31.25mm (pitch of my led stripes). Font: Varsity Regular

word_clock_4

Word Clock Front

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.

916434330

2. Second Part of the Project: The back

Drawing of the laser cut back (layer 1)

g4168

Since I am limited by the cutting area of my laser cutter, I had to divide the area in 4 pieces.

Laser Cutting…

l_cut_2 l_cut_3 l_cut_1

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…

clock

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…

remote
Remote Control used

Another Jinx Led Matrix Control Remote

Posted on Updated on

Since I had the dashboard node installed, I wanted to test a UI remote for Jinx.

    1. In Jinx, enable the remote
    2. Select Device Type: Art-Net
    3. Addressing: Set Net to: 2
    4. Other option unchanged
    5. In Node-Red (need version0.14 or newer and node-red-dashboard installed)
    6. 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}]

Jinx_Remote

Raspbian Jessie – Enable ttyAMA0

Posted on Updated on

I spent a bit of time trying to find out how to enable the gpio port /dev/ttyAMA0.

  1. In terminal
    sudo raspi-config
    
  2. Select 9 Advanced Options
  3. Select A7 Serial
  4. Select No for: Would you like a login shell to be accessible over serial?
  5. reboot
  6. Enable uart in /boot/config.txt
  7. reboot
  8. 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)

Posted on Updated on

To setup Node-Red Dashboard, I started from a fresh install of Raspbian (Raspbian Jessie, May 2016)

  1. Once Raspbian is loaded, expend file system
  2. Open terminal and do an update
    sudo apt-get update
  3. reinstall Node-Red
    sudo apt-get install nodered
  4. install npm
    sudo apt-get install npm
    sudo npm i -g npm@2.x
    
  5. install dashboard node
    cd ~/.node-red
    sudo npm install node-red-dashboard
  6. Done

Temperature dry-well block calibrator

Posted on Updated on

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)

  1. Material
    1. Peltier Module
    2. Aduino Mega
    3. ADC converter (ADS1115)
    4. Aluminium Profile 2020
    5. AMD or Intel CPU cooler (I used a water cooled system)
    6. PC Power Supply
    7. Aluminium for the dry-well
  2. Software
    1. Frame Designer (www.framexpert.com)
    2. Inkscape
    3. Arduino IDE
    4. VB or similar for user interface
  3. 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.

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

dry-well_print

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.

675769618896305636

Done, the new one is on the way. I will start again to work on this next week.

Touch OSC – Node-red – Jinx

Posted on Updated on

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.

  1. Raspberry
    1. Use latest Raspbian-Jessie
    2. install npm
      sudo apt-get install npm
    3. update npm
      sudo npm i -g npm@2.x
    4. install node-red-contrib-osc
      cd $HOME/.node-red
      npm install node-red-contrib-osc
  2. 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"]]}]

  1. Jinx setting
    1. enable remote control in Setup/Remote Control
    2. set to Art-Net
    3. Don’t change the default addressing
  2. Touch OSC interface design
    1. Download Jinx_remote
    2. 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

Posted on Updated on

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.

  1. I flash a new lua based firmware in the ESP8266 using Marcel’s NodeMCU custom build cloud service.
    Add WS2801 and / or WS2812 modules
  2. Wait and download the compiled firmware
  3. Flash it using the tool ESPtool
  4. I use ESPlorer to program the ESP
    1. Create a new ini.lua
    2. 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)
  5. 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

Posted on Updated on

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
    1. select with “space” bar the required options
    2. keep the option “desktop”
    3. when requested enter admin password
    4. confirm admin password

Install phpmyadmin

  1. sudo apt-get install phpmyadmin
    1. select with “space” bar the option “apache2”
    2. when requested, select “no” to Configure database for phpmyadmin with dbconfig-common

Node-Red

Posted on Updated on

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.