Week 12: Mechanical Design & Machine Design

Week 12 focused on machine design, and unlike previous weeks, this was a group-based project where multiple systems had to come together - mechanical, electronics, firmware, and interaction.

To begin with, we referred to previous years’ documentation to understand the scope and limitations of what could be realistically achieved within the given time.

During discussions around tabletop systems, especially setups where objects are arranged or shared, I was reminded of the rotating lazy Susan used in the Chinese dining contexts. That became the starting point for the idea:

An automated rotary table that can bring specific items to specific users using voice commands (Alexa).

I was assigned the development of the firmware, specifically focusing on stepper motor control, including precise positioning, homing logic, and overall motion control of the rotary system. In addition to the technical role, I was also responsible for project management and preparing the presentation slide.


Team and Roles

Mechanical Design - Abhishek
Electronics - Ardra
Fabrication & Assembly - Ali
Firmware - Mishael
Alexa Integration - Ashtami

Although roles were distributed, the system required continuous coordination.Say, for example: Firmware decisions depended on mechanical constraints (gear ratio), and interaction logic depended on physical positioning.


System Definition

The system was defined as:

  • Circular table (~55 cm diameter)
  • 6 compartments (60° separation)
  • Multiple fixed user positions (homes)
  • Central stepper-driven mechanism

  • Design Thinking Before Implementation

    A significant portion of my time was spent imagining system behavior before testing.

    Key questions:

  • How will a user call a compartment?
  • Should the table always rotate in one direction?
  • Or should it choose the shortest path?
  • What kind of motion feels natural to a user?
  • How do we ensure repeatability every time?
  • This early reasoning helped identify core issues before hardware testing:

  • Direction ambiguity (CW vs CCW)
  • Position drift over time
  • Need for a consistent reference

  • Hardware Overview: Stepper Motor Fundamentals

    What is a Stepper Motor?
    A stepper motor rotates in discrete angular steps, enabling precise position control.

    Typical NEMA 17:

  • 200 steps per revolution
  • 1 step = 1.8°
  • Image source mechtex.com, www.moonsindustries.com

    Bipolar Stepper (Used in this system)

  • Contains two coils (phases)
  • Driver reverses current direction
  • Magnetic field rotates → rotor aligns step-by-step

  • How does a Stepper Motor work?

    Why a Driver is Required

    What is Motor Driver?

    Microcontrollers cannot directly drive motors.
    The DRV8825 stepper motor driver:

  • Supplies required current
  • Converts STEP + DIR signals into coil switching
  • Protects the microcontroller


  • Control Signals

    Signal Function
    STEP Each pulse = one step
    DIR Controls direction
    ENABLE Enables/disables motor


    Hall Sensor - AH49E

  • Analog Hall effect sensor
  • Used for detecting magnetic reference
  • Processing approach:

  • Low-pass filtering → remove noise
  • Threshold → detect magnet
  • Hysteresis → avoid flicker
  • Step Resolution and Core Problem

    Base Calculation

    200 x 16 = 3200 (motor steps)
    3200 x 5 = 16000 (table steps per revolution)
    

    Derived Values

  • 1° ≈ 44.44 steps
  • 60° ≈ 2666.67 steps
  • Critical Issue

    The non-integer value (2666.67) leads to:

  • Rounding errors
  • Accumulated drift
  • Misalignment over repeated movements
  • Shift to Absolute Positioning

    Instead of calculating movement incrementally, I moved to:

    Defining fixed, absolute positions for every (Compartment, Home) pair

    Core Concept

    Position = (Compartment Offset + Home Offset) % 16000

    Key Insight

    Position control is not about movement—it is about reference.


    Step Mapping (Before LUT)

    Compartments (6 → 60° each)

    Compartment Table
    Compartment Angle Ideal Steps Rounded
    C1 0 0
    C2 60° 2666.67 2665
    C3 120° 5333.33 5332
    C4 180° 8000 7999
    C5 240° 10666.67 10666
    C6 300° 13333.33 13333

    Homes (Initial: 4 → 90° each)

    Home Positions
    Home Angle Steps
    H1 0
    H2 90° 4000
    H3 180° 8000
    H4 270° 12000

    Lookup Table (LUT)

    Each row = compartment

    Each column = home

    Each value = absolute step position

    const long LUT[7][5] = {
      {0,     0,      0,     0,       0  },
    
      {0,     0,   4000,   8000,  12000  },// C1
      {0,  2665,   6665,  10665,  14665  },// C2
      {0,  5332,   9332,  13332,   1332  },// C3
      {0,  7999,  11999,  15999,   3999  },// C4
      {0, 10666,  14666,   2666,   6666  },// C5
      {0, 13333,   1333,   5333,   9333  },// C6
    };
    

    Homing Logic (Reference Establishment)

    Since the system relies on absolute positioning, a physical reference is required at startup.

    Homing Flow

    SEARCH (fast CW)
    → detect magnet
    → BACKOFF (CCW)
    → APPROACH (slow CW)
    → detect magnet again
    → SET POSITION = 0
    

    Why This Works

  • First detection → rough position
  • Backoff → removes overlap
  • Slow approach → precise alignment

  • System Architecture (FSM)

    HOMING → IDLE → POSITIONING → IDLE

    States

  • HOMING → establish reference
  • IDLE → wait for command
  • POSITIONING → execute motion

  • Motion Control Fundamentals


    Motion Logic Evolution

    Stage 1: Clockwise Only

    delta = target - current
    if (delta < 0) delta += 16000
    
  • Always rotates clockwise
  • Used for initial validation
  • Stage 2: Shortest Path

    delta = target - current
    
    if (delta > 8000)  delta -= 16000
    if (delta < -8000) delta += 16000
    

    Concept

  • Full rotation = 16000
  • Half rotation = 8000
  • If movement > half → reverse direction


    Final Mapping (After Alexa Integration)

    Homes → People

    Home Person
    H1 Abhishek
    H2 Ardra
    H3 Ali
    H4 Ashtami
    H5 Mishael

    Compartments → Items

    Compartment Item
    C1 Nachos
    C2 Juice
    C3 Lays
    C4 Snickers
    C5 Popcorn
    C6 Cookies

    Updated Step Mapping (5 Homes)

    Home Offsets

    Home Steps
    H1 0
    H2 3200
    H3 6400
    H4 9600
    H5 12800

    Combined Positions (Sample)

    Compartment H1 H2 H3 H4 H5
    Nachos 0 3200 6400 9600 12800
    Juice 2667 5867 9067 12267 15467
    Lays 5333 8533 11733 14933 2133
    Snickers 8000 11200 14400 1600 4800

    Code Logic Overview

    Stepper Setup

  • Defines pins and microstepping
  • Establishes system resolution (16000 steps)
  • Hall Sensor Processing

  • Filters noise
  • Uses hysteresis for stable detection
  • Homing

  • Multi-stage FSM ensures repeatable reference
  • Movement

  • Uses LUT for absolute positions
  • Applies shortest path logic
  • Refinement

  • Crawl speed near target improves accuracy

  • Code Explanation (Core Logic Breakdown)

    Homing Logic (State Machine Implementation)

    Homing is required because the system uses absolute positioning. Without a reference, the step count has no real-world meaning.

    Code Snippet

    switch (state) {
    
    caseSEARCH:
    stepper.setSpeed(SEARCH_SPEED);
    stepper.runSpeed();
    
    if (currentHall&&!lastHall) {
    state =BACKOFF;
      }
    break;
    
    caseBACKOFF:
    stepper.setSpeed(-BACKOFF_SPEED);
    stepper.runSpeed();
    
    if (!currentHall&&lastHall) {
    state =APPROACH;
      }
    break;
    
    caseAPPROACH:
    stepper.setSpeed(APPROACH_SPEED);
    stepper.runSpeed();
    
    if (currentHall&&!lastHall) {
    stepper.setCurrentPosition(0);
    state =DONE;
      }
    break;
    }
    

    Block-by-Block Explanation

    SEARCH (Fast Clockwise Rotation)

  • Motor rotates continuously in clockwise direction
  • Purpose: find magnet zone quickly
  • Condition:
  • if (currentHall&&!lastHall)

    Detects rising edge→ entering magnetic field


    BACKOFF (Reverse Movement)

  • Motor rotates counter-clockwise
  • Purpose: move away from magnet to remove overlap
  • Condition:
  • if (!currentHall&&lastHall)

    Detects falling edge → fully exited magnet zone


    APPROACH (Slow Precision Alignment)

  • Motor rotates slowly clockwise
  • Purpose: precise edge detection
  • On detection:
  • stepper.setCurrentPosition(0);

    This defines:

    Absolute zero (C1 aligned with H1)


    Why This Works

  • First detection is not reliable → too wide
  • Backoff removes ambiguity
  • Slow approach ensures repeatable alignment

  • Shortest Path Logic

    Once absolute positions are known, the next problem is:

    Which direction should the motor rotate?

    Code Snippet

    longdelta =target-turntableStepPos;
    
    if (delta>STEPS_PER_REV/2)delta-=STEPS_PER_REV;
    if (delta<-STEPS_PER_REV/2)delta+=STEPS_PER_REV;
    
    if (delta==0)return;
    

    Block-by-Block Explanation

    Raw Difference

    longdelta =target-turntableStepPos;
  • Calculates how far the target is from current position
  • Can be positive (CW) or negative (CCW)

  • Normalization to Shortest Path

    if (delta>8000)delta-=16000;
    if (delta<-8000)delta+=16000;
    

  • Full rotation = 16000
  • Half rotation = 8000
  • Logic:

    If movement is more than half a circle → go the other way


    Zero Movement Check

    if (delta==0)

    Prevents unnecessary motion


    Key Insight

  • Motion is computed relative
  • Position is tracked absolutely
  • This separation is what makes the system stable.

    Movement Execution

    stepper.moveTo(stepper.currentPosition()+delta);

    Explanation

  • currentPosition() → actual motor step count
  • delta → shortest movement required
  • Final command = relative move based on shortest path

  • Lookup Table Integration

    longtarget =LUT[c][h];

    Explanation

  • c → compartment
  • h → home
  • This converts:

    User command → exact step position

    No runtime calculation required.


    Hall Sensor Processing

    filtered = 0.8f * filtered + 0.2f * raw;
    
    if (!hallState && filtered > ON_THRESHOLD) hallState = true;
    if (hallState && filtered < OFF_THRESHOLD) hallState = false;
    

    System State Machine

    switch (sysState) {
    
      case HOMING:
        runHoming();
        break;
    
      case POSITIONING:
        if (stepper.distanceToGo() != 0) {
          stepper.run();
        } else {
          sysState = IDLE;
        }
        break;
    
      case IDLE:
        if (Serial.available()) {
          parseCommand(cmd);
        }
        break;
    }
    

    Explanation

    HOMING

    POSITIONING

    IDLE


    Crawl Speed (Final Refinement)

    if (abs(stepper.distanceToGo()) < CRAWL_THRESHOLD) {
      stepper.setMaxSpeed(CRAWL_SPEED);
    }
    

    Why This Matters


    Final System Behavior (End-to-End)

    1. System starts → HOMING
    2. Position set to 0
    3. Wait for command
    4. Command parsed → LUT lookup
    5. Shortest path calculated
    6. Motor moves
    7. System returns to IDLE


    Development Process

    Due to design and fabrication delays, time was used to:

    Testing Approach

    Each subsystem was tested independently before integration.


    Code Annotations

    Core Setup and Definitions

    #include 
    
    // PIN DEFINITIONS
    #define STEP_PIN D1
    #define DIR_PIN  D0
    #define EN_PIN   D3
    
    #define M0_PIN D2
    #define M1_PIN D4
    #define M2_PIN D5
    
    #define HALL_PIN D8
    
    // SYSTEM CONSTANTS
    #define MOTOR_STEPS   200
    #define MICROSTEPS    16
    #define GEAR_RATIO    5
    
    #define STEPS_PER_REV (MOTOR_STEPS * MICROSTEPS * GEAR_RATIO)
    
    // SPEED SETTINGS
    #define SEARCH_SPEED    800
    #define BACKOFF_SPEED   400
    #define APPROACH_SPEED  200
    
    #define MOVE_MAX_SPEED  1200
    #define MOVE_ACCEL      800
    
    #define CRAWL_SPEED     300
    #define CRAWL_THRESHOLD 200
    

    Lookup Table (Absolute Positions)

    const long LUT[7][6] = {
      {0,     0,     0,     0,     0,     0},
      {0,     0,  3200,  6400,  9600, 12800}, // Nachos
      {0,  2667,  5867,  9067, 12267, 15467}, // Juice
      {0,  5333,  8533, 11733, 14933,  2133}, // Lays
      {0,  8000, 11200, 14400,  1600,  4800}, // Snickers
      {0, 10667, 13867,  1067,  4267,  7467}, // Popcorn
      {0, 13333,   533,  3733,  6933, 10133}  // Cookies
    };
    

    This eliminates rounding errors and positional drift.


    Stepper Initialization

    AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
    

    Movement Function (Shortest Path)

    long currentPos = 0;
    
    void moveToTarget(int c, int h) {
    
      long target = LUT[c][h];
      long delta  = target - currentPos;
    
      if (delta > 8000)  delta -= 16000;
      if (delta < -8000) delta += 16000;
    
      if (delta == 0) return;
    
      stepper.moveTo(stepper.currentPosition() + delta);
    
      currentPos = target;
      sysState = POSITIONING;
    }
    

    Main Loop

    void loop() {
    
      switch (sysState) {
    
        case HOMING:
          runHoming();
          break;
    
        case POSITIONING:
          if (stepper.distanceToGo() != 0) {
    
            if (abs(stepper.distanceToGo()) < CRAWL_THRESHOLD) {
              stepper.setMaxSpeed(CRAWL_SPEED);
            } else {
              stepper.setMaxSpeed(MOVE_MAX_SPEED);
            }
    
            stepper.run();
    
          } else {
            sysState = IDLE;
          }
          break;
    
        case IDLE:
          // waiting for commands
          break;
      }
    }
    

    Observations


    Limitations


    Future Improvements


    Final Note

    This project shifted the focus from writing code to designing system behavior.