How to Retrofit a Standard NEMA 17 Motor with Encoder Feedback

·Grafito Innovations
NEMA 17 motor with CANStepper board mounted on the rear, showing encoder magnet and alignment

If you work with stepper motors in robotics, CNC, or automation, you have probably experienced missed steps — that moment when your open-loop stepper fails to execute a commanded move because of binding, sudden load, or overly aggressive acceleration profiles. The fix? Add position feedback.

This guide walks through retrofitting a standard NEMA 17 stepper motor with a magnetic encoder, step by step. We use Grafito's CANStepper controller board as the example platform, but the mechanical and electrical principles apply to any encoder-based retrofit.

Why Retrofit Instead of Replacing?

Buying a new closed-loop stepper motor out of the box is one path. Retrofitting your existing motor is another — and often the better choice when:

  • You already have motors mounted in your machine and don't want to redesign the bracket geometry.
  • Your NEMA 17 motors are high-quality units you trust (good bearings, known torque curves).
  • You want to add closed-loop capability without discarding working hardware.
  • You need a path to gradually upgrade — retrofit one axis at a time.

The core idea: mount a magnetic encoder behind the motor's rear shaft, let a controller board read absolute angle in real time, and close the position loop in firmware.

What You Need

Here is the bill of materials for one retrofit:

ItemNotes
NEMA 17 stepper motorMust have a rear shaft (dual-shaft) or accessible rear bearing face. Single-shaft motors with a flat rear end can work with adhesive-mounted magnets.
Magnetic rotary encoderMT6701 (14-bit, SPI/I2C) is the recommended choice. It offers 0.022° resolution and a wide air-gap tolerance.
Diametrically magnetised disc magnetØ6 mm × 2.5 mm is standard. Must be diametrically polarised (N-S across the diameter, not through the thickness).
Mounting bracket or adapterHolds the encoder PCB at a fixed distance from the magnet. CANStepper includes an integrated bracket. For DIY builds, 3D-print a spacer ring.
Controller boardWe use the CANStepper (ESP32-C3 + TMC2209 + MT6701). Alternatives: any MCU with SPI/I2C + a stepper driver.
Power supply5–24 V DC, rated for your motor's current draw plus controller overhead.
USB-C cableFor flashing firmware and serial monitoring.

Step 1: Mechanical Mounting

Access the Rear Shaft

If your NEMA 17 has a dual shaft (shaft protruding from both ends), the rear shaft is your magnet mounting surface. Clean it with isopropyl alcohol first.

If your motor is single-shaft, the rear face is typically a flat bearing cap. You can bond the magnet directly to the centre of this face — but alignment becomes more critical, and you lose the self-centring benefit of a shaft.

Magnet Alignment

The magnet must be centred over the encoder IC and sit within the specified air gap:

  • Gap range: 0.5–2.0 mm between magnet face and encoder chip surface.
  • Too close (< 0.3 mm) risks mechanical contact if the shaft has any axial play.
  • Too far (> 2.5 mm) degrades signal-to-noise ratio and can cause angle jitter.

Attachment options:

MethodBest for
Press-fit onto rear shaftDual-shaft motors — fast, reliable, no cure time.
Cyanoacrylate (super glue)Quick fix; can become brittle under vibration.
Epoxy (two-part)Strongest bond; recommended for production use.

If gluing, apply a tiny amount to the magnet centre only — avoid squeeze-out onto the encoder PCB.

Mount the Encoder Board

The encoder PCB must be rigidly fixed relative to the motor body. CANStepper uses a PCB that sandwiches between the motor and the mounting surface, with a cutout that aligns the MT6701 over the rear shaft. If you are fabricating your own bracket:

  1. Measure the motor's bolt pattern (standard NEMA 17: 31 mm × 31 mm, M3 screws).
  2. Design a spacer that stands the PCB off the motor by the correct distance.
  3. Use nylon standoffs to avoid shorting the PCB to the motor housing.

Step 2: Magnet Calibration

Once mechanically mounted, calibrate the encoder before trusting its readings.

CANStepper Calibration Routine

