Skip to content

WEEK 12/13 Mechanical Design, Machine Design

SLIDE & PRESENTATION:

MACHINE_SLIDE.png

The Cat Communication Robot

Our revised concept was to build a drawing robot inspired by the Polargraph Plotter, but with a unique twist. The idea was to reimagine it as a medium for cat-to-human communication.

Concept

Cats communicate in subtle and complex ways. What if we could build a machine that could "translate" a cat’s meows into written messages for their human companions?

We imagined a robot that could recognize different cat vocalizations like meows asking for food, attention, or a clean litter box, and interpret them. Then, it would draw or write a message on a piece of paper or wall, effectively becoming a "feline secretary."

While the actual voice recognition part was too advanced for this week’s scope, we focused on the mechanical design that would allow for such expressive drawing.


MECHANICAL DESIGN:

Polargraph Plotter

The original Polargraph works by using two motors mounted at the top corners of a surface. These motors control the length of two cords or belts, which suspend a pen in between them. By precisely changing the lengths of these cords, the pen moves smoothly across a 2D surface, plotting images or text.

We adopted this basic idea, but adapted the design to match the aesthetics and thematic goals of the FitnessCat.

catcut.jpg

paperholder.jpg

In the back there’s a space for paper roll.

Custom Pen Holder

  1. Pen Holder with Rack and Pinion System

    I designed a custom pen holder featuring a rack and pinion system. This setup is controlled by a servo motor, allowing the pen to be lifted and lowered precisely. This is essential for drawing clean lines and separating strokes.

  2. Whisker-Inspired Sliding Mechanism

    To reinforce the "cat" theme, we added sliding counterweights that mimic the shape and movement of cat whiskers. These are attached to a timing belt system, which adds visual charm and helps balance the pen holder's motion.

  3. Frame & Mounting

    The motors are mounted on a vertical frame, similar to a traditional Polargraph. We used light plywood and 3D-printed parts to keep the structure simple and easy to assemble.

penholder.jpg

Here’s the prototyping process:

prototypes.jpg

prototypes2.jpg

prototypes3.jpg

CONTROL:

Hardware Components

electronics3.jpg

Required Components

  • Arduino Uno R3
  • 2× 28BYJ-48 Stepper Motors
  • 2× ULN2003 Driver Boards
  • 1× Small Servo Motor (SG90 or similar)
  • Power Supply (5-12V DC, at least 1A)
  • Jump Wires
  • Drawing Surface
  • Gondola (pen holder)
  • Dented Belts (for transmission)
  • Counterweights
  • Rack and Pinion System (for pen up/down movement)

Hardware Setup

electronics2.jpg

Arduino and Motor Setup

  1. Gather the Arduino Uno R3, two 28BYJ-48 stepper motors with ULN2003 driver boards, and a small servo motor.
  2. Prepare a breadboard for connecting components during testing phase.
  3. Connect the external lab power supply to provide consistent power to the motors.

Transmission System

  1. Install dented belts for transmitting movement from the stepper motors to the gondola.
  2. Add counterweights on one side to balance with the gondola weight, ensuring smooth movement.
  3. The servo motor connects to a rack and pinion system that precisely controls the pen's up/down movement.

Wiring

electronics1.jpg

Arduino to Stepper Motor Connections

  • Left Stepper (ULN2003 Driver Board)
  • IN1 → Arduino Pin 8
  • IN2 → Arduino Pin 9
  • IN3 → Arduino Pin 10
  • IN4 → Arduino Pin 11
  • VCC → 5V (external power supply)
  • GND → GND (common ground with Arduino)
  • Right Stepper (ULN2003 Driver Board)
  • IN1 → Arduino Pin 4
  • IN2 → Arduino Pin 5
  • IN3 → Arduino Pin 6
  • IN4 → Arduino Pin 7
  • VCC → 5V (external power supply)
  • GND → GND (common ground with Arduino)

Arduino to Servo Connections

  • Signal → Arduino Pin 12
  • VCC → 5V (external power supply)
  • GND → GND (common ground with Arduino)

