Community project

SKEMATIK ROV

ESP32
Photo of SKEMATIK ROV
Generated with AI

hanifzakki

Last updated September 25, 2026

The SKEMATIK ROV is a remotely operated underwater vehicle powered by an ESP32 microcontroller and six brushless motors controlled via 30 A PWM ESCs. The system uses a 15-meter RS-485 tether to communicate between the surface controller and the submerged ROV, with dual logic level shifters managing the 3.3 V to 5 V signal conversion for reliable motor control in a waterproof enclosure.

This guide provides a complete wiring diagram, full parts list, and ready-to-flash firmware for both the ROV and surface controller. Assembly steps cover power distribution from a 24 V 30 A PSU, motor connections, tether preparation, and safe testing procedures to get your ROV operational.

Wiring diagram

Wiring diagram for SKEMATIK ROV

Gather all the parts

QtyComponent
1

30 A PWM ESC

30 A, 2–3S compatible

Pengendali kecepatan elektronik yang menerima pulsa throttle dan memberi tiga fase ke motor brushless.

1

30 A PWM ESC

30 A, 2–3S compatible

Pengendali kecepatan elektronik yang menerima pulsa throttle dan memberi tiga fase ke motor brushless.

1

30 A PWM ESC

30 A, 2–3S compatible

Pengendali kecepatan elektronik yang menerima pulsa throttle dan memberi tiga fase ke motor brushless.

1

30 A PWM ESC

30 A, 2–3S compatible

Pengendali kecepatan elektronik yang menerima pulsa throttle dan memberi tiga fase ke motor brushless.

1

30 A PWM ESC

30 A, 2–3S compatible

Pengendali kecepatan elektronik yang menerima pulsa throttle dan memberi tiga fase ke motor brushless.

1

30 A PWM ESC

30 A, 2–3S compatible

Pengendali kecepatan elektronik yang menerima pulsa throttle dan memberi tiga fase ke motor brushless.

1

A2212 1000KV brushless motor

1000 KV

Motor brushless tiga kabel yang memutar satu baling-baling pendorong ROV.

1

A2212 1000KV brushless motor

1000 KV

Motor brushless tiga kabel yang memutar satu baling-baling pendorong ROV.

1

A2212 1000KV brushless motor

1000 KV

Motor brushless tiga kabel yang memutar satu baling-baling pendorong ROV.

1

A2212 1000KV brushless motor

1000 KV

Motor brushless tiga kabel yang memutar satu baling-baling pendorong ROV.

1

A2212 1000KV brushless motor

1000 KV

Motor brushless tiga kabel yang memutar satu baling-baling pendorong ROV.

1

A2212 1000KV brushless motor

1000 KV

Motor brushless tiga kabel yang memutar satu baling-baling pendorong ROV.

1

MAX3485 3.3 V RS-485 module

3.3 V

Modul penerima serial tahan gangguan yang membawa perintah ROV melalui dua kabel data dari permukaan.

1

24v Buck Converter

diatur ke 5 V

LM2596-based adjustable step-down buck converter module. Commonly used to regulate a higher battery rail, such as a 2S 18650 pack, down to 5V for Arduino logic. It is a regulator, not a charger or battery protection board.

1

PSU DC 24 V 30 A

24 V, 30 A

Catu daya utama yang memasok 24 V untuk sistem ROV dari darat.

1

24 V to 12 V 30 A DC-DC step-down

24 V ke 12 V, 30 A / 360 W

Konverter daya 360 W yang menurunkan 24 V menjadi 12 V untuk tiga ESC pertama.

1

24 V to 12 V 30 A DC-DC step-down

24 V ke 12 V, 30 A / 360 W

Konverter daya 360 W yang menurunkan 24 V menjadi 12 V untuk tiga ESC kedua.

1

ESP32 DevKit v1 (pengendali permukaan)

pengendali permukaan

Papan pengendali di permukaan yang membaca stik PS3 melalui Bluetooth dan mengirim perintah motor melalui kabel.

1

MAX3485 3.3 V RS-485 module (permukaan)

3.3 V

Modul komunikasi yang mengirim perintah dari ESP32 di permukaan melalui sepasang kabel tether.

1

BSS138 logic level shifter 4-channel #1

3.3 V ke 5 V

Modul kecil yang menaikkan empat sinyal kontrol ESP32 dari 3,3 V ke 5 V agar dibaca andal oleh ESC.

1

BSS138 logic level shifter 4-channel #2

3.3 V ke 5 V

Modul kecil yang menaikkan tiga sinyal kontrol ESP32 dari 3,3 V ke 5 V agar dibaca andal oleh ESC.

Assemble it in 7 steps

1. Matikan catu daya dan siapkan rumah kedap air

