Friday, May 22, 2020

ATOM Matrix: Using the MPU6886 Accelerometer

The ATOM Matrix includes an accelerometer and gyroscope in its MPU6886. The MPU6886 also includes an internal temperature sensor.


Reading and Displaying Values

The MPU6886 must first be initialized using M5.IMU.Init() which will return 0 if the initialization was successful. Reading from the IMU then awalys follows the following steps:

  • Declare floating-point variables
  • Pass the memory location of those variables into the appropriate method
All this is demonstrated in the following application.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
 * MPU6886.ino
 * 
 * By: Mike Klepper
 * Date: 26 April 2020
 * 
 * Basically the same as the MPU6886 example sketch but with C -> F conversion
 */

#include "M5Atom.h"

float accX = 0, accY = 0, accZ = 0;
float gyroX = 0, gyroY = 0, gyroZ = 0;
float tempC = 0;
bool IMU6886Flag = false;

void setup()
{
    M5.begin(true, false, true);
    delay(20);
    
    IMU6886Flag = M5.IMU.Init() == 0;
  
    if(!IMU6886Flag)
    {
        Serial.println("Error initializing the IMU! :-(");
    }
}

void loop()
{
    if(IMU6886Flag)
    {
        M5.IMU.getGyroData(&gyroX, &gyroY, &gyroZ);
        M5.IMU.getAccelData(&accX, &accY, &accZ);
        M5.IMU.getTempData(&tempC);
    
        float tempF = 9*tempC/5 + 32;
    
        Serial.printf("Gyroscope: %.2f,%.2f,%.2f o/s \r\n", gyroX, gyroY, gyroZ);
        Serial.printf("Accelerometer: %.2f,%.2f,%.2f mg\r\n", accX * 1000, accY * 1000, accZ * 1000);
        Serial.printf("Temperature: %.2f C \r\n", tempC);
        Serial.printf("Temperature: %.2f F \r\n", tempF);
        Serial.println("");
    }
    
    delay(500);
    M5.update();
}


Showing Device Orientation

The accelerometer data can be used to have the ATOM take different actions based on its orientation. Using the above code, we can perform experiments to see what values accX, accY, and accZ take on as we hold the device in different positions. Those values are included in comments in the code.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
 * AccelerometerTest02.ino
 * 
 * By: Mike Klepper
 * Date: 26 April 2020
 * 
 * Displays arrow indicating device orientation based on info from the MPU6886
 */


#include "M5Atom.h"

int GRB_COLOR_WHITE = 0xffffff;
int GRB_COLOR_BLACK = 0x000000;
int GRB_COLOR_RED = 0x00ff00;
int GRB_COLOR_ORANGE = 0xa5ff00;
int GRB_COLOR_YELLOW = 0xffff00;
int GRB_COLOR_GREEN = 0xff0000;
int GRB_COLOR_BLUE = 0x0000ff;
int GRB_COLOR_PURPLE = 0x008080;

int upArrow[25] = 
{
    0,0,1,0,0,
    0,1,1,1,0,
    1,0,1,0,1,
    0,0,1,0,0,
    0,0,1,0,0
};

int downArrow[25] = 
{
    0,0,1,0,0,
    0,0,1,0,0,
    1,0,1,0,1,
    0,1,1,1,0,
    0,0,1,0,0
};

int leftArrow[25] = 
{
    0,0,1,0,0,
    0,1,0,0,0,
    1,1,1,1,1,
    0,1,0,0,0,
    0,0,1,0,0
};

int rightArrow[25] = 
{
    0,0,1,0,0,
    0,0,0,1,0,
    1,1,1,1,1,
    0,0,0,1,0,
    0,0,1,0,0
};

int roundShape[25] = 
{
    0,1,1,1,0,
    1,0,0,0,1,
    1,0,0,0,1,
    1,0,0,0,1,
    0,1,1,1,0
};

int circleWithX[25] = 
{
    0,1,1,1,0,
    1,0,2,0,1,
    1,2,2,2,1,
    1,0,2,0,1,
    0,1,1,1,0
};


int delayAmt = 1000;

int colorList[] = {GRB_COLOR_BLACK, GRB_COLOR_PURPLE, GRB_COLOR_YELLOW};

float accX = 0;
float accY = 0;
float accZ = 0;

bool IMU6886Flag = false;

/*
 * Screen Up: 
 * |accX| < LOW_TOL -15, |accY| < LOW_TOL, accZ ~ -980
 * 
 * Screen Down: 
 * |accX| < LOW_TOL -7, |accY| < LOW_TOL 3, accZ ~ 1020
 * 
 * Note Up: 
 * |accX| < LOW_TOL -7, accY ~ 1000, |accZ| < LOW_TOL
 * 
 * Note Down: 
 * |accX| < LOW_TOL -7, accY ~ -1000, |accZ| < LOW_TOL
 * 
 * Reset Up: 
 * accX ~ 990, |accY| < LOW_TOL, |accZ| < LOW_TOL
 * 
 * Reset Down: 
 * accX ~ -1000, |accY| < LOW_TOL - 10, |accZ| < LOW_TOL, -20
 */

float LOW_TOL = 100;
float HIGH_TOL = 900;

float scaledAccX = 0;
float scaledAccY = 0;
float scaledAccZ = 0;

void setup() 
{
    M5.begin(true, false, true);
    delay(20);
    
    IMU6886Flag = M5.IMU.Init() == 0;
  
    if(!IMU6886Flag)
    {
        Serial.println("Error initializing the IMU! :-(");
    }
}

