Guest User

Untitled

a guest
Mar 14th, 2026
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.49 KB | None | 0 0
  1. #include <BleMouse.h>
  2.  
  3. #include <MPU6050_tockn.h>
  4.  
  5. #include <Wire.h>
  6.  
  7. MPU6050 mpu6050(Wire);
  8.  
  9. BleMouse mouse("ESP32-Air-Mouse", "ESP32", 100);
  10.  
  11. // Параметры микрофона
  12.  
  13. #define MIC_PIN 34
  14.  
  15. // Параметры управления
  16.  
  17. float sensitivity = 0.8;  // Уменьшена чувствительность
  18.  
  19. float deadZone = 0.15;    // Увеличена мертвая зона
  20.  
  21. bool connected = false;
  22.  
  23. // Фильтр для стабилизации
  24.  
  25. float filteredX = 0, filteredY = 0;
  26.  
  27. const float filterFactor = 0.2; // Коэффициент фильтрации
  28.  
  29. // Калибровочные смещения
  30.  
  31. float offsetX = 0, offsetY = 0;
  32.  
  33. bool calibrated = false;
  34.  
  35. // Переменные для обработки звука
  36.  
  37. unsigned long lastClapTime = 0;
  38.  
  39. const unsigned long clapCooldown = 500;
  40.  
  41. const int soundThreshold = 800;
  42.  
  43. void calibrateMPU() {
  44.  
  45.   Serial.println("Calibrating MPU6050... Keep device STILL on flat surface!");
  46.  
  47.   delay(1000);
  48.  
  49.   // Собираем 100 samples для калибровки
  50.  
  51.   float sumX = 0, sumY = 0;
  52.  
  53.   for (int i = 0; i < 100; i++) {
  54.  
  55.     mpu6050.update();
  56.  
  57.     sumX += mpu6050.getAccX();
  58.  
  59.     sumY += mpu6050.getAccY();
  60.  
  61.     delay(10);
  62.  
  63.   }
  64.  
  65.   offsetX = sumX / 100;
  66.  
  67.   offsetY = sumY / 100;
  68.  
  69.   Serial.printf("Calibration complete! Offsets: X=%.3f, Y=%.3f\n", offsetX, offsetY);
  70.  
  71.   calibrated = true;
  72.  
  73. }
  74.  
  75. void applyLowPassFilter(float &filtered, float newValue, float factor) {
  76.  
  77.   filtered = filtered (1 - factor) + newValue factor;
  78.  
  79. }
  80.  
  81. void processMovement() {
  82.  
  83.   if (!calibrated) return;
  84.  
  85.   mpu6050.update();
  86.  
  87.   // Получаем данные с компенсацией смещения
  88.  
  89.   float rawX = mpu6050.getAccX() - offsetX;
  90.  
  91.   float rawY = mpu6050.getAccY() - offsetY;
  92.  
  93.   // Применяем фильтр низких частот
  94.  
  95.   applyLowPassFilter(filteredX, rawX, filterFactor);
  96.  
  97.   applyLowPassFilter(filteredY, rawY, filterFactor);
  98.  
  99.   // Применяем мертвую зону
  100.  
  101.   if (abs(filteredX) < deadZone) filteredX = 0;
  102.  
  103.   if (abs(filteredY) < deadZone) filteredY = 0;
  104.  
  105.   // Преобразуем в движение мыши
  106.  
  107.   int moveX = 0, moveY = 0;
  108.  
  109.   if (filteredX != 0) {
  110.  
  111.     moveX = filteredX sensitivity 15;
  112.  
  113.     moveX = constrain(moveX, -127, 127);
  114.  
  115.   }
  116.  
  117.   if (filteredY != 0) {
  118.  
  119.     moveY = filteredY sensitivity 15;
  120.  
  121.     moveY = constrain(moveY, -127, 127);
  122.  
  123.   }
  124.  
  125.   // Отправляем движение только если есть значительное изменение
  126.  
  127.   if (moveX != 0 || moveY != 0) {
  128.  
  129.     mouse.move(moveX, moveY);
  130.  
  131.     // Вывод отладочной информации (редко, чтобы не засорять консоль)
  132.  
  133.     static unsigned long lastDebug = 0;
  134.  
  135.     if (millis() - lastDebug > 500) {
  136.  
  137.       Serial.printf("Move: X=%d, Y=%d (Raw: X=%.2f, Y=%.2f)\n",
  138.  
  139.                    moveX, moveY, rawX, rawY);
  140.  
  141.       lastDebug = millis();
  142.  
  143.     }
  144.  
  145.   }
  146.  
  147. }
  148.  
  149. void handleSoundCommands() {
  150.  
  151.   int micValue = analogRead(MIC_PIN);
  152.  
  153.   int amplitude = abs(micValue - 1800); // Компенсация смещения MAX9814
  154.  
  155.   if (amplitude > soundThreshold) {
  156.  
  157.     unsigned long currentTime = millis();
  158.  
  159.     if (currentTime - lastClapTime > clapCooldown) {
  160.  
  161.       // Одиночный хлопок - левый клик
  162.  
  163.       mouse.click(MOUSE_LEFT);
  164.  
  165.       Serial.println("Left click - clap detected");
  166.  
  167.       lastClapTime = currentTime;
  168.  
  169.     }
  170.  
  171.   }
  172.  
  173. }
  174.  
  175. void setup() {
  176.  
  177.   Serial.begin(115200);
  178.  
  179.   Serial.println("\n=== ESP32 BLE Air Mouse with Stabilization ===\n");
  180.  
  181.   // Инициализация MPU6050
  182.  
  183.   Wire.begin();
  184.  
  185.   mpu6050.begin();
  186.  
  187.   // Калибровка MPU6050
  188.  
  189.   calibrateMPU();
  190.  
  191.   // Дополнительная калибровка гироскопа
  192.  
  193.   Serial.println("Calibrating gyro... move device in figure 8 pattern");
  194.  
  195.   mpu6050.calcGyroOffsets(true);
  196.  
  197.   Serial.println("Gyro calibration complete");
  198.  
  199.   // Инициализация BLE мыши
  200.  
  201.   mouse.begin();
  202.  
  203.   Serial.println("BLE Mouse started");
  204.  
  205.   // Настройка пина микрофона
  206.  
  207.   pinMode(MIC_PIN, INPUT);
  208.  
  209.   Serial.println("\n=== Device Ready ===");
  210.  
  211.   Serial.println("Voice command: Clap for left click");
  212.  
  213.   Serial.println("Keep device steady when not in use");
  214.  
  215.   Serial.println("=================================");
  216.  
  217. }
  218.  
  219. void loop() {
  220.  
  221.   // Проверяем подключение
  222.  
  223.   if (mouse.isConnected() != connected) {
  224.  
  225.     connected = mouse.isConnected();
  226.  
  227.     if (connected) {
  228.  
  229.       Serial.println("Connected to host");
  230.  
  231.     } else {
  232.  
  233.       Serial.println("Disconnected from host");
  234.  
  235.     }
  236.  
  237.   }
  238.  
  239.   if (connected) {
  240.  
  241.     // Обработка движения
  242.  
  243.     processMovement();
  244.  
  245.     // Обработка звуковых команд
  246.  
  247.     handleSoundCommands();
  248.  
  249.   } else {
  250.  
  251.     // В режиме ожидания периодически калибруемся
  252.  
  253.     static unsigned long lastCalibration = 0;
  254.  
  255.     if (millis() - lastCalibration > 5000) {
  256.  
  257.       calibrateMPU();
  258.  
  259.       lastCalibration = millis();
  260.  
  261.     }
  262.  
  263.     delay(100);
  264.  
  265.   }
  266.  
  267.   // Небольшая задержка для стабильности
  268.  
  269.   delay(15);
  270.  
  271. }
  272.  
  273. // Функция для принудительной перекалибровки
  274.  
  275. void forceRecalibration() {
  276.  
  277.   Serial.println("Forcing recalibration...");
  278.  
  279.   calibrated = false;
  280.  
  281.   calibrateMPU();
  282.  
  283. }
  284.  
  285. // Функция для тестирования стабильности
  286.  
  287. void testStability() {
  288.  
  289.   Serial.println("Testing stability - device should be still");
  290.  
  291.   for (int i = 0; i < 20; i++) {
  292.  
  293.     mpu6050.update();
  294.  
  295.     float x = mpu6050.getAccX() - offsetX;
  296.  
  297.     float y = mpu6050.getAccY() - offsetY;
  298.  
  299.     Serial.printf("Stability: X=%.3f, Y=%.3f\n", x, y);
  300.  
  301.     delay(100);
  302.  
  303.   }
  304.  
  305.   Serial.println("Stability test completed");
  306.  
  307. }
  308.  
  309. // Функция для регулировки параметров
  310.  
  311. void adjustSensitivity(float newSensitivity) {
  312.  
  313.   sensitivity = newSensitivity;
  314.  
  315.   Serial.printf("Sensitivity set to: %.2f\n", sensitivity);
  316.  
  317. }
  318.  
  319. void adjustDeadZone(float newDeadZone) {
  320.  
  321.   deadZone = newDeadZone;
  322.  
  323.   Serial.printf("Dead zone set to: %.2f\n", deadZone);
  324.  
  325. }
Advertisement
Add Comment
Please, Sign In to add comment