Did I get this schematic right? Uno R3 + MG996R servo + WS2815

Hello all, I'm a newb to electronics, and this is my first time posting.

I'm using an Uno R3 to run a MG996R servo, and a cluster of 6 short WS2815 strips in parallel, of 9 LEDs each, and all LEDs will be on at the same time. Each of these components will be powered by its own separate power source.

I also have a mini breadboard for mounting pieces, and being able to make secure wire connections and have a common ground.

I was a little overwhelmed reading through so much information and differing opinions about adding resistors or capacitors, so I wanted to double check that I got things right. I have two 470uf capacitors on the servo power, and a 330 ohm resistor on the data line running to the parallel WS2815 strips.

Do I need any additional components? In line fuses anywhere? Thanks!

  • All 6 strips are in parallel, you might need a driver if things don’t work as expected.

  • Good work on your wiring diagram.

1 Like

Apart from the wiring of the WS2815. You don't actually wire them like this. They are a strip, with two data inputs, and all the rest is chained.
See this

Also I hope that none of these external power sources are batteries. If so you will run into trouble.

It should certainly be possible to run strips in parallel as well, as long as you wanted them to always display the same colors/patterns. Less overhead for the Uno. Like LarryD, I don't know if an AVR adta output is quite up to driving 6 parallel strips.

1 Like

The WS2815s are on a chained strip, but I'm going to have 6 parallel strips of 9 LED's each... I know it's weird, but these short strips will be arranged around an object like a bulb. So there will only be 54 LEDs lit at once, so hopefully not enough power draw to require a driver?

And no batteries, they'll all be connected to 110v and converted to the output shown.

It's not "power draw" that is a concern here (you already have a nice separate power supply for the LEDs.)
It's the integrity of the data SIGNAL value as load (capacitance and resistance) is added.

1 Like

Ahh, that's super helpful. I could split the strip array into two parts, and have 3 on one data pin, and 3 on another data pin, and just have the program output the same signal to both of them, like this?

No.
This is because after each LED in the strip the signal is regenerated, so the main problem with signal integrate will be from the output to your chip.
Use a series resistor of 200 to 450Ω along with a large capacitor, like 100uF or bigger between power and ground at both ends of the strip.

1 Like

Hello! I'm trying to use a ESP-WROOM-32 to control a MG996R servo and two clusters of WS2815 strips, but I'm running into problems. The servo should sweep slowly from 40° to 140°, but it's very jerky and has large unexpected movements, and the LEDs aren't lighting up. The servo works relatively smoothly when I use the FastLED library, but goes bonkers when I use the NeoPixel library.

I've successfully made LED strip clusters like this before with an ESP32, but I was using WS2812s and not WS2815s, and used FastLED instead of NeoPixel too. I think I need to add a logic level shifter like a TXS0108E to bump the data signal from 3.3v to 5v, right? Or is there a simpler method that wouldn't invert the logic?

Here's my wiring diagram and all the code, which ChatGPT helped me with, which is likely part of the problem too. I'd love any feedback on how I can improve this!

#include <ESP32Servo.h>            // Use ESP32-specific Servo library
#include <Adafruit_NeoPixel.h>     // Include Adafruit NeoPixel library

#define LED_PIN_1 26               // First LED strip data pin
#define LED_PIN_2 33               // Second LED strip data pin
#define NUM_LEDS 9                 // Number of LEDs per strip
#define BRIGHTNESS_MIN 155         // Minimum brightness at 40 degrees
#define BRIGHTNESS_MAX 255         // Maximum brightness at 140 degrees
#define COLOR_CHANGE_INTERVAL 15000 // Color change interval in milliseconds

#define SERVO_PIN 12               // MG996R servo control pin
#define START_ANGLE 40             // Start angle
#define END_ANGLE 140              // End angle
#define UP_DURATION 4000           // Time to move from 40 to 140 degrees (in milliseconds)
#define DOWN_DURATION 6000         // Time to move from 140 to 40 degrees (in milliseconds)
#define SERVO_UPDATE_INTERVAL 20   // Servo update interval (in milliseconds)

Servo myServo;