void loop() 
{
    if(IMU6886Flag)
    {
        M5.IMU.getAccelData(&accX, &accY, &accZ);

        Serial.printf("Accel: %.2f, %.2f, %.2f mg\r\n", accX * 1000, accY * 1000, accZ * 1000);
        
        scaledAccX = accX * 1000;
        scaledAccY = accY * 1000;
        scaledAccZ = accZ * 1000;

        if(abs(scaledAccX) < LOW_TOL && abs(scaledAccY) < LOW_TOL && abs(scaledAccZ) > HIGH_TOL && scaledAccZ > 0)
        {
            drawArray(roundShape, colorList);
        }

        else if(abs(scaledAccX) < LOW_TOL && abs(scaledAccY) < LOW_TOL && abs(scaledAccZ) > HIGH_TOL && scaledAccZ < 0)
        {
            drawArray(circleWithX, colorList);
        }
        
        else if(abs(scaledAccX) < LOW_TOL && abs(scaledAccY) > HIGH_TOL && abs(scaledAccZ) < LOW_TOL && scaledAccY > 0)
        {
            drawArray(upArrow, colorList);
        }

        else if(abs(scaledAccX) < LOW_TOL && abs(scaledAccY) > HIGH_TOL && abs(scaledAccZ) < LOW_TOL && scaledAccY < 0)
        {
            drawArray(downArrow, colorList);
        }

        else if(abs(scaledAccX) > HIGH_TOL && abs(scaledAccY) < LOW_TOL && abs(scaledAccZ) < LOW_TOL && scaledAccX > 0)
        {
            drawArray(leftArrow, colorList);
        }

        else if(abs(scaledAccX) > HIGH_TOL && abs(scaledAccY) < LOW_TOL && abs(scaledAccZ) < LOW_TOL && scaledAccX < 0)
        {
            drawArray(rightArrow, colorList);
        }
        else
        {
            M5.dis.clear();
        }
    }

    delay(250);
    M5.update();
}


void drawArray(int arr[], int colors[])
{
    for(int i = 0; i < 25; i++)
    {
        M5.dis.drawpix(i, colors[arr[i]]);
    }
}


Detect a Shake and Roll a Die

The final project revisits the 6-sided die roller from a previous blog post. Again, to determine what constitutes a shake, experiment with the first the application in this post.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * AccelerometerTest03.ino
 * 
 * By: Mike Klepper
 * Date: 26 April 2020
 * 
 * Display a random integer between 1 and 6 inclusive when the 
 * M5 ATOM Matrix is shook
 */

#include "M5Atom.h"

int GRB_COLOR_WHITE = 0xffffff;
int GRB_COLOR_BLACK = 0x000000;
int GRB_COLOR_RED = 0x00ff00;
int GRB_COLOR_ORANGE = 0xa5ff00;
int GRB_COLOR_YELLOW = 0xffff00;
int GRB_COLOR_GREEN = 0xff0000;
int GRB_COLOR_BLUE = 0x0000ff;
int GRB_COLOR_PURPLE = 0x008080;

int activeColor = GRB_COLOR_RED;

int colorList[] = {GRB_COLOR_BLACK, activeColor};

int one[25] = 
{
    0,0,1,0,0,
    0,1,1,0,0,
    0,0,1,0,0,
    0,0,1,0,0,
    0,1,1,1,0
};

int two[25] = 
{
    0,1,1,1,0,
    0,0,0,0,1,
    0,0,1,1,0,
    0,1,0,0,0,
    0,1,1,1,1
};

int three[25] = 
{
    0,1,1,1,0,
    0,0,0,0,1,
    0,0,1,1,0,
    0,0,0,0,1,
    0,1,1,1,0
};

int four[25] = 
{
    0,0,0,1,0,
    0,1,0,1,0,
    0,1,1,1,1,
    0,0,0,1,0,
    0,0,0,1,0
};

int five[25] = 
{
    0,1,1,1,1,
    0,1,0,0,0,
    0,1,1,1,0,
    0,0,0,0,1,
    0,1,1,1,0
};

int six[25] = 
{
    0,0,1,1,0,
    0,1,0,0,0,
    0,1,1,1,0,
    0,1,0,0,1,
    0,0,1,1,0
};

int *displayNumbers[6] = { one, two, three, four, five, six };


float accX = 0, accY = 0, accZ = 0;

float accTolerance = 3;

bool IMU6886Flag = false;

void setup() 
{
    M5.begin(true, false, true);
    delay(20);
    
    IMU6886Flag = M5.IMU.Init() == 0;
  
    if(!IMU6886Flag)
    {
        Serial.println("Error initializing the IMU! :-(");
    }

    randomSeed(analogRead(0));
    
    showRandomNumber();
}

void loop() 
{
    if(IMU6886Flag)
    {
        while(1) 
        {
            M5.IMU.getAccelData(&accX, &accY, &accZ);
            
            if(abs(accX) > accTolerance || abs(accY) > accTolerance) 
            {
                break;
            }
        }
    
        Serial.println("Shake Detected!");
        M5.dis.clear();
        showRandomNumber();
        Serial.printf("Accel: %.2f, %.2f, %.2f \r\n", accX, accY, accZ);
    }

    delay(250);
    M5.update();
}

void showRandomNumber()
{
    int numberToShow = random(0, 6);
  
    Serial.println(numberToShow + 1);
  
    drawArray(displayNumbers[numberToShow], colorList);
}

void drawArray(int arr[], int colors[])
{
    for(int i = 0; i < 25; i++)
    {
        M5.dis.drawpix(i, colors[arr[i]]);
    }
}

Click here to go to the table of contents for this series.

No comments:

Post a Comment