Rainbow effect and stepper continuous rotation

Hello guys, I need your help please. I am trying to have a stepper motor (28BYJ-48) and one led ws2811 3W to run together controlled by Digispark. I would like the stepper motor to have continuous clockwise rotation while the led would do a continous raindow fade. I have tried to merge 2 codes together but the stepper rotates, then stops for the led to fade through one rainbow cycle. How can I merge the code so that the stepper doesn't stop and goes into continuous rotation while the led fades through rainbow continously. Please find my code below:

/* Example sketch to control a 28BYJ-48 stepper motor with ULN2003 driver board and Arduino UNO. More info: https://www.makerguides.com */

// Include the Arduino Stepper.h library:
#include <Stepper.h>
#include <Adafruit_NeoPixel.h>

// Define number of steps per rotation:
const int stepsPerRevolution = 2048;
const int ledPin = 4;     // the number of the neopixel strip
const int numLeds = 1;


// Create stepper object called 'myStepper', note the pin order:
Stepper myStepper = Stepper(stepsPerRevolution, 3, 1, 2, 0);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  // Set the speed to 5 rpm:
  myStepper.setSpeed(12);
   strip.begin();
  strip.setBrightness(20); // 1/3 brightness

  
  // Begin Serial communication at a baud rate of 9600:
  Serial.begin(9600);
}

void loop() {
  // Step one revolution in one direction:
  Serial.println("Rotating Anti-clockwise...");
  myStepper.step(-stepsPerRevolution);
 delay(10);
    rainbow(30);
      delay(10);

}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i*1+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } 
  else if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } 
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  }

Thank you

Your for loop runs a complete cycle every time it is called.
What you want is for it to advance one step each time it is called.
maybe something like this:

// Change rainbow one step at a time
void rainbowSteps(uint8_t wait) {

  uint16_t nextStep;
  strip.setPixelColor(i, Wheel((i * 1 + j) & 255)); // change this since i&j are no longer here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  strip.show();
  delay(wait);
  nextStep++;
  if (nextStep > 256) {
    nextStep = 0;
  }
}

Thank you for your reply. Where exactly in the code do I have to change it? I have tried multiple of times but unfortunately it's coming with an error message. Thank you

We get this question at least once a day in various guises. The answer is always to write the code as a state machine.

So a simple forum surcharge for things like
State machine
Two things at once

The problem here is that you can't interrupt the stepping motor driver to send the update to the LEDs without making it stutter. So you have to generate the steps with external hardware. Like this board.

Thank you for your reply. Is there a way to just modify the code as I am very limited with space to be able to add another small pcb. I got it running but the only problem is the stepper motor does not rotate continuously.

If you create the steps based on a timer-interrupt it might work.
There is a different stepper-motor-library called MobaTools that works this way.
But I don't know if this library runs on digisparks.
or if you can setup a timer-interrupt at all on a digispark.

If it does not work based on a timer-interrupt
to have the step-pulses created spot-on-regularly in time your complete code needs to be restructured to use absolutely consequently non-blocking timing.

non-blocking timing means replace each and every delay() by non-blocking timing

non-blocking timing means: change thinking from sequential mutliple looping based on for-loops / while-loops
to
single-top-level looping where the only allowed loop is void loop itself

So at this time you have the learning steps for advanced coding in front of you.

best regards Stefan

No.
Because the code that sends out the information to the addressable strips must be done with the interrupts turned off. That means no other code can run during this time.

However if you change the type of addressable LEDs you use from neopixel to dot star you can do this, because the dot star LEDs use a data and clock signal and so that code is not tied to the software producing precise timing.

However many people will be reluctant to spend more money on a different sort of strip.

Did you only adjust it accordian to #2 above?

Please post the code you are running now, that works but doesn't work well.

a7

Yes I have tried to change it according to the updated second post but as soon as I change it, I get an error message. The code that is working now is the code in my first post. It may make sense what Grumpy_Mike says but I can't understand why there is no way to modify the code just to have the stepper rotate continuously in one direction and a rainbow fade effect on one LED.


// Include the Arduino Stepper.h library:
#include <Stepper.h>
#include <Adafruit_NeoPixel.h>

// Define number of steps per rotation:
const int stepsPerRevolution = 2048;
const int ledPin = 4;     // the number of the neopixel strip
const int numLeds = 1;


// Create stepper object called 'myStepper', note the pin order:
Stepper myStepper = Stepper(stepsPerRevolution, 3, 1, 2, 0);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, ledPin, NEO_GRB + NEO_KHZ800);

void setup() {
  // Set the speed to 5 rpm:
  myStepper.setSpeed(12);
   strip.begin();
  strip.setBrightness(20); // 1/3 brightness

  
  // Begin Serial communication at a baud rate of 9600:
  Serial.begin(9600);
}

void loop() {
  // Step one revolution in one direction:
  Serial.println("Rotating Anti-clockwise...");
  myStepper.step(-stepsPerRevolution);
 delay(10);
    rainbow(30);
      delay(10);

}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i*1+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } 
  else if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } 
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  }

So try that again, post the error message.

If you aren't going to try the suggestions, you won't get too far.

You prolly did something wrong simlpl enough to fix.

a7

See if this runs the stepper and the neopixels as you want

#include <Stepper.h>
#include <Adafruit_NeoPixel.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
const int ledPin = 4;
const int numLeds = 1;
Stepper myStepper(stepsPerRevolution, 3, 1, 2, 0);
Adafruit_NeoPixel strip(numLeds, ledPin, NEO_GRB + NEO_KHZ800);

void rainbow() {
  static uint8_t i = 0;
  static uint8_t j = 0;

  for (i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, Wheel((i * 1 + j) & 255));
  }
  strip.show();
  j++;
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

void setup() {
  strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) 
  myStepper.setSpeed(12);
  Serial.begin(115200);
}

void loop() {
  myStepper.step(-1);

  static unsigned long lastTime = 0;
  if (millis() - lastTime >= 30)
  {
    lastTime = millis();
    rainbow();
  }
  
}
1 Like

I think this is the library for the 28BYj48 (not Stepper.h)

Thank you so much for your help. It is exactly working the way it needs. One last thing, is there a way to adjust the time that it takes to cycle through rainbow colour to make it slower?
Thank you

Look at the code. See what the number 30 is doing, then use your best common sense to answer your own question.

a7

I did try to add the 30 to the loop but then I get an error as per picture. I am very sorry for my capability at coding as I am very new and am trying to understand

This common pattern, which you will know about when you find time to look at "blink without delay" and the other pointers that may have been provided on this thread or things than turn up when you search

  static unsigned long lastTime = 0;
  if (millis() - lastTime >= 30)
  {
    lastTime = millis();
    rainbow();
  }

calls rainbow() to take a single step every 30 milliseconds.

What might you change to make it call rainbow() every 60 milliseconds, so as to run the effect at half speed?

What might you change to make it call rainbow() every 15 milliseconds, so as to run the effect at double speed?

You have to start putting your finger o the code and stepping yourself through it to see how it works…

a7

2 Likes

Thank you for your help. Appreciate everyone for taking the time to help me.

3 posts were merged into an existing topic: The fact that something has been used for a long time is in no way an argument for making it the same for another 100 years

At the request of @StefanL38 some posts moved as they were straying away from what @BOOM90 was asking about.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.