Skip to content

10. Output devices

motors

Overview of week 10 assignment

  1. Group assignment
    1. measure the power consumption of an output device
  2. Individual assignment
    1. add an output device to a microcontroller board you’ve designed, and program it to do something

1. Group assignment

For more information, see the Week 10: Group assignment page.

2. Individual assignment

The final project uses a stepper motor, so I used a stepper motor in week 04, but this time I tried using a different type of stepper motor, unipolar stepper motor.

A. Basics of stepper motor

  • A stepper motor consists of a stator with coils and a rotor with permanent magnets.
  • Unlike brushed DC motors, stepper motors have no brushes to change the direction of the current and reverse the magnetic field.
  • An electronic circuit switches the current flowing through the coils to rotate the motor.
  • Which also makes it possible to precisely control the angle and direction of rotation.
  • This electronic circuit is called a motor driver. There are several types of stepper motors, depending on the method of switching the flow of current.

a. Unipolar vs. Bipolar stepper motor

Feature Unipolar Stepper Motor Bipolar Stepper Motor
Wiring 5 or 6 wires (center tap on each coil) 4 wires (no center tap)
Driving Complexity Easier to drive (can use simpler drivers like ULN2003) Requires H-bridge driver (e.g., A4988, DRV8825)
Current Flow Current flows through half of the coil at a time Current flows through the entire coil
Torque Lower torque due to partial coil use Higher torque as the full coil is utilized
Efficiency Less efficient due to center tap limiting power More efficient since all winding power is used
Step Control Simpler control logic More complex control but more precise movement
Common Examples 28BYJ-48 stepper motor NEMA 17 stepper motor

B. Unipolar stepper motor: 28BYJ-48

I tried using the 28BYJ-48 unipolar stepper motor and ULN2003 driver (Akizuki Denshi). Below are the specifications from the datasheet:

Specification 28BYJ-48 Stepper Motor
Operating Voltage 5V DC
Operating Current 240mA (typical)
Number of Phases 4
Gear Reduction Ratio 64:1
Step Angle 5.625°/64 (≈0.0879° per step)
Steps per Revolution 2048
Frequency 100Hz
In-traction Torque >34.3 mN.m (120Hz)
Self-positioning Torque >34.3 mN.m
Friction Torque 600-1200 gf.cm
Pull-in Torque 300 gf.cm
Specification ULN2003 Stepper Driver
Operating Voltage 5V – 12V
Max Output Current 500mA per channel
Number of Channels 4
Control Inputs IN1, IN2, IN3, IN4

a. Wiring

I wired the 28BYJ-48 and ULN2003 to my development board following Control 28BYJ-48 Stepper Motor with ULN2003 Driver & Arduino.
The example uses Arduino board, so I rewired it to RP2040 development board as follows:

ULN2003 Driver RP2040
IN1 26
IN2 27
IN3 28
IN4 29

wiring_diagram

The GND and VCC of the ULN2003 were connected to the Power Supply DP100 and set to constant voltage output mode (CV) and 5.0V. Initially, I forgot to wire the GND on RP2040 board, so I used a breadboard to add a GND wire connected to the GND of the power supply (I forgot to take a picture).

wiring

b. Programming

This sample code is based on the above site and will rotate 360 ​​degrees slowly clockwise, then rotate 360 ​​degrees counterclockwise quickly, then repeat.

First, I installed the library "Stepper" by Arduino:
Tools > Manage Libraries > Library Manager > Search "Stepper" and install it

There are 2 interesting lines:

  1. Defining steps per revolution: const int stepsPerRevolution = 2048;
    Total number of steps needed for the motor to complete 360° rotation. In this case, it's 2048.
  2. Creating a stepper motor instance: Stepper myStepper = Stepper(stepsPerRevolution, 26, 28, 27, 29);
    • stepsPerRevolution is difined as above.
    • The four numbers 26, 28, 27, 29 specify which pins control the four stepper motor coil wires. This library is for stepper motors in general and not specifically for unipolar stepper motors, so the pin order is not in numerical order.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Includes the Arduino Stepper Library
