If you are building a DIY CNC router, a heavy-duty linear actuator, or a high-torque pan/tilt rig, your default hardware pick should be a NEMA 23 bipolar stepper motor paired with a TB6600 microstepping driver. While smaller NEMA 17 motors dominate 3D printing, they lack the pull-out torque required for heavier mechanical loads. The right arduino stepper motor code relies entirely on matching the physical torque curve of your motor to a driver that can deliver the necessary current without thermal shutdown.

This guide cuts through the guesswork. We will size the motor, wire the driver, and write the exact C++ code to move the load reliably without stalling.

The Core Decision: Which Stepper and Driver Fit Your Load?

Stepper motors are not interchangeable with servos; they operate open-loop and lose torque rapidly as speed increases. Selecting the wrong frame size or driver results in missed steps and ruined workpieces. Below is a comparison of the three most common DIY stepper setups.

Motor Frame Typical Holding Torque Torque Curve Profile Matched Driver Approx. Cost (2026)
NEMA 17 0.40 - 0.59 Nm Drops sharply after 300 RPM A4988 / DRV8825 $12 - $18 (pair)
NEMA 23 1.20 - 3.00 Nm Flat to 600 RPM, drops at 1000 RPM TB6600 / DQ542MA $35 - $55 (pair)
NEMA 34 4.00 - 12.0 Nm High inertia, needs high voltage to maintain torque DM542 / DM860H $90 - $150 (pair)

Decision Path: Pick Your Hardware

If Your Load Profile Is... Then Pick This Motor & Driver Combo
Payload < 2kg, belt-driven, high speed (>800 RPM) NEMA 17 + A4988 (Set to 1/16 microstepping)
Payload 2kg - 15kg, lead-screw or belt, medium speed NEMA 23 + TB6600 (Default Pick for CNC/Actuators)
Payload > 15kg, direct drive, high static holding torque NEMA 34 + DM542 (Requires 48V+ power supply)

For the remainder of this guide, we will proceed with the NEMA 23 and TB6600 combination, as it represents the sweet spot for 90% of advanced hobbyist and light-industrial builds.

Sizing Rule of Thumb and a Worked Load Example

A common mistake is sizing a stepper motor based solely on its holding torque (the torque when the motor is stationary and energized). In motion, you must calculate the pull-out torque at your target speed.

The Sizing Rule of Thumb:
Required Motor Torque = (Calculated Load Torque) × 2.0 (Safety Factor).
Never run a stepper at more than 50% of its rated torque curve at your target RPM, or a sudden load spike will cause a stall.

Worked Example: Lifting a 15kg Load via a Timing Belt

Imagine you are building a vertical Z-axis for a router using a 20mm pitch-diameter GT2 pulley to lift a 15kg spindle assembly.

  1. Calculate Force: F = mass × gravity = 15kg × 9.81 m/s² = 147.15 Newtons.
  2. Calculate Load Torque: Torque = Force × Radius. The pulley radius is 10mm (0.01m).
    T = 147.15 N × 0.01 m = 1.47 Nm.
  3. Apply Safety Factor: 1.47 Nm × 2.0 = 2.94 Nm.

You need a motor that can deliver at least 2.94 Nm at your desired lifting speed. A standard 3.0 Nm NEMA 23 motor is the exact fit. If you tried to use a NEMA 17 (max ~0.59 Nm), the motor would instantly stall and hum loudly the moment you applied power.

Wiring, Terminals, and Driver Setup

The TB6600 is an external chopper driver. Unlike the A4988 which plugs into a breadboard, the TB6600 uses screw terminals and requires its own dedicated power supply (typically 24VDC to 42VDC for NEMA 23 motors).

Identifying Stepper Coil Pairs

NEMA 23 motors often ship with 4, 6, or 8 wires. For the TB6600, you need a 4-wire bipolar configuration. If your motor has 8 wires, you must wire the coils in series for high torque at low speeds, or parallel for high speed. Assuming a standard 4-wire bipolar motor, use your multimeter to find the pairs:

  • Set your multimeter to continuity or resistance (Ohms).
  • Probe the wires until you find two that show a low resistance (typically 1 to 3 Ohms). This is Coil A.
  • The remaining two wires will also show continuity. This is Coil B.
  • Wires from different coils will show infinite resistance (open loop).

TB6600 Terminal and DIP Switch Setup

