ESP32 UNO - Actuator with Feedback

Need a linear actuator that knows where it is? Use the ESP32 Uno with a feedback linear actuator and stop the rod at an exact length, measured in millimeters. A small potentiometer inside the motor housing reports the rod position, and the ESP32 Uno form board turns that voltage into a number you can act on.

A plain linear actuator without feedback can only run to one end or the other. With feedback, your code can halt it anywhere along the travel.

By the end, you can:

  1. Name the five wires of a feedback actuator and what each one carries
  2. Hook the actuator to the ESP32 Uno through an L298N driver
  3. Calibrate the position sensor with analogRead()
  4. Show the position of the linear actuator in millimeters
  5. Control the position of the linear actuator with a target value in code
ESP32 Uno feedback linear actuator

Components You Need

1×ESP32 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×12V Linear Actuator with Feedback
1×L298N Motor Driver Module
1×12V Power Adapter
1×DC Power Jack
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

What Is a Feedback Linear Actuator?

After this part, you know what makes this actuator different from a basic one.

It is a DC motor with a lead screw that pushes a rod out and pulls it back, plus one extra part: a position sensor. That sensor is a potentiometer linked to the rod. As the rod travels, the wiper slides, and the output voltage rises or falls with it.

Part Job
DC motor and lead screw Moves the rod in or out
Feedback potentiometer Gives a voltage that follows the rod position
End limit switches (inside) Cut the motor at full travel on both ends

Feedback Linear Actuator Pinout

By the end of this part, you can tell the motor wires from the sensor wires.

Feedback Linear Actuator Pinout
Wire Role Goes To
Positive (motor) High-voltage motor supply, 12V / 24V / 48V by model L298N OUT1
Negative (motor) Return path of the motor L298N OUT2
5V (sensor supply) Powers the feedback potentiometer, works at 5V or 3.3V ESP32 Uno 3.3V
GND (sensor) Ground of the feedback potentiometer ESP32 Uno GND
Potentiometer (feedback output) Voltage that changes with the stroke position ESP32 Uno A0 (GPIO2)

Good to know: the motor wires carry 12V or more. Keep them away from every ESP32 Uno pin; only the L298N touches them.

How It Works

After this part, you know how polarity sets the direction and how the sensor reports the rod.

Positive Wire Negative Wire Result
High voltage (12V, 24V, 48V…) GND Rod extends at full speed up to the end stop
GND High voltage (12V, 24V, 48V…) Rod retracts at full speed up to the end stop
GND GND (power removed) Rod halts at its present spot

※ NOTE THAT:

  • Motor voltage differs from model to model. Read the label or datasheet of your unit before you apply power.
  • With the power off, the screw locks the rod in place, so it holds a load without any current.

While the rod moves, the feedback wire moves along with it. Read that wire with an analog pin and you get the rod position at any moment.

ESP32 Uno Pinout

Every Uno-style header on the ESP32 Uno form board hides a GPIO number, and that number is what goes into your sketch. Find D5, D6, D11 and A0 on this diagram first.

ESP32 Uno pinout diagram

How to Connect the Actuator to the ESP32 Uno

When this part is done, the L298N, the actuator and the board share one circuit and one ground.

Pull all three jumpers off the L298N board before you connect anything.

The wiring diagram between ESP32 Uno Linear Actuator L298N Driver

This image is created using Fritzing. Click to enlarge image

Component Pin ESP32 Uno Pin
L298N ENA D11 (GPIO23)
L298N IN1 D6 (GPIO27)
L298N IN2 D5 (GPIO16)
L298N GND GND
Actuator potentiometer (feedback) wire A0 (GPIO2)
Actuator 5V wire 3.3V
Actuator GND wire GND
Other Connection To
Actuator positive wire L298N OUT1
Actuator negative wire L298N OUT2
12V adapter + (through the DC power jack) L298N 12V input
12V adapter - (through the DC power jack) L298N GND

WARNING

The chip samples A0 (GPIO2) at every reset because it is a boot strapping pin, and it must be LOW or floating to enter upload mode. When the rod sits far out, the feedback wire is near 3.3V and can block the upload. If an upload stalls, retract the rod fully first, or unplug the A0 wire while you upload, then plug it back in.