Adafruit_NeoPixel strip1(NUM_LEDS, LED_PIN_1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2(NUM_LEDS, LED_PIN_2, NEO_GRB + NEO_KHZ800);

uint32_t colors[] = {
  strip1.Color(255, 0, 255), // Magenta
  strip1.Color(0, 255, 255), // Teal
  strip1.Color(255, 165, 0), // Orange
  strip1.Color(0, 0, 255),   // Blue
  strip1.Color(255, 255, 0)  // Yellow
};

int colorIndex = 0;
unsigned long lastColorChangeTime = 0;
unsigned long servoStartTime = 0;
unsigned long lastServoUpdateTime = 0;
bool movingUp = true;
int currentAngle = START_ANGLE;
int lastAngle = START_ANGLE; // Track last servo angle

void setup() {
  Serial.begin(115200);

  // Initialize servo

  myServo.attach(SERVO_PIN, 500, 2500); // Set pulse range (500 to 2500 µs for MG996R)
  myServo.write(START_ANGLE); // Move servo to the initial start position - 40deg
  servoStartTime = millis();
  lastServoUpdateTime = millis();

  // Initialize LED strips
  strip1.begin();
  strip2.begin();
  strip1.setBrightness(BRIGHTNESS_MIN);
  strip2.setBrightness(BRIGHTNESS_MIN);
  strip1.show(); // Initialize to all LEDs off
  strip2.show();
  delay(10); // Give some time for LEDs to initialize

  // Set initial color
  setAllLEDs(colors[colorIndex]);
}

void loop() {
  // Update servo position
  updateServo();

  // Update LED colors and brightness
  updateLEDColor();
}

// Function to handle smooth servo movement
void updateServo() {
  unsigned long currentTime = millis();
  unsigned long duration = movingUp ? UP_DURATION : DOWN_DURATION;
  int startAngle = movingUp ? START_ANGLE : END_ANGLE;
  int endAngle = movingUp ? END_ANGLE : START_ANGLE;

  // Check if the servo needs to switch direction
  if (currentTime - servoStartTime >= duration) {
    servoStartTime = currentTime;
    movingUp = !movingUp;
  }

  // Update the servo position only if enough time has passed
  if (currentTime - lastServoUpdateTime >= SERVO_UPDATE_INTERVAL) {
    lastServoUpdateTime = currentTime;

    // Calculate smooth sine wave progress
    float progress = (float)(currentTime - servoStartTime) / duration;
    float sineProgress = (1 - cos(progress * PI)) / 2; // Smooth transition
    int targetAngle = startAngle + sineProgress * (endAngle - startAngle);

    // Update the servo only if the target angle has changed to avoid jitter
    if (abs(targetAngle - lastAngle) > 1) {
      myServo.write(targetAngle);
      lastAngle = targetAngle;

      // Adjust LED brightness based on servo position
      int brightness = map(targetAngle, START_ANGLE, END_ANGLE, BRIGHTNESS_MIN, BRIGHTNESS_MAX);
      strip1.setBrightness(brightness);
      strip2.setBrightness(brightness);
      strip1.show();
      strip2.show();
    }
  }
}

// Function to update the LED color fading effect
void updateLEDColor() {
  unsigned long currentTime = millis();

  // Change color every COLOR_CHANGE_INTERVAL milliseconds
  if (currentTime - lastColorChangeTime >= COLOR_CHANGE_INTERVAL) {
    lastColorChangeTime = currentTime;
    colorIndex = (colorIndex + 1) % (sizeof(colors) / sizeof(colors[0]));
  }

  // Smoothly transition between colors
  float progress = (float)(currentTime - lastColorChangeTime) / COLOR_CHANGE_INTERVAL;
  int nextColorIndex = (colorIndex + 1) % (sizeof(colors) / sizeof(colors[0]));
  uint32_t blendedColor = blendColor(colors[colorIndex], colors[nextColorIndex], progress * 255);

  // Update both LED strips with the new blended color
  setAllLEDs(blendedColor);
}

void setAllLEDs(uint32_t color) {
  for (int i = 0; i < NUM_LEDS; i++) {
    strip1.setPixelColor(i, color);
    strip2.setPixelColor(i, color);
  }
  strip1.show();
  strip2.show();
}

// Helper function to blend between two colors
uint32_t blendColor(uint32_t color1, uint32_t color2, uint8_t blendAmount) {
  uint8_t r1 = (color1 >> 16) & 0xFF;
  uint8_t g1 = (color1 >> 8) & 0xFF;
  uint8_t b1 = color1 & 0xFF;

  uint8_t r2 = (color2 >> 16) & 0xFF;
  uint8_t g2 = (color2 >> 8) & 0xFF;
  uint8_t b2 = color2 & 0xFF;

  uint8_t rBlend = r1 + ((r2 - r1) * blendAmount / 255);
  uint8_t gBlend = g1 + ((g2 - g1) * blendAmount / 255);
  uint8_t bBlend = b1 + ((b2 - b1) * blendAmount / 255);

  return strip1.Color(rBlend, gBlend, bBlend);
}

So if I add the TXS0108E logic level converter, I think I add it to the system like this? I want to have the ESP32 powered by its own USB cable so that i don't accidentally fry it when I do code updates, so I'll get a USB wall wart with 2 slots and output one to the ESP32 and one to the converter.

possibly a problem with Migration from ESP32 Arduino Core 2.x to 3.x
I have had problems with the Adafruit_NeoPixel library when using more than 85 LEDs
maybe worth trying ESP32 core 2.0.17

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