Terminal / Switch Connection / Setting Notes
A+, A-, B+, B- Stepper Coil A and Coil B If motor runs backward, swap A+ and A-.
PUL+, PUL- Arduino Pin 3 (Step) Pulse signal. Use a 5V logic pin.
DIR+, DIR- Arduino Pin 4 (Direction) High = CW, Low = CCW.
ENA+, ENA- Arduino Pin 5 (Enable) Active LOW. Connect to GND or Pin 5.
DIP Switches (Current) Set to match motor rated Amps Check motor spec sheet. E.g., for 2.5A peak, set SW1=ON, SW2=ON, SW3=OFF (varies by board revision).
DIP Switches (Microstep) Set to 1/16 or 1/32 1/16 is ideal for smooth CNC motion without overloading the Arduino CPU.
Warning: Never disconnect the stepper motor wires from the TB6600 while the power supply is turned on. The resulting voltage spike from the inductive kickback will instantly destroy the driver's internal MOSFETs.

Writing the Arduino Stepper Motor Code (With Acceleration)

The standard Arduino Stepper.h library is useless for real-world loads. It commands the motor to jump instantly to full speed, which exceeds the rotor's inertia and causes an immediate stall. You must use the AccelStepper library to ramp the pulse frequency up and down.

Below is the complete, copy-pasteable Arduino stepper motor code for a TB6600 setup. It moves the motor 6400 steps (one full revolution at 1/16 microstepping), pauses, and returns.

#include <AccelStepper.h>

// Define the stepper driver pins
#define STEP_PIN 3
#define DIR_PIN  4
#define ENA_PIN  5

// Initialize AccelStepper for a 2-wire driver (Step/Dir)
// The '1' denotes a standard step/direction driver
AccelStepper stepper(1, STEP_PIN, DIR_PIN);

void setup() {
  Serial.begin(115200);
  
  // Configure Enable pin
  pinMode(ENA_PIN, OUTPUT);
  digitalWrite(ENA_PIN, LOW); // TB6600 Enable is Active LOW
  
  // Set motor parameters based on TB6600 DIP switches
  // If set to 1/16 microstepping: 200 steps/rev * 16 = 3200 steps/rev
  stepper.setMaxSpeed(3200.0);      // 1 revolution per second max
  stepper.setAcceleration(1600.0);  // Ramp up to max speed in 0.5 seconds
  
  // Set initial position
  stepper.setCurrentPosition(0);
  
  Serial.println("Homing complete. Ready for motion.");
}

void loop() {
  // Move 6400 steps (2 revolutions) forward
  if (stepper.distanceToGo() == 0) {
    if (stepper.currentPosition() == 0) {
      stepper.moveTo(6400);
      Serial.println("Moving Forward 2 Revs...");
    } else {
      stepper.moveTo(0);
      Serial.println("Moving Reverse 2 Revs...");
    }
  }
  
  // The run() function must be called as frequently as possible
  // It handles the acceleration math and step timing
  stepper.run();
}

Why this code works: The stepper.run() function calculates the exact microsecond delay required between pulses to maintain the acceleration curve defined by setAcceleration(). If you put long delay() functions inside your loop(), the step pulses will stutter, and the motor will lose synchronization.

Diagnosing Failure Signatures: Hum, Overheat, and Stall

When a stepper system fails, it rarely does so silently. The physical symptoms tell you exactly whether the fault lies in the mechanical load, the driver DIP switches, or the Arduino code.

Failure Signature Root Cause The Fix
Loud Humming / Vibrating but No Movement The code is commanding a starting speed higher than the motor's pull-in torque, OR the TB6600 current limit is set too low to overcome static friction. Increase setAcceleration() to a lower value (e.g., 800.0) to ramp up slower. Verify TB6600 DIP switches match the motor's rated peak current.
Motor Overheating (>60°C / 140°F) Driver current limit is set significantly higher than the motor's rated RMS current, or the motor is holding a heavy load at 100% duty cycle without airflow. Drop the TB6600 current setting by one DIP switch tier. Add a heatsink to the motor casing or reduce the holding current via code when stationary.
Stalling Mid-Move (Loss of Position) The load exceeds the motor's pull-out torque at the target RPM. Stepper torque drops inversely with speed due to coil inductance limiting current rise time. Increase the TB6600 power supply voltage (e.g., from 24V to 36V). Higher voltage forces current into the coils faster, flattening the torque curve at high RPMs.
Erratic Jittering at Standstill Electrical noise on the Step/Dir lines, or floating Enable pins. Ensure PUL-, DIR-, and ENA- are tied to a common Arduino GND. Use shielded twisted-pair cable for long runs between the Arduino and TB6600.

By treating the arduino stepper motor code and the physical driver hardware as a single integrated system, you eliminate the trial-and-error that plagues most DIY motion control builds. Stick to the 2.0x safety factor, use AccelStepper for all motion profiling, and let the TB6600 handle the heavy current switching.