Controlling a Nema 23 closed loop stepper motor with Arduino Nano (2023)

Code walkthrough for Arduino C++ code loaded into the famous Arduino Nano board to control a Nema 23 hybrid closed loop stepper motor.

What is covered

  • Importing libraries, assigning values to constants and variables
  • setup() function
  • loop() function
  • Helper functions

Code repository


Importing libraries, assigning values to constants and variables

We need the Wire library to be able to receive new settings via I2C from the master board ESP32, Arduino Nano being set up as a slave. The fantastic and very well known AccelStepper library is used of course to control our stepper motor.

Do not forget you can download the Fritzing .fzz file from here to take a look at the breadboard and schematic views. It would help you to better picture the project set up.

Between the lines 6 and 9 we assign the pin values. homeSet, isHoming, isStopping are control variables to discern the current operation the stepper motor is engaged on. stepperParams are of a size of 3 (steps to move, steps per second for inspiration, steps per second for expiration). maxBVMVolume is used to determine the ratio between the received volume setting and this maximum volume possible.

That maximum amount of volume can be pushed by the crank shaft linked to the stepper motor axle at half a revolution. That’s why we need to also know the stepsPerRevolution. maximumSpeed is for safety and defaultSpeed is for movements where steps per second are not specified. settings and prevSettings are for keeping track of the data sent by the master ESP32 board. isClockWise registers the direction of the rotation and it is a control variable as well as newStepperParams.

#include <Wire.h>#include <AccelStepper.h>AccelStepper stepper(1, 3, 2);const int relayPin = 4;const int trackerPin = 9;const int I2CSlaveAddress = 4;bool homeSet = false;bool isHoming = true;bool isStopping = false;const int stepperParamsSize = 3;int stepperParams[stepperParamsSize] = {0, 0, 0};const int maxBVMVolume = 1600;const int stepsPerRevolution = 500;const int maximumSpeed = 3000;const int defaultSpeed = 1000;const int settingsSize = 4;int settings[settingsSize] = {0, 0, 0, 0};int prevSettings[settingsSize] = {0, 0, 0, 0};bool isClockWise = true;bool newStepperParams = false;

setup() function

On lines 2-3 we set the pin mode for the relay and for the line tracer used to home in the stepper motor. On lines 7-8 we initiate the Wire I2C communication and we assign an event listener for the receive event. On line 13 we open the relay, on lines 16-17 we are setting the maximum and default speeds for the stepper instance of the AccelStepper class.

void setup() { pinMode(relayPin, OUTPUT); pinMode(trackerPin, INPUT);  digitalWrite(relayPin, LOW); Wire.begin(I2CSlaveAddress); Wire.onReceive(receiveEvent);  Serial.begin(115200); delay(3000); digitalWrite(relayPin, HIGH); delay(4000); stepper.setMaxSpeed(maximumSpeed); stepper.setSpeed(defaultSpeed);  Serial.println(""); Serial.println("Starting");}

loop() function

Please keep in mind that we do not have blocking operations induced by the stepper. We call stepper.runSpeedToPosition() at each loop cycle and if a step is due it is executed. The first thing we do is to set the “home” position. Then we check if isStopping and we call the helper function stopStepper again and again until that control variable is false.

We only proceed if there is no homing or stopping operation in progress. We then check if new settings are received (line 11). At line 14 we verify if the new settings are associated with a stop command (if all 4 values are set to 0). If we are good to go, we computeNewParams() (total steps to move, steps per second for inspiration and expiration) using the newly received settings.

Of course there are cases when there is nothing to do and we have to verify that at lines 31-33. If newStepperParams we need to move the motor back to “home” position before starting the movement with the new settings (lines 35-49). Then and only then we call the moveStepper() function.

void loop() { if (homeSet == false) { executeHoming(); } if (isStopping == true) { stopStepper(); } if (isHoming == false && isStopping == false) { if (hasNewValues() == true) { Serial.println("hasNewValues");  if (isItStopping() == true) { isStopping = true; } if (isStopping == false) { if (prevSettings[0] != 0) { newStepperParams = true;  } computeNewParams(); } for (int i = 0; i < settingsSize; i++) { prevSettings[i] = settings[i]; }  } if (nothingToDo() == true) { return; } if (newStepperParams == true) { Serial.println("newStepperParams move to zero"); stepper.moveTo(0); stepper.setSpeed(defaultSpeed); stepper.runSpeedToPosition(); printPositionalData(); if (stepper.distanceToGo() != 0) { return; } else { Serial.println("Stepper is back at zero"); newStepperParams = false; isClockWise = true; } }  moveStepper(); }}

