-
Notifications
You must be signed in to change notification settings - Fork 2
/
datalogger.py
393 lines (291 loc) · 12.5 KB
/
datalogger.py
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# Racing car data logger for SenseHat equipped Raspberry Pi
# By David Edwards (Dedward5)
#
# Find the project on GitHUb at https://github.com/Dedward5/motorsportdatalogger
import time
from sense_hat import SenseHat # for core sensehat functions #import this first so we can use sense hat display
sense = SenseHat()
sense.show_letter("!",text_colour=[0, 0, 0], back_colour=[255,0,0]) # prints ! on the matrix to indicate "starting up"
time.sleep(5) # added to dealy load for warmup
####################################### Configuration and Settings ###############################
import configparser
configparser = configparser.RawConfigParser()
configparser.read("options.cfg")
pi_camera_installed = configparser.get('video_options', 'pi_camera')
pi_camera_vertical_flip = configparser.get('video_options', 'flip_pi_vertical')
pi_camera_horizontal_flip = configparser.get('video_options', 'flip_pi_horizontal')
do_overlay_sensedata = configparser.get('video_options', 'overlay_sense_data')
do_overlay_gpsdata = configparser.get('video_options', 'overlay_gps_data')
chosen_path = configparser.get('general_options', 'file_path')
usb_gps_installed = configparser.get('gps_options', 'usb_gps')
usb_mic_installed = configparser.get('video_options', 'usb_mic')
do_video_preview = configparser.get('video_options', 'video_preview')
launch_g = configparser.get('general_options', 'launch_threshold')
log_revs = configparser.get('general_options', 'rpm_input')
print ("Datalogger started")
print ("Configuration settings")
print ("Pi camera option = ",pi_camera_installed) # display the camera option setting on screen as a debug helper
print ("Pi camera vertical flip = ",pi_camera_vertical_flip) # display the camera option setting on screen as a debug he$
print ("Pi camera horizontal flip = ",pi_camera_horizontal_flip) # display the camera option setting on screen as a debug he$
print ("Overlay sense data on video = ",do_overlay_sensedata) # display the config option for video overlay of sense data
print ("Overlay GPS data on video = ",do_overlay_gpsdata) # display the config option for the video overlay of GPS data
print ("GPS installed = ",usb_gps_installed) # display the config option for the USB BPS
print ("USB Microphone = ", usb_mic_installed)
print ("Video Preview =", do_video_preview)
print ("Logs Revs =",log_revs)
print ("Launch Threshold =",launch_g)
FILENAME = ""
WRITE_FREQUENCY = 20
############################################ Libraries ############################################
import sys # revisit to see if needed
import os # used for the shutdown
# import time # used for time functions
from datetime import datetime # for date and time function
# Import and setup the camera if camera option set in config file
if pi_camera_installed == "yes":
try:
from picamera import PiCamera
camera = PiCamera()
if pi_camera_vertical_flip == "yes":
camera.vflip = True
if pi_camera_horizontal_flip == "yes":
camera.hflip = True
except:
pi_camera_installed = "no"
print ("Camera Error!")
sense.show_message("Camera Error!",scroll_speed=0.02, text_colour=[255,0,0], back_colour=[0,0,0])
# Import and setup the GPS if GPS option set in the config file
if usb_gps_installed == "yes":
try:
print("Installing GPS")
from gps3.agps3threaded import AGPS3mechanism
agps_thread = AGPS3mechanism() # Instantiate AGPS3 Mechanisms
agps_thread.stream_data() # From localhost (), or other hosts, by example, (host='gps.ddns.net')
agps_thread.run_thread() # Throttle time to sleep after an empty lookup, default '()' 0.2 two tenths of a second
except:
usb_gps_installed = "no"
print ("GPS Error, Check Connection!")
sense.show_message("GPS Error!",scroll_speed=0.02, text_colour=[255,0,0], back_colour=[0,0,0])
# import dependencies for Audio Recording
import subprocess
from decimal import *
#import the GPIO functions for RPM sensing
if log_revs == "yes":
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18,GPIO.IN) #set up pin 18 for input
global last_rpm
last_rpm = 600
############################################ Functions ############################################
def file_setup(filename): # setup the CSV headers using the right options for any add-ons like GPS
header =["runtime",
"accel_x","accel_y","accel_z",
"pitch","roll","yaw",
"mag_x","mag_y","mag_z",
"gyro_x","gyro_y","gyro_z",
"temp_h","temp_p","humidity","pressure"]
if log_revs == "yes":
header +=["rpm"]
if usb_gps_installed == "yes":
header += "alt","lat","lon","mps","mph","gpstime"
with open(filename,"w") as f:
f.write(",".join(str(value) for value in header)+ "\n")
def get_sense_data(): # Main function to get all the sense data
global sense_overlay_data
global moving
global launch_time
global run_time
sense_data=[]
log_time = time.time() - start_time
acc = sense.get_accelerometer_raw()
x = acc["x"]
y = acc["y"]
z = acc["z"]
o = sense.get_orientation()
yaw = o["yaw"]
pitch = o["pitch"]
roll = o["roll"]
mag = sense.get_compass_raw()
mag_x = mag["x"]
mag_y = mag["y"]
mag_z = mag["z"]
gyro = sense.get_gyroscope_raw()
gyro_x = gyro["x"]
gyro_y = gyro["y"]
gyro_z = gyro["z"]
# Magic timer: This starts a timer if the PI sees an accelleration over a value e.g. a launch.
# print(moving)
if moving == 1:
if y > 0.2: # check y accellerometer to see if you are launching
launch_time = time.time() # record the launch time
moving = 0 # set the variable to say you are launched in this logging session
run_time = 00.00
else:
run_time = 00.00 # if not launching you are stationary
else:
run_time = time.time() - launch_time # you must be launched so the timer is now - launch time
# now write the sense data to the list
sense_data.append(run_time)
sense_data.extend([x,y,z])
sense_data.extend([pitch,roll,yaw])
sense_data.extend([mag_x,mag_y,mag_z])
sense_data.extend([gyro_x,gyro_y,gyro_z])
sense_data.append(sense.get_temperature_from_humidity())
sense_data.append(sense.get_temperature_from_pressure())
sense_data.append(sense.get_humidity())
sense_data.append(sense.get_pressure())
sense_overlay_data ="Time " + '{: <5}'.format(str(round(run_time,2))) + " Acc-G " +'{: <5}'.format(str(round(y,2))) + " Lat-G " + '{: <5}'.format(str(round(x,2)))
# print(sense_overlay_data) # prints the overlay data on the screen, left to aid debugging if needed
return sense_data
def get_rpm_data ():
global rpm_overlay_data
global rpm_data
global last_rpm
GPIO.wait_for_edge(18, GPIO.RISING, timeout = 50)
first_pulse = time.time()
GPIO.wait_for_edge(18, GPIO.RISING, timeout = 50)
second_pulse = time.time()
pulse_gap = second_pulse - first_pulse
try:
rpm = 0.5 /pulse_gap
except:
# see if there is a devide by zero errror and just fudge the RPM
# this will make RPM = 600.
rpm = 10
rpm_data = int(rpm*60)
if rpm_data > 8000 :
rpm_data = last_rpm
last_rpm = rpm_data
rpm_overlay_data = " RPM " + '{: <4}'.format(str(rpm_data))
print (rpm_overlay_data) #for debugging, this prints the RPM data to the screen
return rpm_data
def get_gps_data (): # function that gets the GPS data
global gps_overlay_data
gps_data=[]
lat = format(agps_thread.data_stream.lat)
lon = format(agps_thread.data_stream.lon)
speed = format(agps_thread.data_stream.speed)
alt = format(agps_thread.data_stream.alt)
gpstime = format(agps_thread.data_stream.time)[0:19]
try:
mph = float(speed) * 2.23694
except:
mph=0
gps_data.extend([alt,lat,lon,speed,mph,gpstime])
gps_overlay_data = " MPH " + '{: <3}'.format(str(int(mph))) + " " + gpstime
print("GPS Data", gps_overlay_data) #prints the overlay data on the screen, left to aid debugging if need
return gps_data
def joystick_push(event): # if stick is pressed toggle logging state by switching "value"
global value
global running
global hold_wait
global start_time
start_time = time.time()
if event.action=='released':
# time.sleep(0.5) #wait half a second to reduce button bounce
hold_wait = 1 # Resets the wait counter for hold-to-shutdown
value = (1, 0)[value]
time.sleep(0.1) #wait half a second to reduce button bounce
if value == 1:
start_logging()
else:
stop_logging()
if event.action=='held':
print("Button is held")
sense.show_letter("H",text_colour=[0, 0, 0], back_colour=[255,181,7]) # prints H on the matrix to indicate held
hold_wait +=1
print(hold_wait)
if hold_wait == 50:
shutdown_pi()
def start_logging ():
print ("Logging started, press joystick button to stop")
global filename
global record_process
global moving
moving = 1
batch_data.clear()
gps_set_time = agps_thread.data_stream.time
if gps_set_time !="n/a":
os.system('date -s %s' % gps_set_time)
print ("System time set to GPS time of ",gps_set_time)
else:
print ("Could not set system time from GPS !")
sense.show_letter("L",text_colour=[0, 0, 0], back_colour=[0,255,0])
filename = "/media/usb/race_data_"+time.strftime("%Y%m%d-%H%M%S")+".csv"
file_setup(filename)
# if the camera is installed and works then start recording if not the say its not installed and carry on
if pi_camera_installed == "yes":
camera.start_recording("/media/usb/race_video_"+time.strftime("%Y%m%d-%H%M%S")+".h264") # starts the camera recording
if do_video_preview == "yes":
camera.start_preview(alpha=200) #shows camea on monior for debugging
try: #try to start recording
if usb_mic_installed == "yes":
arecord_cmd = "arecord -D plughw:1 -f cd /media/usb/race_audio"+time.strftime("%Y%m%d-%H%M%S")+".wav"
record_process = subprocess.Popen("exec " + arecord_cmd,stdout=subprocess.PIPE, shell=True)
except:
sense.show_message("Microphone Error!",text_colour=[255,0,0], back_colour=[0,0,0])
def log_data ():
global rpm_data
sense_output_string = ",".join(str(value) for value in sense_data)
gps_output_string = ",".join(str(value) for value in gps_data)
rpm_string = "," + str(rpm_data) + ","
output_string = sense_output_string + rpm_string + gps_output_string
batch_data.append(output_string)
print (output_string) #prints the video overlay data to the screen for debug/testing
def video_overlay ():
try:
if do_overlay_sensedata == "yes":
if do_overlay_gpsdata == "yes":
camera.annotate_text = sense_overlay_data+rpm_overlay_data+gps_overlay_data
else:
camera.annotate_text = sense_overlay_data
else:
print("Overlay disabled")
except:
print("Overlay error, is camera working?")
def stop_logging ():
print("Logging stopped, still ready") # prints to the main screen
batch_data.clear() #clear out any values in the list
sense.show_letter("R",text_colour=[0, 0, 0], back_colour=[255,181,7])
if pi_camera_installed == "yes":
camera.stop_recording() # stops the camera from recording
if do_video_preview == "yes":
camera.stop_preview()
if usb_mic_installed =="yes":
record_process.kill()
def shutdown_pi ():
print ("Shutting down the Pi") # displays this on the main screen
stop_logging()
sense.show_message("Shutting down the Pi", scroll_speed=0.02, text_colour=[255,255,255], back_colour=[0,0,0]) # show this text on the matrix
sense.clear() # blank the LED matrix
os.system('shutdown now -h') # call the OS command to shutdown
################################################ Main Program #####################################
print("Press Ctrl-C to quit")
global batch_data
global count
sense = SenseHat()
batch_data= [] # creates an empty list called batch_data
sense.clear() # blank the LED matrix
sense.show_letter("R",text_colour=[0, 0, 0], back_colour=[255,181,7]) # prints R on the matrix to indicate "Ready"
sense.stick.direction_middle = joystick_push #call the callback (function) joystick_push if pressed at any time including in a loop
value = 0
running = 1
hold_wait = 1
print("Ready, press sensehat jostick to start logging") # prints to the main screen
while running: # Loop around until CRTL-C keyboard interrupt
# print(".") prints to the main screen after "Ready" not the postion of the comma
# print("GPS time is",agps_thread.data_stream.time) #debug line to see if GPS has picked up the time
while value: # When we are logging
sense.show_letter("L",text_colour=[0, 0, 0], back_colour=[0,255,0])
sense_data = get_sense_data()
gps_data = get_gps_data()
rpm_data = get_rpm_data()
log_data()
video_overlay()
if len(batch_data) >= WRITE_FREQUENCY:
sense.show_letter("W",text_colour=[0, 0, 0], back_colour=[0,255,0])
print("Writing to file")
with open(filename,"a") as f:
for line in batch_data:
f.write(line + "\n")
batch_data = []