How to Control 4 Motors With Two ESP32s Over I2C (Arduino IDE)

by Emilian0 in Circuits > Microcontrollers

18 Views, 1 Favorites, 0 Comments

How to Control 4 Motors With Two ESP32s Over I2C (Arduino IDE)

IMG_2505.JPG

This guide will walk you through the process of using the Arduino IDE to set up two ESP32 microcontrollers—one as the Master and the other as the Slave—to communicate over I2C and control four DC motors.

Supplies

  1. 2 ESP32 Boards
  2. 4 DC motors
  3. 4 L298N motor driver boards
  4. External 12V power supply
  5. Breadboard
  6. Jumper wires (female-to-male and male-to-male)
  7. Common GND rail (can be part of breadboard or custom bus bar)
  8. USB A-to-C cables for ESP32 programming
  9. Computer with Arduino IDE installed

Set Up the Arduino IDE

Before we can write and upload code to the ESP32, we need to configure the Arduino IDE.

  1. Open the Arduino IDE.
  2. Go to File > Preferences.
  3. In the Additional Boards Manager URLs field, paste:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  1. Click “OK”.
  2. Now go to Tools > Board > Boards Manager…
  3. Search for “ESP32” and install esp32 by Espressif Systems.
  4. Once installed, select ESP32 Dev Module from the Tools > Board menu.

I2C Communication

IMG_2572.JPG

With the IDE ready, connect your two ESP32 boards using I2C. By default, the ESP32 uses:

  1. SDA = GPIO 21
  2. SCL = GPIO 22
  3. Connect the SDA (GPIO 21) pin of the Master to the SDA (GPIO 21) pin of the Slave.
  4. Connect the SCL (GPIO 22) pin of the Master to the SCL (GPIO 22) pin of the Slave.
  5. Connect GND of both ESP32s together to ensure a common reference.
⚠️ Disclaimer: While ESP32 pins are technically addressable and can be reassigned, this does not appear to work reliably within the Arduino IDE environment. Stick with the default GPIO 21 and 22 for SDA and SCL.
⚠️ Disclaimer: When driving motors using PWM signals with an ESP32, the ESP32 documentation uses the ledcWrite() function to generate PWM rather than analogWrite(). However, the Arduino IDE fails to compile when ledcWrite() is used, we will use analogWrite().


Test I2C Communication

To verify that the two ESP32 boards are communicating over I2C, upload the following test sketches.

Leader (Master) Sketch:

#include <Wire.h>

void setup() {
Wire.begin(); // Join I2C bus as Master
Serial.begin(115200);
}

void loop() {
Wire.beginTransmission(8); // Transmit to device #8
Wire.write("Hello World!"); // Send string
Wire.endTransmission(); // Stop transmitting
delay(1000);
}

Follower (Slave) Sketch:

#include <Wire.h>

