Uses 11 motors and lights
>1200 Watts DC Power Max
Practical Max: 326 W
List of electrical parts:
Fuse box
Vehicle LED Headlights
Power Supply (12V and 36V)
Relays (Controlled by Teensy)
Waterproof NEMA 17 Stepper Motors
Motor Drivers
Capacitors, Thermistors, buck converter, bus bar
// Define motor directions
#define CW HIGH
#define CCW LOW
const int dotLength = 250;
const int dashLength = dotLength * 3;
const int intraCharGap = dotLength;
const int interCharGap = dotLength * 3;
const int interWordGap = dotLength * 7;
String morse(char c) {
switch (toupper(c)) {
case 'A': return ".-";
case 'B': return "-...";
case 'C': return "-.-.";
case 'D': return "-..";
case 'E': return ".";
case 'F': return "..-.";
case 'G': return "--.";
case 'H': return "....";
case 'I': return "..";
case 'J': return ".---";
case 'K': return "-.-";
case 'L': return ".-..";
case 'M': return "--";
case 'N': return "-.";
case 'O': return "---";
case 'P': return ".--.";
case 'Q': return "--.-";
case 'R': return ".-.";
case 'S': return "...";
case 'T': return "-";
case 'U': return "..-";
case 'V': return "...-";
case 'W': return ".--";
case 'X': return "-..-";
case 'Y': return "-.--";
case 'Z': return "--..";
default: return ""; // ignore numbers, punctuation, etc.
}
}
// Pin definitions for motors (PUL, DIR)
const int motorPins[12][2] = {
{ 0, 0 }, // Index 0 unused
{ 9, 4 }, // Motor 1: C
{ 1, 0 }, // Motor 2: Rv
{ 6, 5 }, // Motor 3: Rc
{ 3, 2 }, // Motor 4: Ra
{ 13, 41 }, // Motor 5: A1
{ 16, 14 }, // Motor 6: A2
{ 18, 17 }, // Motor 7: Ft
{ 20, 19 }, // Motor 8: Fv
{ 22, 21 }, // Motor 9: Fm
{ 23, 12 }, // Motor 10: Tv
{ 10, 11 } // Motor 11: Tt
};
// Initial directions
const bool initialDirection[12] = {
false, // Index 0 unused
CCW, // Motor 1: CCW
CCW, // Motor 2: CCW
CW, // Motor 3: CW
CCW, // Motor 4: CCW
CW, // Motor 5: CW
CCW, // Motor 6: CCW
CCW, // Motor 7: CCW
CCW, // Motor 8: CCW
CCW, // Motor 9: CCW
CCW, // Motor 10: CCW
CCW // Motor 11: CCW
};
// Step counts for each motor
const int motorSteps[12] = {
0,
3500,
2163,
4150,
2525,
4800,
4840,
3545,
4200,
1952,
4200,
2451
};
const int lightPins[12] = { 0, 26, 30, 33, 29, 34, 35, 40, 32, 40, 38, 36 };
const int lightPins2[11] = { 0, 26, 30, 33, 29, 34, 35, 32, 40, 38, 36 };
const int lightShowTime[5] = { 0, 100, 1, 1000, 200 }; //[1] = on time [2] = off time [3] = hold after sequence [4] = hold between full light shows
void stepMotor(int motor, bool dir, int steps) {
int pulPin = motorPins[motor][0];
int dirPin = motorPins[motor][1];
digitalWrite(dirPin, dir);
for (int i = 0; i < steps; i++) {
digitalWrite(pulPin, HIGH);
delay(1);
digitalWrite(pulPin, LOW);
delay(1);
}
}
void blinkSymbol(char symbol) {
for (int i = 0; i < 11; i++) {
digitalWrite(lightPins[i], HIGH);
}
delay(symbol == '.' ? dotLength : dashLength);
for (int i = 0; i < 11; i++) {
digitalWrite(lightPins[i], LOW);
}
delay(intraCharGap); // Space between parts of a letter
}
void sendMorse(String message) {
for (int i = 0; i < message.length(); i++) {
char c = message[i];
if (c == ' ') {
delay(interWordGap);
} else {
String code = morse(c);
for (int j = 0; j < code.length(); j++) {
blinkSymbol(code[j]);
}
delay(interCharGap - intraCharGap); // Adjust for extra intraChar delay
}
}
}
void dualMotorDoubleSpeed(int motor1, bool dir1, int steps1, int motor2, bool dir2) {
int pulPin1 = motorPins[motor1][0];
int dirPin1 = motorPins[motor1][1];
int pulPin2 = motorPins[motor2][0];
int dirPin2 = motorPins[motor2][1];
digitalWrite(dirPin1, dir1);
digitalWrite(dirPin2, dir2);
for (int i = 0; i < steps1; i++) {
digitalWrite(pulPin1, HIGH);
digitalWrite(pulPin2, HIGH);
delay(1);
digitalWrite(pulPin1, LOW);
digitalWrite(pulPin2, LOW);
delay(1);
digitalWrite(pulPin1, HIGH);
delay(1);
digitalWrite(pulPin1, LOW);
delay(1);
}
}
void dualMotor(int motor1, bool dir1, int steps1, int motor2, bool dir2) {
int pulPin1 = motorPins[motor1][0];
int dirPin1 = motorPins[motor1][1];
int pulPin2 = motorPins[motor2][0];
int dirPin2 = motorPins[motor2][1];
digitalWrite(dirPin1, dir1);
digitalWrite(dirPin2, dir2);
for (int i = 0; i < steps1; i++) {
digitalWrite(pulPin1, HIGH);
digitalWrite(pulPin2, HIGH);
delay(1);
digitalWrite(pulPin1, LOW);
digitalWrite(pulPin2, LOW);
delay(1);
}
}
void tripMotor(int motor1, bool dir1, int steps1, int motor2, bool dir2, int motor3, bool dir3) {
int pulPin1 = motorPins[motor1][0];
int dirPin1 = motorPins[motor1][1];
int pulPin2 = motorPins[motor2][0];
int dirPin2 = motorPins[motor2][1];
int pulPin3 = motorPins[motor3][0];
int dirPin3 = motorPins[motor3][1];
digitalWrite(dirPin1, dir1);
digitalWrite(dirPin2, dir2);
digitalWrite(dirPin3, dir3);
for (int i = 0; i < steps1; i++) {
digitalWrite(pulPin1, HIGH);
digitalWrite(pulPin2, HIGH);
digitalWrite(pulPin3, HIGH);
delay(1);
digitalWrite(pulPin1, LOW);
digitalWrite(pulPin2, LOW);
digitalWrite(pulPin3, LOW);
delay(1);
}
}
void runLightSequence() {
for (int i = 1; i < 7; i++) {
digitalWrite(lightPins[i], HIGH);
delay(lightShowTime[1]);
digitalWrite(lightPins[i], LOW);
delay(lightShowTime[2]);
}
digitalWrite(lightPins[8], HIGH);
delay(lightShowTime[1]);
digitalWrite(lightPins[8], LOW);
delay(lightShowTime[2]);
digitalWrite(lightPins[7], HIGH);
delay(lightShowTime[1]);
digitalWrite(lightPins[7], LOW);
delay(lightShowTime[2]);
for (int i = 10; i < 12; i++) {
digitalWrite(lightPins[i], HIGH);
delay(lightShowTime[1]);
digitalWrite(lightPins[i], LOW);
delay(lightShowTime[2]);
}
}
void fullLightSequence() {
runLightSequence();
delay(lightShowTime[3]);
for (int i = 1; i < 12; i++) digitalWrite(lightPins[i], HIGH);
delay(lightShowTime[1]);
for (int i = 1; i < 12; i++) digitalWrite(lightPins[i], LOW);
delay(lightShowTime[4]);
for (int i = 1; i < 12; i++) digitalWrite(lightPins[i], HIGH);
delay(lightShowTime[1]);
for (int i = 1; i < 12; i++) digitalWrite(lightPins[i], LOW);
runLightSequence();
}
void buildingLights() {
for (int j = 1; j <= 11; j++) {
for (int i = 1; i <= 11; i++) {
digitalWrite(lightPins2[i], HIGH);
delay(100);
if (i > j) {
digitalWrite(lightPins2[i], LOW);
}
}
digitalWrite(lightPins2[j], HIGH);
}
}
void setup() {
for (int i = 1; i <= 11; i++) {
pinMode(motorPins[i][0], OUTPUT);
pinMode(motorPins[i][1], OUTPUT);
pinMode(lightPins[i], OUTPUT);
}
// Open with light show
fullLightSequence();
// Prep C, Rv, A1, Ft, Fm, Tt, Fc
tripMotor(1, CW, motorSteps[2], 2, CCW, 5, CW); // Finish Rv
tripMotor(1, CW, 3000 - motorSteps[2], 8, CCW, 5, CW); //Finish C
dualMotor(8, CCW, motorSteps[5] - 3000, 5, CW); //Finish A1
//tripMotor(9, CCW, motorSteps[9] - motorSteps[5] + 3000, 7, CCW, 11, CCW); //Finish Fm
//tripMotor(7, CCW, motorSteps[7] - motorSteps[9] - 3000 + motorSteps[2], 11, CCW, 8, CCW); //Finish Ft
//dualMotor(11, CCW, motorSteps[11] + motorSteps[5] - motorSteps[2] - motorSteps[7], 8, CCW); //Finish Tt
stepMotor(8, CCW, motorSteps[8] + motorSteps[2] - motorSteps[5]); //Finish Fv
stepMotor(11, CCW, 20);
stepMotor(11, CW, 400);
runLightSequence(); // Acknowledge prep
}
void loop() {
for (int k = 0; k < 25; k++) {
// Start of full show
// Move C
digitalWrite(lightPins[1], HIGH);
stepMotor(1, CCW, motorSteps[1] + motorSteps[2] - motorSteps[3] - 30);
// Finish C and preload RC
dualMotor(1, CCW, motorSteps[3] - motorSteps[2] - motorSteps[2] + 30, 3, CCW);
// Finish C, prep Rv, preload RC
tripMotor(1, CCW, motorSteps[2], 2, CW, 3, CCW);
digitalWrite(lightPins[1], LOW);
// Move Rv and complete prep of Rc
digitalWrite(lightPins[2], HIGH);
dualMotor(2, CCW, motorSteps[2] - 30, 3, CCW);
stepMotor(2, CCW, 30);
digitalWrite(lightPins[2], LOW);
// Move RC
digitalWrite(lightPins[3], HIGH);
stepMotor(3, CW, motorSteps[3] - motorSteps[4]);
// Move RC and start Ra prep
dualMotor(3, CW, motorSteps[4] - motorSteps[5] + motorSteps[4], 4, CCW);
// Move RC, finish Ra prep, preprep A1
tripMotor(3, CW, motorSteps[5] - motorSteps[4], 4, CCW, 5, CCW);
digitalWrite(lightPins[3], LOW);
// Move Ra and finish A1 prep
digitalWrite(lightPins[4], HIGH);
dualMotor(4, CW, motorSteps[4], 5, CCW);
digitalWrite(lightPins[4], LOW);
// Move A1 and prep A2
digitalWrite(lightPins[5], HIGH);
dualMotor(5, CW, motorSteps[6], 6, CCW);
stepMotor(5, CW, motorSteps[5] - motorSteps[6]); // Finish moving A1
digitalWrite(lightPins[5], LOW);
// Move A2 and prep Fv and start prepping Tt
digitalWrite(lightPins[6], HIGH);
tripMotor(6, CW, motorSteps[11], 8, CW, 11, CW);
// Move A2 and prep Fv and start prepping Tv
tripMotor(6, CW, motorSteps[8] - motorSteps[11], 8, CW, 10, CCW);
// Finish moving A2 and prep Tv
stepMotor(6, CW, motorSteps[6] - motorSteps[8]);
digitalWrite(lightPins[6], LOW);
// Move Fv and prep FM and Ft
digitalWrite(lightPins[8], HIGH);
tripMotor(8, CCW, motorSteps[9], 7, CW, 9, CW);
// Move Fv and finish Ft
dualMotor(8, CCW, motorSteps[7] - motorSteps[9], 7, CW);
// Finish moving Fv
stepMotor(8, CCW, motorSteps[8] - motorSteps[7]);
digitalWrite(lightPins[8], LOW);
// Move 7 and 9
digitalWrite(lightPins[7], HIGH);
const int trickySplitter[8] = { 0, 350, 110, 400, 110, 450, 139, 393 };
for (int i = 0; i < 8; i += 2) {
dualMotor(7, CCW, trickySplitter[i], 9, CCW);
dualMotorDoubleSpeed(7, CCW, trickySplitter[i + 1], 9, CCW);
}
digitalWrite(lightPins[7], LOW);
// Move Tt and finish Tv prep
digitalWrite(lightPins[11], HIGH);
dualMotor(11, CCW, motorSteps[10] - motorSteps[8] + motorSteps[11], 10, CCW);
// Finish moving Tt
stepMotor(11, CCW, motorSteps[8] - motorSteps[10]);
digitalWrite(lightPins[11], LOW);
// Move Tv and prep C
digitalWrite(lightPins[10], HIGH);
dualMotor(10, CW, motorSteps[1], 1, CW);
// Move Tv
stepMotor(10, CW, motorSteps[10] - motorSteps[1]);
digitalWrite(lightPins[10], LOW);
// End of full show
//back to a lightshow
fullLightSequence();
//Meld of lightshow and letter movement
// Move C
digitalWrite(lightPins[1], HIGH);
stepMotor(1, CCW, motorSteps[1] + motorSteps[2] - motorSteps[3] - 30);
// Finish C and preload RC
dualMotor(1, CCW, motorSteps[3] - motorSteps[2] - motorSteps[2] + 30, 3, CCW);
// Finish C, prep Rv, preload RC
tripMotor(1, CCW, motorSteps[2], 2, CW, 3, CCW);
// Move Rv and complete prep of Rc
digitalWrite(lightPins[2], HIGH);
dualMotor(2, CCW, motorSteps[2] - 30, 3, CCW);
stepMotor(2, CCW, 30);
// Move RC
digitalWrite(lightPins[3], HIGH);
stepMotor(3, CW, motorSteps[3] - motorSteps[4]);
// Move RC and start Ra prep
dualMotor(3, CW, motorSteps[4] - motorSteps[5] + motorSteps[4], 4, CCW);
// Move RC, finish Ra prep, preprep A1
tripMotor(3, CW, motorSteps[5] - motorSteps[4], 4, CCW, 5, CCW);
// Move Ra and finish A1 prep
digitalWrite(lightPins[4], HIGH);
dualMotor(4, CW, motorSteps[4], 5, CCW);
// Move A1 and prep A2
digitalWrite(lightPins[5], HIGH);
dualMotor(5, CW, motorSteps[6], 6, CCW);
stepMotor(5, CW, motorSteps[5] - motorSteps[6]); // Finish moving A1
// Move A2 and prep Fv and start prepping Tt
digitalWrite(lightPins[6], HIGH);
tripMotor(6, CW, motorSteps[11], 8, CW, 11, CW);
// Move A2 and prep Fv and start prepping Tv
tripMotor(6, CW, motorSteps[8] - motorSteps[11], 8, CW, 10, CCW);
// Finish moving A2 and prep Tv and Tt
stepMotor(6, CW, motorSteps[6] - motorSteps[8]);
// Move Fv and prep FM and Ft
digitalWrite(lightPins[8], HIGH);
tripMotor(8, CCW, motorSteps[9], 7, CW, 9, CW);
// Move Fv and finish Ft
dualMotor(8, CCW, motorSteps[7] - motorSteps[9], 7, CW);
// Finish moving Fv
stepMotor(8, CCW, motorSteps[8] - motorSteps[7]);
// Move 7 and 9
digitalWrite(lightPins[7], HIGH);
for (int i = 0; i < 8; i += 2) {
dualMotor(7, CCW, trickySplitter[i], 9, CCW);
dualMotorDoubleSpeed(7, CCW, trickySplitter[i + 1], 9, CCW);
}
// Move Tt and finish Tv prep
digitalWrite(lightPins[11], HIGH);
dualMotor(11, CCW, motorSteps[10] - motorSteps[8] + motorSteps[11], 10, CCW);
// Finish moving Tt
stepMotor(11, CCW, motorSteps[8] - motorSteps[10]);
// Move Tv and prep C
digitalWrite(lightPins[10], HIGH);
dualMotor(10, CW, motorSteps[1], 1, CW);
// Move Tv
stepMotor(10, CW, motorSteps[10] - motorSteps[1]);
delay(500);
for (int i = 0; i < 11; i++) {
digitalWrite(lightPins2[i], LOW);
delay(200);
}
buildingLights();
for (int i = 11; i > 0; i--) {
digitalWrite(lightPins2[i], LOW);
delay(100);
}
delay(5000);
fullLightSequence();
//turn on all the lights slowly
for (int i = 0; i < 11; i++) {
digitalWrite(lightPins2[i], HIGH);
delay(100);
digitalWrite(lightPins2[i], LOW);
delay(200);
digitalWrite(lightPins2[i], HIGH);
delay(200);
digitalWrite(lightPins2[i], LOW);
delay(150);
digitalWrite(lightPins2[i], HIGH);
delay(300);
}
//All lights on section
tripMotor(1, CCW, motorSteps[9], 9, CW, 4, CCW); // C, Ra, Fm
tripMotor(3, CCW, motorSteps[9], 5, CCW, 11, CW); //Rc, A1, Tt
tripMotor(1, CW, motorSteps[9], 6, CCW, 8, CW); //C, A2, Fv
tripMotor(2, CW, motorSteps[9], 7, CW, 10, CCW); //Rv, Ft, Tv
dualMotor(9, CCW, motorSteps[9], 4, CW);
dualMotor(3, CW, motorSteps[9], 5, CW);
tripMotor(11, CCW, motorSteps[9], 6, CW, 8, CCW);
tripMotor(2, CCW, motorSteps[9], 7, CCW, 10, CW);
digitalWrite(lightPins[11], LOW);
delay(150);
digitalWrite(lightPins[11], HIGH);
delay(200);
digitalWrite(lightPins[11], LOW);
delay(150);
digitalWrite(lightPins[11], HIGH);
delay(200);
digitalWrite(lightPins[11], LOW);
delay(150);
digitalWrite(lightPins[11], HIGH);
delay(700);
for (int i = 11; i > 0; i--) {
digitalWrite(lightPins2[i], LOW);
delay(100);
}
delay(180000);
}
sendMorse("LONG LIVE ATLANTIS");
} //void loop end