# Larson Scanner

**URL:** <https://forums.pimoroni.com/t/larson-scanner/18959>\
**Category:** Arduino & AVR\
**Created:** [February 26, 2022, 11:08am UTC](https://forums.pimoroni.com/t/larson-scanner/18959 "2022-02-26T11:08:51Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon83280986](https://avatars.discourse-cdn.com/v4/letter/a/8e7dd6/32.png) [@anon83280986](https://forums.pimoroni.com/u/anon83280986)\
**Post date:** [February 26, 2022, 11:08am UTC](https://forums.pimoroni.com/t/larson-scanner/18959/1 "2022-02-26T11:08:51Z")

</div>

**Not Battlestar Galactica.**

Most people associate a Larson scanner with Battlestar Galactica (1978) and Knight Rider (1982) but there was an underrated sci-fi film in 1979 called [The Black Hole](https://en.wikipedia.org/wiki/The_Black_Hole_(1979_film)), with a robot sidekick henchman called [Maximilian](https://borg.com/tag/maximilian-robot/).

[ScrewedSculpts](https://screwedsculpts.com/) asked if I could create this iconic effect for a version of Maximilian that he was building.

The outcome and Arduino sketch is below.

**Chip Choices**

Arduino Mini or Arduino Nano ?

Yes these are clones, as the end product is going to live permanently in a robot shell with no future access.

They will live there forever and will never be reused.

 ![01_ArduinoMini_ArduinoNano](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/3/38eeb67b33595f29a6ccb3003806bf85e98f8d97.jpeg)

**First Prototype**

The original plan was to have larger LEDs.

These 10mm clear LEDs are crazy bright but the overall form factor could be too wide.

 ![02_ArduinoMini_Larson_Breadboard](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/8/85cd6edd030d1ae61e781ab07d2e32c5098fee64.jpeg)

**LED Comparison**

The 10mm LEDs would have a greater impact and are brighter overall but would take up too much horizontal space.

 ![05_LED_Comparison](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/a/ae41d47ca98d7f917533e65faa3b32ed8079a25b.jpeg)

**A Slight Redesign**

So at this point it was decided to add in motion detection functionality.

The plan being that when movement is detected it will trigger the scanner effect.

Time to add a PIR sensor into the mix.

I have zero CAD skills but I do own a pen.

 ![05_Who_Needs_EAGLE](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/4/461c69fd0dfac2e362251ff8d04be56786bec5d1.jpeg)

**A Working PIR**

Using a pair of breadboards I can now trigger the scanner effect.

This particular PIR detector is (I think) the HC-SR505 with an effective range of 3m.

 ![04_Added_PIR](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/0/0c88189a1c808de158c71350f884705b0d02cd08.jpeg)

**LEDs in Place**

Now that the proof of concept is all working, time to dig out the toolbox.

LEDs on Veroboard first.

 ![07_VeroBoard_With_LEDs](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/7/731f886efa9c00d06942d0c9bf27df4f1da6f36c.jpeg)

**LEDs and Resistors in Place**

Closely followed by adding all the resistors.

(The underneath of the board has already had the appropriate tracks cut.)

 ![08_VeroBoard_With_LEDs_And_Resistors](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/7/7e443d322e8a1fa311baa51e179f3ffff74edd20.jpeg)

**All Wired Up**

And then start to create a wiring loom.

 ![09_LED_Board_Wired](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/0/079db7f2ba0fccb70367bb38c3e64227b302e51c.jpeg)

**Testing The Arduino**

The LED board has been wired up (and liberal amounts of hot glue to ensure that none of the wires break free.

Testing to see that all of the LEDs still work.

 ![10_LED_Board_Test_Rig](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/1/100b5926b0cb6ece0ae880368ca5ad1dd02320f9.jpeg)

**Testing The Arduino and PIR**

With a working LED board and a known working Arduino it’s time to add in the PIR module.

There are two sets of buttons now:

- A power button that when on, the scanner effect will run
- A sensor button that then on will only trigger the scanner effect when activated (asssuming the power is on

 ![11_LED_Board_Test_Rig_With_PIR](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/3/3b677fcbafb7dfca990ab5d8d6930a4e99643a5c.jpeg)

**Final Board and All Wrapped Up**

Finally all working and wrapped up in cable tidy wrap.

 ![12_LED_Board_Completed_With_PIR_All_Wrapped_up](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/e/e36bac932a5a688d044d14fc29220bd3bb93bc10.jpeg)

This site won’t allow the uploading of videos but there is a facebook video of the finished piece here:

https://www.facebook.com/plugins/video.php?height=224&width=400&href=https://www.facebook.com/RobotSculpts/videos/max-the-lethal-extraction-droid/471245096793257/

**The Arduino Sketch:**

- The scanner code came from [here](http://incredulist.blogspot.com/p/larson-scanner.html)
- The PIR code attribution is in the comments

Both of the above work fine in isolation, any errors after that are all mine.

I hope this sketch helps someone looking to do something similar.

> **Larson Scanner sketch with PIR activation.**
>
> ```auto
> // Larson array
> //
> // PORTDB_larsen2ways
> // 
> // goes both ways: Back AND Forth :)
> 
> // 
> // 11
> // 1098765432    
> const word dimbits[] = { 0b0000000011111100, // frame 1
> 0b0000000011111000,
> 0b0000000011110000, 
> 0b0000000011100000, 
> 0b0000000011000000, 
> 0b0000000010000000, 
> 0b0000000010000000, 
> 0b0000000010000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000000111111000, // frame 2
> 0b0000000111110000,
> 0b0000000111100000, 
> 0b0000000111000000, 
> 0b0000000110000000, 
> 0b0000000100000000, 
> 0b0000000100000000, 
> 0b0000000100000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000001111110000, // frame 3
> 0b0000001111100000,
> 0b0000001111000000, 
> 0b0000001110000000, 
> 0b0000001100000000, 
> 0b0000001000000000, 
> 0b0000001000000000, 
> 0b0000001000000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000011111100000, // frame 4
> 0b0000011111000000,
> 0b0000011110000000, 
> 0b0000011100000000, 
> 0b0000011000000000, 
> 0b0000010000000000, 
> 0b0000010000000000, 
> 0b0000010000000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000111111000000, // frame 5 ****
> 0b0000111110000000,
> 0b0000111100000000, 
> 0b0000111000000000, 
> 0b0000110000000000, 
> 0b0000100000000000, 
> 0b0000100000000000, 
> 0b0000100000000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000111110000000, // frame 6
> 0b0000111100000000,
> 0b0000111000000000, 
> 0b0000110000000000, 
> 0b0000110000000000, 
> 0b0000010000000000, 
> 0b0000010000000000, 
> 0b0000010000000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000111100000000, // frame 7
> 0b0000111000000000,
> 0b0000111000000000, 
> 0b0000111000000000, 
> 0b0000011000000000, 
> 0b0000001000000000, 
> 0b0000001000000000, 
> 0b0000001000000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000111100000000, // frame 8
> 0b0000111100000000,
> 0b0000111100000000, 
> 0b0000011100000000, 
> 0b0000001100000000, 
> 0b0000000100000000, 
> 0b0000000100000000, 
> 0b0000000100000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000111110000000, // frame 9
> 0b0000111110000000,
> 0b0000011110000000, 
> 0b0000001110000000, 
> 0b0000000110000000, 
> 0b0000000010000000, 
> 0b0000000010000000, 
> 0b0000000010000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000111111000000, // frame 10
> 0b0000011111000000,
> 0b0000001111000000, 
> 0b0000000111000000, 
> 0b0000000011000000, 
> 0b0000000001000000, 
> 0b0000000001000000, 
> 0b0000000001000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                                 
> 0b0000011111100000, // frame 11
> 0b0000001111100000,
> 0b0000000111100000, 
> 0b0000000011100000, 
> 0b0000000001100000, 
> 0b0000000000100000, 
> 0b0000000000100000, 
> 0b0000000000100000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                              
> 0b0000001111110000, // frame 12
> 0b0000000111110000,
> 0b0000000011110000, 
> 0b0000000001110000, 
> 0b0000000000110000, 
> 0b0000000000010000, 
> 0b0000000000010000, 
> 0b0000000000010000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                              
> 0b0000000111111000, // frame 13
> 0b0000000011111000,
> 0b0000000001111000, 
> 0b0000000000111000, 
> 0b0000000000011000, 
> 0b0000000000001000, 
> 0b0000000000001000, 
> 0b0000000000001000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                              
> 0b0000000011111100, // frame 14 ***
> 0b0000000001111100,
> 0b0000000000111100, 
> 0b0000000000011100, 
> 0b0000000000001100, 
> 0b0000000000000100, 
> 0b0000000000000100, 
> 0b0000000000000100, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000, 
> // 1098765432                              
> 0b0000000001111100, // frame 15
> 0b0000000000111100,
> 0b0000000000011100, 
> 0b0000000000001100, 
> 0b0000000000001100, 
> 0b0000000000001000, 
> 0b0000000000001000, 
> 0b0000000000001000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000, 
> // 1098765432                              
> 0b0000000000111100, // frame 16
> 0b0000000000011100,
> 0b0000000000011100, 
> 0b0000000000011100, 
> 0b0000000000011000, 
> 0b0000000000010000, 
> 0b0000000000010000, 
> 0b0000000000010000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                              
> 0b0000000000111100, // frame 17
> 0b0000000000111100,
> 0b0000000000111100, 
> 0b0000000000111000, 
> 0b0000000000110000, 
> 0b0000000000100000, 
> 0b0000000000100000, 
> 0b0000000000100000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> // 1098765432                              
> 0b0000000001111100, // frame 18
> 0b0000000001111100,
> 0b0000000001111000, 
> 0b0000000001110000, 
> 0b0000000001100000, 
> 0b0000000001000000, 
> 0b0000000001000000, 
> 0b0000000001000000, 
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000,
> 0b0000000000000000};                         
>                          
> unsigned long duration = 0;
> unsigned long times_out = 7500; // frame's time out "speed"
> // 500 for way fast
> // 50000 for way slow
>                         
> int idx;
> byte framepointer = 0;
> 
> /* 
> * //////////////////////////////////////
> * //making sense of the sensor's output
> * //////////////////////////////////////
> *
> * Switches a LED according to the state of the sensors output pin.
> * Determines the beginning and end of continuous motion sequences.
> *
> * @author: Kristian Gohlke / krigoo (_) gmail (_) com / https://krx.at
> * @date: 3. September 2006 
> *
> * kr1 (cleft) 2006 
> * released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
> * https://creativecommons.org/licenses/by-nc-sa/2.0/de/
> *
> * The sensor's output pin goes to HIGH if motion is present.
> * However, even if motion is present it goes to LOW from time to time, 
> * which might give the impression no motion is present. 
> * This program deals with this issue by ignoring LOW-phases shorter than a given time, 
> * assuming continuous motion is present during these phases.
> *  
> */
> 
> /////////////////////////////
> //VARS
> //the time we give the sensor to calibrate (10-60 secs according to the datasheet)
> //different sensor so smaller calibration time
> int calibrationTime = 5;        
> 
> //the time when the sensor outputs a low impulse
> long unsigned int lowIn;        
> 
> //the amount of milliseconds the sensor has to be low 
> //before we assume all motion has stopped
> long unsigned int pause = 5000;  
> 
> boolean lockLow = true;
> boolean takeLowTime;  
> 
> int radPin = 12; //the digital pin connected to the sensor's output
> //int ledPin = 13;
> 
> /////////////////////////////
> //SETUP
> void setup(){
> 
> //Larson
> //pinMode(13,OUTPUT);
> pinMode(2, OUTPUT);
> pinMode(3, OUTPUT);
> pinMode(4, OUTPUT);
> pinMode(5, OUTPUT);
> pinMode(6, OUTPUT);
> pinMode(7, OUTPUT);
> pinMode(8, OUTPUT);
> pinMode(9, OUTPUT);
> pinMode(10, OUTPUT);
> pinMode(11, OUTPUT);
> //PORTD &= 0b00000011;
> 
> Serial.begin(9600);
> pinMode(radPin, INPUT);
> //pinMode(ledPin, OUTPUT);
> digitalWrite(radPin, LOW);
> 
> //give the sensor some time to calibrate
> Serial.print("calibrating sensor ");
> for(int i = 0; i < calibrationTime; i++){
> Serial.print(".");
> delay(1000);
> }
> Serial.println(" done");
> Serial.println("SENSOR ACTIVE");
> delay(50);
> }
> 
> ////////////////////////////
> //LOOP
> void loop(){
> 
> if(digitalRead(radPin) == HIGH){
> //digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
> if(lockLow){  
> //makes sure we wait for a transition to LOW before any further output is made:
> lockLow = false;            
> Serial.println("---");
> Serial.print("motion detected at ");
> Serial.print(millis()/1000);
> Serial.println(" sec"); 
> delay(50);
> }
> 
> // Larson code
> for (framepointer = 0; framepointer < 216; framepointer = (framepointer + 12))
> // 0-11,12-33,24-35,36-47,48-59,60-71,72-83,84-95,96-107,
> // 108-119,120-131,132-143,144-155,156-167,168-179,
> // 180-191,192-203,204-215,216
> {
> for(duration=0; duration<times_out; duration++)
> // times_out is the number of
> // frame repetitions
> {
> for(idx = framepointer; idx < (framepointer + 12); idx++)
> {
> commitPORTs();
> }
> }
> }
> framepointer = 0;
> //delay(500);
>              
> takeLowTime = true;
> }
> 
> if(digitalRead(radPin) == LOW){       
> //digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
> 
> if(takeLowTime){
> lowIn = millis(); //save the time of the transition from high to LOW
> takeLowTime = false; //make sure this is only done at the start of a LOW phase
> }
> //if the sensor is low for more than the given pause, 
> //we assume that no more motion is going to happen
> if(!lockLow && millis() - lowIn > pause){  
> //makes sure this block of code is only executed again after 
> //a new motion sequence has been detected
> lockLow = true;                        
> Serial.print("motion ended at "); //output
> Serial.print((millis() - pause)/1000);
> Serial.println(" sec");
> delay(50);
> }
> }
> }
> 
> // Larson array
> void commitPORTs ()
> {
> PORTD = dimbits[idx];
> PORTB = dimbits[idx]/256;
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![alphanumeric](https://sea2.discourse-cdn.com/flex016/user_avatar/forums.pimoroni.com/alphanumeric/32/2729_2.png) [@alphanumeric](https://forums.pimoroni.com/u/alphanumeric)\
**Post date:** [February 26, 2022, 12:04pm UTC](https://forums.pimoroni.com/t/larson-scanner/18959/2 "2022-02-26T12:04:10Z")

</div>

Nice, that looks pretty darn cool. =)

---

<div class="post-metadata">

**Author:** ![anon83280986](https://avatars.discourse-cdn.com/v4/letter/a/8e7dd6/32.png) [@anon83280986](https://forums.pimoroni.com/u/anon83280986)\
**Post date:** [February 26, 2022, 12:08pm UTC](https://forums.pimoroni.com/t/larson-scanner/18959/3 "2022-02-26T12:08:04Z")

</div>

Hi Kerry,

Ta, I don’t do a lot of Veroboard work these days so it was nice and quite satisfying to go back to it.

Cheers,

Simon.

---

<div class="post-metadata">

**Author:** ![alphanumeric](https://sea2.discourse-cdn.com/flex016/user_avatar/forums.pimoroni.com/alphanumeric/32/2729_2.png) [@alphanumeric](https://forums.pimoroni.com/u/alphanumeric)\
**Post date:** [February 26, 2022, 1:21pm UTC](https://forums.pimoroni.com/t/larson-scanner/18959/4 "2022-02-26T13:21:58Z")

</div>

Nothin wrong with old school. I use a lot of Proto Hats and proto boards in my projects.

---

<div class="post-metadata">

**Author:** ![alphanumeric](https://sea2.discourse-cdn.com/flex016/user_avatar/forums.pimoroni.com/alphanumeric/32/2729_2.png) [@alphanumeric](https://forums.pimoroni.com/u/alphanumeric)\
**Post date:** [February 26, 2022, 7:23pm UTC](https://forums.pimoroni.com/t/larson-scanner/18959/5 "2022-02-26T19:23:22Z")

</div>

Did some poking around and see that the Blinkt and LED Shim both have Larson example code for Python. Might give that a try with my just sitting there doing nothing Blinkt. I have two LED shims but they are in use.  
The first thing that came to mind when I read your first post was,  
**By Your Command** lol. showing my age, =)
