Introduction: Arduino Laser Projector + Control App

  • XY - 2 dimensional laser scanning
  • 2x 35mm 0.9° stepper motors - 400 steps/rev
  • Automatic mirror calibration
  • Remote serial control (via bluetooth)
  • Auto mode
  • Remote control app with GUI
  • Open Source

Download:

github.com/stanleyondrus

stanleyprojects.com

Step 1: Theory

Laser projectors can be divided into two main categories. Either they use a diffraction glass/foil to project a pattern or they have a system which moves laser beam in XY axis directions. The second option usually looks much better because it is possible to program the pattern to be projected. While in the first case, the laser beam is being diffracted and projects a static image, in the second one, the laser still consists of just one beam, that moves very fast. If this movement is fast enough, we perceive it as a pattern because of persistence of vision (POV). This is usually done by having two perpendicular mirrors, each capable of moving the laser beam in one axis. By combining them, it is possible to position the laser beam to the exact location.

For professional applications, galvanometer scanners are usually used. Some of these scanners are capable of doing 60kpps (kilo point per second). That means, they can position the laser beam to 60000 different locations during 1 second. This creates a really smooth projection without the stroboscopic effect. However, they can be really expensive. I have used the stepper motors, which is the cheap, not so fast, alternative.

The laser draws the pattern by orbiting the lines over and over at really high speed. Sometimes there are multiple parts of the pattern that are not connected together. In this example, each letter is separated, however when the laser moves from one letter to another one, it creates an unwanted line. This is solved by a technology called blanking. The whole idea behind is, that the laser is switched of when moving from one, to another pattern. This is done by a high-speed controlling unit, which needs to be synchronized with the scanning system.

Step 2: Obtaining Components

