/* Weryt Solutions - ESP8266 Wi-Fi Car (starter firmware) Board: NodeMCU ESP8266 / ESP-12E (select the matching board in your build setup) Control: phone/laptop connects to the car's Wi-Fi access point, then opens http://192.168.4.1 Motor-driver assumption: - Two L298N modules, one module per side. - On each module, connect the two motors for that side in parallel to OUT1/OUT2. - Use only channel A on each module; remove the ENA jumper if using PWM speed control. - This is a basic example. Verify each driver's current capacity and your motors' stall current. Suggested NodeMCU pins: Left driver: ENA=D1 (GPIO5), IN1=D5 (GPIO14), IN2=D6 (GPIO12) Right driver: ENA=D2 (GPIO4), IN1=D7 (GPIO13), IN2=D0 (GPIO16) Avoid GPIO 0/2/15 (D3/D4/D8) for motor control because they affect ESP8266 boot mode. Power: - Do NOT power motors from the ESP8266 3.3V pin. - Use a suitable motor battery and common ground between ESP8266 and driver logic. - L298N has significant voltage drop; check the motor voltage under load. - If using a 3S Li-ion pack, use appropriate regulation for the NodeMCU VIN/USB input and ensure motor driver, motors, battery protection, wiring and fuse are appropriately rated. */ #include #include const char* AP_SSID = "Weryt-Car"; const char* AP_PASSWORD = "weryt123"; // Change this before distribution (8+ characters). ESP8266WebServer server(80); // Left-side L298N, channel A const uint8_t LEFT_EN = D1; // GPIO5, PWM const uint8_t LEFT_IN1 = D5; // GPIO14 const uint8_t LEFT_IN2 = D6; // GPIO12 // Right-side L298N, channel A const uint8_t RIGHT_EN = D2; // GPIO4, PWM const uint8_t RIGHT_IN1 = D7; // GPIO13 const uint8_t RIGHT_IN2 = D0; // GPIO16 int motorSpeed = 800; // ESP8266 analogWrite range set below: 0..1023 const int PWM_MAX = 1023; const char PAGE[] PROGMEM = R"HTML( Weryt Wi-Fi Car
Weryt Solutions

Wi-Fi Car Control

Connect to the car's Wi-Fi network, then hold a direction button to move. Release to stop.

Ready · Weryt-Car
)HTML"; void stopMotors() { digitalWrite(LEFT_IN1, LOW); digitalWrite(LEFT_IN2, LOW); digitalWrite(RIGHT_IN1, LOW); digitalWrite(RIGHT_IN2, LOW); analogWrite(LEFT_EN, 0); analogWrite(RIGHT_EN, 0); } void setSide(uint8_t en, uint8_t in1, uint8_t in2, int direction, int speedValue) { if (direction > 0) { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); } else if (direction < 0) { digitalWrite(in1, LOW); digitalWrite(in2, HIGH); } else { digitalWrite(in1, LOW); digitalWrite(in2, LOW); } analogWrite(en, direction == 0 ? 0 : constrain(speedValue, 0, PWM_MAX)); } void moveCar(String dir) { int leftDir = 0, rightDir = 0; if (dir == "forward") { leftDir = 1; rightDir = 1; } else if (dir == "backward"){ leftDir = -1; rightDir = -1; } else if (dir == "left") { leftDir = -1; rightDir = 1; } else if (dir == "right") { leftDir = 1; rightDir = -1; } else { leftDir = 0; rightDir = 0; dir = "stop"; } setSide(LEFT_EN, LEFT_IN1, LEFT_IN2, leftDir, motorSpeed); setSide(RIGHT_EN, RIGHT_IN1, RIGHT_IN2, rightDir, motorSpeed); server.send(200, "text/plain", "Command: " + dir); } void handleRoot() { server.send_P(200, "text/html", PAGE); } void handleMove() { String dir = server.arg("dir"); moveCar(dir); } void handleSpeed() { if (server.hasArg("value")) { int percent = constrain(server.arg("value").toInt(), 0, 100); motorSpeed = map(percent, 0, 100, 0, PWM_MAX); } server.send(200, "text/plain", "Speed set to " + String(map(motorSpeed, 0, PWM_MAX, 0, 100)) + "%"); } void setup() { pinMode(LEFT_EN, OUTPUT); pinMode(LEFT_IN1, OUTPUT); pinMode(LEFT_IN2, OUTPUT); pinMode(RIGHT_EN, OUTPUT); pinMode(RIGHT_IN1, OUTPUT); pinMode(RIGHT_IN2, OUTPUT); analogWriteRange(PWM_MAX); analogWriteFreq(1000); stopMotors(); WiFi.mode(WIFI_AP); WiFi.softAP(AP_SSID, AP_PASSWORD); delay(200); server.on("/", HTTP_GET, handleRoot); server.on("/move", HTTP_GET, handleMove); server.on("/speed", HTTP_GET, handleSpeed); server.onNotFound([](){ server.send(404, "text/plain", "Not found"); }); server.begin(); } void loop() { server.handleClient(); }