HELP! - Custom laser harp w/ stepper motor (frameless)

Hello All,

I have reviewed so many threads here and on many many other sites regarding a frameless laser harp setup using the 28byj-48 stepper motor and uln2003 driver IC. Mine is a little different. This is for a project at school (due in 2 days) and I have been working on this for some time now. I’ve done all the research I could, but I am having so much trouble getting this stepper motor to work properly.

My basic setup is a project box that incorporates an lcd display, speaker, volume control, MIDI jack for external sourcing, selector switch to switch between the onboard speaker and the external source, stepper motor, ic driver, laser, an LDR. The lcd display is just for looks.

I have everything put together, but I just can’t get the motor to function properly, and it’s killing me. I have seen several threads discussing the pin changes, as apparently the datasheet is incorrect, and the stepping sequence varies as well. The only time I got it to function correctly is when I hooked the motor up to a motor shield I purchased and used an example code to move it CW and CCW, which it finally worked perfectly. I noticed the step sequence was pin1-high pin2-high pin3-low pin4-low, pin1-low pin2-low pin3-high pin4-high, which is a new one to me. I corrected the sequence in my coding and it seems to respond correctly. The motor just moves a bit slow.

My current code is a little messy, as I have been messing with it so much to figure out the motor, I’m not focusing on the rest of it right now as I need to get this motor to function properly first. The current code allows it so move in one direction only.

So my question - how would I get it to rotate from CW to CCW then repeat? Note that the laser must turn on, the motor must step, then take a reading from the LDR, output a note if high, then turn the laser off and move to the next step, then so on.

Also, is there a way I can improve my code to speed things up? Is it possible to rotate the motor in one loop while taking the readings in another sub-loop? Thank you in advance for your help. I’ll be keeping an eye on here for any updates while I continue to try and work it out.

laser_harp_proj.ino (28.9 KB)

as apparently the datasheet is incorrect

What datasheet? What motor?

The only time I got it to function correctly is when I hooked the motor up to a motor shield I purchased and used an example code to move it CW and CCW, which it finally worked perfectly.

So, since that worked perfectly, you quit using the motor shield. Might I ask why the hell you did that?

I noticed the step sequence was pin1-high pin2-high pin3-low pin4-low, pin1-low pin2-low pin3-high pin4-high, which is a new one to me.

The step sequence could be stepper.step(numberOfSteps). Let the library bang the pins in the right order. It knows the correct order (assuming you tell it which pins the appropriate wires are connected to).

So my question - how would I get it to rotate from CW to CCW then repeat?

Steppers don't rotate. They step. So, you need to rephrase the question.

Yes, I know that a series of steps makes the motor rotate, but you need to stop think in terms of rotating, and start thinking in terms of stepping.

How do you define when to stop stepping one way and start stepping the other way?

Also, is there a way I can improve my code to speed things up?

You should ONLY worry about doing things faster when you are doing everything properly first.

Is it possible to rotate the motor in one loop while taking the readings in another sub-loop?

You said that the sequence was step once, read once, step once, read once, etc. Why do you need a nested for loop to read once?

Okay, I’m going to start over, trying a different approach. Thank you PaulS for the reply.

I’m basically using the Arduino Stepper One Step at a Time sketch, and would like for the stepper motor to step forward 8 steps, then step backwards 8 steps, then repeat. I do want to step it one line at a time to allow me to take a reading from an LDR. The stepper motor is a 28byj-48 5-12V motor. I have the sequencing correct now, found one that works, though there are several that will work as well. Any ideas on the best approach to this? I’m not too familiar with coding it this way, so I’ve been trying to research as well. Thank you again.

#include <Stepper.h>

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 9, 11, 8, 10);

int stepCount = 0;         // number of steps the motor has taken

void setup() {
  // initialize the serial port:
  Serial.begin(9600);
  // set the speed at 200 rpm:
  myStepper.setSpeed(200);
}

void loop() {
  // step one step:
  myStepper.step(1);
  stepCount++;
}

28BYJ-48.pdf (193 KB)

28BYJ-48-Stepper-Motor.jpg

To go 8 steps, change direction and repeat make a new variable called "direction", initialized to 1.

Step through your 8 steps just like you are doing except pass "direction" to the step method. When stepCount is 8 reset it to zero and flip the direction so that 1 becomes -1 and vice versa.

Thanks Blue Eyes! are you saying to replace “step” with “direction” in the loop?

I’ve been trying to add to the code but of course when I try to add direction change it wasn’t working for me.

#include <Stepper.h>

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper CW(stepsPerRevolution, 8, 10, 9, 11);
Stepper CCW(stepsPerRevolution,11, 10, 9, 8);

int stepCount = 0;         // number of steps the motor has taken
int direction = 1;

