9.4- Implementation

9.4- Implementation

Fabrication and Assembly

Fabrication of our final design was accomplished through a combination of laser cutting and 3D printing to balance structural strength with low-friction dynamics.

The main base frame was laser-cut from wood. The precision of the laser cutter ensured that the central slot dictating the slider's linear path was perfectly straight, which was crucial for preventing the mechanism from jamming. The dynamic components—the lower links, upper links, and the slider blocks—were 3D printed.

During assembly, overcoming the fragility of the 3D-printed parts was the primary challenge. Because the initial linkages cracked under torque , we reprinted the links with increased wall thickness at the joint hubs. We successfully press-fit the 8mm metal shafts and utilized M3 screws to finalize the low-friction joints. Finally, the custom 3D-printed motor cradle was attached to anchor the 12V DC motor directly to the wooden base.

WhatsApp Image 2026-05-02 at 8.41.16 PM-20260503-014439.jpeg
Image of the 3d printer motor/driver mount, the motor is secures in place via pressure of the screw onto motor hole plate.

Electronics and Circuitry

To actuate the simultaneous dual-leg mechanism, our electronics included the following hardware:

  • Arduino Microcontroller

  • Motor Driver (to handle current draw and direction switching)

  • 12V DC Motor

  • Jumper cables and standard breadboard

The system was routed to the Arduino to control the speed (via PWM) and the direction of the 12V DC motor. The custom-designed cradle ensured the motor remained secure against the high-torque operation required to push both legs simultaneously.

 

WhatsApp Image 2026-05-02 at 9.53.42 PM.jpeg
circuit schematic of dual motor system for project

 

Software The software was developed to logically separate the motor's output into the distinct functional phases, modeled as a Four-State Model.

  • Phase A (Extension): Upon initialization, the code runs the motor to drive the slider linearly, transitioning the flat 2D chassis into a rigid 3D structure.

  • Phase B (Retraction): Once the robot is popped up, the software enters an oscillating loop to drive the walking gait. The system shifts between the Four-State Model: State 1 (Pull Extended), State 2 (Buckling), State 3 (Push Bent), and State 4 (Unbuckling).

By operating the software in this sequence, the robot behaves as shifting between separate 4-bar linkages, meaning only 1 input is required to achieve continuous locomotion despite multiple theoretical DOFs. The asymmetric friction logic (anchoring during push, sliding during pull) effectively drives the unified bounding motion.

 

// Motor 1 Pins const int IN1 = 2; const int IN2 = 3; const int IN3 = 4; const int IN4 = 5; // Motor 2 Pins (Mirrored) const int IN5 = 8; const int IN6 = 9; const int IN7 = 10; const int IN8 = 11; // Switch and LED pins const int switchGround = A0; const int switchInput = A1; const int ledPin = LED_BUILTIN; // Movement Configuration const int initialLiftSteps = 700; // Steps to move up from the "flat" position const int toggleSteps = 600; // Steps for the back-and-forth movement const int stepDelay = 1000; // Microseconds between steps // Step indices for each motor int i1 = 0; int i2 = 0; // State tracking bool hasDoneInitialLift = false; void setup() { // Configure Motor 1 pins pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); // Configure Motor 2 pins pinMode(IN5, OUTPUT); pinMode(IN6, OUTPUT); pinMode(IN7, OUTPUT); pinMode(IN8, OUTPUT); // Configure switch pins pinMode(switchGround, OUTPUT); digitalWrite(switchGround, LOW); // Set A0 to LOW so it acts as Ground pinMode(switchInput, INPUT_PULLUP); // Configure LED pin pinMode(ledPin, OUTPUT); // Ensure motors start de-energized disableMotors(); } void loop() { // Switch closed (LOW) = RUN, Switch open (HIGH) = STOP/RESET bool isSwitchOn = (digitalRead(switchInput) == LOW); if (!isSwitchOn) { // SYSTEM RESET / DISABLED STATE digitalWrite(ledPin, LOW); disableMotors(); hasDoneInitialLift = false; return; // Exit loop early and wait for switch to turn on } // SYSTEM ACTIVE STATE digitalWrite(ledPin, HIGH); // Perform the initial movement upwards if (!hasDoneInitialLift) { if (!moveSteps(initialLiftSteps, true)) return; hasDoneInitialLift = true; } // Toggle back and forth if (!moveSteps(toggleSteps, false)) return; if (!delayWithAbort(100)) return; // 500ms pause if (!moveSteps(toggleSteps, true)) return; if (!delayWithAbort(100)) return; // 500ms pause } // --- Helper Functions --- // Moves the motors while constantly checking the switch. // Returns false if the switch is turned off mid-movement. bool moveSteps(int steps, bool forward) { for (int stepCount = 0; stepCount < steps; stepCount++) { // Check switch instantly if (digitalRead(switchInput) == HIGH) { return false; // Abort movement! } if (forward) { doHalfStepForward(); } else { doHalfStepBackward(); } delayMicroseconds(stepDelay); } return true; // Successfully finished movement } // A delay function that continually checks the switch bool delayWithAbort(int milliseconds) { for (int p = 0; p < milliseconds; p++) { if (digitalRead(switchInput) == HIGH) { return false; // Abort delay! } delay(1); } return true; } // Removes holding torque void disableMotors() { digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); digitalWrite(IN5, LOW); digitalWrite(IN6, LOW); digitalWrite(IN7, LOW); digitalWrite(IN8, LOW); } void setHalfStep(bool isForward) { int m1_step = isForward ? 1 : -1; int m2_step = isForward ? -1 : 1; int steps[] = {B1000, B1100, B0100, B0110, B0010, B0011, B0001, B1001}; digitalWrite(IN1, bitRead(steps[i1], 0)); digitalWrite(IN2, bitRead(steps[i1], 1)); digitalWrite(IN3, bitRead(steps[i1], 2)); digitalWrite(IN4, bitRead(steps[i1], 3)); digitalWrite(IN5, bitRead(steps[i2], 0)); digitalWrite(IN6, bitRead(steps[i2], 1)); digitalWrite(IN7, bitRead(steps[i2], 2)); digitalWrite(IN8, bitRead(steps[i2], 3)); i1 = (i1 + m1_step + 8) % 8; i2 = (i2 + m2_step + 8) % 8; } void doHalfStepForward(){ setHalfStep(true); } void doHalfStepBackward(){ setHalfStep(false); }