Power Supply Connections

  • Connect the external lab power supply to provide 5V to the stepper motor driver boards and servo
  • Ensure common ground between the power supply and Arduino
  • The 28BYJ-48 motors typically draw 150-200mA each at 5V
  • The servo may draw up to 500mA during operation

Connection Notes

  • Make sure the stepper motor wires are connected in the correct order to the ULN2003 driver boards
  • The common ground connection between Arduino and power supply is essential
  • If using a higher voltage power supply (e.g., 12V), make sure to use a voltage regulator to provide 5V to the components
  • When testing, secure all wires properly to prevent accidental disconnection

Installation:

installation.jpg

installation2.jpg

installation3.jpg

installation4.jpg

installation5.jpg

idea.jpg

idea2.jpg

Test Software

testing.jpg

testing2.jpg

We had to add some weights for stable movements

Test Codes

References and Resources

Before implementing the full IPAD solution, it's essential to test the hardware components individually. The following Arduino test sketch allows you to verify the connections and proper functioning of both stepper motors and the servo.

// Polargraph Components Test Sketch
// Tests 28BYJ-48 stepper motors and servo on specified pins

#include <Stepper.h>
#include <Servo.h>

// Define stepper parameters
const int stepsPerRevolution = 2048;  // 28BYJ-48 steps per revolution with gear reduction
Servo penServo;

// Initialize left stepper on pins 8, 10, 9, 11 (this order is important for proper rotation)
Stepper leftStepper(stepsPerRevolution, 8, 10, 9, 11);

// Initialize right stepper on pins 4, 6, 5, 7 (this order is important for proper rotation)
Stepper rightStepper(stepsPerRevolution, 4, 6, 5, 7);

// Servo setup on pin 12
int servoPin = 12;
int penUp = 90;   // Adjust these angles based on your setup
int penDown = 140;

void setup() {
  // Set stepper motor speed (RPM)
  leftStepper.setSpeed(10);  // 10 RPM is a good starting speed for testing
  rightStepper.setSpeed(10);

  // Initialize servo
  penServo.attach(servoPin);
  penServo.write(penUp);  // Start with pen up

  // Initialize serial for debugging
  Serial.begin(9600);
  Serial.println("Polargraph Components Test");
  Serial.println("Commands: 'L' - Left stepper, 'R' - Right stepper, 'U' - Pen up, 'D' - Pen down, 'B' - Both steppers");
}

void loop() {
  // Check if there's any incoming serial data
  if (Serial.available() > 0) {
    char command = Serial.read();

    switch (command) {
      case 'L':
      case 'l':
        // Test the left stepper motor with 1/4 rotation in each direction
        Serial.println("Testing left stepper - 1/4 rotation clockwise");
        leftStepper.step(stepsPerRevolution / 4);  // 512 steps = 1/4 rotation
        delay(500);
        Serial.println("Testing left stepper - 1/4 rotation counter-clockwise");
        leftStepper.step(-stepsPerRevolution / 4);
        break;

      case 'R':
      case 'r':
        // Test the right stepper motor with 1/4 rotation in each direction
        Serial.println("Testing right stepper - 1/4 rotation clockwise");
        rightStepper.step(stepsPerRevolution / 4);
        delay(500);
        Serial.println("Testing right stepper - 1/4 rotation counter-clockwise");
        rightStepper.step(-stepsPerRevolution / 4);
        break;

      case 'U':
      case 'u':
        // Move the servo to pen-up position
        Serial.println("Pen up");
        penServo.write(penUp);  // 90 degrees by default
        break;

      case 'D':
      case 'd':
        // Move the servo to pen-down position
        Serial.println("Pen down");
        penServo.write(penDown);  // 140 degrees by default
        break;

      case 'B':
      case 'b':
        // Test both steppers simultaneously for coordinated movement
        Serial.println("Testing both steppers simultaneously");
        // Move both steppers forward simultaneously
        for (int i = 0; i < (stepsPerRevolution / 8); i++) {
          leftStepper.step(1);
          rightStepper.step(1);
        }
        delay(500);
        // Move both steppers backward simultaneously
        for (int i = 0; i < (stepsPerRevolution / 8); i++) {
          leftStepper.step(-1);
          rightStepper.step(-1);
        }
        break;
    }
  }
}

