Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Руководство по акселерометру и гироскопу Arduino и MPU6050

<основной класс="главный сайт" id="главный">

В этом уроке мы узнаем, как использовать датчик акселерометра и гироскопа MPU6050 с Arduino. Сначала я объясню, как работает MPU6050 и как считывать с него данные, а затем мы приведем два практических примера.

Вы можете посмотреть следующее видео или прочитать письменное руководство ниже.

Обзор

В первом примере с помощью среды разработки Processing мы сделаем 3D-визуализацию ориентации сенсора, а во втором примере сделаем простую самостабилизирующуюся платформу или самодельный подвес. Основываясь на ориентации MPU6050 и объединенных данных акселерометра и гироскопа, мы управляем тремя сервоприводами, которые удерживают платформу на одном уровне.

Как это работает

IMU MPU6050 имеет 3-осевой акселерометр и 3-осевой гироскоп, интегрированные в один чип.

Гироскоп измеряет скорость вращения или скорость изменения углового положения во времени вдоль осей X, Y и Z. Он использует технологию MEMS и эффект Кориолиса для измерения, но для получения более подробной информации об этом вы можете проверить мой конкретный учебник «Как работают датчики MEMS». Выходные данные гироскопа в градусах в секунду, поэтому для получения углового положения нам просто нужно проинтегрировать угловую скорость.

С другой стороны, акселерометр MPU6050 измеряет ускорение так же, как объяснялось в предыдущем видео для датчика акселерометра ADXL345. Вкратце, он может измерять гравитационное ускорение по трем осям, и, используя некоторую тригонометрическую математику, мы можем вычислить угол, под которым расположен датчик. Таким образом, если мы объединим или объединим данные акселерометра и гироскопа, мы сможем получить очень точную информацию об ориентации датчика.

IMU MPU6050 также называют шестиосевым устройством отслеживания движения или устройством с шестью степенями свободы (6 DoF) из-за его шести выходов или трех выходов акселерометра и трех выходов гироскопа.

Arduino и MPU6050

Давайте посмотрим, как мы можем подключить и прочитать данные с датчика MPU6050 с помощью Arduino. Мы используем протокол I2C для связи с Arduino, поэтому нам нужно всего два провода для его подключения, а также два провода для питания.

Компоненты, необходимые для этого руководства по Arduino, можно получить по ссылкам ниже:

Код MPU6050 Arduino

Вот код Arduino для чтения данных с датчика MPU6050. Под кодом вы можете найти его подробное описание.

/*
   Arduino and MPU6050 Accelerometer and Gyroscope Sensor Tutorial
   by Dejan, https://howtomechatronics.com
*/
#include <Wire.h>
const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
float roll, pitch, yaw;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;
float elapsedTime, currentTime, previousTime;
int c = 0;
void setup() {
  Serial.begin(19200);
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  /*
  // Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register (1C hex)
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000deg/s full scale)
  Wire.endTransmission(true);
  delay(20);
  */
  // Call this function if you need to get the IMU error values for your module
  calculate_IMU_error();
  delay(20);
}
void loop() {
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value
  // Calculating Roll and Pitch from the accelerometer data
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)
  // === Read gyroscope data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
  GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
  // Correct the outputs with the calculated error values
  GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
  GyroY = GyroY - 2; // GyroErrorY ~(2)
  GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg
  gyroAngleY = gyroAngleY + GyroY * elapsedTime;
  yaw =  yaw + GyroZ * elapsedTime;
  // Complementary filter - combine acceleromter and gyro angle values
  roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
  pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;
  
  // Print the values on the serial monitor
  Serial.print(roll);
  Serial.print("/");
  Serial.print(pitch);
  Serial.print("/");
  Serial.println(yaw);
}
void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    GyroZ = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 131.0);
    GyroErrorY = GyroErrorY + (GyroY / 131.0);
    GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  GyroErrorZ = GyroErrorZ / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
  Serial.print("GyroErrorZ: ");
  Serial.println(GyroErrorZ);
}Code language: Arduino (arduino)

