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;
}
}