University of Cincinnati CCM Mechatronics Spring 2026 — Dancing Snowman - Blake Y & Jack W.

by blakeyav05 in Circuits > Arduino

30 Views, 0 Favorites, 0 Comments

University of Cincinnati CCM Mechatronics Spring 2026 — Dancing Snowman - Blake Y & Jack W.

IMG_8860.jpg

This project guides you through the wiring, construction, and basic programming to make a snowman puppet and a control box. This project is coded using C++ on an Arduino Mega.

Supplies

This project uses:

(2) Momentary Pushbutton with 120V AC Indicator

(1) Momentary Pushbutton with 12V AC Indicator

(1) 2-Position Selector Switch

(1) On/Off Toggle Switch

(4) LED with Surface Mounting Hardware

(4) 150-ohm Resistor

(1) Edison Duplex outlet

(1) 120V AC Breaker

(1) Surface Mount IEC Connector

(2) Servo Motors

(1) Arduino Mega Board with AC Power Supply

(1) 12v Power Supply

(1) 5v Power Supply

(1) 12v Relay

(1) E26 Screw Base

(1) Terminal Strip

(1) Strain Relief

Assortment of wire

Solder

Zip Ties

Create a Schematic

BSY_JBW_MECH_FINAL.jpg

Before building anything, we developed a detailed schematic that maps out the entire control system. This meant carefully identifying every component that would be part of the project and showing how each one connects electrically. The schematic included the incoming 120V AC supply, which powers the system at a high level, as well as the step-down power supplies that convert this into usable 12V DC and 5V DC for lower voltage components.

Prepare Box

IMG_8797.jpg
IMG_8798.jpg
IMG_8799.jpg

To prepare the box, cut out the holes needed for the switches/buttons, breaker, strain relief, IEC connector, LEDs, duplex, and light bulb socket. Do this by tracing the shape that is needed on the side of the box, then drill a small hole to start. We found success in using a die grinder or file to expand the holes to get them to the right size. Once each hole has been drilled and filed out, start installing all the surface-mount components.

Instal the PSU/Arduino

IMG_8803.jpg

Now that all the surface-mount components have been installed, decide where to place your two power supplies and the Arduino Mega. Once decided, drill and screw the standoffs for the Arduino and screw or bolt down each PSU directly to the plastic box.

Wire the 120v Components

IMG_8876.jpg

Begin wiring the 120v circuit by starting from the IEC, following the schematic to the breaker, selector switch, light bulb, and duplex. We used thicker gauge wire to connect all our high-voltage components, and wire nuts made this easy. Once the light bulb and duplex outlet have been installed and tested, include the PSUs by supplying both with 120V as well.

Wire the 5v System

IMG_8878.jpg

In this step, we built out the low-voltage control side of the project by wiring all 5V components to the microcontroller. This included connecting one relay, four switches (inputs), two servos (outputs), and four LEDs (indicators) to the Arduino board. Each component was wired with careful attention to both power and signal connections.

The switches were connected to digital input pins. The LEDs were connected to digital output pins through 150-ohm resistors to prevent damage and allow for visual feedback of system states.

The servos required three connections each: 5V power, ground, and a signal wire connected to PWM-capable pins on the Arduino. Since servos can draw more current than the Arduino can safely supply, they were powered from the dedicated 5V power supply while still sharing a common ground with the Arduino to ensure proper signal control and flow of electrons.

The relay was wired so that the Arduino could control it via a digital output pin, allowing the low-voltage system to safely switch higher-voltage components when needed. A transistor or relay module may be used here to handle the current requirements and protect the microcontroller.

All grounds for the 5V system were tied together to create a common ground point, ensuring consistent operation across all inputs and outputs.

Wire Pushbutton Indicators

IMG_8879.jpg

In this step, we connected the 120V system to power the indicator lamps inside our small orange push buttons. This involved wiring from our 120V source to a relay, which acts as a switch controlled by a low-voltage output on the Arduino.

The relay has two positions: normally open and normally closed. We fed our 120v line voltage into the “common” terminal on the relay. Then, we wired the “normally open” terminal to one button and the “normally closed” to another. The neutrals from each button’s light bulb were then ganged together with the 120v system’s neutral.