WARNING

No ESP32 Uno pin can take 5V (they are NOT 5V tolerant). Feed the actuator's sensor wire (labeled 5V) from the 3.3V pin. On a 5V supply, the feedback output can climb to 5V near full extension and damage A0.

Good to know: the L298N sees 3.3V as a valid HIGH, so D5, D6 and D11 can drive it directly. A shared GND between the L298N and the board is a must.

How to Extend and Retract the Actuator

Plain in-and-out motion is covered in its own guide. Start with the ESP32 Uno - Linear Actuator page if you have never run the motor before.

How to Read the Actuator Position

By the end of this part, your sketch turns the sensor voltage into millimeters.

You need three numbers for that conversion: the full stroke length, the reading with the rod all the way in, and the reading with the rod all the way out.

Calibration

After this part, you have the real min and max readings of your own unit.

Step 1 — Get the stroke length

Measure the full travel of the rod with a ruler, or take it from the datasheet. The example unit travels 102 mm.

Step 2 — Run the calibration sketch

This sketch drives the rod out for 20 seconds, prints the reading, then drives it back for 20 seconds and prints the reading again.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-actuator-with-feedback */ // calibration sketch: read the feedback value at full extend and at full retract #define ENA_PIN 23 // D11 (GPIO23) goes to the ENA pin of the L298N #define IN1_PIN 27 // D6 (GPIO27) goes to the IN1 pin of the L298N #define IN2_PIN 16 // D5 (GPIO16) goes to the IN2 pin of the L298N #define POTENTIOMETER_PIN 2 // A0 (GPIO2) reads the feedback wire of the actuator void setup() { Serial.begin(9600); // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); // the three L298N control pins are outputs pinMode(ENA_PIN, OUTPUT); pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT); digitalWrite(ENA_PIN, HIGH); } void loop() { // push the stroke out digitalWrite(IN1_PIN, HIGH); digitalWrite(IN2_PIN, LOW); delay(20000); // give it 20 s; the actuator halts by itself at its end limit // take the 12-bit feedback reading (0-4095) int POTENTIOMETER_MAX = analogRead(POTENTIOMETER_PIN); Serial.print("POTENTIOMETER_MAX = "); Serial.println(POTENTIOMETER_MAX); // pull the stroke back in digitalWrite(IN1_PIN, LOW); digitalWrite(IN2_PIN, HIGH); delay(20000); // give it 20 s; the actuator halts by itself at its start limit int POTENTIOMETER_MIN = analogRead(POTENTIOMETER_PIN); Serial.print("POTENTIOMETER_MIN = "); Serial.println(POTENTIOMETER_MIN); }

Step 3 — Note the two values

Open the Serial Monitor at 9600 baud and wait for both moves to finish. A run on our bench printed:

∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
POTENTIOMETER_MAX = 3972 POTENTIOMETER_MIN = 38
Ln 11, Col 1
ESP32 Dev Module on COM15
2

Good to know: the ESP32 Uno ADC is 12-bit, so the numbers fall between 0 and 4095, not 0 and 1023.

Step 4 — Check the direction

If MAX comes out smaller than MIN, the motor wires are reversed in code. Swap the IN1_PIN and IN2_PIN values and run the sketch once more.

Step 5 — Copy the numbers

Write STROKE_LENGTH, POTENTIOMETER_MAX and POTENTIOMETER_MIN into the next two sketches.

Good to know: every sketch here calls analogSetAttenuation(ADC_11db) in setup(). The 11 dB setting lets the ESP32 Uno analog pin read the whole 0V to about 3.3V span. With a narrower span, the value hits 4095 long before full extension and the millimeter result is wrong.

ESP32 Uno Code to Calculate the Actuator Position

