Can I reduce this chatter/buzz in my two servos?

Hello,
I've built an Ironman style suit with a helmet with a lifting faceplate using two servos run by an Uno R4 Wifi. The servos are running off of a 12V 10000Ah battery, stepped down using a DC-DC 5V 15A converter. The Uno and lights are powered by a separate 12V 10000Ah battery again with a DC-DC converter for the LEDs. The servo GND is shared, one end using the same pin on the R4 that runs to the battery, and the other grounding to the dedicated servo battery. I also have 16V 10000uF capacitor across the power leads for the servo and a 16V 2200uF capacitor across the LED leads.

I get a lot of jitter/buzz/shake from the servos whenever it's maintaining position, whether under load or not, however sweeping movements are all reasonably smooth. I've read a number of forum posts regarding the R4 and the interupts(?) and the timers used(?). Unfortunately, I'm wayyyy out of my depth, and I've run out of time to understand the intricacies of a deep dive into PWM management for servos (my event is in a week). My understanding is that the Uno R4 PWM frequency is too low and causing this buzzing/shaking. Is there a "simple" fix which I can utilize to reduce this effect? I'm posting my full code below

#include <FastLED.h>
#include <Servo.h>
using namespace fl;  // for FastLED library

// How many leds in each strip?
#define NUM_EYE_LEDS 155     //Not Accurate
#define NUM_BICEP_LEDS 155   //Not Accurate =
#define NUM_BRACER_LEDS 155  //Accurate = 124
#define NUM_THIGH_LEDS 155   //Accurate = 155
#define NUM_SHIN_LEDS 155    //Not Accurate

// Define the array of leds
CRGB eye_leds[NUM_EYE_LEDS];
CRGB bicep_leds[NUM_BICEP_LEDS];
CRGB bracer_leds[NUM_BRACER_LEDS];
CRGB thigh_leds[NUM_THIGH_LEDS];
CRGB shin_leds[NUM_SHIN_LEDS];

// Define the button pins
const byte button1Pin = A0;  // pin for button 1
const byte button2Pin = A1;  // pin for button 2
const byte button3Pin = A2;  // pin for button 3

// Define the states
enum { standby,
       initialized,
       idle,
       attack,
       scanning,
       party,
       just_lights,
       shutDown };
unsigned char suitState;

// create some variables
int brightness = 0;  // brightness of LEDS
int fadeAmount = 0;  // amount to fade
int dur;             // duration of blink
int rep;             // number of repetitions
int angle1;          // angle of servo1
int angle2;          // angle of servo2
uint8_t gHue = 0;    // rotating "base color" used by many of the patterns

// Define the servos
Servo helmet;
Servo helmet2;

void setup() {
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
  pinMode(button3Pin, INPUT_PULLUP);

  helmet.attach(13);
  helmet2.attach(12);
  helmet.write(2);
  helmet2.write(180);

  //Setup the LEDs
  FastLED.addLeds<WS2812, 2, GRB>(bicep_leds, NUM_BICEP_LEDS);
  FastLED.addLeds<WS2812, 3, GRB>(bracer_leds, NUM_BRACER_LEDS);
  FastLED.addLeds<WS2812, 4, GRB>(thigh_leds, NUM_THIGH_LEDS);
  FastLED.addLeds<WS2812, 6, GRB>(shin_leds, NUM_SHIN_LEDS);
  FastLED.addLeds<WS2812, 11, GRB>(eye_leds, NUM_EYE_LEDS);
  FastLED.setBrightness(100);
  suitState = standby;
}

void faceplate_close() {
  helmet.write(2);
  helmet2.write(180);
  for (int i = 0; i < 126; i++) {
    angle1 = 2 + i;    // Ending angle1 == 127 (Closed)
    angle2 = 180 - i;  // Ending angle2 == 55 (Closed)
    helmet.write(angle1);
    helmet2.write(angle2);
    delay(10);
  }
  delay(1000);
}

void faceplate_open() {
  // Faceplate Open
  for (int i = 0; i < 126; i++) {
    angle1 = 127 - i;  // Ending angle1 == 2 (Open)
    angle2 = 55 + i;   // Ending angle2 == 180 (Open)
    helmet.write(angle1);
    helmet2.write(angle2);
    delay(10);
  }
  delay(500);
}