How to Use the Test Software

  1. Connect the Arduino to your computer via USB.
  2. Make sure all hardware connections match the wiring diagram.
  3. Open the Arduino IDE and upload the sketch.
  4. Open the Serial Monitor (Tools → Serial Monitor, set to 9600 baud).
  5. Send the following single-character commands to test each component:
  6. L to test the left stepper motor (connected to pins 8,9,10,11)
  7. R to test the right stepper motor (connected to pins 4,5,6,7)
  8. U to move the servo to pen-up position
  9. D to move the servo to pen-down position
  10. B to test both stepper motors simultaneously

What to Look For During Testing

  • Stepper Motors: Should rotate smoothly without stuttering or skipping steps
  • Servo: Should move reliably between up and down positions
  • Power Supply: Should provide stable voltage and current during operation
  • Temperature: Components should not overheat during testing

IPAD Software Installation

This polargraph setup uses the IPAD (Improved Polargraph Art Device) firmware from https://github.com/zanedrys/IPAD. Follow these steps to install and configure the software:

Step 1: Install Required Software

  1. Download and install the Arduino IDE from arduino.cc
  2. Download and install Processing from processing.org
  3. Clone or download the IPAD repository from GitHub

Step 2: Install Required Arduino Libraries

  1. Open the Arduino IDE
  2. Go to Sketch → Include Library → Manage Libraries
  3. Search for and install the following libraries:
  4. AccelStepper (for improved stepper motor control)
  5. Servo (for pen control)

Step 3: Upload the IPAD Firmware

  1. Open the IPAD_Firmware.ino file from the downloaded repository
  2. Modify the pin assignments in the code to match your specific setup:

    // Modify these lines to match your pin connections
    // Left stepper on pins 8,9,10,11
    #define LEFT_STEP_PIN1 8
    #define LEFT_STEP_PIN2 9
    #define LEFT_STEP_PIN3 10
    #define LEFT_STEP_PIN4 11
    
    // Right stepper on pins 4,5,6,7
    #define RIGHT_STEP_PIN1 4
    #define RIGHT_STEP_PIN2 5
    #define RIGHT_STEP_PIN3 6
    #define RIGHT_STEP_PIN4 7
    
    // Servo on pin 12
    #define SERVO_PIN 12
    
  3. Make sure the Arduino is connected to your computer via USB

  4. Select the correct board (Arduino Uno) and port in the Arduino IDE
  5. Upload the firmware to your Arduino

Step 4: Configure and Run the IPAD Processing Controller

  1. Open Processing
  2. Open the IPAD_Controller.pde file from the downloaded repository
  3. In the IPAD_Controller.pde file, find the configuration section and make sure:
  4. The COM port matches your Arduino's connection
  5. The machine dimensions match your physical setup
  6. The motor specifications match the 28BYJ-48 steppers
  7. Run the Processing sketch to open the IPAD control interface

IPAD Software Interface

IPAD software control interface showing drawing controls

IPAD Software Implementation

Using IPAD with Your Hardware

  1. The IPAD software provides a much more advanced control system than the test sketch
  2. Key features of IPAD when used with your hardware:
  3. Vector drawing support
  4. Advanced path planning
  5. Better motor control and acceleration handling
  6. GUI interface for easy control

Important IPAD Configuration Options

When working with the IPAD software, pay special attention to:

  1. Machine Settings in Processing Controller
  2. Set the correct COM port for your Arduino
  3. Configure the machine width and height
  4. Set the motor steps per revolution (2048 for 28BYJ-48)
  5. Adjust the microstepping settings if you modified the firmware
  6. Motor Settings
  7. Set the correct motor speed (start with 500-800 steps/min for the 28BYJ-48)
  8. Set acceleration values (typically 100-200 steps/sec² for 28BYJ-48)
  9. If motors skip steps, reduce speed and increase power supply current
  10. Pen Settings
  11. Configure servo up/down positions (typically between 70-150 degrees)
  12. Set pen lift and lower delay (200-500ms recommended)

IPAD Settings Panel

IPAD software settings panel showing configuration options

The software was constantly crashing and not letting us proceed so we came up with a solution:

We took the test file from before and added:

TRIANGLE:

// Draw a triangle in the center of the canvas
void drawTriangle()
{
    Serial.println(F("Drawing Triangle"));

    // Calculate a centered triangle
    float centerX = CANVAS_WIDTH / 2;
    float centerY = CANVAS_HEIGHT / 2;
    float size = min(CANVAS_WIDTH, CANVAS_HEIGHT) / 6; // Smaller triangle (was /4)

    // Calculate vertices
    float x1 = centerX;
    float y1 = centerY - size;
    float x2 = centerX - size * 0.866; // sin(60°) = 0.866
    float y2 = centerY + size * 0.5;   // cos(60°) = 0.5
    float x3 = centerX + size * 0.866;
    float y3 = centerY + size * 0.5;

    // Draw triangle
    drawLine(x1, y1, x2, y2);
    drawLine(x2, y2, x3, y3);
    drawLine(x3, y3, x1, y1);

    // Lift pen
    penUp();

    Serial.println(F("Triangle complete"));
}

CIRCLE

// Draw a circle in the center of the canvas
void drawCircle()
{
    Serial.println(F("Drawing Circle"));

    float centerX = CANVAS_WIDTH / 2;
    float centerY = CANVAS_HEIGHT / 2;
    float radius = min(CANVAS_WIDTH, CANVAS_HEIGHT) / 8; // Smaller circle (was /5)

    // Number of segments to approximate the circle
    const int segments = 36; // More segments = smoother circle

    // Move to starting point with pen up
    penUp();
    float startX = centerX + radius;
    float startY = centerY;
    moveTo(startX, startY);

    // Put pen down to start drawing
    penDown();

    // Draw circle as a series of short lines
    for (int i = 1; i <= segments; i++)
    {
        float angle = 2 * PI * i / segments;
        float x = centerX + radius * cos(angle);
        float y = centerY + radius * sin(angle);
        moveTo(x, y);
    }

    // Lift pen
    penUp();

    Serial.println(F("Circle complete"));
}

HERE’S THE FULL CODE FOR THE VSCODE+PLATFORMIO platformio.ini

[env:uno]
platform = atmelavr
board = uno
framework = arduino
monitor_speed = 115200

lib_deps =
    arduino-libraries/Servo@^1.1.8
    arduino-libraries/Stepper@^1.1.3 

main.cpp

#include "Polargraph_Test.h"
#include <math.h>

// Initialize stepper and servo objects
Stepper leftStepper(STEPS_PER_REVOLUTION, LEFT_MOTOR_PIN1, LEFT_MOTOR_PIN2, LEFT_MOTOR_PIN3, LEFT_MOTOR_PIN4);
Stepper rightStepper(STEPS_PER_REVOLUTION, RIGHT_MOTOR_PIN1, RIGHT_MOTOR_PIN2, RIGHT_MOTOR_PIN3, RIGHT_MOTOR_PIN4);
Servo penServo;

// Current position tracking
float currentX = CANVAS_WIDTH / 2;
float currentY = CANVAS_HEIGHT / 2;

void setup()
{
    // Set stepper motor speeds
    leftStepper.setSpeed(MOTOR_SPEED_RPM);
    rightStepper.setSpeed(MOTOR_SPEED_RPM);

    // Initialize servo
    penServo.attach(SERVO_PIN);
    penServo.write(PEN_UP_ANGLE); // Start with pen up

    // Initialize serial for debugging
    Serial.begin(115200);
    Serial.println(F("Polargraph Components Test"));
    printInstructions();
}

void loop()
{
    // Check if there's any incoming serial data
    if (Serial.available() > 0)
    {
        char command = Serial.read();

        switch (command)
        {
        case 'L':
        case 'l':
            testLeftMotor();
            break;

        case 'R':
        case 'r':
            testRightMotor();
            break;

        case 'U':
        case 'u':
            penUp();
            break;

        case 'D':
        case 'd':
            penDown();
            break;

        case 'B':
        case 'b':
            testBothMotors();
            break;

        case 'T':
        case 't':
            drawTriangle();
            break;

        case 'C':
        case 'c':
            drawCircle();
            break;

        case '?':
            printInstructions();
            break;
        }
    }
}