This sketch pushes the rod out and prints its position in millimeters on every loop.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-actuator-with-feedback */ #define ENA_PIN 23 // D11 (GPIO23) goes to the ENA pin of the L298N #define IN1_PIN 27 // D6 (GPIO27) goes to the IN1 pin of the L298N #define IN2_PIN 16 // D5 (GPIO16) goes to the IN2 pin of the L298N #define POTENTIOMETER_PIN 2 // A0 (GPIO2) reads the feedback wire of the actuator #define STROKE_LENGTH 102 // put your own stroke length here (mm) #define POTENTIOMETER_MAX 3972 // put your own full-extend reading here (0-4095) #define POTENTIOMETER_MIN 38 // put your own full-retract reading here (0-4095) void setup() { Serial.begin(9600); // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); // the three L298N control pins are outputs pinMode(ENA_PIN, OUTPUT); pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT); digitalWrite(ENA_PIN, HIGH); } void loop() { // keep the stroke moving out digitalWrite(IN1_PIN, HIGH); digitalWrite(IN2_PIN, LOW); int potentiometer_value = analogRead(POTENTIOMETER_PIN); int stroke_pos = map(potentiometer_value, POTENTIOMETER_MIN, POTENTIOMETER_MAX, 0, STROKE_LENGTH); Serial.print("The stroke's position = "); Serial.print(stroke_pos); Serial.println(" mm"); }
  1. Enter your calibration numbers in the three #define lines at the top.
  2. Upload the sketch to the ESP32 Uno.
  3. Watch the Serial Monitor as the number climbs with the rod.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
The stroke's position = 1 mm The stroke's position = 12 mm The stroke's position = 27 mm The stroke's position = 41 mm The stroke's position = 55 mm The stroke's position = 70 mm The stroke's position = 84 mm The stroke's position = 97 mm The stroke's position = 101 mm
Ln 11, Col 1
ESP32 Dev Module on COM15
2

How to Move the Actuator to a Set Position

After this part, the rod drives itself to a target length and stays there.

/* * This ESP32 Uno code was developed by newbiely.com * * This ESP32 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-uno/esp32-uno-actuator-with-feedback */ #define ENA_PIN 23 // D11 (GPIO23) goes to the ENA pin of the L298N #define IN1_PIN 27 // D6 (GPIO27) goes to the IN1 pin of the L298N #define IN2_PIN 16 // D5 (GPIO16) goes to the IN2 pin of the L298N #define POTENTIOMETER_PIN 2 // A0 (GPIO2) reads the feedback wire of the actuator #define STROKE_LENGTH 102 // put your own stroke length here (mm) #define POTENTIOMETER_MAX 3972 // put your own full-extend reading here (0-4095) #define POTENTIOMETER_MIN 38 // put your own full-retract reading here (0-4095) #define TOLERANCE 5 // allowed error around the target, in mm int targetPosition_mm = 50; // where the stroke should stop, in mm void setup() { Serial.begin(9600); // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); // the three L298N control pins are outputs pinMode(ENA_PIN, OUTPUT); pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT); digitalWrite(ENA_PIN, HIGH); } void loop() { int potentiometer_value = analogRead(POTENTIOMETER_PIN); int stroke_pos = map(potentiometer_value, POTENTIOMETER_MIN, POTENTIOMETER_MAX, 0, STROKE_LENGTH); Serial.print("The stroke's position = "); Serial.print(stroke_pos); Serial.println(" mm"); if (stroke_pos < (targetPosition_mm - TOLERANCE)) ACTUATOR_extend(); else if (stroke_pos > (targetPosition_mm + TOLERANCE)) ACTUATOR_retract(); else ACTUATOR_stop(); } void ACTUATOR_extend() { digitalWrite(IN1_PIN, HIGH); digitalWrite(IN2_PIN, LOW); } void ACTUATOR_retract() { digitalWrite(IN1_PIN, LOW); digitalWrite(IN2_PIN, HIGH); } void ACTUATOR_stop() { digitalWrite(IN1_PIN, LOW); digitalWrite(IN2_PIN, LOW); }

Upload and Test

  1. First time with this board? Set it up with ESP32 Uno - Getting Started before you continue.
  2. Build the circuit by following the wiring table above.
  3. Plug in the USB Type-C cable between the ESP32 Uno and your computer.
  4. Select the board in Arduino IDE: pick ESP32 Dev Module and the COM port of the board (CH340).
  5. Paste your calibration values into the sketch and set targetPosition_mm to the length you want.
  6. Upload the code, then switch on the 12V adapter.
  7. Open the Serial Monitor at 9600 baud. The rod runs toward the target and stops inside the tolerance band.
  8. Pro tip: mark the 50 mm point on the rod with a strip of tape. When the motor stops, you can see at a glance how close the real stop is to the target.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