Wiring our buttons in this way ensured that only one could be illuminated at a time as voltage was switched via the relay to each of the buttons’ indicators.

For our third pushbutton, we needed to supply its indicator with 12V. Because the indicator was an incandescent lightbulb, it didn’t matter whether we used AC or DC voltage. We decided to jump off of our 12V DC power supply, wiring this button’s indicator in parallel with the 12V relay.

Begin Making the Puppet

IMG_8893.jpg
IMG_8895.jpg

With the electronics in place, we began constructing the physical puppet that the system would control. We started by creating a raised base out of plywood.

Next, we assembled the snowman figure by gluing together its individual parts, making sure the structure was secure and properly aligned on the base. Once the body was complete, we focused on adding movement to the arms. Stiff metal wires were attached to each arm and routed down into the plywood base through some slit holes we cut. Inside the base, each metal wire was wrapped around a screw which connected to the arm of a servo motor.

As the servos rotate, they pull or push the wires, causing the arms to move up or down. This setup acts as a simple mechanical linkage system, allowing the electronic signals from the Arduino to translate into physical motion.

Creating the Code

In this step, we programmed the system to control how the puppet behaves based on user input. We designed the code to run two pre-programmed sequences, each activated by one of the orange buttons. These sequences control the timing and movement of the servos, as well

as any corresponding outputs like LEDs or relays, allowing the puppet to perform two unique “dance” routines.

To add an extra layer of control, we included an arm/disarm switch in the system. The code checks the state of this switch before allowing either program to run, meaning the robot will only respond to button presses when it is intentionally armed. This helps prevent accidental activation and makes the system safer and more predictable to use.

Additionally, we assigned a fourth button as a reset control. When pressed, this button interrupts any current activity and returns the system to its default state. This ensures that the robot can be quickly stopped or restarted if needed, which is especially useful during testing or demonstrations.

Code:

PINOUT:

Red LED: 38

Blue LED: 42

Yellow LED: 40

White LED: 44

Relay: 48

Servo 1: 9

Servo 2: 10

Bat Switch: 26

Reset: 27

Button A: 32

Button B: 34

PROJECT SOURCE CODE:

#include <Servo.h>

//SYSTEM MILLIS TIME

unsigned long timeNow = millis();

unsigned long previousTime = 0;

unsigned long fastInterval = 50;

unsigned long slowInterval = 1000;

//SEQUENCE SETUP

void runSequence1();

void runSequence2();

void runSequence3();

//BUTTON MODE TEST CODE

enum ModeState { MODE_A, MODE_B, MODE_X };

ModeState modeState = MODE_X;

bool lastButtonState1 = HIGH;

bool lastButtonState2 = HIGH;

// for edge detection

bool lastA = HIGH;

bool lastB = HIGH;

bool lastX = HIGH;

//--------------------------------------

//Define servo objects

Servo servo1;

Servo servo2;

//Define Outputs

int red = 38;

int blue = 42;

int yellow = 40;

int white = 44;

int relay = 48;

1

//Define switches

int bswitch = 26;

int redbut = 27;

int but1 = 32;

int but2 = 34;

//VARIABLE SETUP

bool buttonEnabled;

char running = 'N';

char program = 'X';

void setup() {

// put your setup code here, to run once:

//LEDs

pinMode (38, OUTPUT); //red

pinMode (42, OUTPUT); //blue

pinMode (40, OUTPUT); //yellow

pinMode (44, OUTPUT); //white

//Relay

pinMode (48, OUTPUT); //relay

//Buttons and Switch

pinMode (26, INPUT_PULLUP);

pinMode (27, INPUT_PULLUP);

pinMode (32, INPUT_PULLUP);

pinMode (34, INPUT_PULLUP);

//Servo Assignments

servo1.attach(9);

servo2.attach(10);

//Text Print

Serial.begin(9600);

Serial.println("Program successfully booted.");

}

2