On CANStepper, calibration is built into the firmware. Connect via USB-C serial (115200 baud) and send:

$CAL

The firmware will:

  1. Spin the motor slowly through several full rotations.
  2. Record the raw magnetic field vectors (X, Y components).
  3. Compute gain and offset corrections for each axis.
  4. Store the calibration in non-volatile memory.

After calibration, verify the readout:

$ANGLE

Rotate the shaft by hand. You should see a smooth 0–360° output with no jumps, dead spots, or wraparound glitches. If you see jitter beyond ±0.1°, re-check the air gap and magnet centring.

DIY Calibration (Without CANStepper)

If you are using a raw MT6701 over I2C/SPI with your own MCU:

  1. Read raw angle at a known rate (e.g., 1 kHz).
  2. Spin the motor at a constant speed (use another motor or a drill).
  3. Collect a full-revolution dataset of raw readings.
  4. Fit an elliptical correction: the raw X-Y plot of magnetic field vectors forms an off-centre ellipse. Scale and shift it to a unit circle.
  5. Apply the correction as atan2(corrected_Y, corrected_X).

This is doable but tedious — CANStepper's built-in calibration saves significant time.

Step 3: Electrical Connections

Motor Phase Wiring

NEMA 17 steppers have two phases (A and B), each with a centre-tapped coil. Wire the full coil (end-to-end) for maximum torque:

Motor wire colour (typical)PhaseCANStepper terminal
BlackA+A1
GreenA-A2
RedB+B1
BlueB-B2

Note: Wire colour conventions vary by manufacturer. Use a multimeter in continuity mode to identify coil pairs: low resistance (~1–5 Ω) between A+ and A-, same for B+ and B-. Infinite resistance between A and B wires.

Encoder Connection

On CANStepper, the MT6701 is already integrated on the PCB — no external wiring needed. If you are wiring a standalone MT6701 breakout:

MT6701 → MCU
VCC    → 3.3V
GND    → GND
SDA    → GPIO (I2C data)
SCL    → GPIO (I2C clock)

Add 4.7 kΩ pull-up resistors on SDA and SCL if your MCU doesn't have internal pull-ups.

Power Supply

CANStepper accepts 5–24 V DC on the main power input. Choose a supply based on your motor's rated voltage:

  • For a 2.8 V / 1.2 A NEMA 17: a 12 V supply gives good high-speed performance.
  • For a 3.6 V / 1.7 A NEMA 17: a 24 V supply improves torque at speed.

The TMC2209 driver regulates current internally, so the supply voltage does not set the motor current — it only affects the maximum speed before back-EMF limits torque.

Step 4: Configure Motor Current

Setting the correct RMS current is critical. Too low and you lose torque. Too high and the motor overheats.

Find Your Motor's Rated Current

Check the motor datasheet. Common NEMA 17 ratings:

Motor lengthTypical rated current (RMS)
34 mm1.0 A
40 mm1.2 A
48 mm1.5–1.7 A
60 mm2.0 A

Set Current on CANStepper

CANStepper uses the TMC2209 in StealthChop2 mode with software-configurable RMS current. Send:

$CURR 1200

This sets 1200 mA RMS (1.2 A). The TMC2209 automatically scales this to the appropriate peak current internally.

Validation: After setting current, run the motor at 60 RPM under load for 10 minutes. The motor case should be warm but not too hot to touch (max ~80 °C on the case is acceptable for most NEMA 17 steppers). If it's scorching, reduce current by 100 mA and retest.

Step 5: Flash Firmware

CANStepper Firmware

CANStepper ships with closed-loop firmware pre-flashed. To update or re-flash:

# Using esptool.py
esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 921600 write_flash \
  0x0 canstepper-firmware.bin

Find the latest firmware at docs.grafito.in.

Verify Encoder Data

After flashing, open a serial terminal:

screen /dev/ttyUSB0 115200

Send $STATUS. You should see:

MODE:CLOSED_LOOP POS:0.00 ERR:0.00 TEMP:32.4 CURR:0.00

Rotate the shaft by hand. The POS field should track the movement. If it stays at 0.00 or jumps erratically, revisit Step 2 (calibration) and check the magnet gap.

