Skip to content

Week 12 — Mechanical Design & Machine Design


Assignment

Group Assignment: - Design a machine that includes mechanism + actuation+ automation + function + user interface - Build the mechanical parts and operate it manually - Document the group project!

Individual Assignment: - Document your individual contribution


Here is my plan for the week:

Planning sheet for the week


What We Built


This week our group of three built a 2-axis pen plotter — a drawing machine that moves a pen across paper using two stepper motors on X and Y axes, controlled by GRBL firmware running on an Arduino Nano. The machine uses GT2 timing belts and 20-tooth pulleys for motion, and an MG90S servo to lift and lower the pen.

We split the work based on what each of us does best. My two teammates handled everything mechanical — the frame design, the CAD work, and the 3D printed pen holder. My part was everything electronics — designing and milling the custom PCB, wiring it all up, testing every component, flashing and configuring GRBL, and getting the whole electronics side talking to the machine.

Rough sketch of the project from the planning stage


My Individual Contribution — Electronics

My work division — electronics

The rest of this page documents my part of the project. For the mechanical side, check out my teammates' pages.


Components

Here's everything that went into the electronics:

Component Spec Quantity
Arduino Nano ATmega328P 1
Stepper Motor NEMA 17 — Jameco 42BYG44B, 1A, 4V rated 2
Motor Driver A4988 module (clone, Rs = 0.1Ω) 2
Servo MG90S 1
Capacitor 100µF electrolytic 1
Power Supply (motors) 12V 5A 1
Power Supply (logic) 5V 2.5A 1

PCB Design

I designed a custom PCB in KiCad to keep all the electronics together cleanly instead of running everything off a breadboard. The board handles both stepper motor drivers, the servo signal, and the Arduino Nano, with separate power rails for the motors (12V) and the logic (5V).

Schematic

I started by placing all the symbols in KiCad — the Arduino Nano, two A4988 footprints, the servo connector, power connectors, and the 100µF decoupling capacitor on the motor rail.

Symbols placed in KiCad schematic

After placing the symbols I wired everything up following the standard GRBL pin mapping:

Signal Arduino Nano Pin
X STEP D2
X DIR D5
Y STEP D3
Y DIR D6
EN (Enable) D8
Servo PWM D11

MS1, MS2, MS3 on both A4988 drivers are hardwired to 5V directly on the board — this locks the drivers into 1/16 microstepping permanently, which gives smooth and quiet movement without needing any firmware configuration for it.

Completed wiring in KiCad schematic

PCB Layout and Routing

Once the schematic was done I updated the PCB from it and started routing traces.

Updating PCB from schematic — step 1

Updating PCB from schematic — step 2

I set the trace width before routing to make sure the power traces were thick enough to handle the current.

Setting trace size before routing

Then I routed all the traces manually.

Routing traces in KiCad PCB editor

Final routed PCB

After routing I added the edge cuts to define the board outline.

Edge cut in PCB editor

Here's the 3D view of the final board.

3D view of the PCB


Generating the RML File for Milling

To mill the board I used MODS CE to generate the RML file from the PCB Gerber. The process is the same as Week 8 so I'll keep this brief.

I selected the SRM-20 PCB preset in MODS CE.

Selecting SRM-20 PCB in MODS CE

Then I set the origin to zero.

Setting origin to zero in MODS CE

I added the save module to export the RML file.

Adding save module — step 1

Adding save module — step 2

I calculated and downloaded the RML file.

RML file calculated and ready to download

I also generated a separate RML file for the edge cuts.

3D MODS view — trace layer

3D MODS view — edge cut layer


Milling the PCB

I used the Roland SRM-20 — same machine as Week 8. First I stuck the copper plate to the sacrificial board with double-sided adhesive tape.

Double sided adhesive tape on the copper plate

Copper plate stuck to the sacrificial board

Then I sent the RML file to the machine from the desktop software.

Sending the RML file from the desktop software

The trace milling went cleanly.

Trace milling in progress

Traces milled — result

Then I ran the edge cut.

Edge cuts milled

Selecting the RML file for edge cut


Soldering

After milling I soldered all the components onto the board.

Components solder list — part 1

Components solder list — part 2

Here's the finished soldered board.

PCB fully soldered


Testing the PCB Connections

Before powering anything I checked all the traces with a multimeter in continuity mode to make sure nothing was shorted or broken. Everything beeped correctly — all traces continuous, no shorts between power rails.

Checking PCB connections with multimeter


Setting the Vref