void loop() {

//SERVO DEFAULT POSITION

servo1.write(90);

servo2.write(90);

bool currentButtonState1 = digitalRead(but1);

bool currentButtonState2 = digitalRead(but2);

//BUTTON MODE TEST CODE---------------

bool currentA = digitalRead(but1);

bool currentB = digitalRead(but2);

bool currentX = digitalRead(redbut);

// Button A selects MODE_A

if (lastA == HIGH && currentA == LOW) {

modeState = MODE_A;

delay(0); // debounce

}

// Button B selects MODE_B

if (lastB == HIGH && currentB == LOW) {

modeState = MODE_B;

delay(0); // debounce

}

// Button RED selects MODE_X

if (lastX == HIGH && currentX == LOW) {

modeState = MODE_X;

delay(0); // debounce

}

lastA = currentA;

lastB = currentB;

// Example behavior

if (modeState == MODE_A) {

digitalWrite(blue, HIGH);

digitalWrite(yellow, LOW);

}

if (modeState == MODE_B) {

3

digitalWrite(blue, LOW);

digitalWrite(yellow, HIGH);

}

if (modeState == MODE_X) {

digitalWrite(blue, LOW);

digitalWrite(yellow, LOW);

digitalWrite(relay, HIGH);

}

//------------------------------------

//RED LED STROBE WHEN BSWITCH ON

if ((digitalRead(bswitch) == LOW) && running == 'N') {

if (millis() - previousTime >= fastInterval) {

previousTime = millis();

digitalWrite(red, !digitalRead(red));

}

buttonEnabled = true;

}

if (digitalRead(bswitch) == HIGH) {

buttonEnabled = false;

digitalWrite(red, LOW);

}

//----------------------------------

//BUTTON SELECTOR VARIABLE

if (modeState == MODE_A) {

digitalWrite(relay, HIGH);

}

if (modeState == MODE_B) {

digitalWrite(relay, LOW);

}

//WHITE LED STROBE

if (running == 'Y') {

if (millis() - previousTime >= fastInterval) {

previousTime = millis();

digitalWrite(white, !digitalRead(white));

4

}

digitalWrite(red, LOW); }

else {

digitalWrite(white, LOW);

}

//-------PLAY MODES-------------

if (lastButtonState1 == HIGH && currentButtonState1 == LOW && buttonEnabled == true)

{

runSequence1();

}

lastButtonState1 = currentButtonState1;

if (lastButtonState2 == HIGH && currentButtonState2 == LOW && buttonEnabled == true)

{

runSequence2();

}

lastButtonState2 = currentButtonState2;

// END OF CODE

}

//PROGRAM 1----------------

void runSequence1() {

running = 'Y';

digitalWrite(white, HIGH);

servo1.write(0);

servo2.write(0);

delay(600);

servo1.write(180);

servo2.write(180);

delay(800);

servo1.write(0);

servo2.write(0);

delay(800);

servo1.write(180);

servo2.write(180);

delay(800);

servo1.write(90);

servo2.write(90);

5

delay(1000);

running = 'N';

}

//PROGRAM 2----------------

void runSequence2() {

running = 'Y';

digitalWrite(white, HIGH);

servo1.write(180);

servo2.write(0);

delay(800);

servo1.write(0);

servo2.write(180);

delay(800);

servo1.write(90);

servo2.write(90);

delay(800);

servo1.write(180);

servo2.write(0);

delay(800);

servo1.write(0);

servo2.write(180);

delay(800);

servo1.write(90);

servo2.write(90);

delay(1000);

running = 'N';

Test and Troubleshoot

IMG_8860.jpg
IMG_8887.jpg

With all components wired and the code uploaded, the final step was to thoroughly test the system and resolve any issues. We began by checking each subsystem individually, verifying that the 5V control components (switches, LEDs, and servo control) responded correctly to inputs, and that the 120V lighting circuit activated properly through the relay.

Next, we tested the full system operation by running each programmed sequence using the orange buttons. During this process, we observed how the servos moved the puppet’s arms, how the indicator lights responded, and whether the relay correctly switched the 120V lamps. This helped us identify any inconsistencies in timing, wiring errors, or unexpected behavior.

Troubleshooting involved checking connections, confirming proper grounding, and using tools like a multimeter to verify voltage levels and continuity. We also reviewed and adjusted the code as needed to fix logic errors or improve performance. Mechanical adjustments, such as tensioning wires connected to the servos, were made to ensure smooth and reliable movement.

By systematically testing and refining each part of the system, we were able to ensure that the final project operated safely, consistently, and as intended.