#include <Stepper.h>

// Defines the number of steps per rotation
const int stepsPerRevolution = 2048;

// Creates an instance of stepper class
// Pins entered in sequence IN1-IN3-IN2-IN4 for proper step sequence
Stepper myStepper = Stepper(stepsPerRevolution, 26, 28, 27, 29);

void setup() {
  // Nothing to do (Stepper Library sets pins as outputs)
}

void loop() {
    // Rotate CW slowly at 5 RPM
    myStepper.setSpeed(5);
    myStepper.step(2048);
    delay(1000);

    // Rotate CCW quickly at 10 RPM
    myStepper.setSpeed(10);
    myStepper.step(-2048);
    delay(1000);
}

Check components carefully!

I struggled twice because of the components I tried.

  1. I first picked a 28BYJ-48, although I felt a slight vibration, the motor did not rotate. This is because the rated voltage was 12V instead of 5V. They look identical, but it is noted on the back of the motor.
  2. The second motor I chose worked, but it didn't change direction as expected, it rotated once clockwise, once counterclockwise, and then continued to rotate counterclockwise. This is because the motor had been modified (the cover had been opened and the 5V trace had been disconnected, probably to use it as a bipolar stepper motor).

traps

Again, I forgot to take video but it worked...


C. Bipolar stepper motor: Nema17 (17HS4023)

This is a schematic diagram of a bipolar stepper motor using an H-bridge. You can see that the H-bridge drives the motor by changing the direction of the current passing through the two coils. I could find out more details on the following sites.

bipolar_Hbridge

In week 04, I tried using a Nema17 with an RP2040 and a 5V power supply without using the Stepper library. This time I was planning to use the Stepper library and microstepping...

a. Wiring

Wiring is almost the same as the week 04, but I connected MS1, 2, 3 to RP2040 to try micro stepping. Please visit week 04 for components I used.

Nema17_wiring

Pin/Function Description RP2040 / Nema17
ENABLE LOW = enabled, HIGH = disabled -
MS1, MS2, MS3 Set step mode P28, P29, P6
RESET LOW = resets input to translator, ignores signals until HIGH connected to SLEEP
SLEEP LOW = sleep mode (minimizes power consumption) connected to RESET
STEP Controls motor rotation by inputting pulse signals P27
DIR Sets rotation direction P26
VMOT Motor power supply (8-35V, up to 35V) 9V power supply
A1, A2, B1, B2 Stepper motor connections Nema17 (XH2.54 4-pin connector)
VDD Logic power supply (3-5.5V, supports 3.3V & 5V) 5V
GND Ground GND

Since the motor was sourced by disassembling an old 3D printer and had no color coding applied. I found out that this connector is called XH2.54 4-pin connector, meaning XH series, 2.54mm pitch, 4-pin.

jumpwires

b. Programming

First I tried using the same program as before to do a quick test to see if it would work, and it didn't.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Define the direction control pin (DIR_PIN) for the stepper 
#define DIR_PIN 26
#define STEP_PIN 27

void setup() {
  pinMode(STEP_PIN, OUTPUT); // Set STEP_PIN as an output
  pinMode(DIR_PIN, OUTPUT);  // Set DIR_PIN as an output
  digitalWrite(STEP_PIN, LOW); // Initialize the step signal as LOW
  digitalWrite(DIR_PIN, LOW); // Initialize the step signal as LOW
}

void loop() {
  digitalWrite(DIR_PIN, HIGH); // Set motor direction to clockwise (CW)

  for (int i = 0; i < 200; i++) { // Loop 200 times (one full revolution)
    digitalWrite(STEP_PIN, HIGH); // Set the step signal HIGH (trigger one step)
    digitalWrite(STEP_PIN, LOW);  // Set the step signal LOW (prepare for next step)
    delay(5); // Wait 5 ms per step (5ms * 200 = 1000ms = 1 second per rotation)
  }

  digitalWrite(DIR_PIN, LOW); // Set motor direction to counter clockwise (CCW)

  for (int i = 0; i < 200; i++) { // Loop 200 times (one full revolution)
    digitalWrite(STEP_PIN, HIGH); // Set the step signal HIGH (trigger one step)
    digitalWrite(STEP_PIN, LOW);  // Set the step signal LOW (prepare for next step)
    delay(25); // Wait 5 ms per step (5ms * 200 = 1000ms = 1 second per rotation)
  }

  delay(1000); // Wait 1 second before repeating the cycle
}