The stroke's position = 18 mm The stroke's position = 26 mm The stroke's position = 34 mm The stroke's position = 41 mm The stroke's position = 46 mm The stroke's position = 47 mm The stroke's position = 47 mm
Ln 11, Col 1
ESP32 Dev Module on COM15
2

Video Tutorial

See the ESP32 Uno build in action in the video below.

Code Explanation

This table covers the control sketch, which builds on the other two.

Code Part What It Does
analogSetAttenuation(ADC_11db) Opens the A0 input range to about 3.3V
map(potentiometer_value, MIN, MAX, 0, STROKE_LENGTH) Turns the raw 0-4095 reading into millimeters
stroke_pos below target minus TOLERANCE Calls ACTUATOR_extend() to push the rod out
stroke_pos above target plus TOLERANCE Calls ACTUATOR_retract() to pull the rod in
Inside the band Calls ACTUATOR_stop() and both IN pins go LOW

The result is a simple on-off position loop. A bigger TOLERANCE gives a calm stop, while a very small one can make the rod hunt back and forth around the target.

ESP32 Uno vs UNO R4 for This Project

This table lists what changes when you move this build from the UNO R4 to the ESP32 Uno.

Item Arduino UNO R4 ESP32 Uno
Logic voltage 5V 3.3V
L298N control pins D11 / D6 / D5 D11 (GPIO23) / D6 (GPIO27) / D5 (GPIO16)
Feedback pin A0 A0 (GPIO2), a boot strapping pin
ADC range 0 to 1023 (10-bit) 0 to 4095 (12-bit)
Extra code line None analogSetAttenuation(ADC_11db)
Sensor supply 5V or 3.3V 3.3V only
Arduino IDE board Arduino UNO R4 WiFi or Minima ESP32 Dev Module

The wiring positions stay the same. Two things need attention: power the sensor from 3.3V, and run the calibration again, because the old 10-bit values are useless on a 12-bit ADC.

Wrap-Up

You connected a feedback linear actuator through an L298N to the ESP32 Uno, measured its min and max readings, printed the rod length in millimeters and made it stop at a chosen point. Use the same loop for a TV lift, a sliding hatch, a solar panel tilt or a desk that remembers its height.

Go Wireless: Set the Rod Length from Your Phone

After this part, you have an idea for adjusting the actuator without a USB cable.

The ESP32 Uno has WiFi and Bluetooth (Classic and BLE) on board. Put a slider on your phone and send its value to targetPosition_mm, and the rod follows your finger. The DIYables Web Apps library gives you that slider in a browser, and the DIYables Bluetooth App gives you the same in a phone app.

WARNING

A0 (GPIO2) is on ADC2, and ADC2 gives no readings while WiFi is running. For the WiFi version, move the feedback wire to an ADC1 pin such as A2 (GPIO35) or GPIO32, and change POTENTIOMETER_PIN to match.

Try These Next

  • Add two push buttons that move the target up and down by 10 mm.
  • Average five analogRead() samples before map() to steady the position value.
  • Drive ENA with analogWrite() and slow the rod down as it gets near the target.
  • Save the last target in flash with the Preferences library so it comes back after a reset.

Troubleshooting