Описание кода: Итак, сначала нам нужно включить библиотеку Wire.h, которая используется для связи I2C, и определить некоторые переменные, необходимые для хранения данных.

В разделе настройки нам нужно инициализировать библиотеку проводов и сбросить датчик через регистр управления питанием. Для этого нам нужно взглянуть на таблицу данных датчика, откуда мы можем увидеть адрес регистра.

Также, если мы хотим, мы можем выбрать Full-Scale Range для акселерометра и гироскопа, используя их регистры конфигурации. В этом примере мы будем использовать диапазон по умолчанию +- 2g для акселерометра и диапазон 250 градусов/с для гироскопа, поэтому я оставлю эту часть кода комментированной.

// Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register (1C hex)
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000deg/s full scale)
  Wire.endTransmission(true);
  */Code language: Arduino (arduino)

В разделе цикла мы начинаем со чтения данных акселерометра. Данные для каждой оси хранятся в двух байтах или регистрах, и мы можем увидеть адреса этих регистров из таблицы данных датчика.

Чтобы прочитать их все, мы начинаем с первого регистра и с помощью функции requiestFrom() запрашиваем чтение всех 6 регистров для осей X, Y и Z. Затем мы считываем данные из каждого регистра и, поскольку выходные данные являются дополнительными до двух, мы соответствующим образом объединяем их, чтобы получить правильные значения.

// === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis valueCode language: Arduino (arduino)

Чтобы получить выходные значения от -1g до +1g, подходящие для расчета углов, мы делим выход с ранее выбранной чувствительностью.

Наконец, используя эти две формулы, мы вычисляем углы крена и тангажа по данным акселерометра.

// Calculating Roll and Pitch from the accelerometer data
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)Code language: Arduino (arduino)

Далее тем же методом получаем данные гироскопа.

Мы считываем шесть регистров гироскопа, соответствующим образом объединяем их данные и делим их на ранее выбранную чувствительность, чтобы получить результат в градусах в секунду.

// === Read gyroscope data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
  GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;Code language: Arduino (arduino)

Здесь вы можете заметить, что я исправляю выходные значения с некоторыми небольшими вычисленными значениями ошибок, которые я объясню, как мы их получаем через минуту. Так как выходные данные представлены в градусах в секунду, теперь нам нужно умножить их на время, чтобы получить только градусы. Значение времени фиксируется перед каждой итерацией чтения с помощью функции millis().

// Correct the outputs with the calculated error values
  GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
  GyroY = GyroY - 2; // GyroErrorY ~(2)
  GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg
  gyroAngleY = gyroAngleY + GyroY * elapsedTime;
  yaw =  yaw + GyroZ * elapsedTime;Code language: Arduino (arduino)

Наконец, мы объединяем данные акселерометра и гироскопа, используя дополнительный фильтр. Здесь мы берем 96% данных гироскопа, потому что они очень точны и не зависят от внешних сил. Недостатком гироскопа является то, что он дрейфует или вносит ошибку в выходные данные с течением времени. Поэтому в долгосрочной перспективе мы используем данные акселерометра, в данном случае 4%, что достаточно для устранения ошибки дрейфа гироскопа.

// Complementary filter - combine acceleromter and gyro angle values
  roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
  pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;Code language: Arduino (arduino)

Однако, поскольку мы не можем рассчитать рыскание по данным акселерометра, мы не можем применить к нему дополнительный фильтр.

Прежде чем мы посмотрим на результаты, позвольте мне быстро объяснить, как получить значения коррекции ошибок. Для расчета этих ошибок мы можем вызвать пользовательскую функцию calculate_IMU_error(), когда датчик находится в горизонтальном неподвижном положении. Здесь мы делаем 200 показаний для всех выходов, суммируем их и делим на 200. Поскольку мы удерживаем датчик в горизонтальном положении, ожидаемые выходные значения должны быть равны 0. Таким образом, с помощью этого расчета мы можем получить среднюю ошибку датчика. делает.