void testLeftMotor()
{
    // Test the left stepper motor with 1/4 rotation in each direction
    Serial.println(F("Testing left stepper - 1/4 rotation clockwise"));
    leftStepper.step(STEPS_PER_REVOLUTION / 4);
    delay(500);
    Serial.println(F("Testing left stepper - 1/4 rotation counter-clockwise"));
    leftStepper.step(-STEPS_PER_REVOLUTION / 4);
}

void testRightMotor()
{
    // Test the right stepper motor with 1/4 rotation in each direction
    Serial.println(F("Testing right stepper - 1/4 rotation clockwise"));
    rightStepper.step(STEPS_PER_REVOLUTION / 4);
    delay(500);
    Serial.println(F("Testing right stepper - 1/4 rotation counter-clockwise"));
    rightStepper.step(-STEPS_PER_REVOLUTION / 4);
}

void penUp()
{
    // Move the servo to pen-up position
    Serial.println(F("Pen up"));
    penServo.write(PEN_UP_ANGLE);
    delay(300); // Give time for the servo to move
}

void penDown()
{
    // Move the servo to pen-down position
    Serial.println(F("Pen down"));
    penServo.write(PEN_DOWN_ANGLE);
    delay(300); // Give time for the servo to move
}

void testBothMotors()
{
    // Test both steppers simultaneously for coordinated movement
    Serial.println(F("Testing both steppers simultaneously"));

    // Move both steppers forward simultaneously
    Serial.println(F("  Forward motion..."));
    for (int i = 0; i < (STEPS_PER_REVOLUTION / 8); i++)
    {
        leftStepper.step(1);
        rightStepper.step(1);
    }

    delay(500);

    // Move both steppers backward simultaneously
    Serial.println(F("  Backward motion..."));
    for (int i = 0; i < (STEPS_PER_REVOLUTION / 8); i++)
    {
        leftStepper.step(-1);
        rightStepper.step(-1);
    }

    Serial.println(F("Test complete"));
}

void printInstructions()
{
    Serial.println(F("Commands:"));
    Serial.println(F("  L - Test Left stepper"));
    Serial.println(F("  R - Test Right stepper"));
    Serial.println(F("  U - Pen up"));
    Serial.println(F("  D - Pen down"));
    Serial.println(F("  B - Test Both steppers"));
    Serial.println(F("  T - Draw Triangle"));
    Serial.println(F("  C - Draw Circle"));
    Serial.println(F("  ? - Show this help"));
}

// Convert Cartesian coordinates to string lengths (distance from each motor)
void convertToSteps(float x, float y, int &leftSteps, int &rightSteps)
{
    // Calculate string lengths using Pythagorean theorem
    float leftStringLength = sqrt(x * x + y * y);
    float rightStringLength = sqrt((MOTOR_DISTANCE - x) * (MOTOR_DISTANCE - x) + y * y);

    // Convert to steps (this is a simplified conversion, might need calibration for your setup)
    leftSteps = leftStringLength * (STEPS_PER_REVOLUTION / (2 * PI * 10)); // Assuming 10mm pulley radius
    rightSteps = rightStringLength * (STEPS_PER_REVOLUTION / (2 * PI * 10));
}

// Move to a specific position with pen up
void moveTo(float x, float y)
{
    Serial.print(F("Moving to: X="));
    Serial.print(x);
    Serial.print(F(", Y="));
    Serial.println(y);

    int leftSteps, rightSteps;
    int currentLeftSteps, currentRightSteps;

    // Calculate current position in steps
    convertToSteps(currentX, currentY, currentLeftSteps, currentRightSteps);

    // Calculate target position in steps
    convertToSteps(x, y, leftSteps, rightSteps);

    // Calculate step differences
    int leftStepDiff = leftSteps - currentLeftSteps;
    int rightStepDiff = rightSteps - currentRightSteps;

    // Move steppers
    // We'll move steppers alternately to make smoother movement
    int maxSteps = max(abs(leftStepDiff), abs(rightStepDiff));
    for (int i = 0; i < maxSteps; i++)
    {
        if (i < abs(leftStepDiff))
        {
            leftStepper.step(leftStepDiff > 0 ? 1 : -1);
        }
        if (i < abs(rightStepDiff))
        {
            rightStepper.step(rightStepDiff > 0 ? 1 : -1);
        }
    }

    // Update current position
    currentX = x;
    currentY = y;
}