void power_up() {
  for (int dur = 200; dur > 0; dur -= 15) {
    for (int rep = 0; rep < 11; rep += 1) {
      if (rep < 10) {
        for (int i = 0; i < NUM_THIGH_LEDS; i++) {
          eye_leds[i] = CRGB::Blue;     //apply the brightness
          bicep_leds[i] = CRGB::Blue;   //apply the brightness
          bracer_leds[i] = CRGB::Blue;  //apply the brightness
          thigh_leds[i] = CRGB::Blue;   //apply the brightness
          shin_leds[i] = CRGB::Blue;    //apply the brightness
        }
        FastLED.show(100);
        delay(1);
        for (int i = 0; i < NUM_THIGH_LEDS; i++) {
          eye_leds[i] = CRGB::Black;     //apply the brightness
          bicep_leds[i] = CRGB::Black;   //apply the brightness
          bracer_leds[i] = CRGB::Black;  //apply the brightness
          thigh_leds[i] = CRGB::Black;   //apply the brightness
          shin_leds[i] = CRGB::Black;    //apply the brightness
        }
        FastLED.show(0);
        delay(dur);
      }
      if (rep == 10) {
        for (int b = 50; b < 100; b++) {
          for (int i = 0; i < NUM_THIGH_LEDS; i++) {
            eye_leds[i] = CRGB::Blue;     //apply the brightness
            bicep_leds[i] = CRGB::Blue;   //apply the brightness
            bracer_leds[i] = CRGB::Blue;  //apply the brightness
            thigh_leds[i] = CRGB::Blue;   //apply the brightness
            shin_leds[i] = CRGB::Blue;    //apply the brightness
          }
          FastLED.show(b);
        }
      } else {
        break;
      }
    }
  }
}

void power_down() {
  for (int dur = 2; dur < 200; dur += 35) {
    for (int rep = 10; rep >= 0; rep -= 1) {
      if (rep > 0) {
        for (int i = 0; i < NUM_THIGH_LEDS; i++) {
          eye_leds[i] = CRGB::Blue;     //apply the brightness
          bicep_leds[i] = CRGB::Blue;   //apply the brightness
          bracer_leds[i] = CRGB::Blue;  //apply the brightness
          thigh_leds[i] = CRGB::Blue;   //apply the brightness
          shin_leds[i] = CRGB::Blue;    //apply the brightness
        }
        FastLED.show(100);
        delay(1);
        for (int i = 0; i < NUM_THIGH_LEDS; i++) {
          eye_leds[i] = CRGB::Black;     //apply the brightness
          bicep_leds[i] = CRGB::Black;   //apply the brightness
          bracer_leds[i] = CRGB::Black;  //apply the brightness
          thigh_leds[i] = CRGB::Black;   //apply the brightness
          shin_leds[i] = CRGB::Black;    //apply the brightness
        }
        FastLED.show(0);
        delay(dur);
      }
      if (rep == 10) {
        for (int b = 100; b > 100; b--) {
          for (int i = 0; i < NUM_THIGH_LEDS; i++) {
            eye_leds[i] = CRGB::Blue;     //apply the brightness
            bicep_leds[i] = CRGB::Blue;   //apply the brightness
            bracer_leds[i] = CRGB::Blue;  //apply the brightness
            thigh_leds[i] = CRGB::Blue;   //apply the brightness
            shin_leds[i] = CRGB::Blue;    //apply the brightness
          }
          FastLED.show(b);
        }
      } else {
        break;
      }
    }
  }
  delay(500);
}

void blue_lights() {
  fill_solid(eye_leds, NUM_EYE_LEDS, CRGB::Blue);
  fill_solid(bicep_leds, NUM_BICEP_LEDS, CRGB::Blue);
  fill_solid(bracer_leds, NUM_BRACER_LEDS, CRGB::Blue);
  fill_solid(thigh_leds, NUM_THIGH_LEDS, CRGB::Blue);
  fill_solid(shin_leds, NUM_SHIN_LEDS, CRGB::Blue);
  FastLED.show(100);
}

void danger_lights() {
  // Increase Brightness
  for (int b = 0; b < 100; b++) {
    for (int i = 0; i < NUM_THIGH_LEDS; i++) {
      eye_leds[i] = CRGB::Red;     //apply the brightness
      bicep_leds[i] = CRGB::Red;   //apply the brightness
      bracer_leds[i] = CRGB::Red;  //apply the brightness
      thigh_leds[i] = CRGB::Red;   //apply the brightness
      shin_leds[i] = CRGB::Red;    //apply the brightness
    }
    FastLED.show(b);

    if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from attack
      suitState = scanning;  // The suit goes to scan
      delay(1000);
      break;
    }
    if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from attack
      suitState = idle;  // The suit goes back to idle
      delay(1000);
      break;
    }
    delay(10);
  }
  // Then decrease Brightness
  for (int b = 100; b > 0; b--) {
    for (int i = 0; i < NUM_BICEP_LEDS; i++) {
      eye_leds[i] = CRGB::Red;     //apply the brightness
      bicep_leds[i] = CRGB::Red;   //apply the brightness
      bracer_leds[i] = CRGB::Red;  //apply the brightness
      thigh_leds[i] = CRGB::Red;   //apply the brightness
      shin_leds[i] = CRGB::Red;    //apply the brightness
    }
    FastLED.show(b);
    if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from attack
      suitState = scanning;  // The suit goes to scan
      delay(1000);
      break;
    }
    if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from attack
      suitState = idle;  // The suit goes back to idle
      delay(1000);
      break;
    }
    delay(10);
  }
}