void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    GyroZ = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 131.0);
    GyroErrorY = GyroErrorY + (GyroY / 131.0);
    GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  GyroErrorZ = GyroErrorZ / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
  Serial.print("GyroErrorZ: ");
  Serial.println(GyroErrorZ);
}Code language: Arduino (arduino)

Мы просто печатаем значения на последовательном мониторе, и как только мы их узнаем, мы можем реализовать их в коде, как показано ранее, как для расчета крена и тангажа, так и для 3 выходных сигналов гироскопа.

Наконец, с помощью функции Serial.print мы можем распечатать значения Roll, Pitch и Yaw на последовательном мониторе и посмотреть, правильно ли работает датчик.

Отслеживание ориентации MPU6050 — 3D-визуализация

Затем, чтобы сделать пример 3D-визуализации, нам просто нужно принять эти данные, которые Arduino отправляет через последовательный порт в среде разработки Processing. Вот полный код обработки:

/*
    Arduino and MPU6050 IMU - 3D Visualization Example 
     by Dejan, https://howtomechatronics.com
*/
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
String data="";
float roll, pitch,yaw;
void setup() {
  size (2560, 1440, P3D);
  myPort = new Serial(this, "COM7", 19200); // starts the serial communication
  myPort.bufferUntil('\n');
}
void draw() {
  translate(width/2, height/2, 0);
  background(233);
  textSize(22);
  text("Roll: " + int(roll) + "     Pitch: " + int(pitch), -100, 265);
  // Rotate the object
  rotateX(radians(-pitch));
  rotateZ(radians(roll));
  rotateY(radians(yaw));
  
  // 3D 0bject
  textSize(30);  
  fill(0, 76, 153);
  box (386, 40, 200); // Draw box
  textSize(25);
  fill(255, 255, 255);
  text("www.HowToMechatronics.com", -183, 10, 101);
  //delay(10);
  //println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values
}
// Read data from the Serial Port
void serialEvent (Serial myPort) { 
  // reads the data from the Serial Port up to the character '.' and puts it into the String variable "data".
  data = myPort.readStringUntil('\n');
  // if you got any bytes other than the linefeed:
  if (data != null) {
    data = trim(data);
    // split the string at "/"
    String items[] = split(data, '/');
    if (items.length > 1) {
      //--- Roll,Pitch in degrees
      roll = float(items[0]);
      pitch = float(items[1]);
      yaw = float(items[2]);
    }
  }
}Code language: Arduino (arduino)

Здесь мы считываем поступающие данные с Arduino и помещаем их в соответствующие переменные Roll, Pitch и Yaw. В основном цикле отрисовки мы используем эти значения для поворота 3D-объекта, в данном случае это простой прямоугольник с определенным цветом и текстом на нем.

Если мы запустим скетч, мы увидим, насколько хорош датчик MPU6050 для отслеживания ориентации. 3D-объект довольно точно отслеживает ориентацию датчика и очень быстро реагирует.

Как я уже упоминал, единственным недостатком является то, что рыскание со временем будет дрейфовать, потому что мы не можем использовать для него дополнительный фильтр. Для улучшения этого нам нужно использовать дополнительный датчик. Обычно это магнитометр, который можно использовать в качестве долговременной поправки на отклонение гироскопа от рыскания. Тем не менее, MPU6050 на самом деле имеет функцию, называемую цифровым процессором движения, которая используется для встроенных вычислений данных и способна устранять дрейф рысканья.

Вот тот же 3D-пример с использованием цифрового процессора движения. Мы можем видеть, насколько точным теперь является отслеживание ориентации без дрейфа рыскания. Встроенный процессор также может вычислять и выводить кватернионы, которые используются для представления ориентации и вращения объектов в трех измерениях. В этом примере мы фактически используем кватернионы для представления ориентации, которая также не страдает от блокировки карданного подвеса, возникающей при использовании углов Эйлера.

