AME 3623: Project 5: Rate Gyroscopes and Damping Control

Key to successful control in embedded systems is the ability to integrate information about the external state of your system into the control decisions that are being made. In this project, we will finally close a loop between sensing and actuation. We will add one more component to your circuit: an inertial measurement unit (IMU). The IMU contains three distinct sensors (with three degrees of freedom each): an accelerometer, a rate gyroscope and a magnetometer. The gyroscope will be used in this project to dampen rotational disturbances. In project 6, we will use all nine degrees-of-freedom to estimate the orientation of the hovercraft.

At the end of this project, you should be able to:

Component 0: Library Installation

Component 1: Hardware and Circuit

In order for your hovercraft to lift off the floor, it must be balanced. Move your circuit board into a position such that your craft is balanced front-to-back and left-to-right.

The IMU is a MPU-9250. Mount the Inertial Measurement (IMU) on the mast that we provide. The advantage of the mast is that your sensor will be less subject to magnetic interference from the hovercraft motors and wires, as well as sources buried in the floor.

Connect the IMU to your circuit. The pins are:

Component 2: Software

  1. Copy the following function from project 1:
  2. Copy the functions that you developed in project 4 into your current project.

  3. Implement the following functions:

  4. The control_step() function has already been provided for you (below). Modify this function to add the following functionality:

Project Template

Below is your starting point for your project. The key things that we have provided are:

#include "PeriodicAction.h"
#include "MPU9250.h"

// Promise that we will implement this function later
void control_step();

// Create a task that will be executed once per 10 ms
PeriodicAction control_task(10, control_step);

// Create a connection to the inertial measurement unit
MPU9250 IMU;

/**
   Initialize the IMU and verify that it is functioning.

   References: MPU9250 Basic Example Code, Kris Winer (April 1, 2014)
*/
void setup_imu()
{
  // Initialize the I2C bus (to which the IMU is connected)
  Wire.begin();

  // Test the connection to the IMU
  byte c = IMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);

  if (c == 0x71) {
    Serial.printf("IMU initialized successfully\n");
  } else {
    Serial.printf("*** UNABLE TO CONTACT IMU ***\n");
    // Loop forever
    while (1) {
      delay(10);
    }
  }

  // Calibrate the gyros and accelerometers.
  // NOTE: THE HOVERCRAFT MUST BE STATIONARY DURING THIS CALIBRATION
  IMU.calibrateMPU9250(IMU.gyroBias, IMU.accelBias);

  // Initialize the IMU
  IMU.initMPU9250();

  // Check the magnetometer
  c = IMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
  if (c == 0x48) {
    Serial.printf("Magnetometer initialized successfully\n");
  } else {
    Serial.printf("*** UNABLE TO CONTACT MAGNETOMETER ***\n");
    // Loop forever
    while (1) {
      delay(10);
    }
  }

  // Retrieve magnetometer calibration
  IMU.initAK8963(IMU.magCalibration);
}


void setup() {
  // Initialize the USB serial connection
  Serial.begin(115200);

  // Initialize the IMU
  setup_imu();

  // Add your project-specific setup code here

}

/**
   Update the state of the IMU by reading calibrated linear acceleration and rotation
   rate information.

   Inputs:
    n/a
   Outputs:
    (implicit): the state of variables IMU.ax, IMU.ay and IMU.az encode linear acceleration in
                  g/sec
    (implicit): the state of variables IMU.gx, IMU.gy and IMU.gz encode rotation rate in
                  deg/sec

   References: MPU9250 Basic Example Code, Kris Winer (April 1, 2014)
*/
void update_imu()
{
  // Read the accelerometer values and compute calibrated accelerations
  IMU.readAccelData(IMU.accelCount);
  IMU.getAres();
  IMU.ax = (float) IMU.accelCount[0] * IMU.aRes;
  IMU.ay = (float) IMU.accelCount[1] * IMU.aRes;
  IMU.az = (float) IMU.accelCount[2] * IMU.aRes;

  // Read the gyros and compute calibrated velocities
  IMU.readGyroData(IMU.gyroCount);
  IMU.getGres();
  IMU.gx = (float)IMU.gyroCount[0] * IMU.gRes;
  IMU.gy = (float)IMU.gyroCount[1] * IMU.gRes;
  IMU.gz = (float)IMU.gyroCount[2] * IMU.gRes;
}

/**
 * Single sensing & control step
 * 
 * Note: delays are allowed in this function (or any function called by this function)
 */
void control_step()
{
  // Update the state of the IMU
  update_imu();

  // Count the number of times that this function has been called
  static unsigned long counter = 0;

  // Increment the counter (1 per 10 ms)
  counter++;

  if(counter < 500) {
    // Ramp up the central fan to 100%

    
  }else if(counter < 6500) {
    // Implement control law here
    
  }else if(counter < 7000) {
    // Ramp down the central fan to 0%
    
  } // Else do nothing
}

/**
 * No changes necessary to the loop (except to add new tasks)
 */
void loop() {
  // Check to see if it is time to execute the control_task
  control_task.step();
}

Component 3: Testing


What to Hand In

All components of the project are due by Thursday, March 30th at 9:00 am.

Grading

Personal programming credit: Group grade distribution:

Group Grading Rubric

Grades for individuals will be based on the group grade, but weighted by the assessed contributions of the group members to the non-personal programming items.


andrewhfagg -- gmail.com

Last modified: Thu Mar 30 01:34:15 2017