Introduction: Color Changing Larson Scanner
Video of scanner in action. Yes, I'm rotating through the colors manually.
Who doesn’t love KITT, the superhero car from Night Rider? The one with the Glowing Bouncing lights of a Larson Scanner up front. That scanner was so cool, they even filmed a remake of the TV Show featuring it. Don’t forget the Larson Scanner also made an appearance in Battelstar Glatica, Whooshing back and forth on the face of the Cylons.
On my version, for my car, I wanted the red glow from the TV car when showing it off, but I also wanted to be able to change to a color that would not be mistaken for an emergency vehicle while on public roads.
- The Larson Scanner is named for Glen Larson, Producer of Knight Rider, and other shows. As I was writing up my build notes, I was sorry to read that Glen Larson passed away. The man clearly understood the appeal of blinking, whooshing, glowing lights.
Step 1: Tools and Materials
Materials used:
Arduino UnoR3
LED strip - Adafruit
Rotary Encoder - Sparkfun
Knob - Sparkfun
Encoder Break out Board - Sparkfun
Power Supply - Ebay 12v to 5v converter 3A $7.77
WS2811 chip - I Got mine from ebay (mounted on circuit board) but also available from Adafruit
Three 220 ohm 1/4 watt resistors
Header Pins - Adafruit
Proto board - I recommend using Arduino Shield protoboard board of some type
Connectors - I salvaged mine from old electronics
fuse holder - local auto supply store
fuse - local auto supply store
silicone glue/Waterproofing - local auto supply store
Main power Switch, Toggle switch for +12V - I salvaged mine from an old Printer
Tools used:
solderless Breadboard
power supply
PC
Soldering station
Jumper wires/test leads/temporary connectors
hand tools: screwdriver/knife/pliers/crescent wrench/
Useful references:
Adafruit Uberguide
Adafruit Larson Scanner
Bildr.org Blog - Rotary Encoder tutorial
Adafruit's NeoPixel library on GitHub
Step 2: Build Circuit and Load Code
Breadboard:
Breadboard up the circuit per the schematic and make sure everything works.
I had issues with my WS2811 boards from Ebay. The Data Out, and Data in were reversed on the silkscreen, also the RGB on the silkscreen had the R and G reversed. The circuit was fine, just the label on both of those were reversed.
.
Code Notes:
The chances are really good that you can write much better code than what I have cobbled together. My code runs, it does what I want it to do, and I am not turning it in to a Computer Science Instructor for a grade. I’ll polish it up in version 2.0
(This was my first time with an object oriented language and I am not one to start at the beginning, especially when there is sample code to start from). Shoulders of giants and all that.
To build the code below, I started with Adafruit’s Larson Scanner demo. It ran great right out of the box, but I was not happy with only having the color red.
I loaded the 'Read an Encoder' sample code from bldr.org and combined it with the Adafruit code, then I could read the encoder while the Scanner scanned.
I used those readings to change colors displayed by the LEDs.
Changing the Values in the look up table changes the displayed LED color. When you like the way it looks on the test bench, move the circuit to a permanent proto board and solder it up. It's probably a good idea to then give it another test before installing in your car.
Test Bench Video Yes, the color of the Rotary encoder does change hue to match the LED strip even though it does not necessarily appear that way in the video. I think I need some practice using the white balance on my camera.
Step 3: Code
//From bildr article: http://bildr.org/2012/08/rotary-encoder-arduino/
//and from Adafruit’s Larson Scanner https://learn.adafruit.com/larson-scanner-shades
//You will also need Adafruit’s NeoPixel library installed https://github.com/adafruit/Adafruit_NeoPixel
#include
#define N_LEDS 60
#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_GRB + NEO_KHZ800);
//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;
volatile int lastEncoded = 0;
volatile int encoderValue = 0;
long lastencoderValue = 0;
int lastMSB = 0;
int lastLSB = 0;
void setup() {
strip.begin();
int pos = 1, dir = 1; // Position, direction of "eye"
Serial.begin (9600); // for testing encoder
pinMode(encoderPin1, INPUT);
pinMode(encoderPin2, INPUT);
digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
digitalWrite(encoderPin2, HIGH); //turn pullup resistor on
//call updateEncoder() when any high/low changed seen
//on interrupt 0 (pin 2), or interrupt 1 (pin 3)
attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);
}
int pos = 1, dir = 1; // Position, direction of "eye"
void loop(){
int count =0;
count = (encoderValue / 4);
// Serial.println(encoderValue); //testing / debugging encoder
Serial.println(count); //testing / debugging encoder
int j;
long colorb = 0;
long colorg = 0;
long colorr =0;
// int count;
colorb = colorb + abs(encoderValue); // blue
colorg = colorb + 2*abs(encoderValue); //green
colorr = colorb + 4*abs(encoderValue); //red
//lookup table for color values 13 sets of 3 colors
int red [13] = { 255,255,255,255,128,0,0,0,0,0,127,255,255};
int red1[13] = { 128,128,204,204,102,0,0,0,0,0,102,204,204};
int red2[13] = { 32,16,153,153,76,0,0,0,0,0,76,153,153};
int green [13] = {255,0,0,0,0,0,127,255,255,255,255,255,127};
int green1[13] = { 128,0,0,0,0,0,102,64,204,128,204,204,102};
int green2[13] = { 32,0,0,0,0,0,76,32,153,16,153,153,76};
int blue [13] = { 255,0,127,255,255,255,255,255,0,0,0,0,0};
int blue1[13] = { 128,0,102,204,204,128,204,32,102,0,0,0,0};
int blue2[13] = { 32,0,76,153,153,16,153,32,76,0,0,0,0};
if (colorb > 255) colorg = colorg ++;
if (colorg >255) colorr = colorr++;
// Draw 5 pixels centered on pos. setPixelColor() will clip any
// pixels off the ends of the strip, we don't need to watch for that.
strip.setPixelColor(0,(red[count]),(green[count]),(blue[count])); // encoder LED (separate WS2811 chip)
strip.setPixelColor(pos - 2,(red2[count]),(green2[count]),(blue2[count])); // red2 green2 blue2 from lookup table
strip.setPixelColor(pos - 1, (red1[count]),(green1[count]),(blue1[count])); // red1 green1 blue1
strip.setPixelColor(pos , (red[count]),(green[count]),(blue[count])); // Center pixel is brightest
strip.setPixelColor(pos + 1, (red1[count]),(green1[count]),(blue1[count])); // red1 green1 blue1
strip.setPixelColor(pos + 2,(red2[count]),(green2[count]),(blue2[count])); // red2 green2 blue2
strip.show();
delay(30);
// Rather than being sneaky and erasing just the tail pixel,
// it's easier to erase it all and draw a new one next time.
for(j=-2; j<= 2; j++) strip.setPixelColor(pos+j, 0);
// Bounce off ends of strip
pos += dir;
if(pos < 2) {
pos = 3;
dir = -dir;
} else if(pos >= strip.numPixels()) {
pos = strip.numPixels() - 2;
dir = -dir;
}
}
void updateEncoder(){
int MSB = digitalRead(encoderPin1); //MSB = most significant bit
int LSB = digitalRead(encoderPin2); //LSB = least significant bit
int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
if (encoderValue >55) encoderValue =0; // chaNGED 10-26-14
if (encoderValue <0) encoderValue =55;
lastEncoded = encoded; //store this value for next time
}
Step 4: Installation
In my case, the Scanner is going into a 2010 Ford Focus.
(The fact that this car parked in the driveway at exactly 50000.0 miles was an omen that this car wanted a shiny upgrade, and thought it was entitled to one.)
There was not too much work to the install once the circuit was built and tested on the bench. The LED strip went behind the grill and was secured with the silicone "glue", a dab on the open end sealed the LED strip from the weather. The positive battery terminal had a screw type connection just waiting for the wire to the fuse and power switch. The hardest part was running the wires through the firewall. I went through an existing grommet on the driver’s side, your millage may vary.
Currently everything is connected and working. The plastic dash still needs to be partially removed and the rotary encoder mounted on it, but the temperature has dropped to -11 degrees Fahrenheit. I think it would be a good idea to wait for warmer temperatures before prying and drilling on plastic. The scanner works great as it is anyway.
Step 5: Lessons Learned
- Use real Arduino shield prototyping shield. The generic proto board just does not fit well, at least not the one I used.
- Look closely at potential Ebay purchases. the Fifty WS2811 chips I bought were all mounted on one board that had no perforations.
- Build on solderless proto board first (WS2811 chips were not exactly as marked on the silkscreen I had to reconfigure some connections)
- In the future, look for parts with breadboard friendly 0.1” pin spacing.
- Consider a jumper connector between the rotary encoder and the proto board for more installation location options.
- Pull extra cable through the firewall for future use. Maybe even shielded twisted pair
- A heated garage, clean enough to pull a car inside, is a worthy goal
Step 6: Going Further
- There are 11 GPIO pins left over on this project. This leaves a lot of room for expansion. The downside is both interrupt pins are used for the rotary encoder, I’m sure one could free up at least one of these interrupts with a code rewrite.
- I built a Larson Scanner page, linked from the Projects page on my website. This is a place I can post my improvements that are not quite ready for an instructable of their own, as well as a place to link to other people's comments / instructables.
- More than one Row of lights, scanning together, might have more visual impact. One may want to consider airflow through the radiator though.
- A PIR sensor to trigger the Larson Scanner from an off (or sleeping) state when someone walks by. That would be fun. Maybe trigger a camera at the same time.
- Add the cool whooshing sound like was used in the TV show.
- I expect the Instructables crowd to come up with ideas I would never have dreamed of for this project. Please, add yours.