void receiveEvent(int bytes) {
while (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
Serial.println();
}

void setup() {
Wire.begin(8); // Join I2C bus with address #8
Wire.onReceive(receiveEvent);
Serial.begin(115200);
}

void loop() {
delay(100);
}

Uploading Code to the ESP32

Sometimes uploading code to the ESP32 can be tricky. You might encounter an error where the IDE hangs on “Connecting…” during upload.

To resolve this:

  1. After the sketch compiles, the IDE will say: Connecting...
  2. Immediately press and hold the physical “BOOT” button on the ESP32.
  3. Keep it held until the upload begins and the Output window shows the upload progress.
  4. You can release the button once the upload starts.

Once the upload is complete, you’ll get a “Done Uploading” message. Repeat this for both the Master and the Slave boards.

Then, open the Serial Monitor on the Slave ESP32. You should see the message "Hello World!" printed repeatedly, confirming that I2C communication is working.

Connect Two Motors With L298N Motor Drivers

  1. Connect Motor Driver to Motors:
  2. Attach the leads of Motor 1 to OUT1 and OUT2 of the first L298N.
  3. Attach the leads of Motor 2 to OUT3 and OUT4 of the second L298N.
  4. Connect ESP32 to L298N Inputs (based on master2motor2.ino and follower4.ino):
  5. Motor 1 (Master ESP32):
  6. ENA1: GPIO 23 (PWM)
  7. IN1: GPIO 2
  8. IN2: GPIO 15
  9. Motor 2 (Master ESP32):
  10. ENA2: GPIO 4 (PWM)
  11. IN3: GPIO 16
  12. IN4: GPIO 17
  13. Motor 3 (Follower ESP32):
  14. ENA1: GPIO 33 (PWM)
  15. IN1: GPIO 19
  16. IN2: GPIO 18
  17. Motor 4 (Follower ESP32):
  18. ENA2: GPIO 25 (PWM)
  19. IN3: GPIO 5
  20. IN4: GPIO 27
  21. Powering the L298N Motor Drivers:
  22. Connect 12V from your external power supply to the 12V input of each L298N.
  23. Connect GND from the power supply to both L298N GND terminals.
  24. Connect the GND of the ESP32 to the same ground rail to ensure a common reference.
⚠️ Power Management Tip: For stable performance, use a separate 12V rail to power the motor drivers. This prevents brownouts or resets during motor startup.

Upload and Run Sketch

Now upload the following sketch to your ESP32.

const int IN1 = 2;
const int IN2 = 15;
const int ENA1 = 0; // PWM

const int IN3 = 16;
const int IN4 = 17;
const int ENA2 = 4; // PWM

// Encoder Pins
const int encoderA = 23;
const int encoderB = 22;
const int encoderC = 33;
const int encoderD = 25;

void setup(){
pinMode(ENA1, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2,OUTPUT);

pinMode(ENA2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4,OUTPUT);
Serial.begin(115200);
}

void loop(){
Serial.println("1: First direction");
digitalWrite(ENA1, HIGH);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);

digitalWrite(ENA2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
delay(1000);

digitalWrite(ENA1,HIGH);
digitalWrite(IN1,LOW);
digitalWrite(IN2, LOW);

digitalWrite(ENA2,HIGH);
digitalWrite(IN3,LOW);
digitalWrite(IN4, LOW);
Serial.println("Setting Motor 2 pins:");
Serial.print("ENA2: "); Serial.println(digitalRead(ENA2));
Serial.print("IN3: "); Serial.println(digitalRead(IN3));
Serial.print("IN4: "); Serial.println(digitalRead(IN4));

delay(1000);
}

Once the code is uploaded and the board is powered:

  1. Motor 1 and Motor 2 should begin spinning in opposite directions.
  2. The motors will ramp up to full speed, then ramp down after a short period.
  3. This forward-backward cycling will repeat if programmed as such.

Observe the motors carefully. If one of them stutters, spins inconsistently, or remains still, check the wiring and ensure the correct GPIO pins are used as specified.

⚠️ Make sure your 12V power rail is active and supplying adequate current. A weak supply may result in inconsistent motor behavior.


Duplicate the Setup for Motors 3 and 4

Now, replicate the setup used in Steps 6 and 7 for the remaining two motors. Use the second ESP32 and an additional pair of L298N motor drivers. Wire them using the connections as before.

Reconnect I2C Communication

With both ESP32s now controlling their respective motors, reconnect the I2C lines:

  1. Connect SDA (GPIO 21) of the first ESP32 to SDA (GPIO 21) of the second ESP32.
  2. Connect SCL (GPIO 22) of the first ESP32 to SCL (GPIO 22) of the second ESP32.
  3. Ensure that both ESP32 GND pins are connected to a common ground rail shared with the motor power supply.

This will enable synchronized control over I2C between the boards.

Upload Leader and Follower Sketches

Now upload the new I2C communication sketches to each ESP32:

  1. Upload leader.ino to the Master ESP32.
  2. Upload follower.ino to the Slave ESP32.

What the Code Does

  1. Leader (leader.ino): Sends increasing PWM values over I2C to the Slave, then ramps them back down. This provides a simple example of dynamic motor control commands sent over I2C.
  2. Follower (follower.ino): Receives the PWM values and applies them to two motors using analogWrite() (or its placeholder form), making both motors respond in real time to commands from the Master.

Physical Behavior

Once uploaded and powered:

  1. All four motors should spin in sync.
  2. As the PWM value increases, the motors will speed up.
  3. When the PWM value ramps back down, the motors will slow accordingly.


Optional: Increase Complexity

You can expand your setup by integrating motor encoders. For instance, you can track position and velocity with encoder ticks. A PID controller can be also be implemented for closed-loop speed and position control.