ALSO - Ardunio Larson Scanner Overbuild

Overview

Everyone agrees that the world can always use a new Larson Scanner build.

A friend celebrated his 13th brithday by building his own super-awesome gaming rig. It came out looking great, but a bit generic. I made the ALSO to add some bling to his rig, but also to give him a tangible way to get into programming on the Ardunio.

Everyone agrees that the world can always use a new Larson Scanner build.

Features

 

The Video!

 

 

Process

SEB-RIG on CNC mill   

First was to make the custom besel on the CNC milling machine.

     
Fliing with epoxy    After much trial and error with hot melt glue and casting resin, I ultimately found that normal hardware store two part epoxy was the best thing to fill the back with. This holds the inside letter peices together and also diffuses the light coming from the LEDs.
     
LEDs in place   These are just some Radio Shack colored LEDs. I used hotmelt glue to attache them to a peice of plastic I found on the floor. Thsis holds them back a bit to s the light beam projects onto the full letter.
     
Side LED view   View inside the plastic tube.
     
Wiring   An old peice of ethernet cable works perfectly for wiring the 7 LEDs plus common ground.
     
Ardunio connection   Made a handy Ardunio connector out of hotmelt and a popsicle stick I also found on the floor. Always pays to have lots of stuff on the floor when you start a project.
     

Instructions

First off, connect up to 7 LEDs to the 7 PWM ports on your Ardunio. In my build, I have a bar of 6 blues and a single red in the middle.  Connect the Aurduino up to a computer, run the Ardunio IDE, and then copy and paste to code from below.

If you've used a different number of LEDs than me, you can chaneg the #defines at the top of the code appropriately. You also might want to change the virtualblues[] array to match the location of your LEDs. Imagine that your blue LEDs are on a number line that starts at 0 on the left and ends at 100 on the right. You can see that in my build the blue LEDs are equally distributed except that there is one missing at location 50 becuase this is where the red LED is.

Compile, download, and run the code and your should see the default demo sequence (this sequence is defined lower down in the code as demostring). Yeay!

Now pull up a termial program and connect to Ardunio press any key. You should a command prompt. From here you can type '?' to see a list of available commands.

To add a new effect, code it up and then add it to commandRecs array. You can use the primatives setBlueLed, redOn, and redOff or use the higher level graphics routines like virtualDot, scan, and sineWave. Let me know if you come up with something nice to share with everyone!

 

Code


#define BLUE_COUNT 6

#define MAX_BLUE_BRIGHTNESS 63

const unsigned int bluePins[] = {3,5,6,9,10,11}; //array of LED pins used with PWM

const unsigned int redPin = 12; // Middle red pin
 
// the location of the blue leds on a virtual number line from 0 - 100 (101 slots)
// where 0 is to the left of the first blue and 80 is to the right
// (missing 50 becuase that is here the red LED is)

const int virtualblues[] = {  20 , 30 , 40 , 60 , 70 , 80  };

// the right end of the virtual blue coordinate line (left end is always 0)

#define VIRTUAL_BLUES_END 101


#define GAMMA_MAX 63

int gamma[64] = {
0,0,0,0,0,0,1,1,2,2,3,3,4,5,6,8,9,10,12,13,15,17,19,22,24,26,29,32,35,38,
41,45,48,52,56,60,65,69,74,79,84,89,94,100,106,112,118,124,131,138,145,152,
159,167,175,183,191,200,208,217,227,236,246,255
};    // gamma levels for linear brightness 0-255

#define MAX_SINE 63

int sine[64] = {
0,0,0,2,3,5,8,11,14,18,22,26,30,35,40,45,49,54,59,64,69,73,77,81,85,88,91,94,96,97,99,99,100,
99,99,97,96,94,91,88,85,81,77,73,69,64,59,54,50,45,40,35,30,26,22,18,14,11,8,5,3,2,0,0
};   // full sine wave table for y=0-100

// turn red led on

void redon() {

    digitalWrite( redPin , HIGH );

}

// turn red led off

void redoff() {

    digitalWrite( redPin , LOW );

}

// set the level of blue LED number l to brightness b
// 0<=b<64 and brightness is gamma corrected

