-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathArdmin.ino
291 lines (230 loc) · 8.01 KB
/
Ardmin.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
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// Made by Lucas Oberwager, 10/5/2020
#include <Wire.h>
#include <NeoSWSerial.h>
#include <NMEAGPS.h>
#include <GPSport.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C
SSD1306AsciiWire oled;
// Use faster I2C library, if theres no memory left change this back.
#define OPTIMIZE_I2C 1
static NMEAGPS gps; // This parses received characters
static gps_fix fix;
NeoSWSerial ss(4, 3); // The serial connection to the GPS device
const int oledDisplayWidth = 128;
// Current lat + lng
float clat , clng;
// Previous lat + lng
// Plat needs to be initialized to 0.0 to check if it has been set yet
// As long as plat is initialized it would be redundant to initialize plng
float plat = 0.0, plng;
// Time since distance tracker has been updated
unsigned long previousMillis = 0;
// GPS distance tracker
// Updates every 10 seconds by counting distance from previous compared point to current location
float gpsDistance = 0;
// Current Speed
int cspd;
// Max Speed
int mspd = 0;
// Avg speed
float spdSum=0;
int spdSamples=1; // Fix divide by zero error
// Boolean to see if the ride is paused
bool paused = false;
// Boolean to see if the ride changed its paused state
bool deltaPaused;
unsigned long currentMillis;
unsigned long pausedMillis = 0;
unsigned long pauseTime;
void setup() {
Wire.begin();
Wire.setClock(400000L);
//Serial.begin(9600);
gpsPort.begin(9600);
oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(System5x7);
oled.clear();
oled.set2X();
//Serial.println("Starting...");
oledprint("Ardmin v2");
oled.set1X();
oledprint("By Lucas Oberwager");
oledprint("Booting up...");
oledprint("Searching for GPS...");
oled.set2X();
}
void loop() {
while (gps.available( gpsPort )) {
fix = gps.read();
currentMillis = millis();
if (!paused) {
// Go to 0,0 on the oled to override previous frame without clearing to save time
oled.home();
// Update current lat and lng
if (fix.valid.location) {
// Update current lat,lng
clat = fix.latitude();
clng = fix.latitude();
} else {
// Dont start ride until lat & lng fix is found
return;
}
// Code to run only on first loop
if (plat == 0) {
oled.clear();
plat = clat;
plng = clng;
// Print total distance travelled, which at start is just 0
oled.print(0.00);
}
// Update total distance
if (currentMillis - previousMillis >= 10000 || plat == 0) {
// Code to run every 10 seconds (10000 ms) or on first run
// Clear the top section of oled in case of unexpected bug
// BUG: sometimes speed overrides distance traveled
oled.clearToEOL();
gpsDistance += calc_dist(clat, clng, plat, plng);
// Save the last time coords were updated
previousMillis = currentMillis;
plat = clat;
plng = clng;
// Print total distance travelled
oled.print(String(gpsDistance, 2));
}
// Print current speed
if (fix.valid.speed) {
cspd = (int) round(fix.speed_mph());
if (cspd <= 1) {
// We are not moving/moving slowly; Pause!
paused = true;
deltaPaused = true;
}
if (cspd > mspd) {
// Set the new max speed
mspd = cspd;
}
// Avg speed calculator
spdSum += cspd;
spdSamples++;
// Set column to right align
// If cspd is zero, manually set length to 1, otherwise just take the log of cspd + 1
// 36 is pixel length of string "MPH"
oled.setCol(oledDisplayWidth-(oled.fieldWidth(cspd==0 ? 1 : (floor(log10(cspd)) + 1) ) + 36) );
oled.print(String(cspd) + "MPH");
} else {
// No speed data found! Cannot autopause.
// Set column to right align
// 36 is pixel length of string "N/A"
oled.setCol(oledDisplayWidth-36);
oled.print("N/A");
}
// Print elapsed ride time
// Center align and center horizontal
// 84 = oled.fieldWidth(7) // 7 = number of characters in time string
oled.setCursor((oledDisplayWidth-84)/2, 3);
// Convert uptime (ride time) to hours minutes seconds
oled.print(millistoHMS(millis()/1000));
// Print current time
// Center align and at last row
// 60 = oled.fieldWidth(5) // 5 = number of characters in time string
oled.setCursor((oledDisplayWidth-60)/2, 6);
static char str[5];
sprintf(str, "%02d:%02d", fix.dateTime.hours % 12 == 7 ? 12 : (fix.dateTime.hours + 5) % 12, fix.dateTime.minutes);
oled.print(str);
} else {
// Ride is paused
if (deltaPaused) {
// Ride paused this loop
// Record time when paused
pauseTime = millis();
oled.clear();
// Alert the ride was paused
oledprint("RIDE PAUSED");
// Set smaller font size to summarize
oled.set1X();
// Print max speed
oledprint("Max Spd: " + String(mspd) + "MPH");
// Print Avg speed
oledprint("Avg Spd: " + String(spdSum / spdSamples) + "MPH");
// Print total distance
oledprint("Distance: " + String(gpsDistance, 2) + "mi");
// Print Current time
static char str[20];
sprintf(str, "Current Time: %02d:%02d", fix.dateTime.hours % 12 == 7 ? 12 : (fix.dateTime.hours + 5) % 12, fix.dateTime.minutes);
oledprint(str);
// Print Total time
oledprint("Elapsed time: " + String(millistoHMS(currentMillis/1000)));
// Print moving time
oledprint("Riding time: " + String(millistoHMS((currentMillis-pausedMillis)/1000)));
deltaPaused = false;
} else {
// This ride has been paused for a while...
// Measure speed to see if we are moving
cspd = (int) round(fix.speed_mph());
Serial.println(fix.speed_mph());
if (cspd > 1) {
// We are moving!
deltaPaused = true;
paused = false;
// compare current time to when ride was paused
pausedMillis += currentMillis - pauseTime;
// reset font size
oled.set2X();
// clear the oled screen
oled.clear();
} else {
// Not moving, update times
oled.setRow(5);
// Print Current time
static char str[20];
sprintf(str, "Current Time: %02d:%02d", fix.dateTime.hours % 12 == 7 ? 12 : (fix.dateTime.hours + 5) % 12, fix.dateTime.minutes);
oledprint(str);
// Print Total time
oledprint("Elapsed time: " + String(millistoHMS(millis()/1000)));
}
}
}
}
}
float calc_dist(float flat1, float flon1, float flat2, float flon2) {
// Calculate distance from starting point using Haversine formula
//formula: a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
//c = 2 ⋅ atan2( √a, √(1−a) )
//d = R ⋅ c
//where φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km);
float dist=0;
float dist2=0;
float diflat=0;
float diflon=0;
// I've to split all the calculation in several steps. If i try to do it in a single line the arduino will explode.
diflat=radians(flat2-flat1);
flat1=radians(flat1);
flat2=radians(flat2);
diflon=radians((flon2)-(flon1));
dist = (sin(diflat/2.0)*sin(diflat/2.0));
dist2= cos(flat1);
dist2*=cos(flat2);
dist2*=sin(diflon/2.0);
dist2*=sin(diflon/2.0);
dist +=dist2;
dist=(2*atan2(sqrt(dist),sqrt(1.0-dist)));
// 3958.76571 is earths circumference in meters divided by 1609 to get miles
dist*=3958.76571; //Converting to miles
//Serial.println(dist_calc);
return dist;
}
char * millistoHMS(unsigned long t) {
static char str[12];
long h = t / 3600;
t = t % 3600;
int m = t / 60;
int s = t % 60;
sprintf(str, "%01ld:%02d:%02d", h, m, s);
return str;
}
void oledprint(char * str) {
oled.print(str);
oled.println();
}