Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*********
- RHS2D made by Riccardo Arciulo For Rainbow team @IRISA Rennes
- Nov 2019 --> On
- *********/
- #include <BLEDevice.h>
- #include <BLEServer.h>
- #include <BLEUtils.h>
- #include <BLE2902.h>
- #include "quaternionFilters.h"
- #include "MPU9250.h"
- #include <Arduino.h>
- #include <Sparkfun_DRV2605L.h> //SparkFun Haptic Motor Driver Library
- #include <Wire.h> //I2C library
- //=================== MPU9250 ACC+GYRO+MAG ==========================
- #define AHRS false // Set to false for basic data read
- #define SerialDebug true // Set to true to get Serial output for debugging
- #define I2Cclock 400000
- #define I2Cport Wire1
- #define MPU9250_ADDRESS MPU9250_ADDRESS_AD0 // Use either this line or the next to select which I2C address your device is using
- //#define MPU9250_ADDRESS MPU9250_ADDRESS_AD1
- MPU9250 myIMU(MPU9250_ADDRESS, I2Cport, I2Cclock);
- #define SDA_1 21
- #define SCL_1 22
- #define SDA_2 5
- #define SCL_2 17
- //================ VIBRO ======================================
- SFE_HMD_DRV2605L HMD; //Create haptic motor driver object
- //=================== MULTITREAD ==============================
- TaskHandle_t Task1;
- TaskHandle_t Task2;
- //*********************** BLE *********************************************************************
- BLECharacteristic *_pCharacteristic;
- bool deviceConnected = false;
- float txValue = 0;
- std::string rxValue; // Could also make this a global var to access it in loop()
- // See the following for generating UUIDs:
- // https://www.uuidgenerator.net/
- #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
- #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
- #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
- class MyServerCallbacks: public BLEServerCallbacks {
- void onConnect(BLEServer* pServer) {
- deviceConnected = true;
- //evolve();
- };
- void onDisconnect(BLEServer* pServer) {
- deviceConnected = false;
- //dissolve();
- }
- };
- // pCharacteristic->setValue(&txValue, 1); // To send the integer value
- // pCharacteristic->setValue("Hello!"); // Sending a test message
- // pCharacteristic->setValue(txString);
- //pCharacteristic->notify(); // Send the value to the app!
- // Serial.print("*** Sent Value: ");
- //Serial.print(txString);
- //Serial.println(" ***");
- // You can add the rxValue checks down here instead
- // if you set "rxValue" as a global var at the top!
- // Note you will have to delete "std::string" declaration
- // of "rxValue" in the callback function.
- /*if (rxValue.find("A") != -1) {
- Serial.println("Turning ON!");
- pCharacteristic->setValue("HIGH"); // Sending a test message
- pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("B") != -1) {
- Serial.println("Turning OFF!");
- pCharacteristic->setValue("LOW"); // Sending a test message
- pCharacteristic->notify(); // Send the value to the app!
- }
- pCharacteristic->notify(); // Send the value to the app!
- }*/
- //*************ble
- /* QUI E' DOVE RICEVI */
- class MyCallbacks: public BLECharacteristicCallbacks {
- void onWrite(BLECharacteristic *pCharacteristic) {
- std::string rxValue = pCharacteristic->getValue();
- if (rxValue.length() > 0) {
- //Serial.println("*********");
- //Serial.print("Received Value: ");
- for (int i = 0; i < rxValue.length(); i++) {
- //Serial.print(rxValue[i]);
- }
- Serial.println();
- // Do stuff based on the command received from the app
- if (rxValue.find("<CMD:0xA0,0x01>") != -1) {
- // digitalWrite(2, HIGH); // sets the digital pin 2 on
- // delay(500); // waits for 500 sec
- // digitalWrite(2, LOW); // sets the digital pin 2 off
- // delay(500); // waits for 500 sec
- // digitalWrite(2, HIGH); // sets the digital pin 2 on
- // delay(500); // waits for 500 sec
- // digitalWrite(2, LOW); // sets the digital pin 2 off
- // delay(500); // waits for 500 sec
- _pCharacteristic->setValue("<ACK:0xA0,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA1,0x01>") != -1) {
- // digitalWrite(15, HIGH); // sets the digital pin 2 on
- // delay(500); // waits for 500 sec
- // digitalWrite(15, LOW); // sets the digital pin 2 off
- // delay(500); // waits for 500 sec
- // digitalWrite(15, HIGH); // sets the digital pin 2 on
- // delay(500); // waits for 500 sec
- // digitalWrite(15, LOW); // sets the digital pin 2 off
- // delay(500); // waits for 500 sec
- _pCharacteristic->setValue("<ACK:0xA1,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA2,0x01>") != -1) {
- // vibro=1;
- _pCharacteristic->setValue("<ACK:0xA2,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA2,0x02>") != -1) {
- //vibro=0;
- _pCharacteristic->setValue("<ACK:0xA2,0x22>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA3,0x01>") != -1) {
- // PulsingGreen();
- _pCharacteristic->setValue("<ACK:0xA3,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- // evolve();
- }
- else if (rxValue.find("<CMD:0xA3,0x02>") != -1) {
- // PulsingRed();
- _pCharacteristic->setValue("<ACK:0xA3,0x22>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- // evolve();
- }
- else if (rxValue.find("<CMD:0xA3,0x03>") != -1) {
- //PulsingBlue();
- _pCharacteristic->setValue("<ACK:0xA3,0x33>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- //evolve();
- }
- else if (rxValue.find("<CMD:0xA4,0x01>") != -1) {
- //servoON=1;
- // ledcWriteTone(0,0); //stop
- // myservo.attach(19); // Attach the servo after it has been detatched
- //
- // myservo.write (0);
- // delay (500);
- // myservo.write (30);
- // delay (500);
- // myservo.write (60);
- // delay (500);
- // myservo.write (90);
- // delay (500);
- // myservo.write (120);
- // delay (500);
- // myservo.write (150);
- // delay (500);
- //
- // myservo.write (180);
- // delay (500);
- //
- // myservo.write (150);
- // delay (500);
- // myservo.write (120);
- // delay (500);
- // myservo.write (90);
- // delay (500);
- // myservo.write (60);
- // delay (500);
- // myservo.write (30);
- // delay (500);
- // myservo.write (0);
- // delay (500);
- //
- // myservo.detach(); // Turn the servo off for a while
- // ledcWriteTone(0,0); //stop
- _pCharacteristic->setValue("<ACK:0xA4,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA4,0x02>") != -1) {
- //servoON=0;
- _pCharacteristic->setValue("<ACK:0xA4,0x22>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA5,0x01>") != -1) {
- //*************if transducer is on ********************************************************
- // ledcWriteTone(0,800);
- // delay(1000);
- // uint8_t octave = 1;
- // ledcWriteNote(0,NOTE_C,octave);
- // delay(1000);
- // ledcWriteTone(0,0); //stop
- _pCharacteristic->setValue("<ACK:0xA5,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA5,0x02>") != -1) {
- _pCharacteristic->setValue("<ACK:0xA5,0x22>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA6,0x01>") != -1) {
- // none
- _pCharacteristic->setValue("<ACK:0xA6,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA7,0x01>") != -1) {
- //pilot = 1;
- }
- else if (rxValue.find("<CMD:0xA7,0x02>") != -1) {
- // pilot = 0;
- _pCharacteristic->setValue("<ACK:0xA7,0x22>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xA8,0x01>") != -1) {
- //calib = true;
- _pCharacteristic->setValue("<ACK:0xA8,0x11>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- else if (rxValue.find("<CMD:0xB8,0x02>") != -1) {
- //calib = false;
- _pCharacteristic->setValue("<ACK:0xB8,0x22>"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- /*
- else if (rxValue.find("0x0") != -1) {
- digitalWrite(15, HIGH); // sets the digital pin 2 on
- delay(500); // waits for 500 sec
- digitalWrite(15, LOW); // sets the digital pin 2 off
- delay(500); // waits for 500 sec
- digitalWrite(15, HIGH); // sets the digital pin 2 on
- delay(500); // waits for 500 sec
- digitalWrite(15, LOW); // sets the digital pin 2 off
- delay(500); // waits for 500 sec
- _pCharacteristic->setValue("0xA1"); // done
- _pCharacteristic->notify(); // Send the value to the app!
- }
- */
- }
- }
- };
- void setup() {
- Serial.begin(115200); // Serial setup
- Wire1.begin(SDA_1, SCL_1);
- Wire.begin(SDA_2, SCL_2);
- //=================== MPU9250 ACC+GYRO+MAG ==========================
- while(!Serial){};
- // Read the WHO_AM_I register, this is a good test of communication
- byte c = myIMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);
- Serial.print(F("MPU9250 I AM 0x"));
- Serial.print(c, HEX);
- Serial.print(F(" I should be 0x"));
- Serial.println(0x71, HEX);
- if (c == 0x71) // WHO_AM_I should always be 0x71
- {
- Serial.println(F("MPU9250 is online..."));
- // Start by performing self test and reporting values
- myIMU.MPU9250SelfTest(myIMU.selfTest);
- Serial.print(F("x-axis self test: acceleration trim within : "));
- Serial.print(myIMU.selfTest[0],1); Serial.println("% of factory value");
- Serial.print(F("y-axis self test: acceleration trim within : "));
- Serial.print(myIMU.selfTest[1],1); Serial.println("% of factory value");
- Serial.print(F("z-axis self test: acceleration trim within : "));
- Serial.print(myIMU.selfTest[2],1); Serial.println("% of factory value");
- Serial.print(F("x-axis self test: gyration trim within : "));
- Serial.print(myIMU.selfTest[3],1); Serial.println("% of factory value");
- Serial.print(F("y-axis self test: gyration trim within : "));
- Serial.print(myIMU.selfTest[4],1); Serial.println("% of factory value");
- Serial.print(F("z-axis self test: gyration trim within : "));
- Serial.print(myIMU.selfTest[5],1); Serial.println("% of factory value");
- // Calibrate gyro and accelerometers, load biases in bias registers
- myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias);
- myIMU.initMPU9250();
- // Initialize device for active mode read of acclerometer, gyroscope, and
- // temperature
- Serial.println("MPU9250 initialized for active data mode....");
- // Read the WHO_AM_I register of the magnetometer, this is a good test of
- // communication
- byte d = myIMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
- Serial.print("AK8963 ");
- Serial.print("I AM 0x");
- Serial.print(d, HEX);
- Serial.print(" I should be 0x");
- Serial.println(0x48, HEX);
- if (d != 0x48)
- {
- // Communication failed, stop here
- Serial.println(F("Communication failed, abort!"));
- Serial.flush();
- abort();
- }
- // Get magnetometer calibration from AK8963 ROM
- myIMU.initAK8963(myIMU.factoryMagCalibration);
- // Initialize device for active mode read of magnetometer
- Serial.println("AK8963 initialized for active data mode....");
- if (SerialDebug)
- {
- // Serial.println("Calibration values: ");
- Serial.print("X-Axis factory sensitivity adjustment value ");
- Serial.println(myIMU.factoryMagCalibration[0], 2);
- Serial.print("Y-Axis factory sensitivity adjustment value ");
- Serial.println(myIMU.factoryMagCalibration[1], 2);
- Serial.print("Z-Axis factory sensitivity adjustment value ");
- Serial.println(myIMU.factoryMagCalibration[2], 2);
- }
- // Get sensor resolutions, only need to do this once
- myIMU.getAres();
- myIMU.getGres();
- myIMU.getMres();
- // The next call delays for 4 seconds, and then records about 15 seconds of
- // data to calculate bias and scale.
- // myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale);
- Serial.println("AK8963 mag biases (mG)");
- Serial.println(myIMU.magBias[0]);
- Serial.println(myIMU.magBias[1]);
- Serial.println(myIMU.magBias[2]);
- Serial.println("AK8963 mag scale (mG)");
- Serial.println(myIMU.magScale[0]);
- Serial.println(myIMU.magScale[1]);
- Serial.println(myIMU.magScale[2]);
- // delay(2000); // Add delay to see results before serial spew of data
- if(SerialDebug)
- {
- Serial.println("Magnetometer:");
- Serial.print("X-Axis sensitivity adjustment value ");
- Serial.println(myIMU.factoryMagCalibration[0], 2);
- Serial.print("Y-Axis sensitivity adjustment value ");
- Serial.println(myIMU.factoryMagCalibration[1], 2);
- Serial.print("Z-Axis sensitivity adjustment value ");
- Serial.println(myIMU.factoryMagCalibration[2], 2);
- }
- } // if (c == 0x71)
- else
- {
- Serial.print("Could not connect to MPU9250: 0x");
- Serial.println(c, HEX);
- // Communication failed, stop here
- Serial.println(F("Communication failed, abort!"));
- Serial.flush();
- abort();
- }
- //================== VIBRO ==============================
- HMD.begin();
- HMD.Mode(0); // Internal trigger input mode -- Must use the GO() function to trigger playback.
- HMD.MotorSelect(0x36); // ERM motor, 4x Braking, Medium loop gain, 1.365x back EMF gain
- HMD.Library(2); //1-5 & 7 for ERM motors, 6 for LRA motors
- //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
- xTaskCreatePinnedToCore(
- Task1code, /* Task function. */
- "Task1", /* name of task. */
- 100000, /* Stack size of task */
- NULL, /* parameter of the task */
- 2, /* priority of the task */
- &Task1, /* Task handle to keep track of created task */
- 0); /* pin task to core 0 */
- //delay(500);
- //create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
- xTaskCreatePinnedToCore(
- Task2code, /* Task function. */
- "Task2", /* name of task. */
- 100000, /* Stack size of task */
- NULL, /* parameter of the task */
- 1, /* priority of the task */
- &Task2, /* Task handle to keep track of created task */
- 1); /* pin task to core 1 */
- //delay(500);
- //******************** BLE DEVICE *************************************************
- // Create the BLE Device
- BLEDevice::init("RHS2D"); // Give it a name ex ESP32 UART Test
- // Create the BLE Server
- BLEServer *pServer = BLEDevice::createServer();
- pServer->setCallbacks(new MyServerCallbacks());
- // Create the BLE Service
- BLEService *pService = pServer->createService(SERVICE_UUID);
- // Create a BLE Characteristic
- _pCharacteristic = pService->createCharacteristic(
- CHARACTERISTIC_UUID_TX,
- BLECharacteristic::PROPERTY_NOTIFY
- );
- _pCharacteristic->addDescriptor(new BLE2902());
- BLECharacteristic *pCharacteristic = pService->createCharacteristic(
- CHARACTERISTIC_UUID_RX,
- BLECharacteristic::PROPERTY_WRITE
- );
- pCharacteristic->setCallbacks(new MyCallbacks());
- // Start the service
- pService->start();
- // Start advertising
- pServer->getAdvertising()->start();
- //Serial.println("Waiting a client connection to notify...");
- }
- //==========================================================
- //==================== TASK 1 CODE =========================
- //==========================================================
- void Task1code( void * pvParameters ){
- //Serial.print("Task1 running on core ");
- //Serial.println(xPortGetCoreID());
- for(;;){
- //==================== VIBRO =====================
- int seq = 0; //There are 8 sequence registers that can queue up to 8 waveforms
- for(int wave = 1; wave <=123; wave++) //There are 123 waveform effects
- {
- HMD.Waveform(seq, wave);
- HMD.go();
- delay(600); //give enough time to play effect
- Serial.print("Waveform Sequence: ");
- Serial.println(seq);
- Serial.print("Effect No.: ");
- Serial.println(wave);
- if (wave%8==0) //Each Waveform register can queue 8 effects
- {
- seq=seq+1;
- }
- if (wave%64==0) // After the last register is used start over
- {
- seq=0;
- }
- }
- delay(1);
- }
- }
- //==========================================================
- //==================== TASK 2 CODE =========================
- //==========================================================
- void Task2code( void * pvParameters ){
- Serial.print("Task2 running on core ");
- Serial.println(xPortGetCoreID());
- for(;;){
- Serial.print("Task2 running on core ");
- Serial.println(xPortGetCoreID());
- //=================== MPU9250 ACC+GYRO+MAG ==========================
- // If intPin goes high, all data registers have new data
- // On interrupt, check if data ready interrupt
- if (myIMU.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)
- {
- myIMU.readAccelData(myIMU.accelCount); // Read the x/y/z adc values
- // Now we'll calculate the accleration value into actual g's
- // This depends on scale being set
- myIMU.ax = (float)myIMU.accelCount[0] * myIMU.aRes; // - myIMU.accelBias[0];
- myIMU.ay = (float)myIMU.accelCount[1] * myIMU.aRes; // - myIMU.accelBias[1];
- myIMU.az = (float)myIMU.accelCount[2] * myIMU.aRes; // - myIMU.accelBias[2];
- myIMU.readGyroData(myIMU.gyroCount); // Read the x/y/z adc values
- // Calculate the gyro value into actual degrees per second
- // This depends on scale being set
- myIMU.gx = (float)myIMU.gyroCount[0] * myIMU.gRes;
- myIMU.gy = (float)myIMU.gyroCount[1] * myIMU.gRes;
- myIMU.gz = (float)myIMU.gyroCount[2] * myIMU.gRes;
- myIMU.readMagData(myIMU.magCount); // Read the x/y/z adc values
- // Calculate the magnetometer values in milliGauss
- // Include factory calibration per data sheet and user environmental
- // corrections
- // Get actual magnetometer value, this depends on scale being set
- myIMU.mx = (float)myIMU.magCount[0] * myIMU.mRes
- * myIMU.factoryMagCalibration[0] - myIMU.magBias[0];
- myIMU.my = (float)myIMU.magCount[1] * myIMU.mRes
- * myIMU.factoryMagCalibration[1] - myIMU.magBias[1];
- myIMU.mz = (float)myIMU.magCount[2] * myIMU.mRes
- * myIMU.factoryMagCalibration[2] - myIMU.magBias[2];
- } // if (readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)
- // Must be called before updating quaternions!
- myIMU.updateTime();
- // Sensors x (y)-axis of the accelerometer is aligned with the y (x)-axis of
- // the magnetometer; the magnetometer z-axis (+ down) is opposite to z-axis
- // (+ up) of accelerometer and gyro! We have to make some allowance for this
- // orientationmismatch in feeding the output to the quaternion filter. For the
- // MPU-9250, we have chosen a magnetic rotation that keeps the sensor forward
- // along the x-axis just like in the LSM9DS0 sensor. This rotation can be
- // modified to allow any convenient orientation convention. This is ok by
- // aircraft orientation standards! Pass gyro rate as rad/s
- //MadgwickQuaternionUpdate(myIMU.ax, myIMU.ay, myIMU.az, myIMU.gx * DEG_TO_RAD,
- // myIMU.gy * DEG_TO_RAD, myIMU.gz * DEG_TO_RAD, myIMU.my,
- // myIMU.mx, myIMU.mz, myIMU.deltat);
- MahonyQuaternionUpdate(myIMU.ax, myIMU.ay, myIMU.az, myIMU.gx * DEG_TO_RAD,
- myIMU.gy * DEG_TO_RAD, myIMU.gz * DEG_TO_RAD, myIMU.my,
- myIMU.mx, myIMU.mz, myIMU.deltat);
- if (!AHRS)
- {
- myIMU.delt_t = millis() - myIMU.count;
- if (myIMU.delt_t > 500)
- {
- if(SerialDebug)
- {
- // Print acceleration values in milligs!
- Serial.print("X-acceleration: "); Serial.print(1000 * myIMU.ax);
- Serial.print(" mg ");
- Serial.print("Y-acceleration: "); Serial.print(1000 * myIMU.ay);
- Serial.print(" mg ");
- Serial.print("Z-acceleration: "); Serial.print(1000 * myIMU.az);
- Serial.println(" mg ");
- // Print gyro values in degree/sec
- Serial.print("X-gyro rate: "); Serial.print(myIMU.gx, 3);
- Serial.print(" degrees/sec ");
- Serial.print("Y-gyro rate: "); Serial.print(myIMU.gy, 3);
- Serial.print(" degrees/sec ");
- Serial.print("Z-gyro rate: "); Serial.print(myIMU.gz, 3);
- Serial.println(" degrees/sec");
- // Print mag values in degree/sec
- Serial.print("X-mag field: "); Serial.print(myIMU.mx);
- Serial.print(" mG ");
- Serial.print("Y-mag field: "); Serial.print(myIMU.my);
- Serial.print(" mG ");
- Serial.print("Z-mag field: "); Serial.print(myIMU.mz);
- Serial.println(" mG");
- myIMU.tempCount = myIMU.readTempData(); // Read the adc values
- // Temperature in degrees Centigrade
- myIMU.temperature = ((float) myIMU.tempCount) / 333.87 + 21.0;
- // Print temperature in degrees Centigrade
- Serial.print("Temperature is "); Serial.print(myIMU.temperature, 1);
- Serial.println(" degrees C");
- }
- myIMU.count = millis();
- //digitalWrite(myLed, !digitalRead(myLed)); // toggle led
- } // if (myIMU.delt_t > 500)
- } // if (!AHRS)
- else
- {
- // Serial print and/or display at 0.5 s rate independent of data rates
- myIMU.delt_t = millis() - myIMU.count;
- // update LCD once per half-second independent of read rate
- if (myIMU.delt_t > 500)
- {
- if(SerialDebug)
- {
- Serial.print("ax = "); Serial.print((int)1000 * myIMU.ax);
- Serial.print(" ay = "); Serial.print((int)1000 * myIMU.ay);
- Serial.print(" az = "); Serial.print((int)1000 * myIMU.az);
- Serial.println(" mg");
- Serial.print("gx = "); Serial.print(myIMU.gx, 2);
- Serial.print(" gy = "); Serial.print(myIMU.gy, 2);
- Serial.print(" gz = "); Serial.print(myIMU.gz, 2);
- Serial.println(" deg/s");
- Serial.print("mx = "); Serial.print((int)myIMU.mx);
- Serial.print(" my = "); Serial.print((int)myIMU.my);
- Serial.print(" mz = "); Serial.print((int)myIMU.mz);
- Serial.println(" mG");
- Serial.print("q0 = "); Serial.print(*getQ());
- Serial.print(" qx = "); Serial.print(*(getQ() + 1));
- Serial.print(" qy = "); Serial.print(*(getQ() + 2));
- Serial.print(" qz = "); Serial.println(*(getQ() + 3));
- }
- // Define output variables from updated quaternion---these are Tait-Bryan
- // angles, commonly used in aircraft orientation. In this coordinate system,
- // the positive z-axis is down toward Earth. Yaw is the angle between Sensor
- // x-axis and Earth magnetic North (or true North if corrected for local
- // declination, looking down on the sensor positive yaw is counterclockwise.
- // Pitch is angle between sensor x-axis and Earth ground plane, toward the
- // Earth is positive, up toward the sky is negative. Roll is angle between
- // sensor y-axis and Earth ground plane, y-axis up is positive roll. These
- // arise from the definition of the homogeneous rotation matrix constructed
- // from quaternions. Tait-Bryan angles as well as Euler angles are
- // non-commutative; that is, the get the correct orientation the rotations
- // must be applied in the correct order which for this configuration is yaw,
- // pitch, and then roll.
- // For more see
- // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
- // which has additional links.
- myIMU.yaw = atan2(2.0f * (*(getQ()+1) * *(getQ()+2) + *getQ()
- * *(getQ()+3)), *getQ() * *getQ() + *(getQ()+1)
- * *(getQ()+1) - *(getQ()+2) * *(getQ()+2) - *(getQ()+3)
- * *(getQ()+3));
- myIMU.pitch = -asin(2.0f * (*(getQ()+1) * *(getQ()+3) - *getQ()
- * *(getQ()+2)));
- myIMU.roll = atan2(2.0f * (*getQ() * *(getQ()+1) + *(getQ()+2)
- * *(getQ()+3)), *getQ() * *getQ() - *(getQ()+1)
- * *(getQ()+1) - *(getQ()+2) * *(getQ()+2) + *(getQ()+3)
- * *(getQ()+3));
- myIMU.pitch *= RAD_TO_DEG;
- myIMU.yaw *= RAD_TO_DEG;
- // Declination of SparkFun Electronics (40°05'26.6"N 105°11'05.9"W) is
- // 8° 30' E ± 0° 21' (or 8.5°) on 2016-07-19
- // - http://www.ngdc.noaa.gov/geomag-web/#declination
- myIMU.yaw -= 8.5;
- myIMU.roll *= RAD_TO_DEG;
- if(SerialDebug)
- {
- Serial.print("Yaw, Pitch, Roll: ");
- Serial.print(myIMU.yaw, 2);
- Serial.print(", ");
- Serial.print(myIMU.pitch, 2);
- Serial.print(", ");
- Serial.println(myIMU.roll, 2);
- Serial.print("rate = ");
- Serial.print((float)myIMU.sumCount / myIMU.sum, 2);
- Serial.println(" Hz");
- }
- myIMU.count = millis();
- myIMU.sumCount = 0;
- myIMU.sum = 0;
- } // if (myIMU.delt_t > 500)
- } // if (AHRS)
- }
- }
- //==========================================================
- //================== START EMPTY LOOP ======================
- //==========================================================
- void loop() {
- }
- //==========================================================
- //==================== ENDEMPTY LOOP =======================
- //==========================================================
Advertisement
Add Comment
Please, Sign In to add comment