void setblueled( int l , int b ) {

 analogWrite( bluePins[ l ]  , gamma[ b ] ); 
  
}



//set all blue LEDs to level n

void allblueset(int n) {
  
  int l ;
  
  for( l =0 ; l < BLUE_COUNT ; l++ ) {
    
   setblueled( l , n );
       
  }
   
}




void allblueon() {
allblueset(MAX_BLUE_BRIGHTNESS); 
}

void allblueoff() {
  allblueset(0);
}


//turn all LEDs on

void allon() {
  
  allblueon(); 
  redon();
  
}

//turn all LEDs off

void alloff() {
  
  allblueoff();  
  redoff();
   
}


// send a little help teaser to the serial port

void sendhelp() {
  
    Serial.println("Universal Programable Bezal Display Unit, (c)2010 Josh Levine [http://josh.com]");
    Serial.println("* to stop, # for demo mode, ? for command list, or ! followed by a new command string");    
    
}

void setup() {
    
   int x;  
   
   pinMode( redPin , OUTPUT );
   
   alloff();

   Serial.begin(9600);
   sendhelp();
      
}


void detonatered() {
  
   int y = 400;
  
   while(  y > 0  ) {
     
     redon();
     
     delay( y );
     
     redoff();
          
     delay( y );
     
     y -= ( y / 10) + 1 ;
     
   }
   
}

void detonateblue() {
  
   int y = 400;
  
   while(  y > 0  ) {
     
     allblueon();
     
     delay( y );
     
     allblueoff();
          
     delay( y );
     
     y -= ( y / 10) + 1 ;
     
   }
   
}

   
void bluefadeoff() {
    
    int y= MAX_BLUE_BRIGHTNESS;
    
    while (y>0) {
      
      y--;
      
      allblueset( y );
      delay(20);
      
    }
}


void bluefadeon() {
    
    int y=0;
    
    while ( y < MAX_BLUE_BRIGHTNESS ) {
      
      
      allblueset( y );
      
      delay(20);
      
      y++;

      
    }
}




// figure out how much of a dot would contibute to the bightness of a given LED
// l = led#, x=virtual location (0-100), w=dot width
// returns 0-63 for how bright the LED would be

int virtualcontribution( int l , int x , int w ) {
  
    int y = virtualblues[l];
        
    int d = abs(x-y);  // d=distance from dot
    
    int b;    //brightness
    
    if ( d > w ) {
      
      b = 0;
      
    } else {
      
      b = (( w - d ) * MAX_BLUE_BRIGHTNESS)  / w ; 
      
    }
    
    return(b);

}


int bluebuffer[BLUE_COUNT];    // A buffer to store brightnesses while working

// set the blue LEDs as if there was a virtual dots at location x where 0<=x<100
// w is width of the dots

void virtualdots( int x1 , int x2 ,  int w ) {
  
  int l;
  
  // Clear all brightnesses to zero
  
  for( l = 0 ; l < BLUE_COUNT ; l++ ) {
    
    bluebuffer[l]=0;
    
  }
  
  // figure out the contribution of first dot 
  
  for( l = 0 ; l < BLUE_COUNT ; l++ ) {
    
    bluebuffer[l]+= virtualcontribution( l , x1 , w )  ;     // div by two becuase we are adding 2 together
    
  }
  
  // add in the contribution of second dot 

  for( l = 0 ; l < BLUE_COUNT ; l++ ) {
    
    bluebuffer[l] += virtualcontribution( l , x2 , w )  ;
      
  }
  
  //set the LEDs        


  for( l = 0 ; l < BLUE_COUNT ; l++ ) {
    
    setblueled( l , min( bluebuffer[l] , MAX_BLUE_BRIGHTNESS ) );   // Clip brightnesses that are too high
      
  }
  
}
  
  
void virtualdot( int x , int w ) {

  int l;
  
  for( l = 0 ; l < BLUE_COUNT ; l++ ) {
  
    setblueled( l , virtualcontribution( l , x , w) );
    
  }

}  


  
//  blue virtual dot smoothly bouncing back and forth
    