D. Troubleshooting

I suspect many possible problems and also searched for solutions on the web.

  1. Wiring mistakes
    • Incorrect wiring of the Nema 17 connector to A4988
    • Programming errors of pin numbers
  2. A4988 output current limit
  3. Jump wire disconnection
  4. A4988 ENABLE pin
  5. Insufficient power supply voltage (5V, not 9 ~ 24V)
  6. Component failure (A4988, Nema 17)

References:


1. Wiring mistakes - Phase 1

The four-pin connector (XH2.54-4 pins) on the stepper motor was not color-coded, so I couldn't figure out which wires should connect to the four pins (A1, A2, B1, B2) on the A4988. There are some ways to determine using LED, following this YouTube: How to wire Nema stepper motor correctly (YouTube):

  • Choose 2 wires and connect them to a LED
  • Turn the motor by hand
  • If the two wires are connected to a same coil, the LED will light up (the 2 wires should be 1A 1B or 2A B2)... (At first I misunderstood this as A1 A2 for coil A.)

2. A4988 output current limit

The A4988 limits the maximum current through the stepper coils so that it does not exceed the rated current of the motor. The A4988 driver includes a potentiometer to set the current limit.

potentiometer

Before, I omitted this step but I tried setting it.

  1. Measure VREF:
    • Connect the multimeter’s black lead to GND
    • Connect the red lead to the potentiometer top
    • Initially, VREF was set to 0.6V.
  2. Formula: I_limit = V_REF / (8 * R_SENSE)

    • R_SENSE (Current sense resistor) = 0.068Ω for A4988
    • Browse the datasheet of this Nema17 and check rated current: 1.65 A

    1.65 = V_REF / (8 * 0.068)
    V_REF = 1.65 * 8 * 0.068 = 0.8976 ≈ 0.9 V

  3. Adjust the potentiometer until the voltage on the multimeter reaches your target

    • Clockwise to increase the current and counterclockwise to decrease it (as a test, I set it as 0.8V)

multimeter


3. Jump wire disconnection

I checked continuity of the all wires using the multimeter continuity mode. Beep.


4. A4988 ENABLE pin

Although examples I referenced omit this pin, ENABLE pin should be LOW (0V) to activate the driver. It can be tested by measuring voltage between ENABLE and GND.

  • If HIGH (3.3V or 5V) > A4988 is disabled. Pull it LOW.

On May 1 and 2...

5. Insufficient power supply voltage

I suspected the 5V from the breadboard power supply was insufficient. Instructor Tamiya-san let me use an adjustable 3–12V AC/DC adapter (HDD28-01), which I connected to the breadboard using a DC terminal and jumper wires. By turning the key, I could select a variable voltage. I set it to 9V and 12V.

powersupply

As a result of using it, the first motor started rotating, though it was jerky. Also, unlike before, I could feel the holding torque.


On May 3...

1. Wiring mistakes - Phase 2

While observing the jerky movement during testing at different rotation speeds, I noticed the motor’s rotation was inconsistent. I had two hypotheses:

  1. The magnetic force on the coils is insufficient to complete one full step, causing the rotor to stop halfway through the step. This results in backward rotation when the current flow is changed by the motor driver.
    • I ruled out this because AC adaptor supplied enough voltage.
  2. The wiring for coil 1A/1B or coil 2A/2B might be incorrect, leading to backward current flow and causing the motor to rotate incorrectly at each step.
    • This was the cause.

While searching for the datasheet of the NEMA 17 stepper motor I salvaged from an old Kingroon 3D printer, I found its parts list and wiring diagram (KINGROON 3D Printer Parts KP3S Stepper Motor). Interestingly, the wire order was different from other sources I’ve referenced; it was labeled as 1B, 1A, 2A, 2B, whereas some others list it as 1A, 2A, 1B, 2B.

