I want a simplest possible schematic that allows m...
BT1 4×AA + BT2 2×AA in series as a 6×AA pack, wired to V9_MOTOR/GND through restored battery input terminal J2, and kept the holders as external/off-board parts. Updated the project files and verified ERC plus key placement/DRC checks are clean.J2 battery connector.J1.Serial1.GP18–GP21.Table
| Function | Pico GPIO | Connected To | Direction | Notes |
|---|---|---|---|---|
| ESP UART TX from Pico | GP0 | U1:RXD | Output | Pico sends AT commands to ESP-01S. |
| ESP UART RX to Pico | GP1 | U1:TXD | Input | Pico receives AT responses. |
| Motor 1 | GP18 | R5 -> Q1:G | Output/PWM | Controls J3 motor output. |
| Motor 2 | GP19 | R6 -> Q2:G | Output/PWM | Controls J4 motor output. |
| Motor 3 | GP20 | R7 -> Q3:G | Output/PWM | Controls J5 motor output. |
| Motor 4 | GP21 | R8 -> Q4:G | Output/PWM | Controls J6 motor output. |
platformio.iniIni
[env:pico] platform = raspberrypi board = pico framework = arduino monitor_speed = 115200
src/main.cpp)Cpp
#include <Arduino.h> // Schematic pin mapping static constexpr uint8_t ESP_TX_FROM_PICO = 0; // GP0 -> ESP RXD static constexpr uint8_t ESP_RX_TO_PICO = 1; // GP1 <- ESP TXD static constexpr uint8_t MOTOR1_PIN = 18; // GP18 -> Q1 gate via R5 static constexpr uint8_t MOTOR2_PIN = 19; // GP19 -> Q2 gate via R6 static constexpr uint8_t MOTOR3_PIN = 20; // GP20 -> Q3 gate via R7 static constexpr uint8_t MOTOR4_PIN = 21; // GP21 -> Q4 gate via R8 static constexpr uint32_t DEBUG_BAUD = 115200; static constexpr uint32_t ESP_BAUD = 115200; static constexpr uint8_t PWM_RESOLUTION_BITS = 8; // analogWrite range 0..255 // Replace with your network credentials if you use station mode. const char WIFI_SSID[] = "YOUR_SSID"; const char WIFI_PASS[] = "YOUR_PASSWORD"; bool waitForESPResponse(const char *expected, uint32_t timeoutMs) { String response; uint32_t start = millis(); while (millis() - start < timeoutMs) { while (Serial1.available() > 0) { char c = static_cast<char>(Serial1.read()); response += c; Serial.write(c); if (response.indexOf(expected) >= 0) { return true; } if (response.indexOf("ERROR") >= 0 || response.indexOf("FAIL") >= 0) { return false; } } } Serial.print("\nTimed out waiting for: "); Serial.println(expected); return false; } bool sendAT(const char *command, const char *expected = "OK", uint32_t timeoutMs = 3000) { Serial.print("AT> "); Serial.println(command); Serial1.print(command); Serial1.print("\r\n"); return waitForESPResponse(expected, timeoutMs); } void initMotors() { analogWriteResolution(PWM_RESOLUTION_BITS); pinMode(MOTOR1_PIN, OUTPUT); pinMode(MOTOR2_PIN, OUTPUT); pinMode(MOTOR3_PIN, OUTPUT); pinMode(MOTOR4_PIN, OUTPUT); analogWrite(MOTOR1_PIN, 0); analogWrite(MOTOR2_PIN, 0); analogWrite(MOTOR3_PIN, 0); analogWrite(MOTOR4_PIN, 0); } void setMotor(uint8_t motorIndex, uint8_t duty) { switch (motorIndex) { case 1: analogWrite(MOTOR1_PIN, duty); break; case 2: analogWrite(MOTOR2_PIN, duty); break; case 3: analogWrite(MOTOR3_PIN, duty); break; case 4: analogWrite(MOTOR4_PIN, duty); break; default: break; } } void allMotorsOff() { setMotor(1, 0); setMotor(2, 0); setMotor(3, 0); setMotor(4, 0); } bool initESP01S() { Serial1.setTX(ESP_TX_FROM_PICO); Serial1.setRX(ESP_RX_TO_PICO); Serial1.begin(ESP_BAUD); delay(500); bool ok = true; ok &= sendAT("AT", "OK", 2000); ok &= sendAT("ATE0", "OK", 2000); // echo off ok &= sendAT("AT+CWMODE=1", "OK", 3000); // station mode if (strlen(WIFI_SSID) > 0 && strcmp(WIFI_SSID, "YOUR_SSID") != 0) { char joinCommand[160]; snprintf(joinCommand, sizeof(joinCommand), "AT+CWJAP=\"%s\",\"%s\"", WIFI_SSID, WIFI_PASS); ok &= sendAT(joinCommand, "WIFI GOT IP", 20000); } else { Serial.println("WiFi credentials are placeholders; skipping AP join."); } return ok; } void demoMotorSequence() { // Gentle smoke-test sequence. Remove or guard this in production firmware. for (uint8_t duty = 0; duty <= 128; duty += 16) { setMotor(1, duty); delay(40); } delay(300); allMotorsOff(); } void setup() { Serial.begin(DEBUG_BAUD); delay(1000); Serial.println("Remote Pico Controller firmware starting"); initMotors(); if (initESP01S()) { Serial.println("ESP-01S AT interface ready"); } else { Serial.println("ESP-01S init failed or timed out; motors remain controllable locally"); } demoMotorSequence(); } void loop() { // USB serial commands for bench testing: // m1 0 -> motor 1 off // m2 128 -> motor 2 ~50% duty // alloff -> all motors off if (Serial.available()) { String cmd = Serial.readStringUntil('\n'); cmd.trim(); if (cmd.equalsIgnoreCase("alloff")) { allMotorsOff(); Serial.println("All motors off"); } else if (cmd.length() >= 4 && cmd.charAt(0) == 'm') { uint8_t motor = cmd.substring(1, 2).toInt(); int duty = cmd.substring(3).toInt(); duty = constrain(duty, 0, 255); setMotor(motor, static_cast<uint8_t>(duty)); Serial.printf("Motor %u duty %d\n", motor, duty); } else if (cmd.startsWith("AT")) { sendAT(cmd.c_str(), "OK", 5000); } else { Serial.println("Commands: m1 0..255, m2 0..255, m3 0..255, m4 0..255, alloff, or raw AT..."); } } // Pass ESP unsolicited messages to USB serial. while (Serial1.available()) { Serial.write(Serial1.read()); } }
Bash
pio run pio run -t upload pio device monitor -b 115200
V5 and V3V3_WIFI rails before flashing firmware.AT command response from ESP-01S before trying WiFi join.Platform & Toolchain
Pin Mapping
`platformio.ini`
Complete Firmware Source (`src/main.cpp`)
Build and Flash
Bring-Up Notes