void setup() {
  // initialize the serial port:
  Serial.begin(9600);
  // set the speed at 200 rpm:
  CW.setSpeed(10);
  CCW.setSpeed(10);
}

void loop() {
  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CW.step(1);
  stepCount++;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);

  // step one step:
  CCW.step(-1);
  stepCount--;
  delay(10);
}

Looks like i finally got it to work correctly doing it this way. Any thoughts? I just need to add in the reading measurements after turning the laser on after each step.

#include <Stepper.h>

const int stepsPerRevolution = 8;  // change this to fit the number of steps per revolution for the 28byj-48 stepper motor.
int LaserPin = 13;

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);  //Step sequence

int stepCount = 0;         // number of steps the motor has taken

void setup() {
  pinMode(LaserPin, OUTPUT);
  // initialize the serial port:
  Serial.begin(9600);
  // set the RPM:
  myStepper.setSpeed(3000);
}

void loop() {

////////////Begin CW Stepping////////////

  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(8);
  stepCount++;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(8);
  stepCount++;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(8);
  stepCount++;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(8);
  stepCount++;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(8);
  stepCount++;
  
  digitalWrite(13, HIGH);
  delay(5);

  ////////////Begin CCW Stepping////////////

  digitalWrite(13, LOW);
  
  // step one step:
  myStepper.step(-8);
  stepCount--;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);
  
  // step one step:
  myStepper.step(-8);
  stepCount--;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);
  
  // step one step:
  myStepper.step(-8);
  stepCount--;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(-8);
  stepCount--;

  digitalWrite(13, HIGH);
  delay(5);
  digitalWrite(13, LOW);
  
  // step one step:
  myStepper.step(-8);
  stepCount--;

  digitalWrite(13, HIGH);
  delay(5);

  //Back to top
}

One more question…I’m a little confused at the spread of the beams as they are not turning out the way I am intending them to. I am trying to create an array of 4 separate beams. I have this sequence in: 1-2-3-4-3-2-
then repeat. My beam spread looks like this: . . . . . . (dots representing beams on a surface). Am I missing something? Should my step count be different at the end of a directional step cycle?

#include <Stepper.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 7, 5, 4, 3, 2);


#define NOTE_C7  2093  //BEAM 1
#define NOTE_D7  2349  //BEAM 2
#define NOTE_E7  2637  //BEAM 3
#define NOTE_FS7 2960  //BEAM 4 
#define melodyPin 6

const int stepsPerRevolution = 16;  // change this to fit the number of steps per revolution for the 28byj-48 stepper motor.
int LaserPin = 13;                 // tells the Arduino that the laser is on pin 13
int sensor = 500;                    // change this value to calibrate your harp's sensor

int note4 = 0x70;
int note3 = 0x71;
int note2 = 0x40;
int note1 = 0x47;

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);  //Step sequence

int stepCount = 0;         // number of steps the motor has taken
int a, b, c, d = 0;       // Iniating the note status markers.

void setup() {
  pinMode(LaserPin, OUTPUT);

  lcd.begin(2, 16); // Set the size of the LCD
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Laser Harp"); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("By James Landry"); // Print this line
    delay(5000); // Wait 5 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading * * * "); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[              ]"); // Print this line
    delay(1500); // Wait 1.5 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading  * * *"); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[-->           ]"); // Print this line
    delay(1500); // Wait 1.5 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading * * * "); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[---->         ]"); // Print this line
    delay(1500); // Wait 1.5 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading  * * *"); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[------>       ]"); // Print this line
    delay(1000); // Wait 1 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading * * * "); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[-------->     ]");
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading  * * *"); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[--------->    ]"); // Print this line
    delay(1000); // Wait 1 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading * * * "); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[----------->  ]"); // Print this line
    delay(1000); // Wait 1 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("Loading  * * *"); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("[------------->]"); // Print this line
    delay(750); // Wait 0.75 seconds
  lcd.clear(); // Clear the screen
  lcd.setCursor(0,0); // Set cursor for next line
  lcd.print("     Done!     "); // Print this line
  lcd.setCursor(0,1); // Set cursor for next line
  lcd.print("               "); // Print this line
    delay(1000); // Wait 1 second
  lcd.clear();
  lcd.setCursor(0,0); lcd.print("Ready to Play!");
  
  // initialize the MIDI port:
  Serial.begin(31250);
  // set the RPM:
  myStepper.setSpeed(2500);
}

void noteOn(int cmd, int pitch, int velocity)     // Function to play the notes
 {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
 }