// Draw a line between two points
void drawLine(float x1, float y1, float x2, float y2)
{
    // Move to start position with pen up
    penUp();
    moveTo(x1, y1);

    // Put pen down to start drawing
    penDown();

    // Move to end position with pen down
    moveTo(x2, y2);
}

// Draw a triangle in the center of the canvas
void drawTriangle()
{
    Serial.println(F("Drawing Triangle"));

    // Calculate a centered triangle
    float centerX = CANVAS_WIDTH / 2;
    float centerY = CANVAS_HEIGHT / 2;
    float size = min(CANVAS_WIDTH, CANVAS_HEIGHT) / 6; // Smaller triangle (was /4)

    // Calculate vertices
    float x1 = centerX;
    float y1 = centerY - size;
    float x2 = centerX - size * 0.866; // sin(60°) = 0.866
    float y2 = centerY + size * 0.5;   // cos(60°) = 0.5
    float x3 = centerX + size * 0.866;
    float y3 = centerY + size * 0.5;

    // Draw triangle
    drawLine(x1, y1, x2, y2);
    drawLine(x2, y2, x3, y3);
    drawLine(x3, y3, x1, y1);

    // Lift pen
    penUp();

    Serial.println(F("Triangle complete"));
}

// Draw a circle in the center of the canvas
void drawCircle()
{
    Serial.println(F("Drawing Circle"));

    float centerX = CANVAS_WIDTH / 2;
    float centerY = CANVAS_HEIGHT / 2;
    float radius = min(CANVAS_WIDTH, CANVAS_HEIGHT) / 8; // Smaller circle (was /5)

    // Number of segments to approximate the circle
    const int segments = 36; // More segments = smoother circle

    // Move to starting point with pen up
    penUp();
    float startX = centerX + radius;
    float startY = centerY;
    moveTo(startX, startY);

    // Put pen down to start drawing
    penDown();

    // Draw circle as a series of short lines
    for (int i = 1; i <= segments; i++)
    {
        float angle = 2 * PI * i / segments;
        float x = centerX + radius * cos(angle);
        float y = centerY + radius * sin(angle);
        moveTo(x, y);
    }

    // Lift pen
    penUp();

    Serial.println(F("Circle complete"));
}

finalll.jpg

Estimated BOM (bill of materials)

Item Quantity Unit Price Total
3D Printing material (PLA/PETG) 1 spool ~20€ ~20€
MDF (12mm) 1 sheets ~15€ ~15€
Arduino Uno 1 29.5€ 29.50€
Servo (SG90) 1 3.30€ 3.30€
Dented belt (GT2) 1 17.50€ 17.50€
Stepper + ULN2003 2 motors set 21.25€ 21.25€
Breadboard 1 board 2,25€ 2,25€
Jumping wires 1 pack 3.50€ 3.50€
Power supply DC 5V 1 8.50€ 8.50€
Total ~121€

FILES

3D

CHECKLIST:

Group assignment:

PART 1/2

  • Design a machine that includes mechanism + actuation + automation + application
  • Build the mechanical parts and operate it manually
  • Document the group project

PART 2/2

  • Actuate and automate your machine
  • Document the group project

Individual assignment:

  • Document your individual contribution

Learning outcomes:

  • Work and communicate effectively as a team
  • Design, plan and build a machine
  • Analyse and solve technical problems
  • Recognise opportunities for improvements in the design

Have you answered these questions?

  • Documented the machine building process to the group page
  • Documented your individual contribution to this project on your own website
  • Linked to the group page from your individual page as well as from group page to your individual pages
  • Shown how your team planned, allocated tasks and executed the project (Group page)
  • Described problems and how the team solved them (Group page)
  • Listed possible improvements for this project (Group page)
  • Included your design files (Group page)
  • You need to present your machine globally and/or include a 1 min video (1920x1080 HTML5 MP4) + slide (1920x1080 PNG) (Group page)