Before connecting any motors I had to set the Vref on both A4988 drivers. This controls the current limit the driver sends to the motor — getting it wrong can burn out the motors or the drivers.

The formula is:

Vref = Imotor × 8 × Rs

My motors are rated at 1A and the A4988 modules have 0.1Ω sense resistors (marked R100 on the chip). I run the motors at 80% of rated current to keep them cool, so:

Vref = 0.8A × 8 × 0.1Ω = 0.64V

I worked out the calculation on paper first before touching the trimmer pot.

Vref calculation worked out on paper

Then I set up the A4988 on the breadboard with 12V and the Nano connected, and measured Vref at the trimmer pot center with the multimeter. Red probe on the trimmer, black probe to GND. I adjusted slowly until both drivers read exactly 0.64V.

Measuring and setting Vref with multimeter


Breadboard Motor Test

Before trusting the PCB I tested everything on a breadboard first — one A4988, one motor, the Nano. Good habit — verify the components work before combining them.

I wired up the full A4988 circuit: VMOT to 12V, VDD to Nano 5V, common GND between Nano and driver, SLEEP and RESET tied together, MS1/2/3 all to 5V for 1/16 microstepping, and the motor wires in the correct coil order (Red→1A, Blue→1B, Green→2A, Black→2B).

The first few tests didn't spin — the motor was just vibrating. Turned out it was a combination of the step delay being too fast and the EN pin not being pulled LOW in the code. Once I fixed both of those and confirmed the SLEEP/RESET tie the motor started spinning cleanly.

I ran through a series of delay values to find the speed limits:

delayMicroseconds Mode Status
2000µs Full step ✅ Smooth
500µs Full step ✅ Smooth
300µs Full step ❌ Not turning
500µs 1/16 micro ✅ Smooth
200µs 1/16 micro ✅ Working
50µs 1/16 micro ✅ Smoothest
30µs 1/16 micro ✅ Working
20µs 1/16 micro ❌ Not spinning

The 1/16 microstepping was noticeably smoother and quieter than full step — the steps blend together almost like a sine wave at high step rates. The sweet spot ended up being around 50µs: smooth, quiet, and reliable. I confirmed both motors worked the same way before moving to the PCB.

Motor and A4988 driver test on breadboard


Testing on the Custom PCB

With breadboard testing done I moved to the custom PCB. The pin mapping follows the GRBL standard so I had to make sure my code matched:

#define STEP_PIN 2   // X STEP → D2
#define DIR_PIN 5    // X DIR → D5
#define EN_PIN 8     // EN → D8

void setup() {
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);  // LOW = driver enabled
  digitalWrite(DIR_PIN, HIGH);
}

void loop() {
  for(int i = 0; i < 3200; i++) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(50);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(50);
  }
  delay(1000);
  digitalWrite(DIR_PIN, LOW);
  for(int i = 0; i < 3200; i++) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(50);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(50);
  }
  digitalWrite(DIR_PIN, HIGH);
  delay(1000);
}

One thing I had to figure out — on the PCB the EN pin goes to D8, which is how GRBL controls it. But since I was running a simple test sketch GRBL wasn't managing it, so D8 was floating. I had to explicitly set digitalWrite(EN_PIN, LOW) to enable the drivers. Without that line the motor does absolutely nothing.

I also added short jumper wires bridging SLEEP and RESET directly on each A4988 module — GRBL handles this automatically later but for manual sketch testing the sketch wasn't controlling those pins so they needed to be tied.

Motor X working:

PCB motor X test setup

Then I tested Motor Y (D3/D6), both motors together in the same direction, both in opposite directions, and finally independent control — X spinning while Y stays still, then Y while X stays still.

Both motors connected to PCB

Each test passed cleanly:

Test Status
Motor X individual (D2/D5)
Motor Y individual (D3/D6)
Both motors same direction
Both motors opposite direction
Independent motor control

Servo Test

With motors confirmed I moved to the servo. The MG90S connects to D11 (signal), 5V, and GND on the PCB. I uploaded a simple angle finder sketch that takes inputs over Serial Monitor and moves the servo to them, cycling UP and DOWN three times so you can check the position visually:

#include <Servo.h>

Servo penServo;
int penUp = -1;
int penDown = -1;

void setup() {
  Serial.begin(9600);
  penServo.attach(11);
  Serial.println("=== Pen Servo Angle Finder ===");
  Serial.print("Enter PEN UP angle (0-180): ");
}