void loop() {

////////////Begin CW Stepping////////////

  digitalWrite(13, HIGH);   //1st beam
  delay(1);
  
  if ( (analogRead(0) > sensor ) && (a == 0) ) // If the sensor gets a signal, and the note is not playing:
  {
    noteOn(0x47, note1, 0x7F);  // Play note 1
    tone(6, NOTE_C7);
    a++;                          // Change the status variable to one.
  }
 
  else if(analogRead(0) < sensor )             // If the sensor does not get a signal:
  {
    noteOn(0x47, NOTE_C7, 0x00);     // Stop playing note 1.
    a = 0;                         // Change the status variable to zero.
  }
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(16);
  stepCount++;


////


  digitalWrite(13, HIGH);   //2nd beam
  delay(1);
  
  if ( (analogRead(0) > sensor ) && (b == 0) ) // If the sensor gets a signal, and the note is not playing:
  {
    noteOn(0x40, note2, 0x7F);  // Play note 1
    tone(6, NOTE_D7);
    b++;                          // Change the status variable to one.
  }
 
  else if(analogRead(0) < sensor )             // If the sensor does not get a signal:
  {
    noteOn(0x40, NOTE_D7, 0x00);     // Stop playing note 1.
    b = 0;                         // Change the status variable to zero.
  }
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(16);
  stepCount++;


  ////


  digitalWrite(13, HIGH);   //3rd beam
  delay(1);

  if ( (analogRead(0) > sensor ) && (c == 0) ) // If the sensor gets a signal, and the note is not playing:
  {
    noteOn(0x71, note3, 0x7F);  // Play note 1
    tone(6, NOTE_E7);
    c++;                          // Change the status variable to one.
  }
 
  else if(analogRead(0) < sensor )             // If the sensor does not get a signal:
  {
    noteOn(0x71, NOTE_E7, 0x00);     // Stop playing note 1.
    c = 0;                         // Change the status variable to zero.
  }
  digitalWrite(13, LOW);

  // step one step:
  myStepper.step(16);
  stepCount++;


  ////

  
  digitalWrite(13, HIGH);   //4th beam
  delay(1);
  
  if ( (analogRead(0) > sensor ) && (d == 0) ) // If the sensor gets a signal, and the note is not playing:
  {
    noteOn(0x70, note4, 0x7F);  // Play note 1
    tone(6, NOTE_FS7);
    d++;                          // Change the status variable to one.
  }
 
  else if(analogRead(0) < sensor )             // If the sensor does not get a signal:
  {
    noteOn(0x70, NOTE_FS7, 0x00);     // Stop playing note 1.
    d = 0;                         // Change the status variable to zero.
  }
  digitalWrite(13, LOW);

  ////////////Begin CCW Stepping////////////


  // step one step:
  myStepper.step(-16);
  stepCount--;
  
  digitalWrite(13, HIGH);   //3rd beam
  delay(1);

  if ( (analogRead(0) > sensor ) && (c == 0) ) // If the sensor gets a signal, and the note is not playing:
  {
    noteOn(0x71, note3, 0x7F);  // Play note 1
    tone(6, NOTE_E7);
    c++;                          // Change the status variable to one.
  }
 
  else if(analogRead(0) < sensor )             // If the sensor does not get a signal:
  {
    noteOn(0x71, NOTE_E7, 0x00);     // Stop playing note 1.
    c = 0;                         // Change the status variable to zero.
  }
  digitalWrite(13, LOW);
  
  // step one step:
  myStepper.step(-16);
  stepCount--;


////


  digitalWrite(13, HIGH);   //2nd beam
  delay(1);

  if ( (analogRead(0) > sensor ) && (b == 0) ) // If the sensor gets a signal, and the note is not playing:
  {
    noteOn(0x40, note2, 0x7F);  // Play note 1
    tone(6, NOTE_D7);
    b++;                          // Change the status variable to one.
  }
 
  else if(analogRead(0) < sensor )             // If the sensor does not get a signal:
  {
    noteOn(0x40, NOTE_D7, 0x00);     // Stop playing note 1.
    b = 0;                         // Change the status variable to zero.
  }
  digitalWrite(13, LOW);
  
  // step one step:
  myStepper.step(-16);
  stepCount--;

  //Back to top
}

I was thinking more like this:

int direction = 1;
const int numSteps=3;
int stepCount=0;

void loop()
{
  // move stepper 
  myStepper.step(16 * direction);

  // check sensor

  // increment or decrement stepCount
  stepCount += direction;

  // if time to turn around
  if( !stepCount || (stepCount == numSteps) )
  {
    direction *= (-1);

  } // if



}

There is a good chance this is not quite right but I think it is close.

Each time through the loop it steps either +16 or -16, which it looks like your code is doing. Since your sensor checking and note playing code is always the same except for the note being played, you could put the notes in an array and index into it with stepCount which goes from zero to three then back down to zero.

  if( !stepCount || (stepCount == numSteps) )

stepCount is not a boolean. Don't treat it as one. Write the code to mean something:

  if(stepCount == 0 || stepCount == numSteps)