Тем не менее, получение этих данных от датчика немного сложнее, чем то, что мы объясняли ранее. Прежде всего, нам нужно подключить дополнительный провод к цифровому выводу Arduino. Это вывод прерывания, который используется для чтения этого типа данных из MPU6050.

Код также немного сложнее, поэтому мы собираемся использовать библиотеку i2cdevlib Джеффа Роуберга. Эту библиотеку можно загрузить с GitHub, и я добавлю ссылку на статью на веб-сайте.

После установки библиотеки мы можем открыть пример MPU6050_DMP6 из библиотеки. Этот пример хорошо поясняется комментариями к каждой строке.

Здесь мы можем выбрать, какой выход мы хотим, кватернионы, углы Эйлера, рыскание, тангаж и крен, значение ускорения или кватернионы для 3D-визуализации. Эта библиотека также включает эскиз обработки для примера 3D-визуализации. Я просто изменил его, чтобы получить форму коробки, как в предыдущем примере. Вот код обработки 3D-визуализации, который работает с примером MPU6050_DPM6 для выбранного выхода «OUTPUT_TEAPOT»:

/*
    Arduino and MPU6050 IMU - 3D Visualization Example 
     by Dejan, https://howtomechatronics.com
*/
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
String data="";
float roll, pitch,yaw;
void setup() {
  size (2560, 1440, P3D);
  myPort = new Serial(this, "COM7", 19200); // starts the serial communication
  myPort.bufferUntil('\n');
}
void draw() {
  translate(width/2, height/2, 0);
  background(233);
  textSize(22);
  text("Roll: " + int(roll) + "     Pitch: " + int(pitch), -100, 265);
  // Rotate the object
  rotateX(radians(-pitch));
  rotateZ(radians(roll));
  rotateY(radians(yaw));
  
  // 3D 0bject
  textSize(30);  
  fill(0, 76, 153);
  box (386, 40, 200); // Draw box
  textSize(25);
  fill(255, 255, 255);
  text("www.HowToMechatronics.com", -183, 10, 101);
  //delay(10);
  //println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values
}
// Read data from the Serial Port
void serialEvent (Serial myPort) { 
  // reads the data from the Serial Port up to the character '.' and puts it into the String variable "data".
  data = myPort.readStringUntil('\n');
  // if you got any bytes other than the linefeed:
  if (data != null) {
    data = trim(data);
    // split the string at "/"
    String items[] = split(data, '/');
    if (items.length > 1) {
      //--- Roll,Pitch in degrees
      roll = float(items[0]);
      pitch = float(items[1]);
      yaw = float(items[2]);
    }
  }
}Code language: Arduino (arduino)

Итак, здесь с помощью функции serialEvent() мы получаем кватернионы, поступающие от Arduino, и в основном цикле отрисовки используем их для вращения 3D-объекта. Если мы запустим скетч, то увидим, насколько хороши кватернионы для вращения объектов в трех измерениях.

Чтобы не перегружать этот урок, я поместил второй пример, самодельный карданный шарнир Arduino или самостабилизирующуюся платформу, в отдельную статью.

Не стесняйтесь задавать любые вопросы, связанные с этим руководством, в разделе комментариев ниже, а также не забудьте проверить мою коллекцию проектов Arduino.


Производственный процесс

  1. Учебное пособие по блокировке RFID для Arduino
  2. ЖК-анимация и игры
  3. Управление серводвигателем с помощью Arduino и MPU6050
  4. Связь Python3 и Arduino
  5. FM-радио с использованием Arduino и RDA8057M
  6. Преобразование ускорения в угол от датчика MPU6050 I2C
  7. Учебное пособие по датчику отпечатков пальцев Arduino
  8. Учебное пособие по Arduino:мини-пианино
  9. Ноутбук Raspberry Pi и Arduino
  10. Учебник по Arduino 01:Начало работы