void standby_lights() {
  fill_solid(eye_leds, NUM_EYE_LEDS, CRGB::Black);
  fill_solid(bicep_leds, NUM_BICEP_LEDS, CRGB::Black);
  fill_solid(bracer_leds, NUM_BRACER_LEDS, CRGB::Black);
  fill_solid(thigh_leds, NUM_THIGH_LEDS, CRGB::Black);
  fill_solid(shin_leds, NUM_SHIN_LEDS, CRGB::Black);
  FastLED.show();
}

void fadeall() {
  for (int i = 0; i < NUM_BICEP_LEDS; i++) {
    eye_leds[i] = CHSV(150, 255, 50);
    bicep_leds[i] = CHSV(150, 255, 50);
    //bicep_leds[i + 1] = CHSV(200, 255, 50);
    bracer_leds[i] = CHSV(150, 255, 50);
    //bracer_leds[i + 1] = CHSV(200, 255, 50);
    thigh_leds[i] = CHSV(150, 255, 50);
    //thigh_leds[i + 1] = CHSV(200, 255, 50);
    shin_leds[i] = CHSV(150, 255, 50);
    //shin_leds[i + 1] = CHSV(200, 255, 50);
  }
}

void cylon() {
  if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from scanning
    suitState = idle;                     // The suit goes back to idle
    delay(500);
    return;
  }
  // First slide the led in one direction
  for (int i = 0; i < NUM_THIGH_LEDS; i++) {
    // Set the i'th led to red
    eye_leds[i] = CHSV(100, 255, 150);
    bicep_leds[i] = CHSV(100, 255, 150);
    //bicep_leds[i + 1] = CHSV(250, 255, 255);
    bracer_leds[i] = CHSV(100, 255, 150);
    //bracer_leds[i + 1] = CHSV(250, 255, 255);
    thigh_leds[i] = CHSV(100, 255, 150);
    //thigh_leds[i + 1] = CHSV(250, 255, 255);
    shin_leds[i] = CHSV(100, 255, 150);
    //shin_leds[i + 1] = CHSV(250, 255, 255);
    // Show the leds
    FastLED.show();
    if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from scan
      suitState = party;  // The suit goes to party
      delay(1000);
      break;
    }
    if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from scan
      suitState = idle;  // The suit goes back to idle
      delay(1000);
      break;
    }
    // now that we've shown the leds, reset to blue
    delay(2);
    fadeall();
  }
  // Now go in the other direction.
  for (int i = (NUM_THIGH_LEDS)-1; i >= 0; i--) {
    // Set the i'th to i'th+5 led to green
    eye_leds[i] = CHSV(100, 255, 150);
    bicep_leds[i] = CHSV(100, 255, 150);
    //bicep_leds[i + 1] = CHSV(250, 255, 255);
    bracer_leds[i] = CHSV(100, 255, 150);
    //bracer_leds[i + 1] = CHSV(250, 255, 255);
    thigh_leds[i] = CHSV(100, 255, 150);
    //thigh_leds[i + 1] = CHSV(250, 255, 255);
    shin_leds[i] = CHSV(100, 255, 150);
    //shin_leds[i + 1] = CHSV(250, 255, 255);
    // Show the leds
    FastLED.show();
    if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from scan
      suitState = party;  // The suit goes to party
      delay(1000);
      break;
    }
    if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from scan
      suitState = idle;  // The suit goes back to idle
      delay(1000);
      break;
    }
    // now that we've shown the leds, reset the i'th led to black
    // leds[i] = CRGB::Black;
    delay(2);
    fadeall();
  }
}