void scan( int start , int end , int width , int slowness ) {
  
  int step; 
  
  int x = start;
  
  if ( start < end ) {
      
    do {
    
        virtualdot( x , width );
        delay(slowness);
      
        x++;
         
    } while (x<=end);
    
  } else {

    do {
    
        virtualdot( x , width );
        delay(slowness);
      
        x--;
         
    } while (x>end);
    
    
  }    

}  


// two dots - one dot starts on left going right, other the oposite. They cross in the middle

void doublescan(int width , int slowness ) {
   
  int step; 
  
  int x = 0;
  
  while (x < VIRTUAL_BLUES_END ) {
    
    virtualdots( x , VIRTUAL_BLUES_END - x , width );
    
    x++;
    
    delay(slowness);
       
  }

  while (x >0  ) {
    
    x--;
    
    virtualdots( x , VIRTUAL_BLUES_END - x , width );
    
    delay(slowness);
        
  }
  

}

void sinewave(int width) {

   int x;
  
   for(x=0; x< MAX_SINE ; x++ ) {
     
     virtualdot( sine[x] , width );
     
     if ( x == 16 || x ==48  ) {
       
       redon();
       
     } else {
       
       redoff();
       
     }
     
     delay(10);

  } 
}
void kitkarright() {
  
  scan( 0 , 100 , 30 , 10 );
  
}


void kitkarleft() {
  
  scan( 100 , 0 , 30 , 10 );
  
}

void sweepright() {
scan( 0 , 100 , 30 , 10 ) ; 
}

void sweepleft() {
scan( 100 , 0 , 30 , 10 ) ; 
}

void shotright() {
scan( 0 , 100 , 20 , 2 ) ; 
}

void shotleft() {
scan( 100 , 0 , 20 , 2 ) ; 
}

void stroberight() {
  
  int i;
  for( i = 20 ; i > 0 ; i--) {
    
    
    scan( 100 , 0 , 30 , i );
    
  }
  
}

void criscross() {

     doublescan( 20 , 10 );
  
}

void strobeleft() {
  
  int i;
  for( i = 20 ; i > 0 ; i--) {
    
    
    scan( 0 , 100 , 30 , i );
    
  }
  
}

void rotator() {
  
  sinewave(20);
  
}

void sparkle() {
  
  int x;
  
  for(x=0;x<100;x++) {
    
    int l = random(0,6);
    
    int b = random(0,MAX_BLUE_BRIGHTNESS);
    
    setblueled( l , b );

    delay(10);

    setblueled( l , 0 );    
    
  }
  
}

void warp() {

 int x;

 
 for(x=0 ; x<50 ; x++) {
   
      virtualdots( 50 + x , 50 - x , 30 );
      
      delay( 5 );
   
      //delay( ( 50-x) );
   
 }   
 
 allblueoff();

}

void breathe() {
  
  int x;
  
  x = 0;
  
  while ( x < MAX_BLUE_BRIGHTNESS  ) {

    x++;    
     
    allblueset( x );
    
    delay(40- (x/10));
    
    //delay( MAX_BLUE_BRIGHTNESS - x + 1 );

  }    
  
  while ( x > 0 ) {
    
    x--;
    
    allblueset( x );
    
    delay(40-(x/10));
    
    //delay( MAX_BLUE_BRIGHTNESS - x + 1 );

  }    
  
  
}


void pause() {
  delay(10); 
}

void wait() {
  
  delay(100);
}

void sleep() {
delay(1000); 
}


typedef struct {

  char command; 
  void (*function)();
  char *description; 
  
} commandrec;


