Andon light
Project: Andon light | |
---|---|
Featured: | No |
State | Stalled |
Members | xopr |
GitHub | midi-andon |
Description | Andon light/signal tower |
Picture | |
synopsis
An andon light is a color-coded visual display for process state control; in short: On-Air light
The first version is completed, and used in the Binary Voice studio at the CCC2011. The second version was for OHM2013.. The third version was for SHA2017 but the second midi port (for the second mixer) failed and needs to be looked at for the next revision (H-2021)..
implementation
I used a light tower/andon light which a good friend Spert modified to fit 6 leds in it.
prototype
Since the media plugin doesn't work, you have to open the file manually:
andon 1.0
The first version listens on a serial port and change the lights depending on the data it receives. On the PC, an application listens to the midi signals and above certain channel thresholds, it will send out the correct signal data over the serial port.
//#define _DEBUG enum SwitchMode { Slow, Normal, Fast }; enum LoopMode { SingleShot, Bounce, Loop }; enum Pins { Red = 0, Orange, Green, Blue }; const int pTelephone = 15; void DebugPrint( char* _strInfo ) { #ifdef _DEBUG Serial.println( _strInfo ); #endif } void DebugPrint( int _nInfo ) { #ifdef _DEBUG Serial.print( _nInfo ); Serial.print( ", " ); #endif } // The analogue have 17 values due to inverse square law on led brighness static const byte MAX_INDEX = 16; static const byte s_fadeValues[] = { 255, 180, 128, 90, 64, 45, 32, 23, 16, 12, 8, 6, 4, 3, 2, 1, 0 }; static const byte s_slowBlinkValues[] = { 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const byte s_fastBlinkValues[] = { 255, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0 }; // the colors are red, orange, green and blue respectively // serial light instructions static const byte s_onCommand[] = { '!', '@', '#', '$' }; static const byte s_offCommand[] = { '1', '2', '3', '4' }; // output pins static const byte s_pins[] = { 3, 5, 6, 9 }; // values (off) volatile byte g_values[] = { MAX_INDEX, MAX_INDEX, MAX_INDEX, MAX_INDEX }; // step volatile byte g_step[] = { 0, 0, 0, 0 }; // light operation modes volatile SwitchMode g_eSwitchMode[] = { Normal, Normal, Normal, Normal }; volatile SwitchMode g_eCurrentSwitchMode = Normal; volatile LoopMode g_eLoopMode[] = { SingleShot, SingleShot, SingleShot, SingleShot }; volatile LoopMode g_eCurrentLoopMode = SingleShot; void setup( ) { Serial.begin( 9600 ); // make it output pinMode( s_pins[ Red ], OUTPUT ); pinMode( s_pins[ Orange ], OUTPUT ); pinMode( s_pins[ Green ], OUTPUT ); pinMode( s_pins[ Blue ], OUTPUT ); /* pinMode( pTelephone, INPUT ); digitalWrite( pTelephone, LOW ); pinMode( 14, INPUT ); digitalWrite( 14, LOW ); pinMode( 20, INPUT ); digitalWrite( 20, LOW ); */ // wait to make sure serial is initialized on the host delay(1000); DebugPrint( "initialization done, starting demo mode" ); demoMode( ); } void loop( ) { byte idx; byte nCurrentPinValue; // check if data has been sent from the computer: if (Serial.available( )) { byte input; // read the most recent byte (which will be from 0 to 255): input = Serial.read( ); switch ( input ) { // switch mode case 's': case 'S': DebugPrint( "switching to slow mode" ); g_eCurrentSwitchMode = Slow; break; case 'n': case 'N': DebugPrint( "switching to normal mode" ); g_eCurrentSwitchMode = Normal; break; case 'f': case 'F': DebugPrint( "switching to fast mode" ); g_eCurrentSwitchMode = Fast; break; // loop mode case 'o': case 'O': DebugPrint( "switching to single shot mode" ); g_eCurrentLoopMode = SingleShot; // aka once break; case 'b': case 'B': DebugPrint( "switching to bounce mode" ); g_eCurrentLoopMode = Bounce; break; case 'l': case 'L': DebugPrint( "switching to loop mode" ); g_eCurrentLoopMode = Loop; break; // version case 'v': case 'V': case 'h': case 'H': Serial.println("xopr's Andon Light v0.2"); Serial.println(""); Serial.println(" Usage:"); Serial.println(" [snf]?[obl]?([1234]|[!@#$])"); Serial.println(""); Serial.println(" Switch modes:"); Serial.println(" [s]low"); Serial.println(" [n]ormal"); Serial.println(" [f]ast"); Serial.println(""); Serial.println(" Loop modes:"); Serial.println(" [o]ne shot"); Serial.println(" [b]bounce"); Serial.println(" [l]loop"); Serial.println(""); Serial.println(" Lights:"); Serial.println(" {1!}: Red"); Serial.println(" {2@}: Orange"); Serial.println(" {3#}: Green"); Serial.println(" {4$}: Blue"); break; // assume it's a switch command default: for ( idx = 0; idx < 4; idx++ ) { if ( input == s_onCommand[ idx ] ) { // apply the optionally prefixed or default modes applyModes( idx ); // set the stepping, so we know that we need to update the output port g_step[ idx ] = -1; // special mode: normal single shot means just toggle the state if ( g_eSwitchMode[ idx ] == Normal && g_eLoopMode[ idx ] == SingleShot ) { DebugPrint( "ultra fast on!!1`" ); g_values[ idx ] = -g_step[ idx ]; } // since we found our character, break out of the loop break; } if ( input == s_offCommand[ idx ] ) { // set the stepping, so we know that we need to update the output port g_step[ idx ] = 1; // special mode: normal single shot means just toggle the state if ( g_eSwitchMode[ idx ] == Normal && g_eLoopMode[ idx ] == SingleShot ) { DebugPrint( "ultra fast off!!1`" ); g_values[ idx ] = MAX_INDEX - g_step[ idx ]; } // apply the optionally prefixed or default modes applyModes( idx ); // since we found our character, break out of the loop break; } } // for break; } // switch input } // serial.available // now do the stepping check/iteration on the lights for ( idx = 0; idx < 4; idx++ ) { if ( g_step[ idx ] ) { /* b0rken // update the current value, if needed if ((g_step[ idx ] < 0 && g_values[ idx ] <= 0) || (g_step[ idx ] > 0 && g_values[ idx ] >= MAX_INDEX )) { g_step[ idx ] = 0; continue; } */ g_values[ idx ] += g_step[ idx ]; // reached the boundaries? update the stepping (and prolly the loopmode) if ( g_values[ idx ] <= 0 || g_values[ idx ] >= MAX_INDEX ) { // reset stepper if we're done with single shot or return if ( g_eLoopMode[ idx ] == SingleShot ) { DebugPrint( idx ); DebugPrint( " is done" ); g_step[ idx ] = 0; } else // invert stepping g_step[ idx ] = -g_step[ idx ]; // after a bounce, loopmode changes into single shot if ( g_eLoopMode[ idx ] == Bounce ) { DebugPrint( idx ); DebugPrint( " bounced to single shot mode" ); g_eLoopMode[ idx ] = SingleShot; } } switch ( g_eSwitchMode[ idx ] ) { case Slow: nCurrentPinValue = s_fadeValues[ min( g_values[ idx ], MAX_INDEX ) ]; break; case Normal: nCurrentPinValue = s_slowBlinkValues[ min( g_values[ idx ], MAX_INDEX ) ]; break; case Fast: nCurrentPinValue = s_fastBlinkValues[ min( g_values[ idx ], MAX_INDEX ) ]; break; } analogWrite( s_pins[ idx ], nCurrentPinValue ); } // if stepping } // for /* if ( digitalRead( pTelephone ) == LOW ) digitalWrite( s_pins[ Blue ], HIGH ); if ( analogRead( pTelephone ) >= 1022 ) digitalWrite( s_pins[ Blue ], HIGH ); */ /* Serial.println( analogRead( pTelephone ) ); Serial.println( analogRead( pTelephone ) ); Serial.print( " " ); Serial.print( analogRead( 14 ) ); Serial.print( " " ); Serial.print( analogRead( 15 ) ); Serial.print( " " ); Serial.print( analogRead( 16 ) ); Serial.print( " " ); Serial.println( analogRead( 17 ) ); */ delay( 50 ); } void applyModes( byte _idx ) { // apply the current modes if ( g_eSwitchMode[ _idx ] != g_eCurrentSwitchMode || g_eLoopMode[ _idx ] != g_eCurrentLoopMode ) { g_eSwitchMode[ _idx ] = g_eCurrentSwitchMode; g_eLoopMode[ _idx ] = g_eCurrentLoopMode; DebugPrint( _idx ); DebugPrint( " has new mode applied" ); } // reset the current modes g_eCurrentSwitchMode = Normal; g_eCurrentLoopMode = SingleShot; } void demoMode( ) { byte idx; // set values and stepping g_values[ Red ] = 17; g_values[ Orange ] = 13; g_values[ Green ] = 10; g_values[ Blue ] = 6; for ( idx = 0; idx < 4; idx++ ) g_step[ idx ] = -1; while ( !Serial.available( )) { for ( idx = 0; idx < 4; idx++ ) { g_values[ idx ] += g_step[ idx ]; if ( g_values[ idx ] >= 30 ) { //DebugPrint( idx ); //DebugPrint( ": value >= 30 == off" ); g_step[ idx ] = -1; } else if ( g_values[ idx ] <= 0 ) { //DebugPrint( idx ); //DebugPrint( ": value <= 30 == on" ); g_step[ idx ] = 1; } analogWrite( s_pins[ idx ], s_fadeValues[ min( g_values[ idx ], MAX_INDEX ) ] ); } delay( 50 ); } DebugPrint( "end of demo mode. cleaning up" ); for ( idx = 0; idx < 4; idx++ ) { g_step[ idx] = 0; g_values[ idx ] = MAX_INDEX; digitalWrite( s_pins[ idx ], LOW); } }
andon 2.0
Currently being worked on..
It does:
- do on-board MIDI
- work stand-alone
- switch a 220V 2A relay output as well
todo
- publish both PC c++ midi-to-serial-instructions code as well as the arduino source
- read values from EEPROM
- store values to EEPROM
- add relay that can switch outlet power
Location: at xopr's