План уроку


  • Повторення кутів Ейлера та принципу, як це працює
  • Візуалізація обертань через кути Ейлера
  • Зміна підходу до обертань. Кватерніони.
  • Комплексні числа
  • Гіперкомплексні числа

Матеріали


  • Роборука
  • Система керування роборукою

Результат уроку


Результатом даного уроку має бути:

  • Розуміння проблематики кутів Ейлера
  • Розуміння доцільності застосування кватерніонів в розрахунках
  • Розуміння основних властивостей кватерніонів
  • Розуміння механізмів роботи комплексних та гіперкомплексних чисел

Візуалізація обертань через кути Ейлера

#include <Arduino.h>  // Підключаємо бібліотеку Arduino для основних функцій

#include <Adafruit_MPU6050.h>  // Підключаємо бібліотеку для роботи з сенсором MPU6050
#include <Adafruit_Sensor.h>   // Бібліотека для роботи з різними сенсорами Adafruit

// Ініціалізація об'єкта для роботи з MPU6050
Adafruit_MPU6050 mpu;

// Оголошення змінних для зберігання даних з акселерометра, гіроскопа та температури
sensors_event_t a, g, temp;

// Змінна для зберігання часу останньої відправки даних
uint32_t lastSendTime = 0;

double deltaX, deltaY, deltaZ;
double angleX, angleY, angleZ;

// Буфер для надсилання даних
char buffer[80];
// Буфер для отримання команд
String inputString = "";
void calcBiases();
void calcOrient();

void(* resetFunc) (void) = 0;
void serialEvent() {
    if (Serial.read() == 'r') {
        resetFunc();
    }
}

void setup()
{
        // Ініціалізація серійного з'єднання зі швидкістю 115200 біт/с
    Serial.begin(115200);
    inputString.reserve(200); // Резервуємо пам'ять для вхідного рядка
    // Перевірка на успішне підключення сенсора MPU6050
    if (!mpu.begin())
    {
        // Якщо сенсор не знайдено, виводимо повідомлення про помилку
        Serial.println("Failed to find MPU6050 chip");  
        while (1)  // Безкінечний цикл у разі помилки
        {
                 // Невелика затримка для зменшення навантаження на систему
        delay(10); 
        }
    }

      // Налаштування діапазону вимірювань акселерометра (до 16g)
      mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
    
    // Налаштування діапазону вимірювань гіроскопа (до 2000 градусів/с)
    mpu.setGyroRange(MPU6050_RANGE_2000_DEG);
    
    // Налаштування смуги пропускання фільтра на 260 Гц
    mpu.setFilterBandwidth(MPU6050_BAND_260_HZ);

    // Невелика затримка для стабілізації роботи сенсора
    delay(100);

    calcBiases();
}


void loop()
{
    // Перевірка часу, щоб оновлювати дані кожні 10 мілісекунд
    if((millis() - lastSendTime) >= 10) {
        // Отримання даних з акселерометра, гіроскопа і температури
        mpu.getEvent(&a, &g, &temp);
        // Оновлення орієнтації
        calcOrient();
        // Виведення значень по кожній осі акселерометра
        sprintf(buffer, "%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\r\n", 
        a.acceleration.x, a.acceleration.y, a.acceleration.z,
        g.gyro.x, g.gyro.y, g.gyro.z,
        angleX * 57.2958, angleY * 57.2958, angleZ * 57.2958);

        Serial.println(buffer);
        // Оновлюємо час останньої відправки даних
        lastSendTime = millis();
    }
}

// Функція розрахунку аддитивної похибки
void calcBiases()
{
    // g.gyro.x - Кутова швидкість навкого осі X
    // g.gyro.y - Кутова швидкість навкого осі Y
    // g.gyro.z - Кутова швидкість навкого осі Z
    // deltaX - Значення аддитивної похибки по осі X
    // deltaY - Значення аддитивної похибки по осі Y
    // deltaZ - Значення аддитивної похибки по осі Z


    // Розрахуємо відхилення за допомогою знаходження середнього значення (500 ітерацій)
    for (size_t i = 0; i < 500; i++)
    {
        // Читаємо дані з давача
        mpu.getEvent(&a, &g, &temp);
        deltaX = deltaX + g.gyro.x; //
        deltaY = deltaY + g.gyro.y; // сумуємо для кожної з осей значення від давачів
        deltaZ = deltaZ + g.gyro.z; //
    }

    deltaX = deltaX / 500; //
    deltaY = deltaY / 500; // Ділимо кожне значення на кількість ітерацій
    deltaZ = deltaZ / 500; // і знаходимо середнє
}


// Функція розрахунку кутів
void calcOrient()
{
    // angleX - Розрахований кут X
    // angleY - Розрахований кут Y
    // angleZ - Розрахований кут Z

    angleX = angleX + (g.gyro.x - deltaX) * 0.01;
    angleY = angleY + (g.gyro.y - deltaY) * 0.01;
    angleZ = angleZ + (g.gyro.z - deltaZ) * 0.01;
}

Зміна підходу до обертань. Кватерніони

5 Зміна підходу до розрахунку орієнтації в просторі (в процесі)

Комплексні числа

Комплексні числа

Гіперкомплексні числа

Гіперкомплексні числа