#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
const char* ssid = "ИМЯ_ТВОЕЙ_СЕТИ";
const char* password = "ПАРОЛЬ_ОТ_WIFI";
ESP8266WebServer server(80);
// Пины для L298N
const int IN1 = D1;
const int IN2 = D2;
const int IN3 = D5;
const int IN4 = D6;
const int lightPin = D3;
int valM1 = 1024, valM2 = 1024, swState = 0;
const int deadzone = 35; // Размер мертвой зоны (1024 +/- 35)
const char PAGE[] PROGMEM = R"=====(
<!DOCTYPE HTML><html><head>
<meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'>
<style>
body { font-family: sans-serif; text-align: center; background: #121212; color: white; margin: 0; overflow: hidden; height: 100vh; }
.header { height: 10vh; display: flex; align-items: center; justify-content: center; background: #1f1f1f; font-size: 1.2rem; font-weight: bold; border-bottom: 1px solid #333; }
.container { display: flex; row-gap: 10px; justify-content: space-around; height: 85vh; align-items: flex-start; padding-top: 20px; }
.slider-box { display: flex; flex-direction: column; align-items: center; width: 35%; }
input[type=range][orient=vertical] { appearance: slider-vertical; width: 70px; height: 70vh; background: #333; cursor: pointer; border-radius: 10px; }
.center-controls { width: 20%; display: flex; flex-direction: column; align-items: center; padding-top: 20px; }
.switch { position: relative; display: inline-block; width: 60px; height: 34px; margin-bottom: 10px; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider-round { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #444; transition: .4s; border-radius: 34px; }
.slider-round:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; }
input:checked + .slider-round { background-color: #f1c40f; box-shadow: 0 0 10px #f1c40f; }
input:checked + .slider-round:before { transform: translateX(26px); }
.label { font-size: 0.7rem; color: #888; text-transform: uppercase; margin-bottom: 5px; }
.val { font-size: 1.1rem; margin-top: 10px; color: #2ecc71; font-family: monospace; min-height: 1.5em; }
</style>
</head>
<body>
<div class="header">RC CONTROL PRO</div>
<div class="container">
<div class="slider-box">
<div class="label">ЛЕВЫЙ</div>
<input type='range' id='m1' min='0' max='2048' value='1024' orient='vertical' oninput='sendMotor(1, this.value)' ontouchend='resetMotor(1)' onmouseup='resetMotor(1)'>
<div class='val' id='v1'>STOP</div>
</div>
<div class="center-controls">
<div class="label">СВЕТ</div>
<label class="switch">
<input type="checkbox" id="sw" onchange="toggleSwitch(this.checked)">
<span class="slider-round"></span>
</label>
</div>
<div class="slider-box">
<div class="label">ПРАВЫЙ</div>
<input type='range' id='m2' min='0' max='2048' value='1024' orient='vertical' oninput='sendMotor(2, this.value)' ontouchend='resetMotor(2)' onmouseup='resetMotor(2)'>
<div class='val' id='v2'>STOP</div>
</div>
</div>
<script>
function sendMotor(m, v) {
let displayVal = "STOP";
let dz = 35;
if (v > (1024 + dz)) displayVal = "↑ " + (v - 1024);
else if (v < (1024 - dz)) displayVal = "↓ " + (1024 - v);
document.getElementById('v' + m).innerHTML = displayVal;
fetch('/set?m=' + m + '&v=' + v);
}
function resetMotor(m) {
document.getElementById('m' + m).value = 1024;
sendMotor(m, 1024);
}
function toggleSwitch(state) {
fetch('/sw?state=' + (state ? 1 : 0));
}
</script>
</body></html>
)=====";
void driveMotor(int m, int value) {
int speed = 0;
// Проверка мертвой зоны
if (value > (1024 + deadzone)) {
speed = map(value, 1024 + deadzone, 2048, 0, 1023); // Плавный старт после мертвой зоны
if (m == 1) { analogWrite(IN1, speed); digitalWrite(IN2, LOW); }
else { analogWrite(IN3, speed); digitalWrite(IN4, LOW); }
}
else if (value < (1024 - deadzone)) {
speed = map(value, 1024 - deadzone, 0, 0, 1023);
if (m == 1) { digitalWrite(IN1, LOW); analogWrite(IN2, speed); }
else { digitalWrite(IN3, LOW); analogWrite(IN4, speed); }
}
else { // СТОП в мертвой зоне
if (m == 1) { digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); }
else { digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); }
}
}
void handleUpdate() {
int m = server.arg("m").toInt();
int v = server.arg("v").toInt();
if (m == 1) valM1 = v;
if (m == 2) valM2 = v;
driveMotor(m, v);
server.send(200, "text/plain", "OK");
}
void handleSwitch() {
swState = server.arg("state").toInt();
digitalWrite(lightPin, swState);
server.send(200, "text/plain", "OK");
}
void setup() {
Serial.begin(115200);
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
pinMode(lightPin, OUTPUT);
analogWriteRange(1023); // Устанавливаем диапазон ШИМ
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
server.on("/", [](){ server.send(200, "text/html", PAGE); });
server.on("/set", handleUpdate);
server.on("/sw", handleSwitch);
server.begin();
Serial.println("\nIP Ready: " + WiFi.localIP().toString());
}
void loop() { server.handleClient(); }
Обновленный код для управления через точку доступа WI-FI создаваемой WEMOS D1.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
const char* ap_ssid = "T-34-TANK";
const char* ap_pass = "12345678";
ESP8266WebServer server(80);
const int IN1 = D1; const int IN2 = D2;
const int IN3 = D5; const int IN4 = D6;
const char PAGE[] PROGMEM = R"=====(
<!DOCTYPE html><html><head><meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=0'>
<style>
body{font-family:sans-serif;text-align:center;background:#0d0d0d;color:#fff;margin:0;height:100vh;overflow:hidden;touch-action:none;display:flex;flex-direction:column;align-items:center}
#t{width:85vw;height:80px;margin-top:20px;-webkit-appearance:none;background:#333;border-radius:15px;border:1px solid #777}
#t::-webkit-slider-thumb{width:80px;height:76px;background:#3498db;-webkit-appearance:none;border-radius:12px;border:2px solid #fff}
.stop{width:160px;min-height:80px;margin:30px 0;background:#e74c3c;border:4px solid #fff;border-radius:20px;color:#fff;font-size:30px;font-weight:bold}
#s{-webkit-appearance:slider-vertical;width:60px;height:55vh;background:#444;outline:none}
#s::-webkit-slider-thumb{-webkit-appearance:none;width:60px;height:60px;background:#2ecc71;border:3px solid #fff;border-radius:50%}
</style></head><body>
<input type='range' id='t' min='0' max='2048' value='1024' oninput='send()'>
<button class='stop' onclick='stopAll()'>STOP</button>
<input type='range' id='s' min='0' max='2048' value='1024' oninput='send()'>
<script>
let last=0;
function send(){
let now=Date.now();
if(now-last<50) return;
last=now;
fetch('/j?s='+document.getElementById('s').value+'&t='+document.getElementById('t').value);
}
function stopAll(){
document.getElementById('s').value=1024;document.getElementById('t').value=1024;
send();
}
document.addEventListener('touchmove',e=>{if(e.target.tagName!='INPUT')e.preventDefault();},{passive:false});
</script></body></html>
)=====";
void drive(int s_raw, int t_raw) {
int dz = 90;
int speed = map(s_raw, 0, 2048, -1023, 1023);
int steer = map(t_raw, 0, 2048, -250, 250);
if (abs(speed) < dz) speed = 0;
if (abs(steer) < dz) steer = 0;
// ИНВЕРСИЯ ПОВОРОТА ПРИ ДВИЖЕНИИ НАЗАД
if (speed < -dz) {
steer = -steer;
}
int l, r;
// РАЗВОРОТ НА МЕСТЕ
if (speed == 0 && abs(steer) > 50) {
l = (steer > 0) ? 400 : -400;
r = (steer > 0) ? -400 : 400;
} else {
l = speed + steer;
r = speed - steer;
}
l = constrain(l, -1023, 1023);
r = constrain(r, -1023, 1023);
// Моторы
auto runL = [](int v){
if(v>50){analogWrite(IN3,v);digitalWrite(IN4,0);}
else if(v<-50){digitalWrite(IN3,0);analogWrite(IN4,-v);}
else{digitalWrite(IN3,0);digitalWrite(IN4,0);}
};
auto runR = [](int v){
if(v>50){digitalWrite(IN1,0);analogWrite(IN2,v);}
else if(v<-50){analogWrite(IN1,-v);digitalWrite(IN2,0);}
else{digitalWrite(IN1,0);digitalWrite(IN2,0);}
};
runL(l); runR(r);
}
void setup() {
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
analogWriteRange(1023); analogWriteFreq(450);
WiFi.softAP(ap_ssid, ap_pass);
server.on("/", [](){ server.send_P(200, "text/html", PAGE); });
server.on("/j", [](){
drive(server.arg("s").toInt(), server.arg("t").toInt());
server.send(200);
});
server.begin();
}
void loop() { server.handleClient(); }
Комментариев нет:
Отправить комментарий