Jangan sambungkan PSU dahulu. Pasang ESP32 ROV, dua modul buck 12 V, buck 5 V, enam ESC, dan modul MAX3485 ROV di dalam wadah yang tetap kering. Motor A2212 dan ESC drone biasa tidak tahan air; gunakan tabung, seal, dan jalur kabel yang benar-benar kedap sebelum ROV masuk air.

  • Lepaskan seluruh baling-baling selama pengujian di meja.
  • Beri label ESC1 sampai ESC6 pada kabel agar tidak tertukar.
  • Air yang masuk ke ESC, motor, atau ESP32 dapat menyebabkan korsleting dan merusak perangkat.

2. Buat jalur daya 24 V dan 12 V

Hubungkan V+ PSU 24 V ke VIN+ buck motor A, VIN+ buck motor B, dan VIN+ buck 5 V. Hubungkan V− PSU ke ketiga VIN−. Atur kedua buck motor ke tepat 12 V memakai multimeter sebelum ESC dipasang. Hubungkan keluaran buck A ke kabel daya ESC1, ESC2, ESC3; hubungkan keluaran buck B ke ESC4, ESC5, ESC6.

  • Buck A → ESC1–ESC3 (daya); buck B → ESC4–ESC6 (daya).
  • Gunakan kabel daya yang cukup besar dan sekring pada tiap keluaran buck bila tersedia.
  • Jangan pernah menyatukan keluaran 12 V dari buck A dan buck B; dua catu yang disatukan dapat saling merusak.
  • Jangan sambungkan 24 V langsung ke ESC atau ESP32 karena dapat merusaknya.

3. Berikan daya 5 V pada ESP32 ROV

Atur buck logic ke tepat 5 V terlebih dahulu. Hubungkan VOUT+ buck logic ke pin VIN/5V ESP32 ROV (daya), lalu VOUT− ke GND ESP32 ROV (ground). Sambungkan GND ini juga ke ground sinyal ESC dan kedua pengubah level agar semua sinyal mempunyai patokan yang sama.

  • Ukur keluaran buck 5 V sebelum memasang ESP32.
  • Jaga kabel sinyal jauh dari kabel motor tiga fasa untuk mengurangi gangguan.
  • Jangan hubungkan keluaran buck 5 V ke pin 3V3 ESP32; tegangan itu dapat merusak papan.

4. Sambungkan enam sinyal ESC melalui pengubah level

Pada pengubah level pertama: LV → 3V3 (daya), HV → 5V (daya), GND → GND (ground); LV1 → GPIO25 (sinyal) dan HV1 → PWM ESC1 (sinyal), LV2 → GPIO26 (sinyal) dan HV2 → PWM ESC2 (sinyal), LV3 → GPIO27 (sinyal) dan HV3 → PWM ESC3 (sinyal). Pada pengubah kedua lakukan sama: LV1 → GPIO32 lalu HV1 → PWM ESC4, LV2 → GPIO33 lalu HV2 → PWM ESC5, LV3 → GPIO4 lalu HV3 → PWM ESC6.

  • Kabel sinyal ESC biasanya putih/kuning; kabel hitam/cokelatnya harus ke GND bersama.
  • Pengubah level kedua mempunyai satu kanal cadangan yang tidak dipakai.
  • Pastikan VCC dan GND pengubah level tidak tertukar — sambungan terbalik dapat merusak modul dan ESP32.

5. Hubungkan motor ke masing-masing ESC

Sambungkan tiga kabel motor_1 ke tiga kabel keluaran esc_1, lalu ulangi untuk pasangan motor_2/esc_2 sampai motor_6/esc_6. Bila arah putar motor salah saat nanti diuji, matikan daya lalu tukar sembarang dua dari tiga kabel fasa motor itu.

  • Gunakan label motor dan ESC yang sama agar arah serta posisi thruster mudah dilacak.
  • Jangan menukar kabel motor ketika sistem menyala; percikan dapat merusak ESC.

6. Buat kabel tether RS-485 sepanjang 15 meter

Pada ESP32 ROV hubungkan MAX3485: VCC → 3V3 (daya), GND → GND (ground), RO → GPIO16 (data masuk), DI → GPIO17 (data keluar), DE dan RE yang disatukan → GPIO21 (arah komunikasi). Hubungkan A MAX3485 ROV ke A MAX3485 permukaan (data), dan B ke B (data) memakai satu pasang kabel terpilin pada tether. Pada sisi permukaan: VCC MAX3485 → 3V3 ESP32 permukaan (daya), GND → GND (ground), DI → GPIO17 (data), RO → GPIO16 (data), dan DE/RE → GPIO21 (arah).

  • Pakai satu twisted pair khusus untuk A dan B; beri label yang sama pada kedua ujung tether.
  • Jika komunikasi tidak berjalan, matikan daya lalu tukar A dan B di salah satu ujung saja.
  • Jangan menyambungkan kabel A/B RS-485 ke 24 V atau 12 V; modul komunikasi akan rusak.