Step 6: Closed-Loop Test

Now the real test — does the loop actually close?

Basic Position Command

Send an absolute move command:

$GOTO 90.0

The motor should rotate to 90°. Read back:

$WHERE

Expected: 90.00 ± 0.1°. If it overshoots and oscillates, the position-loop gains need tuning (Step 7).

Load Test

  1. Command a move to 180°.
  2. While holding position, apply a gentle load with your hand (try to back-drive the shaft).
  3. Monitor the error with $ERR.

A well-tuned loop should resist the load, detect the position error, and drive current to restore position — all within a few hundred milliseconds. The error should settle back to near zero.

Repeatability Test

Run a sequence:

$GOTO 0
$GOTO 360
$GOTO 0
$GOTO 360

After 10 cycles, check that the shaft returns to the same physical position each time. A repeatability of ±0.05° is achievable with the MT6701.

Step 7: Tuning

Closed-loop performance depends on three gain terms.

PID Gains

TermEffectTypical CANStepper default
P (proportional)Stiffness — how hard the motor pushes back against position error.8.0
I (integral)Eliminates steady-state error over time. Too high causes slow oscillation.0.5
D (derivative)Damping — resists rapid changes, reduces overshoot.2.0

Tuning process:

  1. Start with P only (I=0, D=0). Increase P until the motor oscillates (audible buzz), then back off by 30%.
  2. Add D to damp the oscillation. Increase until the motor feels "stiff but quiet."
  3. Add I to eliminate any residual steady-state error after a move completes.

Send gains via serial:

$PID 8.0 0.5 2.0

Velocity Feedforward

Feedforward predicts the required current for a target velocity, reducing the burden on the feedback loop. CANStepper exposes this as:

$VFF 0.15

A good starting value is 0.10–0.20. Too high causes overshoot on deceleration; too low and the motor lags during constant-velocity segments.

Trapezoidal Velocity Profiles

For point-to-point moves, a trapezoidal profile (accelerate → cruise → decelerate) minimises jerk and missed steps:

$PROFILE TRAPEZOID
$ACCEL 500      # deg/s²
$VEL 300        # deg/s cruise
$GOTO 720.0     # two full revolutions

The motor should accelerate smoothly, hold speed, then decelerate to a clean stop — no audible knocking or oscillation at the endpoints.

Step 8: Limitations

Closed-loop retrofitting is powerful, but it has real-world constraints:

Speed Under Load

A NEMA 17 running closed-loop at 24 V can typically hold torque up to ~300 RPM. Beyond that, back-EMF reduces available current, and the loop may not keep up with rapid load changes. For high-speed applications (> 1000 RPM), consider a NEMA 23 or a dedicated servo motor.

NEMA 17 Only

The CANStepper form factor is designed for NEMA 17 (42 mm frame) motors. It does not fit NEMA 14, NEMA 23, or larger frames without mechanical modification.

GCSP Protocol, Not CANopen

CANStepper uses GCSP (Grafito Closed-Loop Stepper Protocol), a lightweight CAN protocol designed for simplicity and low overhead. It is not CANopen or CiA 402 compatible. If your system requires standards-compliant CANopen, verify protocol compatibility before committing.

Encoder Resolution

The MT6701 provides 14-bit resolution (16,384 counts/rev). This is excellent for most applications, but high-precision metrology or sub-arcminute positioning may need optical encoders with higher line counts.

Next Steps

Once your first motor is running closed-loop:

  • Add a second motor and test multi-axis coordination.
  • Connect via CAN Bus — daisy-chain up to 16 nodes on a single twisted pair. CANStepper auto-negotiates node IDs.
  • Integrate limit switches for homing routines.
  • Explore the GCSP command set at docs.grafito.in — absolute/relative moves, velocity mode, position streaming, and diagnostics.

Resources


Retrofitting encoder feedback onto your existing NEMA 17 motors is one of the most cost-effective upgrades you can make to a motion system. Start with one axis, dial in the tuning, and expand from there. If you hit a snag, reach out — we build these boards and we answer the phone.