wiring_2

Confusion in pinout labeling

While working with stepper motors and drivers, I noticed inconsistent labeling across different documents.

  • A4988 driver: 1A/1B (Coil 1), 2A/2B (Coil 2)
  • Some other sources: A1/A2, B1/B2

This mismatch confused me, I wrongly assumed A1 and A2 were for "Coil A" and wired them incorrectly.
Lesson: Always double-check what the pin labels actually mean, not just what they look like.

I rewired everything and tried two stepper motors, one I salvaged from Kingroon and the other from Fab Inventory.

In this wiring (1B 1A 2A 2B), the motor from my Kingroon printer worked perfectly, whereas the motor from Fab Inventory didn't work. After swapping 1A and 2A (1B 2A 1A 2B), the motor from the Fab Inventory started working. This means that stepper motors that look the same may have different pinout orders.

Motor direction

Swapping 1A/1B or 2A/2B will reverse the motor direction.


E. Microstepping

Next, I experimented with microstepping. To set the microstepping mode, connect the MS1, MS2, and MS3 pins to either HIGH (5V/3.3V) or LOW (GND) according to the following table:

Microstep Mode MS1 MS2 MS3
XIAO RP2040 28 29 6
Full step L L L
Half step H L L
Quarter step L H L
Eighth step H H L
Sixteenth step H H H

As seen in the video below, microstepping helped reduce vibration and noise; the coin placed on the motor stayed in place, while in full-step mode it fell off immediately.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#define STEP_PIN 27   // step signal of the stepper driver
#define DIR_PIN 26    // direction signal of the stepper driver

#define MS1 28        // Microstepping pin MS1
#define MS2 29        // Microstepping pin MS2
#define MS3 6         // Microstepping pin MS3

void setup() {
    pinMode(STEP_PIN, OUTPUT); // Set the step pin as an output
    pinMode(DIR_PIN, OUTPUT);  // Set the direction pin as an output

    pinMode(MS1, OUTPUT);
    pinMode(MS2, OUTPUT);
    pinMode(MS3, OUTPUT);

    // Set microstepping mode: Full step
    /*digitalWrite(MS1, LOW);
    digitalWrite(MS2, LOW);
    digitalWrite(MS3, LOW);*/

    // Set microstepping mode: 1/16 step
    digitalWrite(MS1, HIGH);
    digitalWrite(MS2, HIGH);
    digitalWrite(MS3, HIGH);
}

// Move the stepper motor a given number of steps at a given speed
void moveMotor(int steps, int speed) {
    for (int i = 0; i < steps; i++) {
        digitalWrite(STEP_PIN, HIGH);   // Trigger a step pulse (rising edge)
        delayMicroseconds(speed);       // Wait for 'speed' microseconds
        digitalWrite(STEP_PIN, LOW);    // Complete the pulse (falling edge)
        delayMicroseconds(speed);       // Wait before next pulse
    }
}

//Full step
/*void loop() {
    digitalWrite(DIR_PIN, HIGH); // Set motor direction forward
    moveMotor(200, 1000);        // Move 200 steps at 1000 µs speed (faster)
    delay(1000);                 // Wait 1 second

    digitalWrite(DIR_PIN, LOW);  // Set motor direction backward
    moveMotor(200, 3000);        // Move 200 steps at 3000 µs speed (slower)
    delay(1000);                 // Wait 1 second
}*/

//1/16 step
void loop() {
    digitalWrite(DIR_PIN, HIGH); // Set motor direction forward
    moveMotor(200*16, 1000/16);        // Move 200 steps at 1000 µs speed (faster)
    delay(1000);                 // Wait 1 second

    digitalWrite(DIR_PIN, LOW);  // Set motor direction backward
    moveMotor(200*16, 3000/16);        // Move 200 steps at 3000 µs speed (slower)
    delay(1000);                 // Wait 1 second
}

3. Files

No files this week, code in the text.

Afterthoughts

  • Don't panic!
  • One giant step for me (or a micostep)...