Problem Possible Cause Solution
Board not listed under Tools then Port CH340 driver not installed or a charge-only USB cable Install the CH340 driver and try a USB cable that carries data
Upload stops at "Failed to connect" or "Waiting for download" Board did not enter upload mode Hold the BOOT button while the upload starts, release it once writing begins
Board does not boot or upload with the actuator connected A0 (GPIO2) is a strapping pin and the feedback wire is high Retract the rod fully, or unplug the A0 wire during upload, then reconnect it
Rod never moves 12V adapter off, ENA wire loose or no common GND Check the adapter, the D11 to ENA wire and the GND link between the L298N and the board
Reading jumps to 4095 before full extension Sensor fed from 5V or attenuation line missing Move the sensor supply to 3.3V and keep analogSetAttenuation(ADC_11db) in setup()
Millimeter value falls while the rod extends IN1 and IN2 swapped Swap the IN1_PIN and IN2_PIN numbers and calibrate again
Millimeter value is far from the ruler Calibration numbers copied from another board Run the calibration sketch on this ESP32 Uno and enter its values
Rod keeps twitching near the target TOLERANCE too tight or a noisy reading Raise TOLERANCE to 6 or 8 mm, or average several readings
Garbage characters in the Serial Monitor Baud rate mismatch Pick 9600 baud in the Serial Monitor

FAQ

How accurate is the position from a feedback actuator?

It depends on the potentiometer and on noise. With a 12-bit reading over about 100 mm, one ADC step is far smaller than a millimeter, but noise usually limits you to roughly 1 to 3 mm. Averaging a few samples helps.

Does the feedback actuator need its own library?

No. The sketches use only built-in functions: analogRead(), map(), digitalWrite() and pinMode(). Install the esp32 by Espressif Systems core and nothing else.

Which pin of the actuator should go to 3.3V on the ESP32 Uno?

The sensor supply wire, often marked 5V. On the ESP32 Uno it must go to 3.3V, so the feedback output never rises above 3.3V. The potentiometer works the same at the lower voltage.

Is it safe to drive the L298N inputs from a 3.3V board?

Yes. The L298N accepts about 2.3V as HIGH, so the 3.3V outputs on D5, D6 and D11 switch it fine. Connect the grounds of both boards.

Why does the code call analogSetAttenuation(ADC_11db)?

This line widens what the analog input can measure to roughly 0 to 3.3V, which spreads the whole feedback swing over 0 to 4095. With a smaller range, the reading saturates long before the rod reaches the end. The UNO R4 has no such call; only the ESP32 Uno needs it. Keep the feedback signal at 3.3V or lower.

Why are my calibration numbers around 4000 instead of around 1000?

The ESP32 Uno reads analog pins with 12 bits, so the scale ends at 4095. A 10-bit board ends at 1023. Always calibrate on the board you will use.

Why does uploading sometimes fail when the actuator is plugged in?

A0 is GPIO2, a boot strapping pin. If the rod is extended, the feedback voltage on GPIO2 is high at reset, and the chip may not enter upload mode. Retract the rod or unplug the A0 wire while you upload.

Can I read the position over WiFi with the ESP32 Uno?

Yes, but not on A0. A0 (GPIO2) and A1 (GPIO4) belong to ADC2, and ADC2 cannot be read while WiFi is on. Move the feedback wire to A2 to A5 (GPIO35, 34, 36, 39) or to GPIO32/33, and update POTENTIOMETER_PIN.

Can I run the same sketch on the ESP32 Uno that I used on an UNO R4?

Almost. Change the pin numbers to GPIO numbers (23, 27, 16 and 2), add the attenuation line, and redo the calibration, because the old values are on a 10-bit scale.

How do I make the actuator move slower?

Keep the ENA jumper off and replace digitalWrite(ENA_PIN, HIGH) with analogWrite(ENA_PIN, value). PWM output is available on D11 (GPIO23). A slower rod also stops closer to the target.

What if my project needs more pins than the Uno headers give?

The ESP32 Uno has extra holes near the power header: GPIO32 and GPIO33 (I/O, PWM, analog on ADC1, so they still read while WiFi is on) and GPIO15 (I/O, PWM, analog on ADC2). Add header pins there and use the plain GPIO number in your sketch. For a second actuator's feedback wire, or for a WiFi build, GPIO32/33 are the best choice. Two warnings: GPIO15 and GPIO0 (the IO0 pin at the unused Uno NC spot) are boot strapping pins, so a wrong connection can stop the board from booting or uploading, which is why you should use GPIO32/33 first. Never use the six holes under the digital header (SD0 to SD3, CMD, CLK = GPIO6 to GPIO11), because they are wired to the flash chip and using them crashes the board.

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!