Community project

SKEMATIK ROV

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
Loading diagram…

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