const commandrec commandrecs[] = {
  
  { 'B' , allblueon ,  "all blue on instantly" } ,
  { 'b' , allblueoff , "all blue off instantly"} ,

  { 'F' , bluefadeon,  "all blue on fade" } ,
  
  { 'f' , bluefadeoff, "all blue off fade" },    
  
  { 'R' , redon      ,  "red on" },
  { 'r' , redoff     ,  "red off"} ,
  
  { 'J' , kitkarleft ,  "kit car left" } ,
  { 'K' , kitkarright,  "kit car right" },
  
  { 'S' , sweepright ,  "sweep right" },
  { 'T' , sweepleft  ,  "sweep left"}, 
  
  { 'U' , shotright ,  "shoot right" },
  { 'V' , shotleft  ,  "shoot left"}, 

  { 'G' , stroberight ,  "strobe right" },
  { 'H' , strobeleft  ,  "strobe left"}, 

  { 'D' , detonatered ,  "detonate red" } ,
  { 'C' , detonateblue, "detonate blue" },
  
  { 'N' , rotator     ,  "police" },
  { 'X' , criscross    , "ambulance" },
  
  { 'L' , sparkle     ,  "sparkle" },
  { 'W' , warp    ,      "warp"    },
  { 'E' , breathe ,      "breathe" },
  
  { 'P' , pause        , "pause 0.01 seconds" },
  { 'I' , wait         , "wait 0.10 seconds" } ,
  { 'Z' , sleep        , "wait 1.00 seconds" } ,
  
  
  { 0x00 , NULL , NULL }
  
};

char *DEMO_STRING = "BfIIIIIIBfIIIIIBfIIIDrBfLLLLLNNNNNNNbrSTSTSTSTXXXXXKKKfJJJfCRbrZZVZZUZZUIIIIIUIIUIIIVIVIIIVZIIIIIVIUIIUVIUVIUVVUUVVVURIIBrfZZZWWWWWWJKJKJKJKJKEPEPEPEPEPEPEPGbZZZ";


void docommand( char command ) {

  int i=0;
  
  while (commandrecs[i].command != 0x00) {
   
     if (commandrecs[i].command == command ) {
       

       Serial.print( command );
       Serial.print('-');
       Serial.println( commandrecs[i].description );       
       
       (*commandrecs[i].function)();       
       
       
       // don't return here to avoid jitter
       
     }
   
     i++; 
  }      
  
}  


char *commandstring = DEMO_STRING;  

void setdemomode() {
         
   Serial.println("Entering demo mode");
   
   commandstring = DEMO_STRING;
         
}
       


void showprompt() {
  
  int i=0;
  
  Serial.println("");
  Serial.println("Current command string is...");
  Serial.println(commandstring);
  
  Serial.println("Available commands:");
  
  while ( commandrecs[i].command != 0x00 ) {
    
    Serial.print( commandrecs[i].command );
    Serial.print( " - " );
    Serial.print( commandrecs[i].description );    
    
    Serial.println("");
    
    i++;
    
  }
  
}


#define COMMANDSTRINGBUFFER_MAX 100
char commandstringbuffer[COMMANDSTRINGBUFFER_MAX+1];



void readcommandstring() {
  
   char k;
   
   int commandstringlen =0; 
   
   Serial.println("Enter new command string followed by enter...");
           
   while (1) {
     
   
       while (Serial.available()==0);  // wait for key
       
       k = Serial.read();
              
       if (k==13 || k==10) {    // enter
       
           Serial.println("");
           
           if (commandstringlen==0) {
             
             Serial.println("Nothing entered, command string unchanged.");
             
           } else {
       
            commandstringbuffer[commandstringlen] = 0x00;
             
            commandstring = commandstringbuffer;
            
            Serial.println("New command string set.");
           }
    
          return;
     
       }
       
       
       
       if (commandstringlen < COMMANDSTRINGBUFFER_MAX) {

         Serial.print( k );
                 
         commandstringbuffer[ commandstringlen++ ] = k;  
         
       } else {
        
        Serial.println("too long");
        
       }
   }
  
}


char *nextcommand = "";

void loop() {
  
  if ( (*nextcommand) == 0x00 ) {
    nextcommand = commandstring;
  }
    
  docommand( *nextcommand );
  nextcommand++;
  
  if (Serial.available()>0) {
    
    char action = Serial.read(); 
    
    switch (action) {
      
      case '?':   showprompt(); break;
      case '!':   readcommandstring(); nextcommand = commandstring; break;
      case '#':   setdemomode(); break;
      case '*':   commandstring=""; Serial.println("Stopped. Enter new command string or demo mode to restart."); break;
      case 13:    break;
      case 10:    break;    // ignore extra unexpected line breaks
      
      default: sendhelp();
      
    };

  }
   
}

 

Support

sopprt email address image

Updates

11/27/2010 - Published.

1/8/11 - Fixed link in video.

###