void loop() {
  if (Serial.available() > 0) {
    String input = Serial.readStringUntil('\n');
    input.trim();
    int angle = input.toInt();

    if (penUp == -1) {
      penUp = angle;
      penServo.write(penUp);
      Serial.print("PEN UP set to: ");
      Serial.println(penUp);
      delay(1500);
      Serial.print("Enter PEN DOWN angle: ");
    } else if (penDown == -1) {
      penDown = angle;
      penServo.write(penDown);
      Serial.print("PEN DOWN set to: ");
      Serial.println(penDown);
      delay(1500);
      Serial.println("Cycling 3 times...");
      for (int i = 0; i < 3; i++) {
        penServo.write(penUp);
        Serial.println("PEN UP");
        delay(1500);
        penServo.write(penDown);
        Serial.println("PEN DOWN");
        delay(1500);
      }
      penUp = -1;
      penDown = -1;
    }
  }
}

My teammate had finished the first version of the 3D printed pen holder at this point so I could test with the actual assembly. After trying a few angles:

Position Angle
Pen UP 90°
Pen DOWN

Servo test with pen holder on PCB


All Components Together

Before moving to firmware I ran one final test with all three components running simultaneously — both stepper motors and the servo — to make sure there were no interference issues between them.

#include <Servo.h>

#define STEP_X 2
#define DIR_X 5
#define STEP_Y 3
#define DIR_Y 6
#define EN_PIN 8
#define SERVO_PIN 11

Servo penServo;

void setup() {
  pinMode(STEP_X, OUTPUT); pinMode(DIR_X, OUTPUT);
  pinMode(STEP_Y, OUTPUT); pinMode(DIR_Y, OUTPUT);
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);
  digitalWrite(DIR_X, HIGH); digitalWrite(DIR_Y, HIGH);
  penServo.attach(SERVO_PIN);
}

void loop() {
  penServo.write(90); // Pen UP
  delay(1000);
  for(int i = 0; i < 3200; i++) {
    digitalWrite(STEP_X, HIGH); digitalWrite(STEP_Y, HIGH);
    delayMicroseconds(50);
    digitalWrite(STEP_X, LOW); digitalWrite(STEP_Y, LOW);
    delayMicroseconds(50);
  }
  delay(500);
  penServo.write(0); // Pen DOWN
  delay(1000);
  for(int i = 0; i < 3200; i++) {
    digitalWrite(STEP_X, HIGH); digitalWrite(STEP_Y, HIGH);
    delayMicroseconds(50);
    digitalWrite(STEP_X, LOW); digitalWrite(STEP_Y, LOW);
    delayMicroseconds(50);
  }
  delay(500);
}

All components test on PCB

Everything worked together cleanly — no jitter, no interference between the servo PWM and the stepper signals. Hardware fully verified. ✅


Flashing GRBL

With all the hardware confirmed working it was time to flash GRBL firmware. I used grbl-servo — a fork of GRBL specifically made for pen plotters that controls the servo through the spindle PWM pin (D11) using M3/M5 commands. The PWM frequency is set to 61Hz which is perfect for the MG90S.

Downloading and Installing

I downloaded the grbl-servo ZIP from the cprezzi/grbl-servo GitHub repository.

Downloading grbl-servo ZIP from GitHub

Extracted the ZIP and found the inner grbl folder.

Extracting the grbl-servo ZIP

Then copied just that inner grbl folder into Documents → Arduino → libraries.

Copying the grbl folder into Arduino libraries

grbl library installed in Arduino IDE

Uploading

I opened File → Examples → grbl → grblUpload and uploaded it to the Nano.

grblUpload sketch open in Arduino IDE

GRBL upload complete

GRBL uses 97% of the Nano's flash — that's completely expected. It's a big firmware that's heavily optimized to fit on the ATmega328P. Upload completed successfully.


Problem — Nano Bootloader Issue

After flashing GRBL and doing some initial testing, the Nano suddenly stopped responding to uploads. TX/RX LEDs weren't blinking on plug-in, and every upload attempt came back with:

Error: programmer is not responding
not in sync: resp=0x00

The Nano was getting power but the bootloader wasn't responding at all. I went through the full diagnosis:

  • Power LED was on ✅
  • COM port visible in Device Manager ✅
  • Tried both ATmega328P and ATmega328P (Old Bootloader) processor settings ❌
  • Tried different baud rates ❌
  • Tried the manual reset timing trick during upload ❌

