This is not a question but code is below for review and improvement. If you're struggling with non blocking code, this may lead you to a solution.
Goal: At the top of the crow's nest on a pirate ship there is a crow's skeleton. One servo to move the wings, multiple LED's around the edge of the nest, one with a "heartbeat" effect for this project. More details as it emerges.
The hard part (for me) was getting the heartbeat. There are many examples out there but I settled on the "timeline" approach. As the millis increases and reaches a specific point, the LED switches on or off depending on where we are in the "timeline" array. Works as expected.
- 2 amp 5v wall wart power supply
- Nano clone
- 8 red LED's around nest
- 1 red LED for heartbeat
- 2 small yellow LED's for eyes
- Lots of hot melt glue and a little 22ga wire
- Piano wire to move the wings and beak
/* Crow's Nest 09-28-24
* See finished video for effect. We have a crow skeleton in a pirate
* ship crow's nest. Servo moves the wings and beak, LED is positioned
* in the chest to emulate a heartbeat from a single LED. There are
* static LED's in the eyes and rim of the nest, powered by the same
* 5v source as the arduino.
*/
#include <Servo.h>
// pin assignments
const int heartPin = 3;
const int servoPin = 4;
// Servo variables
Servo myservo;
// Keep track of servo direction. 1 increase angle, 0 decrease angle
int dir = 1;
// Keep track of the last time servo was moved
unsigned long startTimeServo;
// Pause at the end of each sweep
unsigned long servoPause = 1000;
// Increasing the value increases servo speed.
unsigned int servoSpeed = 4;
// Start and stop, 0 to 180.
int startAngle = 20;
int stopAngle = 110;
// Keep track of current servo position
int pos = startAngle;
// LED heartbeat blink variables. Set up an array as a "timeline" to switch on
// and off. off, on, off, on, off with pause.
int timeline[] = { 0, 50, 150, 190, 1000 };
// Track the current index of the array
int index = 0;
// Track the last time the LED was turned on or off.
unsigned long ledCurrentTime = 0;
/*
* attach pins and servo, delay by half a second to allow the servo to home.
* @return void
*/
void setup()
{
// Serial.begin(9600);
pinMode(heartPin, OUTPUT);
myservo.attach(servoPin);
myservo.write(pos);
delay(500);
startTimeServo = ledCurrentTime = millis();
}
/*
* Call the heartbeat and servo move.
* @return void
*/
void loop()
{
heartBeat();
moveServo();
}
/*
* Heartbeat
* move along the timeline array to turn led's on and off
* @return void
*/
void heartBeat()
{
unsigned long currentMillis = millis();
if (index >= 5) { index = 0; }
// Ensure LED starts LOW or it will invert the pattern.
if ((index == 0) && (digitalRead(heartPin)) == HIGH) {
digitalWrite(heartPin, LOW);
}
if (currentMillis - ledCurrentTime >= timeline[index]) {
//Serial.println("Switch led index " + String(index) + " value " + String(timeline[index]) + " read pin " + String(digitalRead(heartPin)) + " Set to " + String(!digitalRead(heartPin)));
ledCurrentTime = currentMillis;
index++;
digitalWrite(heartPin, !digitalRead(heartPin));
}
}
/*
* Move the servo. Pauses by servoPause at the end of each sweep.
* This code is a little smelly but it works and enough is enough. :-P
* @return void
*/
void moveServo()
{
unsigned long currentTimeServo = millis();
if (currentTimeServo - startTimeServo >= servoSpeed) {
if (pos >= stopAngle) {
if (currentTimeServo - startTimeServo <= servoPause) {
return;
}
dir = 0;
}
if (pos <= startAngle) {
if (currentTimeServo - startTimeServo <= servoPause) {
return;
}
dir = 1;
}
startTimeServo = currentTimeServo;
pos = (dir == 1)? ++pos : --pos;
myservo.write(pos);
}
}