7. Siapkan pengendali permukaan dan uji aman

Nyalakan ESP32 pengendali permukaan dengan USB 5 V, pasangkan stik PS3 melalui Bluetooth, lalu nyalakan sistem ROV. Saat ESP32 ROV menyala, ia mengirim pulsa berhenti selama empat detik untuk mempersiapkan ESC. Uji setiap motor tanpa baling-baling dan naikkan perintah secara perlahan. Bila tether lepas atau perintah berhenti selama setengah detik, firmware ROV menghentikan seluruh motor.

  • Mulai dari throttle nol dan pastikan semua ESC berbunyi siap sebelum perintah motor diberikan.
  • Untuk tahap awal, batas keluaran firmware adalah sekitar 30% agar sesuai dengan kemampuan PSU dan buck yang ada.
  • Jauhkan tangan, kabel longgar, dan benda kecil dari motor saat pengujian; motor dapat berputar mendadak.

Review all connections

1. Connections between "psu_24v" and "ESP32"

Functionpsu_24vESP32
powerV+ → 24 V to 12 V 30 A DC-DC step-down VIN+EXT
powerV+ → 24 V to 12 V 30 A DC-DC step-down VIN+EXT
powerV+ → 24v Buck Converter VIN+EXT
groundV- → 24 V to 12 V 30 A DC-DC step-down VIN-EXT
groundV- → 24 V to 12 V 30 A DC-DC step-down VIN-EXT
groundV- → 24v Buck Converter VIN-EXT

2. Connections between "buck_motor_a" and "ESP32"

Functionbuck_motor_aESP32
powerVOUT+ → 30 A PWM ESC VCCEXT
powerVOUT+ → 30 A PWM ESC VCCEXT
powerVOUT+ → 30 A PWM ESC VCCEXT
groundVOUT- → 30 A PWM ESC GNDEXT
groundVOUT- → 30 A PWM ESC GNDEXT
groundVOUT- → 30 A PWM ESC GNDEXT

3. Connections between "buck_motor_b" and "ESP32"

Functionbuck_motor_bESP32
powerVOUT+ → 30 A PWM ESC VCCEXT
powerVOUT+ → 30 A PWM ESC VCCEXT
powerVOUT+ → 30 A PWM ESC VCCEXT
groundVOUT- → 30 A PWM ESC GNDEXT
groundVOUT- → 30 A PWM ESC GNDEXT
groundVOUT- → 30 A PWM ESC GNDEXT

4. Connections between "buck_logic_5v" and "ESP32"

Functionbuck_logic_5vESP32
powerVOUT+VIN
groundVOUT-GND

5. Connections between "esc_1" and "ESP32"

Functionesc_1ESP32
dataM1 → A2212 1000KV brushless motor Phase AEXT
dataM2 → A2212 1000KV brushless motor Phase BEXT
dataM3 → A2212 1000KV brushless motor Phase CEXT

6. Connections between "esc_2" and "ESP32"

Functionesc_2ESP32
dataM1 → A2212 1000KV brushless motor Phase AEXT
dataM2 → A2212 1000KV brushless motor Phase BEXT
dataM3 → A2212 1000KV brushless motor Phase CEXT

7. Connections between "esc_3" and "ESP32"

Functionesc_3ESP32
dataM1 → A2212 1000KV brushless motor Phase AEXT
dataM2 → A2212 1000KV brushless motor Phase BEXT
dataM3 → A2212 1000KV brushless motor Phase CEXT

8. Connections between "esc_4" and "ESP32"

Functionesc_4ESP32
dataM1 → A2212 1000KV brushless motor Phase AEXT
dataM2 → A2212 1000KV brushless motor Phase BEXT
dataM3 → A2212 1000KV brushless motor Phase CEXT

9. Connections between "esc_5" and "ESP32"

Functionesc_5ESP32
dataM1 → A2212 1000KV brushless motor Phase AEXT
dataM2 → A2212 1000KV brushless motor Phase BEXT
dataM3 → A2212 1000KV brushless motor Phase CEXT

10. Connections between "esc_6" and "ESP32"

Functionesc_6ESP32
dataM1 → A2212 1000KV brushless motor Phase AEXT
dataM2 → A2212 1000KV brushless motor Phase BEXT
dataM3 → A2212 1000KV brushless motor Phase CEXT

11. Connections between "rs485_rov" and "ESP32"

Functionrs485_rovESP32
powerVCC3V3
groundGNDGND
uartROGPIO 16
uartDIGPIO 17
digitalDE_REGPIO 21
dataA → MAX3485 3.3 V RS-485 module (permukaan) AEXT
dataB → MAX3485 3.3 V RS-485 module (permukaan) BEXT

12. Connections between "level_shifter_1" and "ESP32"