After some digging the real fix turned out to be a CH340 driver version issue. The latest CH340 driver on Windows has a known incompatibility with certain clone Nanos. The fix was to install an older version — specifically version 3.7.2022.01 — from the archived WCH page.

I also had to switch the processor setting to ATmega328P (Old Bootloader) to match the bootloader on the clone boards.

With those two fixes applied to a second Nano from the lab, uploads started working immediately.

Setting Value
Board Arduino Nano
Processor ATmega328P (Old Bootloader)
CH340 driver Version 3.7.2022.01
Port COM17
Baud (upload) 57600

Port, board and processor settings confirmed in Arduino IDE

I reflashed GRBL on the new Nano and verified it in Serial Monitor at 115200 baud.

GRBL responding in Serial Monitor — Grbl 1.1f

Grbl 1.1f ['$' for help] — we're back. ✅

The lesson: if you're using clone Nanos on Windows and getting not in sync errors, try the older CH340 driver before assuming the board is dead.


Configuring GRBL

With GRBL running on the new Nano I configured all the settings. The most important one is steps/mm — this tells GRBL how many motor steps equal one millimeter of travel.

Steps/mm calculation:

  • 1/16 microstepping → 3200 steps per revolution
  • GT2 belt → 2mm pitch
  • 20 tooth pulley
steps/mm = (200 × 16) ÷ (20 × 2) = 80 steps/mm

I sent these commands one by one in Serial Monitor, each returning ok:

$100=80    → X steps/mm
$101=80    → Y steps/mm
$110=3000  → X max speed (mm/min)
$111=3000  → Y max speed (mm/min)
$120=500   → X acceleration (mm/s²)
$121=500   → Y acceleration (mm/s²)
$30=255    → Servo max S value
$31=0      → Servo min S value
$32=0      → Laser mode OFF

I verified with $$ to confirm everything saved correctly.


Testing with UGS

To verify GRBL was actually controlling the motors I installed Universal G-code Sender (UGS Platform).

Downloading UGS

Extracting UGS files

First launch showed a Windows security warning — clicked "More info" then "Run anyway".

UGS installed and running

Windows protection warning on UGS launch

I connected UGS to COM17 at 115200 baud. GRBL responded immediately. I used the Machine Control panel to jog X and Y — set feed rate to 1000 mm/min and step size to 10mm and both motors responded correctly to every button press.

UGS connection settings — port and baud

UGS Machine Control — jogging X and Y

XY control working through UGS

Motors responding to G-code commands through GRBL — that was a big moment. Everything from the PCB traces all the way up to the firmware layer was working.


Setting Up GRBL-Plotter

UGS is great for jogging but to actually send drawing files to the machine I needed something that generates G-code from a design. I initially looked into Inkscape extensions but most of them were built for older Inkscape versions and output Z-axis commands for pen up/down — not the M3/M5 servo commands my setup uses.

GRBL-Plotter was the better choice — it's an all-in-one tool that imports SVG files directly and has built-in servo pen up/down support. I downloaded it from the GRBL-Plotter GitHub releases page.

Downloading GRBL-Plotter from GitHub

After connecting to COM17 at 115200 I went into the setup and configured the servo pen commands. I switched from Z-axis mode to PWM mode and set:

Setting Value
Pen UP (P90) S100
Pen DOWN (P92) S30
XY Feedrate 2000 mm/min
G-code Header G21; G90; M3 S100
G-code Footer M3 S100; G0 X0 Y0; M5

GRBL-Plotter servo configuration — PWM pen up/down settings

The G-code header lifts the pen before any movement starts and sets millimeter units and absolute positioning. The footer lifts the pen again, returns to home, then turns the servo off. These are important — without them the pen drags across the paper whenever the machine moves between shapes.

I also verified the servo S values by sending commands directly from GRBL-Plotter's console before running any files:

Command Result
M3 S100 Pen UP ✅
M3 S30 Pen DOWN ✅

First G-code Test

With everything configured I generated a text G-code file using GRBL-Plotter's built-in text tool and ran it to test all components working together end to end — both motors moving on X and Y, servo lifting and lowering the pen at the right moments, all coordinated through GRBL.

The frame isn't fully assembled yet at the time of writing — I'm running the motors, servo, and PCB off the bench for now — but all the electronics responded exactly as expected to the G-code commands.

Text G-code test — all components running together through GRBL-Plotter

This is the full electronics setup on the bench:

Hero shot — full electronics setup on the bench


After that I assembled the frame and also I designed and added a drag-chain for the servo wires.

Final Project Results

Final project results