In the list bellow you can find the components I used and the links where I bought them.

    And then some material and tools you can find at home. Hopefully ;)

    • Mirror (the best is a metallic mirror like HDD Platter)
    • Aluminium sheet
    • Snips
    • Hot Glue (or Pattex Repair Express )
    • Wires
    • Pliers
    • Drill (or scissors in my case :D)
    • Box (e.g. Junction Box)

    Step 3: Mounting Steppers

    Aluminium sheet needed to be cut and bent into the proper shape. Then holes were drilled and steppers attached.

    Step 4: Laser Blanking + Mirror Calibration

    Motor Shield has a small prototyping area that was used for two small circuits.

    Laser Blanking

    We want to control our laser with an Arduino. However we need to limit current flowing into the laser and also driving it directly from a digital output pin is not a good idea. My laser module already had a current protection. Thus I've built just a simple circuit where transistor is switching the laser on and off. Base current can be regulated by trimmer and controls the brightness of the laser.

    Mirror Calibration

    Photodiode was placed in the hole in the central axis right above the X-axis stepper. Pull-down resistor circuit was necessary to obtain exact measurements. When calibrating, we are reading values from the photodiode and when the value exceeds a specific value (laser directly shines into it), steppers stop and return to the home position.

    pseudo code for calibration
    // 1step = 0.9° / 400steps = 360° = full rotation
    laserOn();
    for (int a=0; a<=400; a++) {
    for (int b=0; b<=400; b++) {
    photodiodeValue = readValue();
    if (photodiodeValue >= photodiodeThreshold) {
    laserOff();
    returnHome();
    }
    stepY(1,1);
    }
    stepX(1,1);
    }
    laserOff();
    unsuccessfull();</p>

    Step 5: Final Assembly

    The whole circuit was put into the plastic junction box and tightened by screws. The whole projector is really portable, just plug the power supply, switch the toggle and we have laser show.

    Step 6: Laser Control App

    The controlling app was made in C# and allows to switch between patterns, adjust the speed and see current actions. It is free to download together with the Arduino code (see Intro).

    Step 7: Video

    Comments

    author
    VintecJ (author)2017-06-12

    help me please...

    i can't compile to arduino uno..

    i have problem with library

    " AFMotor.h" and

    utility/Adafruit_MS_PWMServoDriver.h.

    i have library at arduino but not work...

    what wrong ???

    author
    stanleyprojects (author)VintecJ2017-06-13

    What is the error message?

    author
    JānisK15 (author)2017-01-26

    That is correct?

    CCI20170127_00000.jpg
    author

    Yes it is. Or you can use in-built pull-up resistors inside Arduino and modify the code. By the way, please use the "Reply" button so we won't start a new conversation every time.

    author

    Hello. Can i make laser drawing smaller? Maybe problem is in motors, i have very old motors from 5,25 FDD

    author
    JānisK15 (author)JānisK152017-03-20

    Hello again!

    Where i must write microstepping code and steps per revolution?

    author

    You can find all the information here: https://learn.adafruit.com/adafruit-motor-shield-v2-for-arduino/using-stepper-motors

    author

    More steps per revolution = smaller single step. You can even use microstepping.

    author

    Ok. Thanks :)

    author
    stanleyprojects (author)2017-01-26

    Both of them to the ground through a pull-down resistor. To switch on, apply 5V.
    Even easier way would be to initialize those pins as INPUT_PULLUP and then just short them to ground as you switch the toggle.

    author
    JānisK15 (author)2017-01-25

    Where i need connect mode switch?

    author

    Serial more - D14
    Auto mode - D15

    author
    stanleyprojects (author)2017-01-22

    The problem is pretty self-explanatory. You are missing the AccelStepper/MultiStepper.h library.

    By the way, when you download a library, make sure to put in the the right folder structure, Documents\Arduino\libraries\xxx, where xxx will be the name of the library, and it will directly contain all the necessary files. It is always better to use the libraries folder located in Documents, in case of you will reinstall or update your Arduino IDE. You can always delete the .github folder to remove the warnings.

    author

    Thanks. It works :)

    author
    JānisK15 (author)2016-11-29

    Hello. Can you help me? ArduinoIDE says Error compiling for board arduino Mega or Mega 2560. What can i do?

    author

    It can be caused by many things. Try to post here the full error log.

    author
    JānisK15 (author)2016-11-24

    Can i make this wit mega2560?

    author

    Yes. As far as I know, motor shield v2 is compatible with Arduino Mega. Basically, it should not be a problem with anything, as far as it is capable of controlling stepper motors and providing modulated output signal for laser blanking. Of course in that case, only the concept of this project should be used, not the exact same code.

    author
    RC 44 (author)2016-09-19

    I`m having a problem with the softare. I`m using windows 10, 64-bit and I click to open the app but it simply doesen`t wanna open. It shows the loading cursor for 4 seconds and stops, with no sign of the app.

    Thanks.

    author
    stanleyprojects (author)RC 442016-09-20

    Try to right-click it, go to properties, and if there is an option called "Unblock", then check it and click apply.

    author
    SiposD made it! (author)2016-04-03

    Hy ! I modified code work Adafruit Motor Shield V1 but not good effect .

    Can i help you ?

    I use order 400 steps/rev motor !!

    It's code

    "/*

    Arduino Laser Scanner

    by Stanley Ondrus 2016

    - XY - 2 dimensional laser scanning

    - Automatic mirror calibration

    - Remote serial control (via bluetooth)

    - Auto mode

    - Remote control app with GUI

    www.stanleyprojects.com

    www.github.com/stanleyondrus/ArduinoLaserScanner

    */

    #include <AccelStepper.h>

    #include <MultiStepper.h>

    #include <Wire.h>

    #include <AFMotor.h>

    int stepsPerRevolution = 350;

    int serialLed = 10;

    int autoLed = 11;

    int calibrationLed = 12;

    int laserPin = 13;

    int switchPin = 14;

    int autoModePin = 15;

    int photodiodePin = 16;

    AF_Stepper myX(stepsPerRevolution, 1);

    AF_Stepper myY(stepsPerRevolution, 2);

    static int METHOD = INTERLEAVE;

    int speedValue = 800;

    int initialSize = 20;

    int currentType = 0;

    int currentId = 0;

    int currentSize = initialSize;

    int currentSpeed = speedValue;

    int currentDuration = 0;

    int minType = 1;

    int maxType = 5; // how many shapes

    int minId = 1;

    int maxId = 5; // how many patterns

    int minSize = 3;

    int maxSize = 30; // size in steps

    int minPatternSpeed = 10;

    int maxPatternSpeed = 800; // speed of steppers

    int minDuration = 1;

    int maxDuration = 10; // iterations of for loop

    int patternSize[] = {5, 10, 15, 20, 25, 30};

    int sizeStart = 0;

    int sizeEnd = 7;

    int photodiodeValue = 0; // photodiode value needed for calibration

    int photodiodeThreshold = 170; // min value when laser points to diode

    int returnY = 109; // Y steps needed to return home from calibration

    int returnX = 12; // X steps needed to return home from calibration

    boolean laser = false;

    boolean calibrated = false;

    boolean calibration = false;

    boolean randomSize = false;

    int c = 0; // used for serial receive

    // you can change these to DOUBLE or INTERLEAVE or MICROSTEP

    void forwardstep1() {

    myX.onestep(FORWARD, METHOD);

    }

    void backwardstep1() {

    myX.onestep(BACKWARD, METHOD);

    }

    void forwardstep2() {

    myY.onestep(FORWARD, METHOD);

    }

    void backwardstep2() {

    myY.onestep(BACKWARD, METHOD);

    }

    AccelStepper x(forwardstep1, backwardstep1); // use functions to step

    AccelStepper y(forwardstep2, backwardstep2); // use functions to step

    void setup()

    {

    Serial.begin(9600); // set up Serial library at 9600 bps

    Serial.println("Arudino Laser Scanner");

    pinMode(serialLed, OUTPUT);

    pinMode(autoLed, OUTPUT);

    pinMode(calibrationLed, OUTPUT);

    pinMode(laserPin, OUTPUT);

    pinMode(switchPin, INPUT);

    pinMode(autoModePin, INPUT);

    pinMode(photodiodePin, INPUT);

    stepperSpeed(speedValue);

    x.setAcceleration(1000);

    y.setAcceleration(1000);

    laserOff();

    sLedOff();

    aLedOff();

    cLedOff();

    }

    void loop()

    {

    if (switchRead())

    {

    if (calibration)

    {

    calibrate();

    }

    if (!(calibrated))

    {

    calibrateOnSerial();

    }

    serialMode();

    }

    if (autoModeRead())

    {

    autoMode();

    }

    }

    void serialEvent() {

    while (Serial.available())

    {

    c = Serial.read();

    switch (c)

    {

    case 'A': //laser on

    laserOn();

    Serial.println("Laser On");

    break;

    case 'B': //laser off

    laserOff();

    Serial.println("Laser Off");

    break;

    case 'C': //calibrate

    calibrate();

    break;

    case 'D': //stop

    setCurrentPattern(0, 0);

    calibration = false;

    Serial.println("Stopped");

    break;

    case 'E': //random size enable

    randomSize = true;

    Serial.println("Random Size Enabled");

    break;

    case 'F': //random size disable

    randomSize = false;

    Serial.println("Random Size Disabled");

    break;

    case 'G': //size increment

    if (currentSize < 30)

    {

    currentSize += 5;

    }

    // Serial.println("Current Size: " + currentSize);

    break;

    case 'H': //size decrement

    if (currentSize > 5)

    {

    currentSize -= 5;

    }

    // Serial.println("Current Size: " + currentSize);

    break;

    case 'I': //square 1

    setCurrentPattern(1, 1);

    currentDetails("Square 1");

    break;

    case 'J': //square 2

    setCurrentPattern(1, 2);

    currentDetails("Square 2");

    break;

    case 'K': //square 3

    setCurrentPattern(1, 3);

    currentDetails("Square 3");

    break;

    case 'L': //square 4

    setCurrentPattern(1, 4);

    currentDetails("Square 4");

    break;

    case 'M': //cross 1

    setCurrentPattern(2, 1);

    currentDetails("Cross 1");

    break;

    case 'N': //cross 2

    setCurrentPattern(2, 2);

    currentDetails("Cross 2");

    break;

    case 'O': //cross 3

    setCurrentPattern(2, 3);

    currentDetails("Triangle 1");

    break;

    case 'P': //cross 4

    setCurrentPattern(2, 4);

    currentDetails("Triangle 2");

    break;

    case 'Q': //line 1

    setCurrentPattern(3, 1);

    currentDetails("Line 1");

    break;

    case 'R': //line 2

    setCurrentPattern(3, 2);

    currentDetails("Line 2");

    break;

    case 'S': //line 3

    setCurrentPattern(3, 3);

    currentDetails("Line 3");

    break;

    case 'T': //line 4

    setCurrentPattern(3, 4);

    currentDetails("Line 4");

    break;

    case 'U': //sticky man figure

    setCurrentPattern(4, 1);

    currentDetails("Man Figure");

    break;

    case 'V': //

    setCurrentPattern(4, 2);

    currentDetails("Smiley");

    break;

    case 'W': //

    setCurrentPattern(4, 3);

    currentDetails("Heart");

    break;

    case 'X': //

    setCurrentPattern(4, 4);

    currentDetails("Star");

    break;

    }

    }

    }

    //----switches-and-button-reads------------

    boolean autoModeRead() {

    if (digitalRead(autoModePin) == HIGH ) {

    return true;

    } else {

    return false;

    }

    }

    boolean switchRead() {

    if (digitalRead(switchPin) == HIGH) {

    return true;

    } else {

    return false;

    }

    }

    //-----------------------------------------

    //------------calibration-----------------

    boolean calibrateOnSerial()

    {

    calibration = true;

    cLedOn();

    Serial.println("XY Calibration");

    stepY(returnY, 1);

    stepX(returnX, 1);

    for (int a = 0; a <= stepsPerRevolution; a++)

    {

    for (int i = 0; i <= stepsPerRevolution; i++)

    {

    serialEvent();

    if (!(calibration) || (!(switchRead())))

    {

    notSuccessful();

    return false;

    }

    laserOn();

    photodiodeValue = map(analogRead(photodiodePin), 0, 1023, 0, 255);

    //delay(50);

    if (photodiodeValue >= photodiodeThreshold)

    {

    laserOff();

    rotateHome();

    Serial.println("Calibrated");

    cLedOff();

    calibration = false;

    calibrated = true;

    return true;

    }

    stepY(1, 1);

    }

    stepX(1, 1);

    }

    notSuccessful();

    }

    boolean calibrate() {

    calibration = true;

    cLedOn();

    Serial.println("XY Calibration");

    stepY(returnY, 1);

    stepX(returnX, 1);

    for (int a = 0; a <= stepsPerRevolution; a++)

    {

    for (int i = 0; i <= stepsPerRevolution; i++)

    {

    serialEvent();

    if (!(calibration))

    {

    notSuccessful();

    return false;

    }

    laserOn();

    photodiodeValue = map(analogRead(photodiodePin), 0, 1023, 0, 255);

    //delay(50);

    if (photodiodeValue >= photodiodeThreshold)

    {

    laserOff();

    rotateHome();

    Serial.println("Calibrated");

    cLedOff();

    calibration = false;

    calibrated = true;

    return true;

    }

    stepY(1, 1);

    }

    stepX(1, 1);

    }

    notSuccessful();

    }

    boolean notSuccessful()

    {

    Serial.println("Calibration not successful.");

    laserOff();

    cLedOff();

    rotateHome();

    calibrated = true;

    calibration = false;

    return false;

    }

    void rotateHome()

    {

    stepY(returnY, 2);

    stepX(returnX, 2);

    }

    //-----------------------------------------

    //--------serial-mode-functions--------------

    void serialMode()

    {

    sLedOn();

    if (currentType != 0 || currentId != 0)

    {

    if (randomSize)

    {

    currentSize = patternSize[random(sizeStart, sizeEnd)];

    }

    currentSpeed = 800;

    currentDuration = 1;

    patternCall(currentType, currentId, currentSize, currentSpeed, currentDuration);

    }

    sLedOff();

    }

    void setCurrentPattern(int patternType, int patternId)

    {

    currentType = patternType;

    currentId = patternId;

    }

    void currentDetails(String pattern)

    {

    String details = pattern + " - Size: " + currentSize + " Speed: " + currentSpeed + " Duration: " + currentDuration;

    Serial.println(details);

    }

    //-----------------------------------------

    //--------auto-mode-functions--------------

    void autoMode()

    {

    aLedOn();

    calibrated = false;

    currentType = random(minType, maxType);

    currentId = random(minId, maxId);

    currentSize = patternSize[random(sizeStart, sizeEnd)];

    //currentSpeed = random(minPatternSpeed, maxPatternSpeed);

    currentDuration = random(minDuration, maxDuration);

    patternCall(currentType, currentId, currentSize, currentSpeed, currentDuration) ;

    currentType = 0;

    currentId = 0;

    currentSize = initialSize;

    currentDuration = 0;

    aLedOff();

    }

    void patternCall(int patternType, int patternId, int patternSize, int patternSpeed, int patternDuration)

    {

    stepperSpeed(patternSpeed);

    for (int i = 0; i <= patternDuration; i++)

    {

    patternTypeCall(patternType, patternId, patternSize);

    }

    }

    void patternTypeCall(int patternType, int patternId, int patternSize)

    {

    switch (patternType) {

    case 1:

    square(patternId, patternSize);

    break;

    case 2:

    object(patternId, patternSize);

    break;

    case 3:

    line(patternId, maxSize);

    break;

    case 4:

    logo(patternId, maxSize / 2);

    break;

    default:

    square(patternId, patternSize);

    break;

    }

    }

    //--------------------------------------

    //-------------patterns-----------------

    void square(int patternId, int patternSize)

    {

    switch (patternId) {

    case 1:

    square1(patternSize);

    break;

    case 2:

    square2(patternSize);

    break;

    case 3:

    square3(patternSize);

    break;

    case 4:

    square4(patternSize);

    break;

    default:

    break;

    }

    }

    void object(int patternId, int patternSize)

    {

    switch (patternId) {

    case 1:

    cross1(patternSize);

    break;

    case 2:

    cross2(patternSize);

    break;

    case 3:

    triangle1(20);

    break;

    case 4:

    cicuska(20);

    break;

    default:

    break;

    }

    }

    void line(int patternId, int patternSize)

    {

    switch (patternId) {

    case 1:

    line1(patternSize);

    break;

    case 2:

    line2(patternSize);

    break;

    case 3:

    line3(patternSize);

    break;

    case 4:

    line4(patternSize);

    break;

    default:

    break;

    }

    }

    void logo(int patternId, int patternSize)

    {

    switch (patternId) {

    case 1:

    manFigure(patternSize);

    break;

    case 2:

    smiley(patternSize);

    break;

    case 3:

    heart(patternSize);

    break;

    case 4:

    star(patternSize);

    break;

    default:

    break;

    }

    }

    //------------------------------------

    //-------------squares-----------------

    void square1(int squareSize)

    {

    laserOn();

    stepX(squareSize, 1);

    stepY(squareSize, 1);

    stepX(squareSize, 2);

    stepY(squareSize, 2);

    laserOff();

    }

    void square2(int squareSize)

    {

    laserOn();

    stepX(squareSize, 1);

    laserOff();

    stepY(squareSize, 1);

    laserOn();

    stepX(squareSize, 2);

    laserOff();

    stepY(squareSize, 2);

    }

    void square3(int squareSize)

    {

    laserOff();

    stepX(squareSize, 1);

    laserOn();

    stepY(squareSize, 1);

    laserOff();

    stepX(squareSize, 2);

    laserOn();

    stepY(squareSize, 2);

    laserOff();

    }

    void square4(int squareSize)

    {

    laserOn();

    delay(50);

    laserOff();

    stepX(squareSize, 1);

    laserOn();

    delay(50);

    laserOff();

    stepY(squareSize, 1);

    laserOn();

    delay(50);

    laserOff();

    stepX(squareSize, 2);

    laserOn();

    delay(50);

    laserOff();

    stepY(squareSize, 2);

    }

    //----------------------------------------

    //-------------objects-----------------

    void cross1(int crossSize)

    {

    laserOn();

    for (int i = 0; i < crossSize; i++)

    {

    stepX(1, 1);

    stepY(1, 1);

    }

    laserOff();

    stepX(crossSize, 2);

    laserOn();

    for (int i = 0; i < crossSize; i++)

    {

    stepX(1, 1);

    stepY(1, 2);

    }

    laserOff();

    stepX(crossSize, 2);

    }

    void cross2(int crossSize)

    {

    square1(crossSize);

    laserOn();

    for (int i = 0; i < crossSize; i++)

    {

    stepX(1, 1);

    stepY(1, 1);

    }

    laserOff();

    stepX(crossSize, 2);

    laserOn();

    for (int i = 0; i < crossSize; i++)

    {

    stepX(1, 1);

    stepY(1, 2);

    }

    laserOff();

    stepX(crossSize, 2);

    }

    void triangle1(int objectSize)

    {

    laserOn();

    stepX(objectSize, 1);

    for (int i = 0; i < objectSize / 2; i++)

    {

    stepY(2, 1);

    stepX(1, 2);

    }

    for (int i = 0; i < objectSize / 2; i++)

    {

    stepY(2, 2);

    stepX(1, 2);

    }

    laserOff();

    }

    void cicuska(int crossSize)

    {

    int pixel = crossSize / 11;

    stepX(2 * pixel, 1);

    laserOn();

    stepX(7 * pixel, 1);

    //DOPRAVA HORE

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 1);

    //STLPEC VPRAVO NAHOR

    stepY(9 * pixel, 1);

    //PRAVE USKO

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 2);

    //STRED

    stepY(1 * pixel, 1);

    stepX(3 * pixel, 2);

    stepY(1 * pixel, 2);

    //LAVE USKO

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 2);

    //PRAVY STLPEC

    stepY(9 * pixel, 2);

    //DOPRAVA DOLE

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 2);

    laserOff();

    stepX(2 * pixel, 2);

    }

    //----------------------------------------

    //-------------line-----------------

    void line1(int lineSize)

    {

    stepY(lineSize / 2, 1);

    laserOn();

    stepX(lineSize, 1);

    stepX(lineSize, 2);

    laserOff();

    stepY(lineSize / 2, 2);

    }

    void line2(int lineSize) // from the center to sides

    {

    int pixel = lineSize / 11;

    stepY(lineSize / 2, 1);

    stepX(5 * pixel, 1);

    laserOn();

    stepX(1 * pixel, 1);

    stepX(2 * pixel, 2);

    stepX(3 * pixel, 1);

    stepX(4 * pixel, 2);

    stepX(5 * pixel, 1);

    stepX(6 * pixel, 2);

    stepX(7 * pixel, 1);

    stepX(8 * pixel, 2);

    stepX(9 * pixel, 1);

    stepX(10 * pixel, 2);

    stepX(11 * pixel, 1);

    stepX(11 * pixel, 2);

    stepX(11 * pixel, 1);

    stepX(11 * pixel, 2);

    laserOff();

    stepY(lineSize / 2, 2);

    }

    void line3(int lineSize) // from the center to sides - up/down

    {

    int pixel = lineSize / 11;

    stepX(5 * pixel, 1);

    laserOn();

    stepX(1 * pixel, 1);

    stepX(2 * pixel, 2);

    laserOff();

    stepY(3 * pixel, 1);

    laserOn();

    stepX(3 * pixel, 1);

    stepX(4 * pixel, 2);

    laserOff();

    stepY(3 * pixel, 1);

    laserOn();

    stepX(5 * pixel, 1);

    stepX(6 * pixel, 2);

    laserOff();

    stepY(3 * pixel, 1);

    laserOn();

    stepX(7 * pixel, 1);

    stepX(8 * pixel, 2);

    laserOff();

    stepY(3 * pixel, 2);

    laserOn();

    stepX(9 * pixel, 1);

    stepX(10 * pixel, 2);

    laserOff();

    stepY(3 * pixel, 2);

    laserOn();

    stepX(11 * pixel, 1);

    stepX(11 * pixel, 2);

    laserOff();

    stepY(3 * pixel, 2);

    laserOn();

    stepX(11 * pixel, 1);

    stepX(11 * pixel, 2);

    laserOff();

    }

    void line4(int lineSize) // from the center to sides - up/down

    {

    int pixel = lineSize / 11;

    stepY(5 * pixel, 1);

    laserOn();

    stepY(1 * pixel, 1);

    stepY(2 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 1);

    laserOn();

    stepY(3 * pixel, 1);

    stepY(4 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 1);

    laserOn();

    stepY(5 * pixel, 1);

    stepY(6 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 1);

    laserOn();

    stepY(7 * pixel, 1);

    stepY(8 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 2);

    laserOn();

    stepY(9 * pixel, 1);

    stepY(10 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 2);

    laserOn();

    stepY(11 * pixel, 1);

    stepY(11 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 2);

    laserOn();

    stepY(11 * pixel, 1);

    stepY(11 * pixel, 2);

    laserOff();

    }

    //----------------------------------------

    //-------------objects-----------------

    void manFigure(int logoSize)

    {

    int pixel = logoSize / 11;

    stepY(3 * pixel, 1);

    stepX(3 * pixel, 1);

    laserOn();

    stepY(6 * pixel, 1);

    stepX(3 * pixel, 2);

    stepY(2 * pixel, 1);

    stepX(4 * pixel, 1);

    stepY(3 * pixel, 1);

    stepX(3 * pixel, 1);

    stepY(3 * pixel, 2);

    stepX(4 * pixel, 1);

    stepY(2 * pixel, 2);

    stepX(3 * pixel, 2);

    stepY(6 * pixel, 2);

    stepX(2 * pixel, 2);

    stepY(3 * pixel, 1);

    stepX(1 * pixel, 2);

    stepY(3 * pixel, 2);

    stepX(2 * pixel, 2);

    laserOff();

    stepX(3 * pixel, 2);

    stepY(3 * pixel, 2);

    }

    void smiley(int logoSize)

    {

    int pixel = logoSize / 11;

    stepY(3 * pixel, 1);

    stepX(2 * pixel, 1);

    stepY(2 * pixel, 1);

    laserOn();

    stepY(4 * pixel, 1);

    stepX(2 * pixel, 1);

    laserOff();

    stepY(1 * pixel, 1);

    laserOn();

    stepX(2 * pixel, 2);

    stepY(2 * pixel, 1);

    stepX(2 * pixel, 1);

    stepY(2 * pixel, 2);

    laserOff();

    stepY(1 * pixel, 2);

    laserOn();

    stepY(2 * pixel, 2);

    stepX(3 * pixel, 1);

    stepY(2 * pixel, 1);

    stepX(2 * pixel, 1);

    laserOff();

    stepY(1 * pixel, 1);

    laserOn();

    stepX(2 * pixel, 2);

    stepY(2 * pixel, 1);

    stepX(2 * pixel, 1);

    stepY(2 * pixel, 2);

    laserOff();

    stepY(1 * pixel, 2);

    laserOn();

    stepY(4 * pixel, 2);

    stepX(7 * pixel, 2);

    laserOff();

    stepY(2 * pixel, 2);

    stepX(2 * pixel, 2);

    stepY(3 * pixel, 2);

    }

    void heart(int logoSize)

    {

    int pixel = logoSize / 11;

    laserOff();

    stepX(5 * pixel, 1);

    laserOn();

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 1);

    //column right

    stepX(1 * pixel, 1);

    stepY(3 * pixel, 1);

    stepX(1 * pixel, 2);

    //

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 1);

    //row 2moves right

    stepX(2 * pixel, 2);

    //

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 1);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 1);

    //row 2moves left

    stepX(2 * pixel, 2);

    //

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 2);

    stepY(1 * pixel, 2);

    //column left

    stepX(1 * pixel, 2);

    stepY(3 * pixel, 2);

    stepX(1 * pixel, 1);

    //

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 2);

    stepX(1 * pixel, 1);

    stepY(1 * pixel, 2);

    laserOff();

    stepX(5 * pixel, 2);

    }

    void star(int logoSize)

    {

    int pixel= logoSize/11;

    laserOff();

    stepX(1*pixel,1);

    stepY(2*pixel,1);

    laserOn();

    stepX(4*pixel,1);

    stepY(2*pixel,1);

    stepX(1*pixel,1);

    stepY(2*pixel,2);

    stepX(4*pixel,1);

    stepY(1*pixel,1);

    stepX(1*pixel,2);

    stepY(1*pixel,1);

    stepX(1*pixel,2);

    stepY(1*pixel,1);

    stepX(1*pixel,1);

    stepY(1*pixel,1);

    stepX(1*pixel,1);

    //column right

    stepY(2*pixel,1);

    //

    stepX(3*pixel,2);

    stepY(2*pixel,1);

    stepX(1*pixel,2);

    stepY(1*pixel,1);

    stepX(1*pixel,2);

    stepY(1*pixel,2);

    stepX(1*pixel,2);

    //column left

    stepY(2*pixel,2);

    //

    stepX(3*pixel,2);

    stepY(2*pixel,2);

    stepX(1*pixel,1);

    stepY(1*pixel,2);

    stepX(1*pixel,1);

    stepY(1*pixel,2);

    stepX(1*pixel,2);

    stepY(1*pixel,2);

    stepX(1*pixel,2);

    stepY(1*pixel,2);

    laserOff();

    stepX(1*pixel,2);

    stepY(2*pixel,2);

    }

    //----------------------------------------

    //-----stepper-and-laser-control----------

    void stepX(int steps, int newDirection)

    {

    if (newDirection == 1)

    myX.step(steps, FORWARD, METHOD);

    else

    myX.step(steps, BACKWARD, METHOD);

    }

    void stepY(int steps, int newDirection)

    {

    if (newDirection == 1)

    myY.step(steps, FORWARD, METHOD);

    else

    myY.step(steps, BACKWARD, METHOD);

    }

    void moveX(int newPosition)

    {

    x.moveTo(newPosition);

    while (x.distanceToGo() != 0)

    {

    x.run();

    }

    }

    void moveY(int newPosition)

    {

    y.moveTo(newPosition);

    while (y.distanceToGo() != 0)

    {

    y.run();

    }

    }

    void moveXY(int newXPosition, int newYPosition)

    {

    x.moveTo(newXPosition);

    y.moveTo(newYPosition);

    while (x.distanceToGo() != 0 || y.distanceToGo() != 0)

    {

    x.run();

    y.run();

    }

    }

    void stepperSpeed(int stepperSpeed)

    {

    x.setSpeed(stepperSpeed);

    y.setSpeed(stepperSpeed);

    x.setMaxSpeed(stepperSpeed);

    y.setMaxSpeed(stepperSpeed);

    myX.setSpeed(stepperSpeed);

    myY.setSpeed(stepperSpeed);

    }

    void laserOn()

    {

    digitalWrite(laserPin, HIGH);

    }

    void laserOff()

    {

    digitalWrite(laserPin, LOW);

    }

    //----------------------------------

    //-----------LED-control------------

    void sLedOn()

    {

    digitalWrite(serialLed, HIGH);

    }

    void aLedOn()

    {

    digitalWrite(autoLed, HIGH);

    }

    void cLedOn()

    {

    digitalWrite(calibrationLed, HIGH);

    }

    void sLedOff()

    {

    digitalWrite(serialLed, LOW);

    }

    void aLedOff()

    {

    digitalWrite(autoLed, LOW);

    }

    void cLedOff()

    {

    digitalWrite(calibrationLed, LOW);

    }

    //----------------------------------

    12952716_1076409939085632_1797835277_o.jpg12966701_1076409772418982_1899634881_n.jpg
    author
    SiposD (author)2016-03-31

    Well done!

    One problem is that the pattern is not pretty.

    I think it's wrong for 1.8 deg step motor.

    author
    SiposD (author)2016-03-31

    I have new questens the project it's work Adafruit Motor Shield V1 ?

    author
    stanleyprojects (author)SiposD2016-03-31

    No, it's for the V2.

    author
    SiposD (author)stanleyprojects2016-03-31

    The code can not be rewritten to be good?

    author
    stanleyprojects (author)SiposD2016-03-31

    Feel free to use V1 library and rewrite the code :)

    author
    SiposD (author)stanleyprojects2016-03-31

    I write code v1 and succesful . It's work but a pc controller not work .

    author
    stanleyprojects (author)2016-03-31

    I am really sorry but I don't have time to review and rewrite the whole code now. I think it will be much easier also for you if you buy Motorshield V2. It doesn't even have to be the original one. On aliexpres.com you can buy a cheap and working one around $6. I hope that helps you :)

    author
    SiposD (author)2016-03-31

    I installed 4.5.2 framework and "System.IndexOutOfRangeException" error .

    author
    stanleyprojects (author)SiposD2016-03-31

    Try to download the last version of LaserControl from GitHub.

    author
    SiposD (author)2016-03-30

    windows 7 not runnig laser control app help

    author
    stanleyprojects (author)SiposD2016-03-30

    Are you sure it is not blocked by something? (antivirus, windows protection,...) What kind of error do you get?

    author
    SiposD made it! (author)stanleyprojects2016-03-30

    Here is a picture of the wranning :/

    I have no idea, I chechk anti virus and fire wall and system right .

    32bit windows 7

    ajahah.png
    author
    stanleyprojects (author)SiposD2016-03-30

    Make sure you have .NET framework 4.5.2 installed on your computer.

    author
    wannabemadsci (author)2016-03-20

    Nice Instructable! What power output is your laser module?

    author

    Thank you! It's just 50mW.

    author
    Andyrob257 (author)2016-03-04

    How do you use HDD platters, I thought they were made of some sort of glass material

    author

    Actually they are made of aluminium so you can cut or press-brake them.

    author

    Really? I've got 26 of 'em because they looked to good to throw away and I've always handled them with care. Now I know what my next project will be!!

    Thanks for the instuctable.

    author
    nccwarp9 (author)2016-03-03

    Could you post a video of operation ?

    Are steppers fast enough ?

    author
    stanleyprojects (author)nccwarp92016-03-03

    You can find the video in the Intro section.

    It depends on what your definition of "fast enough" is. In my opinion, for a small laser show it's more than enough, but if you want to make a precise 2D animation system, you will need high Kpps galvo scanners.

    About This Instructable

    7,803views

    68favorites

    License:

    Bio: I am a 22 years old student from Slovakia currently studying ICT Engineering (Embedded Systems) in Denmark. In my free time I like working with ... More »
    More by stanleyprojects:Robotic ArmLaser EngraverArduino Laser Projector + Control App
    Add instructable to: