-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathRollPitchYaw.ino
157 lines (128 loc) · 5.03 KB
/
RollPitchYaw.ino
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
/**
What is this file?
This is an arduino example that calculates accurate roll,pitch,yaw from raw gyro/accelerometer data
It has a calibration stage which removes most of the gyro drift and a complementary filter
that combines gyro and accelerometer angles to produce roll/pitch angles that don't drift (like the gyro angle) and aren't noisy
(like the accel angles). As there is no magnetic compass on the nano iot 33, it's not possible to 'complement' the yaw
- hence yaw will drift and is 'relative'.
*/
#include <Arduino_LSM6DS3.h>
#include <Wire.h>
float accelX, accelY, accelZ, // units m/s/s i.e. accelZ if often 9.8 (gravity)
gyroX, gyroY, gyroZ, // units dps (degrees per second)
gyroDriftX, gyroDriftY, gyroDriftZ, // units dps
gyroRoll, gyroPitch, gyroYaw, // units degrees (expect major drift)
gyroCorrectedRoll, gyroCorrectedPitch, gyroCorrectedYaw, // units degrees (expect minor drift)
accRoll, accPitch, accYaw, // units degrees (roll and pitch noisy, yaw not possible)
complementaryRoll, complementaryPitch, complementaryYaw; // units degrees (excellent roll, pitch, yaw minor drift)
long lastTime;
long lastInterval;
void setup() {
Serial.begin(1000000);
pinMode(LED_BUILTIN, OUTPUT);
// this sketch will wait until something connects to serial!
// this could be 'serial monitor', 'serial plotter' or 'processing.org P3D client' (see ./processing/RollPitchYaw3d.pde file)
while (!Serial);
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
calibrateIMU(250, 250);
lastTime = micros();
}
/*
the gyro's x,y,z values drift by a steady amount. if we measure this when arduino is still
we can correct the drift when doing real measurements later
*/
void calibrateIMU(int delayMillis, int calibrationMillis) {
int calibrationCount = 0;
delay(delayMillis); // to avoid shakes after pressing reset button
float sumX, sumY, sumZ;
int startTime = millis();
while (millis() < startTime + calibrationMillis) {
if (readIMU()) {
// in an ideal world gyroX/Y/Z == 0, anything higher or lower represents drift
sumX += gyroX;
sumY += gyroY;
sumZ += gyroZ;
calibrationCount++;
}
}
if (calibrationCount == 0) {
Serial.println("Failed to calibrate");
}
gyroDriftX = sumX / calibrationCount;
gyroDriftY = sumY / calibrationCount;
gyroDriftZ = sumZ / calibrationCount;
}
/**
Read accel and gyro data.
returns true if value is 'new' and false if IMU is returning old cached data
*/
bool readIMU() {
if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable() ) {
IMU.readAcceleration(accelX, accelY, accelZ);
IMU.readGyroscope(gyroX, gyroY, gyroZ);
return true;
}
return false;
}
// the loop function runs over and over again forever
void loop() {
if (readIMU()) {
long currentTime = micros();
lastInterval = currentTime - lastTime; // expecting this to be ~104Hz +- 4%
lastTime = currentTime;
doCalculations();
printCalculations();
}
}
/**
I'm expecting, over time, the Arduino_LSM6DS3.h will add functions to do most of this,
but as of 1.0.0 this was missing.
*/
void doCalculations() {
accRoll = atan2(accelY, accelZ) * 180 / M_PI;
accPitch = atan2(-accelX, sqrt(accelY * accelY + accelZ * accelZ)) * 180 / M_PI;
float lastFrequency = (float) 1000000.0 / lastInterval;
gyroRoll = gyroRoll + (gyroX / lastFrequency);
gyroPitch = gyroPitch + (gyroY / lastFrequency);
gyroYaw = gyroYaw + (gyroZ / lastFrequency);
gyroCorrectedRoll = gyroCorrectedRoll + ((gyroX - gyroDriftX) / lastFrequency);
gyroCorrectedPitch = gyroCorrectedPitch + ((gyroY - gyroDriftY) / lastFrequency);
gyroCorrectedYaw = gyroCorrectedYaw + ((gyroZ - gyroDriftZ) / lastFrequency);
complementaryRoll = complementaryRoll + ((gyroX - gyroDriftX) / lastFrequency);
complementaryPitch = complementaryPitch + ((gyroY - gyroDriftY) / lastFrequency);
complementaryYaw = complementaryYaw + ((gyroZ - gyroDriftZ) / lastFrequency);
complementaryRoll = 0.98 * complementaryRoll + 0.02 * accRoll;
complementaryPitch = 0.98 * complementaryPitch + 0.02 * accPitch;
}
/**
This comma separated format is best 'viewed' using 'serial plotter' or processing.org client (see ./processing/RollPitchYaw3d.pde example)
*/
void printCalculations() {
Serial.print(gyroRoll);
Serial.print(',');
Serial.print(gyroPitch);
Serial.print(',');
Serial.print(gyroYaw);
Serial.print(',');
Serial.print(gyroCorrectedRoll);
Serial.print(',');
Serial.print(gyroCorrectedPitch);
Serial.print(',');
Serial.print(gyroCorrectedYaw);
Serial.print(',');
Serial.print(accRoll);
Serial.print(',');
Serial.print(accPitch);
Serial.print(',');
Serial.print(accYaw);
Serial.print(',');
Serial.print(complementaryRoll);
Serial.print(',');
Serial.print(complementaryPitch);
Serial.print(',');
Serial.print(complementaryYaw);
Serial.println("");
}