Helper functions

  • moveStepper is the most important: we set the speed and move the stepper to position, clockwise and anti-clockwise.

When permitted by the previous checks, this is called at each loop cycle, in a continuous back and forth movement.

void moveStepper() { if (isClockWise == true) { stepper.moveTo(stepperParams[0]); stepper.setSpeed(stepperParams[1]); printPositionalData(); if (stepper.distanceToGo() == 0) { isClockWise = false; } } else { stepper.moveTo(0); stepper.setSpeed(stepperParams[2]);  printPositionalData(); if (stepper.distanceToGo() == 0) { isClockWise = true; } } stepper.runSpeedToPosition();}
  • stopStepper is responsible for stopping any previous command and for getting the motor to the “zero” position. When its job is done it is setting the isStopping control variable to false to let other parts of the code do their jobs.
void stopStepper() { Serial.println("stopStepper move to zero"); stepper.moveTo(0); stepper.setSpeed(defaultSpeed); stepper.runSpeedToPosition(); printPositionalData(); if (stepper.distanceToGo() != 0) { return; } else { Serial.println("Stepper is back at zero"); isStopping = false; }}
  • executeHoming is setting the “zero” position with the help of the tracing sensor. Again, it is setting the isHoming control variable to false to signal other parts of the code.
void executeHoming() { const int notAtHome = digitalRead(trackerPin); if (notAtHome == false) { Serial.println("Homing successful"); stepper.setCurrentPosition(0); //now the current motor speed is zero homeSet = true; isHoming = false; return; } stepper.runSpeed();}
  • computeNewParams only seems complicated. It is finding the ratio between the volume setting and the maximum volume. It is using that to determine how much of the half revolution, measured in steps, it is allowed to move. Then, based on the inspiration / expiration ratio and the number of respirations per minute, determines the steps per second for inspiration and expiration.
void computeNewParams() { Serial.println("computeNewParams"); Serial.println("settings[0]: " + String(settings[0])); Serial.println("settings[1]: " + String(settings[1])); Serial.println("settings[2]: " + String(settings[2])); Serial.println("settings[3]: " + String(settings[3]));  // Compute steps to move  // TODO measure precise volumes to determine  // the correlation between piston amplitude and pushed volume of air // the current formula assumes a linear correlation stepperParams[0] = ceil((float(stepsPerRevolution) / 2) * (float(settings[0]) / float(maxBVMVolume))); const float secondsPerFraction = 60 / ((float(settings[2]) + float(settings[3])) * float(settings[1]));  // compute the steps per second for inspiration stepperParams[1] = ceil(float(stepperParams[0]) / (secondsPerFraction * float(settings[2]))); // compute the steps per second for expiration stepperParams[2] = ceil(float(stepperParams[0]) / (secondsPerFraction * float(settings[3]))); Serial.println("stepperParams[0]: " + String(stepperParams[0])); Serial.println("stepperParams[1]: " + String(stepperParams[1])); Serial.println("stepperParams[2]: " + String(stepperParams[2]));}
  • receiveEvent is the handler for the I2C “receive” event. It has to verify how many bytes were sent in the received stream. Then it is parsing that array buffer character by character until it finds a x value separator. Each of the 4 values is stored in the settings array.
void receiveEvent(int howMany) { Serial.println("I2C Receive event"); char t[30]; int i = 0;  while (Wire.available()) {  t[i] =; i = i + 1; }  int j = 0; if (checkForData(t, howMany, settingsSize) == false) return; String sett = ""; for (int i = 0; i < howMany; i++) { String current = String(t[i]); // look for x as the values separator if (current != "x") { sett = sett + current;  } else { settings[j] = sett.toInt(); sett = ""; j++; } if (i == howMany - 1) { settings[j] = sett.toInt(); } }}


Can you control stepper motor with Arduino Nano? ›

The answer is yes you can control a stepper motor with a Nano or Micro. You cannot drive (power) a stepper motor with any Arduino. Any stepper motor will need a driver. The appropriate driver depends on the particular stepper.

How to control NEMA stepper motor with Arduino? ›

Stepper motor is powered using a 12V power source, and the A4988 module is powered via Arduino. Potentiometer is used to control the direction of the motor. If you turn the potentiometer clockwise, then stepper will rotate clockwise, and if you turn potentiometer anticlockwise, then it will rotate anticlockwise.

Can stepper motor be controlled by Arduino? ›

Learn how to control a variety of stepper motors using unipolar / bipolar circuits with Arduino. Stepper motors, due to their unique design, can be controlled to a high degree of accuracy without any feedback mechanisms.

How many stepper motors can an Arduino Nano control? ›

Depending on the maximum-stepfrequency you need you could use IO-pin-expanders to go up to 32, 64 or 128 stepper-drivers.

Can you control a stepper motor with PWM? ›

Ever wanted to control several stepper motors precisely with just one microcontroller? Use PWM! Instead of bit-banging and writing your own delay functions to create square waves, you can use the builtin timers and pin-change interrupts available on most hobbyist microcontrollers.

What is the best stepper motor library for Arduino? ›

The most popular library for controlling stepper motors with Arduino is the AccelStepper library by Mike McCauley. It's an extremely versatile library featuring speed, acceleration and deceleration control, setting target positions, controlling multiple stepper motors simultaneously and so on.

What is the difference between DRV8825 and A4988? ›

There are many differences between the A4988 and DRV8825. The DRV8825 offers 1/32-step micro stepping, while the A4988 only goes down to 1/16-step. And The DRV8825 has a greater maximum supply voltage (45 V vs. 35 V), making it safer to operate at higher voltages and less prone to LC voltage spike damage.

How to run a stepper motor using Arduino? ›

For a stepper motor, the 4 terminal pins on the H-Bridge should connect to the 4 leads of the motor. The 4 logic pins will then connect to the Arduino (8, 9, 10, and 11 in this tutorial). As shown in the Fritzing diagram, an external power source can be connected to power the motors.

How to connect potentiometer to Arduino Nano? ›

Connect the three wires from the potentiometer to your board. The first goes from one of the outer pins of the potentiometer to ground. The second goes from the other outer pin of the potentiometer to 5 volts. The third goes from the middle pin of the potentiometer to the analog pin A0.

How do I know if my stepper motor is unipolar or bipolar? ›

A bipolar motor has generally four wires whereas a unipolar motor has six or eight wires if the middle point is not connected (see figure 8). If the unipolar motor has eight wires, it can be converted into a bipolar version by connecting the half-phases.

What is the best way to control a stepper motor? ›

Fundamentally, the basic method of controlling a stepper motor is energizing and de-energizing the coils that surround the gear in the correct sequence. Varying the sequence and timing of the coil activations is how engineers customize the operation of a stepper motor to the needs of their applications.

How do you control the rotation of a stepper motor? ›

The rotating speed of the stepper motor is determined by the speed of the pulse frequency (Hz) given to the driver, and it is possible to freely change the motor rotation by simply changing the number of input pulses or frequencies to the driver.

How much current can an Arduino Nano handle? ›

As mentioned, the maximum output current an Arduino's digital pin can supply is 40mA (or 20mA continuous current).

What is the max voltage to Arduino Nano? ›

Power can be supplied from USB or into the Vin pin (30) at a recommended 7 - 12v with the voltage limits being 6 - 20v (higher voltages will make the voltage regulator hot!).

What is the maximum program size for Arduino Nano? ›

Maximum is 2048 bytes. Sketch too big; see for tips on reducing it. Error compiling for board Arduino Nano. 103% program storage space.

Can you make a stepper motor run continuously? ›

Stepper motors can continue to rotate indefinitely, just as most motors will. If you use a properly designed controller and a stepper motor that's sized appropriately for the application, the motor can be left running.

How many rpm can a stepper motor handle? ›

If you want to know about stepper motor max speed, you should know that the maximum speed that's typical of a stepper motor is 1000rpms while the max speed of gearmotors comes in at 400-550 RPM.

How fast can an Arduino drive a stepper motor? ›

The fastest motor speed that can be reliably supported is about 4000 steps per second at a clock frequency of 16 MHz on Arduino such as Uno etc.

What is the difference between servo and stepper motor Arduino? ›

Stepper motors are used in an open-loop system that does not require positional or torque feedback which makes it simpler and less costly to control. They are also easier to set up and use. Compared to servo motors, they are better suited for low acceleration and high holding applications.

Are stepper motors more precise than servos? ›

Servo motors have the speed and torque to deliver higher accelerations than stepper motors. They also deliver more accurate positioning, thanks to closed-loop control.

How to control motor direction with Arduino? ›

To control the direction of the motor, the pins in1 and in2 must be set to opposite values. If in1 is HIGH and in2 is LOW, the motor will spin one way, if on the other hand in1 is LOW and in2 HIGH then the motor will spin in the opposite direction.

Can DRV8825 drive nema 23? ›

If the current per phase is really just 1 amp (seems low for a Nema 23) then you could use a DRV8825 driver. You should use as high a voltage as you can (subject to the limit for the driver) and adjust the current limit on the driver board to suit your motor.

Can A4988 be used for NEMA 23? ›

Can we use arduino, cnc shield and driver a4988 with stepper motor nema 23 3.5A? NO. An A4988 is good for about 1.4 amps.

How to control stepper motor with DRV8825? ›

The DRV8825 is a micro-stepping driver for controlling bipolar stepper motors which have a built-in translator for easy operation. Thus, we can control the stepper motor with just 2 pins from our controller. The DIR pin will control the rotation direction and the STEP pin will control the steps.

How to control speed of a DC motor with Arduino and without potentiometers? ›

The speed of the DC motor can be easily controlled by adjusting the input voltage supplied to the motor. We can control the input voltage with a PWM signal. Using pulse-width modulation (PWM), we can apply the average voltage value to our device, adjusting its value by turning the signal on and off at high speed.

Which controller is used in Arduino Nano? ›

The Arduino Nano is an open-source breadboard-friendly microcontroller board based on the Microchip ATmega328P microcontroller (MCU) and developed by and initially released in 2008.

Which potentiometer is best for Arduino? ›

For use with the Arduino A/D inputs, a pot value in the range of 1K, 5K or 10K will give you the best results.

Can Arduino act as a potentiometer? ›

We will also see how to read analog voltages, and how to use the serial monitor. Lots of Arduino sensors output an analog voltage just like a potentiometer. The same concepts used to setup and program a potentiometer can be used to setup a wide variety of other sensors and devices on the Arduino.

Is NEMA 23 stepper motor bipolar or unipolar? ›

Furthermore, this NEMA 23 is both a unipolar or bipolar Stepper Motor, operating at 2A and 2.7V. You are able to use either a unipolar or bipolar stepper motor driver with this NEMA 23 by simply connecting the compatible wire leads. Six wire leads with clear colour-coding are available to you.

Is NEMA 23 stepper motor bipolar? ›

This NEMA 23-size hybrid stepping motor can be used as a unipolar or bipolar stepper motor and has a 1.8° step angle (200 steps/revolution). Each phase draws 1 A at 5.7 V, allowing for a holding torque of 4 kg-cm (55 oz-in).

Does polarity matter on stepper motor? ›

To get the stepper just moving, polarity of each coil doesn't matter, nor does it matter which coil is which. So make sure each pair of wires for a coil are together on one side of the plug (or the other side for the other coil), and plug it in.

What voltage does a stepper motor control? ›

Generally, 12 [V] is the smallest voltage used to drive actuator motors, with higher voltages at 24 [V], 48 [V] and even 80[V] being used for motion control systems. A good rule of thumb is to use between 10 and 24 times the motor's nameplate voltage for the system bus voltage.

Can you control a stepper motor with a potentiometer? ›

As discussed earlier you have to rotate the potentiometer to control the rotation of the Stepper motor. Rotating it in clockwise will turn the stepper motor in clockwise direction and vice versa.

What do I need to program a stepper motor? ›

  1. EasyDriver Stepper Motor Driver.
  2. Small Stepper Motor.
  3. Breadboard.
  4. Male-to-male Jumper Wires.
  5. Male Break Away Headers - Straight.
  6. Arduino Uno (or similar microcontroller)
  7. Soldering iron and accessories.
  8. 12V Power supply (or variable power supply)
Jan 3, 2013

Which microcontroller is used for stepper motor? ›

The project will be using a ULN2003 IC and the L293D Motor Driver to drive the stepper motor as the controller cannot provide current required by the motor. We will see how to connect a stepper motor with an 8051 Microcontroller.

How do you control a stepper motor with Bluetooth? ›

Control the Stepper Motor With Bluetooth
  1. Step 1: What I Need. Hardware: ...
  2. Step 2: GoBLE. You can download the GoBLE from the App Store. ...
  3. Step 3: Bluno. Bluno integrates a TI CC2540 BT 4.0 chip with the Arduino UNO development board. ...
  4. Step 4: Test the Motor. ...
  5. Step 5: Test the GoBLE. ...
  6. Step 6: Control the Stepper Motor.

Can stepper motor rotate manually? ›

The motor does not rotate, but we cannot move it freely by hand (more torque has to be applied to move it now), because of a larger 'holding torque'. This torque is generated by the attraction of the north and south poles of the rotor magnet and the electromagnet produced in the stator by the current.

How to control stepper motor using PWM? ›

Step 3: PWM for Stepper Motors

Each pulse on the step line causes the motor to move a step, or part step, in a give direction. For stepper motor driver control the duty cycle can be fixed and the Frequency varied. The stepper motor driver expects a series of input pulses to move the motor to any given angle.

What is the minimum rpm for a stepper motor? ›

On the downside, stepper motors have speed limitations. They generally run best at 1200 RPM or lower. Although they generate high torque at zero speed, torque falls off as speed increases (see figure 2).

Can stepper motor rotate clockwise and counterclockwise? ›

In this mode, separate clockwise (CW) and counter-clockwise (CCW) pulse inputs determine the direction of rotation. That is, CW pulses turn the motor clockwise and CCW pulses turn it counter-clockwise.

Can Arduino Nano run a servo? ›

Introduction: Sweep Servo Motor With Arduino Nano

In this instructable, i have shown how to sweep a servo motor with Arduino Nano. Generally servo motor is used where is low speed but with a high torque is needed. this work can be done by a geared motor too.

How many DC motors can an Arduino Nano control? ›

Arduino Nano DC Motor code

DC motors can be controlled by the L298N DC motor driver IC, which is connected to your microcontroller. L298Ns can control up to 2 DC motors. You can easily add motors through the program code.

Can Arduino Nano power a servo? ›

The Nano can talk to 4 servos, however, you must use an external servo power supply. An Arduino is not a power supply. Four SG-90 have a combined stall current of about 2.5Amp. You need a power supply that can deliver 5volt/3Amp.

Do I need a driver for Arduino Nano? ›

In general, you will need to install an Arduino driver on your computer whenever you want to use an Arduino with your computer. Arduino Nano comes with a different UART chip for serial communication.

Does Arduino Nano have 5V regulator? ›

The signal 5V supply is created by a linear voltage regulator on board the Arduino Nano.

Can I supply 12V to Arduino Nano? ›

"The board can operate on an external supply of 6 to 20 volts. If supplied with less than 7V, however, the 5V pin may supply less than five volts and the board may be unstable. If using more than 12V, the voltage regulator may overheat and damage the board.

How do I externally power my Arduino Nano? ›

The most common and easiest way we can power an Arduino board is by using its onboard USB connector. The USB connector provides a regulated 5V line to power the board's electronics. However, 5V from the USB connector can also power external components through the 5V pin that can be found in Arduino boards.

What power options for Arduino Nano? ›

The Arduino Nano can be powered via the Mini-B USB connection, 6-20V unregulated external power supply (pin 30), or 5V regulated external power supply (pin 27). The power source is automatically selected to the highest voltage source.

Where does servo motor connect to Arduino Nano? ›

Servo motors have three wires: power, ground, and signal. The power wire is typically red, and should be connected to the 5V pin on the Arduino board. The ground wire is typically black or brown and should be connected to a ground pin on the board.


Top Articles
Latest Posts
Article information

Author: Kimberely Baumbach CPA

Last Updated: 11/09/2023

Views: 6331

Rating: 4 / 5 (41 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Kimberely Baumbach CPA

Birthday: 1996-01-14

Address: 8381 Boyce Course, Imeldachester, ND 74681

Phone: +3571286597580

Job: Product Banking Analyst

Hobby: Cosplaying, Inline skating, Amateur radio, Baton twirling, Mountaineering, Flying, Archery

Introduction: My name is Kimberely Baumbach CPA, I am a gorgeous, bright, charming, encouraging, zealous, lively, good person who loves writing and wants to share my knowledge and understanding with you.