void pride() {
  EVERY_N_MILLISECONDS(20) {
    gHue++;
  }
  fill_rainbow(eye_leds, NUM_EYE_LEDS, gHue, 7);
  fill_rainbow(bicep_leds, NUM_BICEP_LEDS, gHue, 7);
  fill_rainbow(bracer_leds, NUM_BRACER_LEDS, gHue, 7);
  fill_rainbow(thigh_leds, NUM_THIGH_LEDS, gHue, 7);
  fill_rainbow(shin_leds, NUM_SHIN_LEDS, gHue, 7);
  FastLED.show();
}

void loop() {
  switch (suitState) {
    case standby:  // Suit is standby, nothing happening, waiting for input
      standby_lights();
      if (digitalRead(button1Pin) == HIGH) {
        suitState = initialized;  //Initialize the suit
        delay(1000);
        break;
      } else {  // No buttons pressed
        break;  // State remains the same, continue
      }

    case initialized:  // Suit turns on and helmet closes
      delay(10);
      for (int i = 0; i < 126; i++) {
        angle1 = 2 + i;    // Ending angle1 == 127 (Closed)
        angle2 = 180 - i;  // Ending angle2 == 55 (Closed)
        helmet.write(angle1);
        helmet2.write(angle2);
        delay(10);
      }
      power_up();
      blue_lights();
      suitState = idle;  // The suit is now idle
      delay(500);
      break;

    case idle:  // Suit lights are on, awaiting further presses
      blue_lights();
      if (digitalRead(button1Pin) == HIGH) {  // button 1 pressed from idle
        suitState = shutDown;                 // The suit is now shutting down
        break;
      }
      if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from idle
        suitState = attack;                   // The suite is now in attack mode
        delay(1000);
        break;
      }
      if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from idle
        suitState = just_lights;              // The suit is now in scanning mode
        delay(1000);
        break;
      } else {
        break;  // if no buttons pressed, remain idle
      }

    case attack:  // Suit lights change to red
      // insert what to do here for attack mode
      danger_lights();
      if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from attack
        suitState = idle;  // The suit goes back to idle
        delay(1000);
        break;
      }
      if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from attack
        suitState = party;                    // The suit goes into party mode
        delay(1000);
        break;
      } else {
        break;
      }

    case scanning:
      cylon();
      break;

    case party:
      // insert what to do here for party mode
      pride();
      if (digitalRead(button2Pin) == HIGH) {  // button 2 pressed from party
        suitState = idle;  // The suit goes to idle
        delay(1000);
        break;
      }
      if (digitalRead(button3Pin) == HIGH) {  // button 3 pressed from scan
        suitState = idle;  // The suit goes back to idle
        delay(1000);
        break;
      } else {
        break;
      }

    case just_lights:
      helmet.write(2);
      helmet2.write(180);
      blue_lights();
      if (digitalRead(button1Pin) == HIGH) {  // button 1 pressed from standby with lights
        faceplate_close();
        suitState = idle;  //Faceplate closes and suit goes to idle
        delay(500);
        break;
      } else {
        break;
      }

    case shutDown:
      power_down();
      delay(1000);
      faceplate_open();
      delay(1000);
      suitState = standby;  // The suit turns standby
      break;
  }
}

Have you tried a simple sketch that does nothing but set a servo to a position and see if the problem persists? And by nothing I mean no FastLED, one servo, set to a position in setup() and then an empty loop. The result would be a quick way to discover whether you should be investigating a software or hardware issue.

1 Like

I had previously, but not recently, I'll do that rn.

Edit: Using this code, I got a similar amount of audible noise, but much less physical shaking.

#include <Servo.h>

// Define the servos
Servo helmet;
Servo helmet2;

void setup() {
  // put your setup code here, to run once:

  helmet.attach(13);
  helmet2.attach(12);
  helmet.write(2);
  helmet2.write(180);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Yes you will. This is because a servo has variable resistor in it that is used to monitor the actual position and then adjust its position in order to maintain it. This will cause buzzing especially when it is stationary at some positions.

The trick is to find values to send the servo to places where the buzzing is minimised. So instead of using degrees to specify the position of the servo, use the writeMicroseconds method to allow you to specify a position more precisely and find spots where the jittering does not occur.

This is from the page:-
servo libraries
Have a look at this.
You say:-

No this is not the cause.

You sure of that? It seems quite a large battery.

Wow, 100 car batteries in parrallel!
Don't make a short!

2 Likes

You could detach the servo if it isn't holding position under load.

You didn't say what exact servos you have, a better brand and model weight do, um, better.

Digital servos have a superior feedback and control system. It might be worth trying that.

a7

Two servos is not the same as one servo. And I strongly suggested starting with one servo.

Good luck with your project.

1 Like

oh my gosh, you're so right about the size of the battery its 10000mAH