Compare commits
No commits in common. "802ae3516632a6a24ae48acaedb1a6aafc1ebbfd" and "b7d0ebfe380835c6835a6b40ad3038beff40eb74" have entirely different histories.
802ae35166
...
b7d0ebfe38
10
src/config.h
10
src/config.h
@ -1,15 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// ===== Robot Info =====
|
|
||||||
#define ROBOT_NAME "OLEG-02"
|
|
||||||
#define FIRMWARE_NAME "ESP32 Robot"
|
|
||||||
#define FIRMWARE_VERSION "1.0.0"
|
|
||||||
|
|
||||||
// ===== Joystick (PS2 analog) =====
|
|
||||||
#define JOY_X_PIN 34 // VRX → ADC1_CH6
|
|
||||||
#define JOY_Y_PIN 35 // VRY → ADC1_CH7
|
|
||||||
#define JOY_SW_PIN 14 // SW → кнопка
|
|
||||||
|
|
||||||
// ===== Wi-Fi =====
|
// ===== Wi-Fi =====
|
||||||
#define WIFI_SSID "Capybara"
|
#define WIFI_SSID "Capybara"
|
||||||
#define WIFI_PASS "qq1234567890"
|
#define WIFI_PASS "qq1234567890"
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "actuators.h"
|
#include "actuators.h"
|
||||||
|
|
||||||
bool actuatorsInit() {
|
void actuatorsInit() {
|
||||||
pinMode(PIN_LB, OUTPUT);
|
pinMode(PIN_LB, OUTPUT);
|
||||||
pinMode(PIN_LF, OUTPUT);
|
pinMode(PIN_LF, OUTPUT);
|
||||||
pinMode(PIN_RB, OUTPUT);
|
pinMode(PIN_RB, OUTPUT);
|
||||||
@ -14,15 +14,8 @@ bool actuatorsInit() {
|
|||||||
ledcAttachPin(L_PWM_PIN, PWM_CH_L);
|
ledcAttachPin(L_PWM_PIN, PWM_CH_L);
|
||||||
ledcAttachPin(R_PWM_PIN, PWM_CH_R);
|
ledcAttachPin(R_PWM_PIN, PWM_CH_R);
|
||||||
|
|
||||||
Serial.println("Actuators initialized");
|
|
||||||
Serial.printf(" L_PWM → GPIO%d\n", L_PWM_PIN);
|
|
||||||
Serial.printf(" R_PWM → GPIO%d\n", R_PWM_PIN);
|
|
||||||
Serial.printf(" L_DIR → GPIO%d, %d\n", PIN_LB, PIN_LF);
|
|
||||||
Serial.printf(" R_DIR → GPIO%d, %d\n", PIN_RB, PIN_RF);
|
|
||||||
|
|
||||||
actuatorsSetSpeed(150, 150);
|
actuatorsSetSpeed(150, 150);
|
||||||
actuatorsStop();
|
actuatorsStop();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void actuatorsStop() {
|
void actuatorsStop() {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
bool actuatorsInit();
|
void actuatorsInit();
|
||||||
void actuatorsStop();
|
void actuatorsStop();
|
||||||
|
|
||||||
void actuatorsForward();
|
void actuatorsForward();
|
||||||
|
|||||||
@ -1,318 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <Adafruit_GFX.h>
|
|
||||||
#include <Adafruit_SSD1306.h>
|
|
||||||
#include "body.h"
|
|
||||||
#include "../../../config.h"
|
|
||||||
#include "../../../server/web_server.h"
|
|
||||||
#include "../../../core/ultrasonic/ultrasonic.h"
|
|
||||||
#include "../../../core/robot_state/robot_state.h"
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
// ===== OLED CONFIG =====
|
|
||||||
// ESP32 ESP-WROOM-32D с OLED 0.96" (SSD1306)
|
|
||||||
#define SCREEN_WIDTH 128
|
|
||||||
#define SCREEN_HEIGHT 64
|
|
||||||
#define OLED_RESET -1
|
|
||||||
#define SCREEN_ADDR 0x3C
|
|
||||||
|
|
||||||
// SDA/SCL пины для CH340 с OLED
|
|
||||||
#define SDA_PIN 21
|
|
||||||
#define SCL_PIN 22
|
|
||||||
|
|
||||||
static Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
||||||
|
|
||||||
// ===== Main Display =====
|
|
||||||
|
|
||||||
static int currentStage = 0;
|
|
||||||
static int totalStages = 5;
|
|
||||||
static bool systemReady = false;
|
|
||||||
static bool debugMode = false;
|
|
||||||
|
|
||||||
// Display update tracking
|
|
||||||
static unsigned long lastDisplayUpdate = 0;
|
|
||||||
static const unsigned long DISPLAY_UPDATE_INTERVAL = 500; // ms
|
|
||||||
|
|
||||||
static void drawHeader() {
|
|
||||||
// Заголовок (инверсия)
|
|
||||||
display.fillRect(0, 0, SCREEN_WIDTH, 16, SSD1306_WHITE);
|
|
||||||
display.setTextColor(SSD1306_BLACK);
|
|
||||||
display.setCursor(2, 4);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.print(ROBOT_NAME);
|
|
||||||
|
|
||||||
// Версия (правый угол) - только если система не готова
|
|
||||||
if (!systemReady && totalStages > 0) {
|
|
||||||
char stageStr[8];
|
|
||||||
snprintf(stageStr, sizeof(stageStr), "%d/%d", currentStage, totalStages);
|
|
||||||
int textWidth = strlen(stageStr) * 6; // ~6px на символ
|
|
||||||
display.setCursor(SCREEN_WIDTH - textWidth - 2, 4);
|
|
||||||
display.print(stageStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Версия ПО (правый угол) - только если система готова
|
|
||||||
if (systemReady) {
|
|
||||||
int textWidth = strlen(FIRMWARE_VERSION) * 6;
|
|
||||||
display.setCursor(SCREEN_WIDTH - textWidth - 2, 4);
|
|
||||||
display.print(FIRMWARE_VERSION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drawFooter() {
|
|
||||||
// Разделительная линия (опущена ниже)
|
|
||||||
// display.drawLine(0, SCREEN_HEIGHT - 10, SCREEN_WIDTH, SCREEN_HEIGHT - 10, SSD1306_WHITE);
|
|
||||||
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setTextSize(1);
|
|
||||||
|
|
||||||
if (systemReady && debugMode) {
|
|
||||||
// Инвертированный фон для DEBUG режима
|
|
||||||
display.fillRect(0, SCREEN_HEIGHT - 9, SCREEN_WIDTH, 9, SSD1306_WHITE);
|
|
||||||
display.setTextColor(SSD1306_BLACK);
|
|
||||||
|
|
||||||
// Кнопка Menu (левый угол)
|
|
||||||
const char* menuBtn = "[MENU]";
|
|
||||||
display.setCursor(2, SCREEN_HEIGHT - 8);
|
|
||||||
display.print(menuBtn);
|
|
||||||
|
|
||||||
// Uptime (правый угол)
|
|
||||||
uint32_t uptime = webServerGetUptime();
|
|
||||||
char uptimeStr[12];
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "UP=%lus", uptime);
|
|
||||||
int textWidth = strlen(uptimeStr) * 6;
|
|
||||||
display.setCursor(SCREEN_WIDTH - textWidth - 2, SCREEN_HEIGHT - 8);
|
|
||||||
display.print(uptimeStr);
|
|
||||||
} else if (systemReady) {
|
|
||||||
// Uptime (правый угол)
|
|
||||||
uint32_t uptime = webServerGetUptime();
|
|
||||||
char uptimeStr[12];
|
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "UP=%lus", uptime);
|
|
||||||
int textWidth = strlen(uptimeStr) * 6;
|
|
||||||
display.setCursor(SCREEN_WIDTH - textWidth - 2, SCREEN_HEIGHT - 8);
|
|
||||||
display.print(uptimeStr);
|
|
||||||
} else {
|
|
||||||
// Версия (правый угол)
|
|
||||||
int textWidth = strlen(FIRMWARE_VERSION) * 6;
|
|
||||||
display.setCursor(SCREEN_WIDTH - textWidth - 2, SCREEN_HEIGHT - 8);
|
|
||||||
display.print(FIRMWARE_VERSION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledSetStage(int current, int total) {
|
|
||||||
currentStage = current;
|
|
||||||
totalStages = total;
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledSetSystemReady(bool ready, bool debug) {
|
|
||||||
systemReady = ready;
|
|
||||||
debugMode = debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool oledIsSystemReady() {
|
|
||||||
return systemReady;
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledShowMain(const char* line1, const char* line2, const char* line3, const char* line4) {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок
|
|
||||||
drawHeader();
|
|
||||||
|
|
||||||
// Основной контент (4 строки)
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(0, 20);
|
|
||||||
if (line1) display.println(line1);
|
|
||||||
display.setCursor(0, 30);
|
|
||||||
if (line2) display.println(line2);
|
|
||||||
display.setCursor(0, 40);
|
|
||||||
if (line3) display.println(line3);
|
|
||||||
display.setCursor(0, 50);
|
|
||||||
if (line4) display.println(line4);
|
|
||||||
|
|
||||||
// Подвал
|
|
||||||
drawFooter();
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledInit() {
|
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
|
||||||
|
|
||||||
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDR)) {
|
|
||||||
Serial.println("SSD1306 allocation failed");
|
|
||||||
for (;;);
|
|
||||||
}
|
|
||||||
|
|
||||||
display.clearDisplay();
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.display();
|
|
||||||
|
|
||||||
oledShowBoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Screens =====
|
|
||||||
|
|
||||||
void oledShowBoot() {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок
|
|
||||||
drawHeader();
|
|
||||||
|
|
||||||
// Контент
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(0, 25);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.println("Robot booting");
|
|
||||||
display.setCursor(0, 35);
|
|
||||||
display.println("Please wait...");
|
|
||||||
|
|
||||||
// Подвал
|
|
||||||
drawFooter();
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledShowWiFi(const char* ssid, int rssi) {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок
|
|
||||||
drawHeader();
|
|
||||||
|
|
||||||
// Контент
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(0, 25);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.print("SSID: ");
|
|
||||||
display.println(ssid);
|
|
||||||
display.setCursor(0, 35);
|
|
||||||
display.print("RSSI: ");
|
|
||||||
display.print(rssi);
|
|
||||||
display.println(" dBm");
|
|
||||||
|
|
||||||
// Подвал
|
|
||||||
drawFooter();
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledShowMode(const char* mode) {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок
|
|
||||||
drawHeader();
|
|
||||||
|
|
||||||
// Контент
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(0, 25);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.print("MODE: ");
|
|
||||||
display.println(mode);
|
|
||||||
display.setCursor(0, 35);
|
|
||||||
display.println("Ready");
|
|
||||||
|
|
||||||
// Подвал
|
|
||||||
drawFooter();
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledShowText(const char* line1, const char* line2) {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок
|
|
||||||
drawHeader();
|
|
||||||
|
|
||||||
// Контент
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(0, 25);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.println(line1);
|
|
||||||
display.setCursor(0, 35);
|
|
||||||
display.println(line2);
|
|
||||||
|
|
||||||
// Подвал
|
|
||||||
drawFooter();
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Calibration =====
|
|
||||||
|
|
||||||
void oledShowCalibration() {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок (верхняя строка)
|
|
||||||
display.fillRect(0, 0, SCREEN_WIDTH, 16, SSD1306_WHITE);
|
|
||||||
display.setTextColor(SSD1306_BLACK);
|
|
||||||
display.setCursor(2, 4);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.println("CALIBRATION");
|
|
||||||
|
|
||||||
// Основная область
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(0, 16);
|
|
||||||
display.println("Line 1: y=16");
|
|
||||||
display.setCursor(0, 26);
|
|
||||||
display.println("Line 2: y=26");
|
|
||||||
display.setCursor(0, 36);
|
|
||||||
display.println("Line 3: y=36");
|
|
||||||
display.setCursor(0, 46);
|
|
||||||
display.println("Line 4: y=46");
|
|
||||||
display.setCursor(0, 56);
|
|
||||||
display.println("Line 5: y=56");
|
|
||||||
|
|
||||||
// Границы
|
|
||||||
display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledDrawMainMenu(const char* ip, const char* mode) {
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
// Заголовок
|
|
||||||
drawHeader();
|
|
||||||
|
|
||||||
// Основной контент (центрирован между шапкой и подвалом)
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setTextSize(1);
|
|
||||||
|
|
||||||
// Строка 1: IP адрес (y=17)
|
|
||||||
display.setCursor(0, 17);
|
|
||||||
display.print("IP: ");
|
|
||||||
display.println(ip);
|
|
||||||
|
|
||||||
// Строка 2: Режим (y=27)
|
|
||||||
display.setCursor(0, 27);
|
|
||||||
display.print("Mode: ");
|
|
||||||
display.println(mode);
|
|
||||||
|
|
||||||
// Строка 3: Дистанция и RSSI (y=37)
|
|
||||||
display.setCursor(0, 37);
|
|
||||||
int dist = ultrasonicReadCm();
|
|
||||||
int rssi = WiFi.RSSI();
|
|
||||||
display.printf("DIST: %dcm RSSI: %d", dist, rssi);
|
|
||||||
|
|
||||||
// Строка 4: Скорости (y=47)
|
|
||||||
display.setCursor(0, 47);
|
|
||||||
display.printf("L: %d R: %d", robot.speedL, robot.speedR);
|
|
||||||
|
|
||||||
// Подвал
|
|
||||||
drawFooter();
|
|
||||||
|
|
||||||
display.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oledUpdateDisplay() {
|
|
||||||
if (!systemReady) return;
|
|
||||||
|
|
||||||
unsigned long now = millis();
|
|
||||||
if (now - lastDisplayUpdate >= DISPLAY_UPDATE_INTERVAL) {
|
|
||||||
lastDisplayUpdate = now;
|
|
||||||
|
|
||||||
const char* ip = webServerGetIP();
|
|
||||||
const char* mode = webServerGetMode();
|
|
||||||
oledDrawMainMenu(ip, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void oledInit();
|
|
||||||
|
|
||||||
// базовые экраны
|
|
||||||
void oledShowBoot();
|
|
||||||
void oledShowWiFi(const char* ssid, int rssi);
|
|
||||||
void oledShowMode(const char* mode);
|
|
||||||
|
|
||||||
// универсально (2 строки)
|
|
||||||
void oledShowText(const char* line1, const char* line2);
|
|
||||||
|
|
||||||
// калибровка
|
|
||||||
void oledShowCalibration();
|
|
||||||
|
|
||||||
// основная отрисовка
|
|
||||||
void oledSetStage(int current, int total);
|
|
||||||
void oledShowMain(const char* line1, const char* line2, const char* line3, const char* line4);
|
|
||||||
|
|
||||||
// состояние системы
|
|
||||||
void oledSetSystemReady(bool ready, bool debugMode = false);
|
|
||||||
bool oledIsSystemReady();
|
|
||||||
|
|
||||||
// меню
|
|
||||||
void oledDrawMainMenu(const char* ip, const char* mode);
|
|
||||||
void oledUpdateDisplay();
|
|
||||||
@ -1,109 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include "joystick.h"
|
|
||||||
#include "../../config.h"
|
|
||||||
|
|
||||||
// ===== ADC CONFIG =====
|
|
||||||
// ADC1: 12 бит (0-4095)
|
|
||||||
// Центр джойстика ≈ 2048 (но может отличаться)
|
|
||||||
|
|
||||||
#define ADC_CENTER_X 1870 // калибровка X (подбирается опытно)
|
|
||||||
#define ADC_CENTER_Y 1850 // калибровка Y (подбирается опытно)
|
|
||||||
#define ADC_DEADZONE 150 // мёртвая зона
|
|
||||||
#define ADC_MIN 0
|
|
||||||
#define ADC_MAX 4095
|
|
||||||
|
|
||||||
// Нормализованные значения
|
|
||||||
#define NORM_MIN -100
|
|
||||||
#define NORM_MAX 100
|
|
||||||
|
|
||||||
// Порог логирования (чтобы не шумело)
|
|
||||||
#define LOG_THRESHOLD 10 // минимальное изменение для лога
|
|
||||||
|
|
||||||
static int joyX = 0;
|
|
||||||
static int joyY = 0;
|
|
||||||
static bool swPressed = false;
|
|
||||||
static int lastLoggedXNorm = 0;
|
|
||||||
static int lastLoggedYNorm = 0;
|
|
||||||
static bool lastLoggedSw = false;
|
|
||||||
|
|
||||||
bool joyInit() {
|
|
||||||
pinMode(JOY_SW_PIN, INPUT_PULLUP);
|
|
||||||
|
|
||||||
// ADC1 каналы (пины 34, 35)
|
|
||||||
analogReadResolution(12); // 12 бит (0-4095)
|
|
||||||
analogSetAttenuation(ADC_11db); // 0-3.3V
|
|
||||||
|
|
||||||
// Проверяем наличие джойстика
|
|
||||||
int x = analogRead(JOY_X_PIN);
|
|
||||||
int y = analogRead(JOY_Y_PIN);
|
|
||||||
|
|
||||||
// Если значения в разумных пределах - джойстик подключен
|
|
||||||
bool connected = (x > 100 && x < 4000) && (y > 100 && y < 4000);
|
|
||||||
|
|
||||||
Serial.println("Joystick initialized");
|
|
||||||
Serial.printf(" VRX → GPIO%d (ADC1_CH6)\n", JOY_X_PIN);
|
|
||||||
Serial.printf(" VRY → GPIO%d (ADC1_CH7)\n", JOY_Y_PIN);
|
|
||||||
Serial.printf(" SW → GPIO%d\n", JOY_SW_PIN);
|
|
||||||
Serial.printf(" Center: X=%d, Y=%d\n", ADC_CENTER_X, ADC_CENTER_Y);
|
|
||||||
Serial.printf(" Status: %s (X=%d, Y=%d)\n",
|
|
||||||
connected ? "OK" : "NOT FOUND", x, y);
|
|
||||||
|
|
||||||
return connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void joyUpdate() {
|
|
||||||
joyX = analogRead(JOY_X_PIN);
|
|
||||||
joyY = analogRead(JOY_Y_PIN);
|
|
||||||
swPressed = (digitalRead(JOY_SW_PIN) == LOW); // LOW = нажата
|
|
||||||
|
|
||||||
// Логирование только при значимых изменениях
|
|
||||||
int xNorm = joyGetXNormalized();
|
|
||||||
int yNorm = joyGetYNormalized();
|
|
||||||
|
|
||||||
bool xChanged = abs(xNorm - lastLoggedXNorm) >= LOG_THRESHOLD;
|
|
||||||
bool yChanged = abs(yNorm - lastLoggedYNorm) >= LOG_THRESHOLD;
|
|
||||||
bool swChanged = (swPressed != lastLoggedSw);
|
|
||||||
|
|
||||||
if (xChanged || yChanged || swChanged) {
|
|
||||||
Serial.printf("[JOY] X=%4d (%4d) | Y=%4d (%4d) | SW=%s\n",
|
|
||||||
joyX, xNorm, joyY, yNorm, swPressed ? "PRESSED" : "released");
|
|
||||||
|
|
||||||
lastLoggedXNorm = xNorm;
|
|
||||||
lastLoggedYNorm = yNorm;
|
|
||||||
lastLoggedSw = swPressed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int joyGetX() {
|
|
||||||
return joyX;
|
|
||||||
}
|
|
||||||
|
|
||||||
int joyGetY() {
|
|
||||||
return joyY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool joyIsPressed() {
|
|
||||||
return swPressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
int joyGetXNormalized() {
|
|
||||||
if (joyX < ADC_CENTER_X - ADC_DEADZONE) {
|
|
||||||
// влево
|
|
||||||
return map(joyX, ADC_MIN, ADC_CENTER_X - ADC_DEADZONE, NORM_MIN, 0);
|
|
||||||
} else if (joyX > ADC_CENTER_X + ADC_DEADZONE) {
|
|
||||||
// вправо
|
|
||||||
return map(joyX, ADC_CENTER_X + ADC_DEADZONE, ADC_MAX, 0, NORM_MAX);
|
|
||||||
}
|
|
||||||
return 0; // мёртвая зона
|
|
||||||
}
|
|
||||||
|
|
||||||
int joyGetYNormalized() {
|
|
||||||
if (joyY < ADC_CENTER_Y - ADC_DEADZONE) {
|
|
||||||
// вверх (инвертировано)
|
|
||||||
return map(joyY, ADC_MIN, ADC_CENTER_Y - ADC_DEADZONE, NORM_MAX, 0);
|
|
||||||
} else if (joyY > ADC_CENTER_Y + ADC_DEADZONE) {
|
|
||||||
// вниз
|
|
||||||
return map(joyY, ADC_CENTER_Y + ADC_DEADZONE, ADC_MAX, 0, NORM_MIN);
|
|
||||||
}
|
|
||||||
return 0; // мёртвая зона
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
bool joyInit();
|
|
||||||
void joyUpdate();
|
|
||||||
|
|
||||||
// возвращает значения 0-4095
|
|
||||||
int joyGetX();
|
|
||||||
int joyGetY();
|
|
||||||
|
|
||||||
// возвращает true, если кнопка нажата
|
|
||||||
bool joyIsPressed();
|
|
||||||
|
|
||||||
// возвращает нормализованные значения -100..100
|
|
||||||
int joyGetXNormalized();
|
|
||||||
int joyGetYNormalized();
|
|
||||||
@ -38,16 +38,10 @@ static uint32_t angleToDuty(int logicalAngle) {
|
|||||||
SERVO_MIN, SERVO_MAX);
|
SERVO_MIN, SERVO_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool servoInit() {
|
void servoInit() {
|
||||||
ledcSetup(SERVO_CH, servoFreq, servoRes);
|
ledcSetup(SERVO_CH, servoFreq, servoRes);
|
||||||
ledcAttachPin(SERVO_PIN, SERVO_CH);
|
ledcAttachPin(SERVO_PIN, SERVO_CH);
|
||||||
|
|
||||||
Serial.println("Servo initialized");
|
|
||||||
Serial.printf(" PIN → GPIO%d\n", SERVO_PIN);
|
|
||||||
Serial.printf(" CH → %d\n", SERVO_CH);
|
|
||||||
|
|
||||||
servoCenter();
|
servoCenter();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void servoCenter() {
|
void servoCenter() {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
bool servoInit();
|
void servoInit();
|
||||||
void servoCenter();
|
void servoCenter();
|
||||||
void servoSetAngle(int angle);
|
void servoSetAngle(int angle);
|
||||||
int servoGetAngle();
|
int servoGetAngle();
|
||||||
|
|||||||
@ -8,17 +8,11 @@
|
|||||||
// таймаут эха (30 мс ≈ 5 м)
|
// таймаут эха (30 мс ≈ 5 м)
|
||||||
static const uint32_t ECHO_TIMEOUT_US = 30000;
|
static const uint32_t ECHO_TIMEOUT_US = 30000;
|
||||||
|
|
||||||
bool ultrasonicInit() {
|
void ultrasonicInit() {
|
||||||
pinMode(TRIG_PIN, OUTPUT);
|
pinMode(TRIG_PIN, OUTPUT);
|
||||||
pinMode(ECHO_PIN, INPUT);
|
pinMode(ECHO_PIN, INPUT);
|
||||||
|
|
||||||
digitalWrite(TRIG_PIN, LOW);
|
digitalWrite(TRIG_PIN, LOW);
|
||||||
|
|
||||||
Serial.println("Ultrasonic initialized");
|
|
||||||
Serial.printf(" TRIG → GPIO%d\n", TRIG_PIN);
|
|
||||||
Serial.printf(" ECHO → GPIO%d\n", ECHO_PIN);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// измерение расстояния
|
// измерение расстояния
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
bool ultrasonicInit();
|
void ultrasonicInit();
|
||||||
|
|
||||||
// возвращает расстояние в см
|
// возвращает расстояние в см
|
||||||
// -1 = нет эхо / ошибка
|
// -1 = нет эхо / ошибка
|
||||||
|
|||||||
68
src/main.cpp
68
src/main.cpp
@ -1,11 +1,10 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "core/display/body/body.h"
|
#include "core/deprecate/lcd_status/lcd_status.h"
|
||||||
#include "core/servo/servo.h"
|
#include "core/servo/servo.h"
|
||||||
#include "core/ultrasonic/ultrasonic.h"
|
#include "core/ultrasonic/ultrasonic.h"
|
||||||
#include "core/display/face/face.h"
|
#include "core/display/face/face.h"
|
||||||
#include "core/robot_state/robot_state.h"
|
#include "core/robot_state/robot_state.h"
|
||||||
#include "core/joystick/joystick.h"
|
|
||||||
|
|
||||||
#include "core/actuators/actuators.h"
|
#include "core/actuators/actuators.h"
|
||||||
#include "server/web_server.h"
|
#include "server/web_server.h"
|
||||||
@ -13,62 +12,17 @@
|
|||||||
#include "core/controller/controller.h"
|
#include "core/controller/controller.h"
|
||||||
// #include "core/deprecate/ir_input/ir_input.h"
|
// #include "core/deprecate/ir_input/ir_input.h"
|
||||||
|
|
||||||
#define TOTAL_STAGES 5
|
|
||||||
#define DELAY_FOR_STARTUP_CHECKS 1000
|
|
||||||
|
|
||||||
void runStartupChecks() {
|
|
||||||
delay(DELAY_FOR_STARTUP_CHECKS);
|
|
||||||
|
|
||||||
// Этап 1: Проверка джойстика
|
|
||||||
oledSetStage(1, TOTAL_STAGES);
|
|
||||||
bool joyOk = joyInit();
|
|
||||||
// irInit();
|
|
||||||
oledShowMain(joyOk ? "Joystick: OK" : "Joystick: NOT FOUND",
|
|
||||||
"IR: NOT FOUND",
|
|
||||||
"", "");
|
|
||||||
delay(DELAY_FOR_STARTUP_CHECKS);
|
|
||||||
|
|
||||||
// Этап 2: Проверка Face дисплея
|
|
||||||
oledSetStage(2, TOTAL_STAGES);
|
|
||||||
bool faceOk = false; // faceInit();
|
|
||||||
oledShowMain("Face display: FAIL",
|
|
||||||
"", "", "");
|
|
||||||
delay(DELAY_FOR_STARTUP_CHECKS);
|
|
||||||
|
|
||||||
// Этап 3: Проверка серво и ультразвука
|
|
||||||
oledSetStage(3, TOTAL_STAGES);
|
|
||||||
bool servoOk = servoInit();
|
|
||||||
bool ultrasonicOk = ultrasonicInit();
|
|
||||||
oledShowMain(servoOk ? "Servo: OK" : "Servo: FAIL",
|
|
||||||
ultrasonicOk ? "Ultrasonic: OK" : "Ultrasonic: FAIL",
|
|
||||||
"", "");
|
|
||||||
delay(DELAY_FOR_STARTUP_CHECKS);
|
|
||||||
|
|
||||||
// Этап 4: Проверка моторов (actuators)
|
|
||||||
oledSetStage(4, TOTAL_STAGES);
|
|
||||||
bool actuatorsOk = actuatorsInit();
|
|
||||||
oledShowMain(actuatorsOk ? "Motors: OK" : "Motors: FAIL",
|
|
||||||
"", "", "");
|
|
||||||
delay(DELAY_FOR_STARTUP_CHECKS);
|
|
||||||
|
|
||||||
// Этап 5: Инициализация WiFi и WebSocket
|
|
||||||
oledSetStage(5, TOTAL_STAGES);
|
|
||||||
bool wifiOk = webServerInit();
|
|
||||||
bool wsOk = wsInit();
|
|
||||||
delay(DELAY_FOR_STARTUP_CHECKS);
|
|
||||||
|
|
||||||
// Все проверки пройдены
|
|
||||||
// joyOk = true означает debug mode (джойстик найден)
|
|
||||||
oledSetSystemReady(wifiOk, joyOk);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
oledInit();
|
lcdInit();
|
||||||
|
servoInit();
|
||||||
// Запуск проверок
|
ultrasonicInit();
|
||||||
runStartupChecks();
|
faceInit();
|
||||||
|
actuatorsInit();
|
||||||
|
webServerInit();
|
||||||
|
wsInit();
|
||||||
|
// irInit();
|
||||||
|
|
||||||
robot.lastCmdMs = millis();
|
robot.lastCmdMs = millis();
|
||||||
}
|
}
|
||||||
@ -76,10 +30,6 @@ void setup() {
|
|||||||
void loop() {
|
void loop() {
|
||||||
webServerLoop();
|
webServerLoop();
|
||||||
wsLoop();
|
wsLoop();
|
||||||
joyUpdate();
|
|
||||||
controllerUpdate();
|
controllerUpdate();
|
||||||
// irPoll();
|
// irPoll();
|
||||||
|
|
||||||
// Обновляем дисплей с IP и режимом
|
|
||||||
oledUpdateDisplay();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,17 +6,10 @@
|
|||||||
#include "core/controller/controller.h"
|
#include "core/controller/controller.h"
|
||||||
#include "core/robot_state/robot_state.h"
|
#include "core/robot_state/robot_state.h"
|
||||||
#include "core/ultrasonic/ultrasonic.h"
|
#include "core/ultrasonic/ultrasonic.h"
|
||||||
#include "core/display/body/body.h"
|
#include "core/deprecate/lcd_status/lcd_status.h"
|
||||||
|
|
||||||
static WebServer server(80);
|
static WebServer server(80);
|
||||||
|
|
||||||
// Static buffers for getters
|
|
||||||
static char ipStr[16] = "No IP";
|
|
||||||
static char modeStr[16] = "IDLE";
|
|
||||||
|
|
||||||
#define WIFI_RETRY_MAX 5
|
|
||||||
#define WIFI_RETRY_DELAY_MS 800
|
|
||||||
|
|
||||||
void handleRoot() {
|
void handleRoot() {
|
||||||
server.send_P(200, "text/html; charset=utf-8", INDEX_HTML);
|
server.send_P(200, "text/html; charset=utf-8", INDEX_HTML);
|
||||||
}
|
}
|
||||||
@ -72,8 +65,7 @@ void handleMode() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(modeStr, sizeof(modeStr), "%s", modeToStr(robot.mode));
|
lcdShowMode(modeToStr(robot.mode));
|
||||||
// oledShowMode(modeStr);
|
|
||||||
// lcdShowText("SERVICE MODE", "Waiting...");
|
// lcdShowText("SERVICE MODE", "Waiting...");
|
||||||
server.send(200, "text/plain",
|
server.send(200, "text/plain",
|
||||||
String("OK MODE=") + modeToStr(robot.mode));
|
String("OK MODE=") + modeToStr(robot.mode));
|
||||||
@ -96,87 +88,30 @@ void handleStatus() {
|
|||||||
server.send(200, "application/json", json);
|
server.send(200, "application/json", json);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool webServerInit() {
|
void webServerInit() {
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
Serial.print("\nConnecting to Wi-Fi");
|
Serial.print("\nConnecting to Wi-Fi");
|
||||||
|
|
||||||
// Показываем экран подключения
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
char statusBuf[32];
|
|
||||||
snprintf(statusBuf, sizeof(statusBuf), "Retry 0/%d", WIFI_RETRY_MAX);
|
|
||||||
oledShowText("Connecting to WiFi", "");
|
|
||||||
|
|
||||||
int retryCount = 0;
|
|
||||||
while (WiFi.status() != WL_CONNECTED && retryCount < WIFI_RETRY_MAX) {
|
|
||||||
// Serial.print("\nRetry connecting to Wi-Fi");
|
|
||||||
// delay(WIFI_RETRY_DELAY_MS);
|
|
||||||
|
|
||||||
// if (retryCount >= 3){
|
|
||||||
// retryCount = 0;
|
|
||||||
// } else {
|
|
||||||
// retryCount++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Обновляем дисплей с номером попытки
|
|
||||||
// snprintf(statusBuf, sizeof(statusBuf), "Retry %d/%d", retryCount, WIFI_RETRY_MAX);
|
|
||||||
// oledShowText("Connecting to WiFi...", statusBuf);
|
|
||||||
|
|
||||||
Serial.print("\nRetry connecting to Wi-Fi");
|
Serial.print("\nRetry connecting to Wi-Fi");
|
||||||
delay(WIFI_RETRY_DELAY_MS);
|
delay(300);
|
||||||
|
|
||||||
// Считаем точки: 1, 2, 3, затем сброс в 0
|
|
||||||
retryCount = (retryCount + 1) % 4; // 0, 1, 2, 3 точки
|
|
||||||
|
|
||||||
// Формируем строку с точками
|
|
||||||
char dots[4] = "";
|
|
||||||
for (int i = 0; i < retryCount; i++) {
|
|
||||||
dots[i] = '.';
|
|
||||||
}
|
|
||||||
dots[retryCount] = '\0';
|
|
||||||
|
|
||||||
// Обновляем дисплей: "Connecting to WiFi" + точки
|
|
||||||
char statusBuf[32];
|
|
||||||
snprintf(statusBuf, sizeof(statusBuf), "Connecting to WiFi%s", dots);
|
|
||||||
oledShowText(statusBuf, ""); // вторая строка пустая, если не нужна
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
// Показываем успешное подключение
|
lcdShowWiFi(WIFI_SSID, WiFi.RSSI());
|
||||||
snprintf(ipStr, sizeof(ipStr), "%s", WiFi.localIP().toString().c_str());
|
|
||||||
oledShowText("WiFi: CONNECTED", ipStr);
|
|
||||||
Serial.print("\nConnected. IP: ");
|
Serial.print("\nConnected. IP: ");
|
||||||
Serial.println(WiFi.localIP());
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
// Настраиваем маршруты
|
|
||||||
server.on("/", handleRoot);
|
|
||||||
server.on("/cmd", handleCmd);
|
|
||||||
server.on("/speed", handleSpeed);
|
|
||||||
server.on("/mode", handleMode);
|
|
||||||
server.on("/status", handleStatus);
|
|
||||||
server.begin();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Не удалось подключиться
|
server.on("/", handleRoot);
|
||||||
oledShowText("WiFi: FAILED", "Check router/network");
|
server.on("/cmd", handleCmd);
|
||||||
Serial.println("\nWiFi connection failed");
|
server.on("/speed", handleSpeed);
|
||||||
return false;
|
server.on("/mode", handleMode);
|
||||||
|
server.on("/status", handleStatus);
|
||||||
|
server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void webServerLoop() {
|
void webServerLoop() {
|
||||||
server.handleClient();
|
server.handleClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* webServerGetIP() {
|
|
||||||
return ipStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* webServerGetMode() {
|
|
||||||
return modeStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t webServerGetUptime() {
|
|
||||||
return millis() / 1000; // seconds
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
bool webServerInit();
|
void webServerInit();
|
||||||
void webServerLoop();
|
void webServerLoop();
|
||||||
|
|
||||||
// Getters for display
|
|
||||||
const char* webServerGetIP();
|
|
||||||
const char* webServerGetMode();
|
|
||||||
uint32_t webServerGetUptime();
|
|
||||||
|
|||||||
@ -4,12 +4,11 @@
|
|||||||
#include "ws_server.h"
|
#include "ws_server.h"
|
||||||
#include "core/controller/controller.h"
|
#include "core/controller/controller.h"
|
||||||
#include "core/robot_state/robot_state.h"
|
#include "core/robot_state/robot_state.h"
|
||||||
#include "core/display/body/body.h"
|
#include "core/display/face/face.h"
|
||||||
|
|
||||||
static WebSocketsServer ws(81); // порт 81
|
static WebSocketsServer ws(81); // порт 81
|
||||||
|
|
||||||
static uint32_t lastWsCmdMs = 0;
|
static uint32_t lastWsCmdMs = 0;
|
||||||
static bool wsReady = false;
|
|
||||||
|
|
||||||
void wsEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
void wsEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -55,16 +54,16 @@ void wsEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// else if (msg.startsWith("FACE:")) {
|
else if (msg.startsWith("FACE:")) {
|
||||||
// String v = msg.substring(5);
|
String v = msg.substring(5);
|
||||||
// v.toUpperCase();
|
v.toUpperCase();
|
||||||
|
|
||||||
// if (v == "HAPPY") faceSet(FACE_HAPPY);
|
if (v == "HAPPY") faceSet(FACE_HAPPY);
|
||||||
// else if (v == "ANGRY") faceSet(FACE_ANGRY);
|
else if (v == "ANGRY") faceSet(FACE_ANGRY);
|
||||||
// else if (v == "BORED") faceSet(FACE_BORED);
|
else if (v == "BORED") faceSet(FACE_BORED);
|
||||||
// else if (v == "SURPRISED") faceSet(FACE_SURPRISED);
|
else if (v == "SURPRISED") faceSet(FACE_SURPRISED);
|
||||||
// else faceSet(FACE_NEUTRAL);
|
else faceSet(FACE_NEUTRAL);
|
||||||
// }
|
}
|
||||||
|
|
||||||
else if (msg.startsWith("SPEED:")) {
|
else if (msg.startsWith("SPEED:")) {
|
||||||
int v = msg.substring(6).toInt();
|
int v = msg.substring(6).toInt();
|
||||||
@ -78,20 +77,9 @@ void wsEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wsInit() {
|
void wsInit() {
|
||||||
// Показываем статус инициализации WebSocket
|
|
||||||
// oledShowText("WebSocket: INIT...", "Queue pending");
|
|
||||||
|
|
||||||
ws.begin();
|
ws.begin();
|
||||||
ws.onEvent(wsEvent);
|
ws.onEvent(wsEvent);
|
||||||
|
|
||||||
wsReady = true;
|
|
||||||
|
|
||||||
// Показываем успешную инициализацию
|
|
||||||
// oledShowText("WebSocket: READY", "Listening on :81");
|
|
||||||
Serial.println("WebSocket initialized on port 81");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wsLoop() {
|
void wsLoop() {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
bool wsInit();
|
void wsInit();
|
||||||
void wsLoop();
|
void wsLoop();
|
||||||
void wsBroadcastStatus();
|
void wsBroadcastStatus();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user