Functionlevel_shifter_1ESP32
powerLV3V3
powerHV5V
groundGNDGND
dataLV1GPIO 25
dataHV1 → 30 A PWM ESC PWMEXT
dataLV2GPIO 26
dataHV2 → 30 A PWM ESC PWMEXT
dataLV3GPIO 27
dataHV3 → 30 A PWM ESC PWMEXT

13. Connections between "level_shifter_2" and "ESP32"

Functionlevel_shifter_2ESP32
powerLV3V3
powerHV5V
groundGNDGND
dataLV1GPIO 32
dataHV1 → 30 A PWM ESC PWMEXT
dataLV2GPIO 33
dataHV2 → 30 A PWM ESC PWMEXT
dataLV3GPIO 4
dataHV3 → 30 A PWM ESC PWMEXT

14. Connections between "esp32_surface" and "ESP32"

Functionesp32_surfaceESP32
power5V → USB 5 V supply at surface control stationEXT
power3V3 → MAX3485 3.3 V RS-485 module (permukaan) VCCEXT
groundGND → MAX3485 3.3 V RS-485 module (permukaan) GNDEXT
uartGPIO17 TX → MAX3485 3.3 V RS-485 module (permukaan) DIEXT
digitalGPIO21 DE_RE → MAX3485 3.3 V RS-485 module (permukaan) DE_REEXT

15. Connections between "rs485_surface" and "ESP32"

Functionrs485_surfaceESP32
uartRO → ESP32 DevKit v1 (pengendali permukaan) GPIO16 RXEXT

Deploy the firmware

#include <Arduino.h>
#include <ESP32Servo.h>

// Firmware for the ESP32 inside the ROV.
// It receives: t1,t2,t3,t4,t5,t6\n over RS-485, where each value is 0..1000.


// Forward declarations
void stopAllMotors();
bool applyCommand(char *line);
void readRs485();

constexpr int ESC1_PIN = 25;
constexpr int ESC2_PIN = 26;
constexpr int ESC3_PIN = 27;
constexpr int ESC4_PIN = 32;
constexpr int ESC5_PIN = 33;
constexpr int ESC6_PIN = 4;
constexpr int RS485_RX_PIN = 16;
constexpr int RS485_TX_PIN = 17;
constexpr int RS485_DE_RE_PIN = 21;

constexpr int STOP_US = 1000;
constexpr int MAX_US = 1300;  // Keeps the existing 24 V / 30 A supply within a cautious initial limit.
constexpr uint32_t ARM_TIME_MS = 4000;
constexpr uint32_t COMMAND_TIMEOUT_MS = 500;

Servo esc[6];
const int escPins[6] = {ESC1_PIN, ESC2_PIN, ESC3_PIN, ESC4_PIN, ESC5_PIN, ESC6_PIN};
char commandLine[64];
size_t commandLength = 0;
uint32_t lastCommandMs = 0;

void stopAllMotors() {
  for (int i = 0; i < 6; ++i) {
    esc[i].writeMicroseconds(STOP_US);
  }
}

bool applyCommand(char *line) {
  int values[6];
  char *token = strtok(line, ",");

  for (int i = 0; i < 6; ++i) {
    if (token == nullptr) return false;
    char *end = nullptr;
    const long value = strtol(token, &end, 10);
    if (*end != '\0' || value < 0 || value > 1000) return false;
    values[i] = static_cast<int>(value);
    token = strtok(nullptr, ",");
  }
  if (token != nullptr) return false;

  for (int i = 0; i < 6; ++i) {
    esc[i].writeMicroseconds(map(values[i], 0, 1000, STOP_US, MAX_US));
  }
  lastCommandMs = millis();
  return true;
}

void readRs485() {
  while (Serial2.available() > 0) {
    const char c = static_cast<char>(Serial2.read());
    if (c == '\r') continue;

    if (c == '\n') {
      commandLine[commandLength] = '\0';
      if (commandLength > 0) applyCommand(commandLine);
      commandLength = 0;
    } else if (commandLength < sizeof(commandLine) - 1) {
      commandLine[commandLength++] = c;
    } else {
      commandLength = 0;
    }
  }
}

void setup() {
  pinMode(RS485_DE_RE_PIN, OUTPUT);
  digitalWrite(RS485_DE_RE_PIN, LOW);  // MAX3485 stays in receive mode.
  Serial2.begin(115200, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);

  for (int i = 0; i < 6; ++i) {
    esc[i].setPeriodHertz(50);
    esc[i].attach(escPins[i], 1000, 2000);
  }

  stopAllMotors();
  delay(ARM_TIME_MS);
  lastCommandMs = millis();
}

void loop() {
  readRs485();
  if (millis() - lastCommandMs > COMMAND_TIMEOUT_MS) {
    stopAllMotors();
  }
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik