Yachtlogger


Using Raspberry Pi SenseHAT and GPS for logging

For my boat I have several instruments that are functional but aged. So an obvious solution would be to expand the pool with an RPi, but at the same time be able to bring the parts back home for programming off-season.

The Sense HAT is an all-inclusive add-on board to the Pi that can be included in a standard casing. As the board has a 8×8 LED matrix for read out and a joystick for control some mechanical modifications must be made to the font panel. Adafruit has a standard case with a clear lid where the parts can be easily fitted so holes have to be drilled on top of the joystick an temperature/pressure/humidity sensors.

One disadvantage with the sense HAT is that CPU heats up the interior so the thermometers will register 5-10 deg higher than they should. Be prepared to make some adjustments to the code but there are examples of good work done where the compensation is made on behalf of CPU-temperature as seen in this post.

Apart from this the Sense HAT and RPi3 is a compact combination of sensors with a simple readout that can be clearly seen in all lighting conditions. I have programmed my sequences so clicking joystick up will raise the color value with 50 steps for each click, starting at 50 (night time) moving up to 250 as a maximum (daylight).

Next challenge was to attach a GPS and the Adafruit Ultimate GPS was selected as it connects to the USB port via a standard TTL cable. The documentation using it miss out some important details if you want to use it together with other applications and make an automatic start every time the RPi boots. The solution is to make a .sh file (script) and refer to this in rc.local. The script file needs to be executable which you do with the CHMOD -X ../path command. In the script file you need to insert delays in order to configure the GPS before the program starts:

[pastacode lang=”python” manual=”%23!%2Fbin%2Fsh%20-e%0A%23Need%20to%20wait%20past%20boot%20so%20everything%20is%20done%0Asleep%2010%0Agpsd%20%2Fdev%2FttyUSB0%20-G%20-n%20-F%20%2Fvar%2Frun%2Fgpsd.sock%0Asleep%2010%0Asudo%20python%20%2Fhome%2Fpi%2FDesktop%2Ffilename.py%26amp%3B%0Aexit%200″ message=”” highlight=”” provider=”manual”/]

The & ensures that the program can run in loop after the script has been executed and the ttyUSB0 refers to the USB port where the GPS is attached.

Finally a little mahogany box was built and mounted on the wall in the cabin for keeping the RPi on board with the display clearly visible. The only thing to do when boarding is to mount the power and GPS cables before switching on the circuit on the panel. So the RPi can be easily detached again after the trip so log files can be read at home.

Link to a Google map with acquired coordinates for the summer trip 2017

This is how the components appear in the 12V installation

When docked and land power is connected the new 220V installation on board services charger and different ammenities:

 

CODE for the SenseHAT:

[pastacode lang=”python” manual=”import%20os%0Afrom%20sense_hat%20import%20SenseHat%0Aimport%20time%0Afrom%20time%20import%20*%0Afrom%20time%20import%20sleep%0Afrom%20datetime%20import%20datetime%2C%20timedelta%0Aimport%20gps%0Afrom%20gps%20import%20*%0Aimport%20threading%0A%20%0A%22%22%22%0AMAIA%20yachting%20sensor%20system%0A%22%22%22%0A%20%0Asense%20%3D%20SenseHat()%0Acount%20%3D%200%0Asense.compass_enabled%3DTrue%0Ajmin%3D1%0Ajmax%3D7%0Aj%3DNone%0ASCSP%3D0.08%20%23Scroll_speed%0Acompass%3D0%20%23Define%20variables%20so%20they%20can%20be%20used%20outside%20def’s%0A%20%0Alogfile_created%3DFalse%20%23Creating%20new%20CSV%20for%20each%20time%20system%20is%20booted%20and%20GPS%20UTC%20time%20has%20been%20found%20%0AGPStime_updated%3DFalse%0Alogname%3DNone%0Aheader%3DNone%0Aheader%20%3D%5B%22UTC%20tid%22%2C%22System%20tid%22%2C%22Hastighed%22%2C%22Kurs%22%2C%22Bredde%22%2C%22Laengde%22%2C%0A%20%20%20%20%20%20%20%20%20%22Temperatur%20(fugt)%22%2C%22Temperatur%20(tryk)%22%2C%22Barometer%22%2C%22Baro%20delta%22%2C%22Fugtighed%22%2C%0A%20%20%20%20%20%20%20%20%20%22Gyro%20pitch%22%2C%22Gyro%20roll%22%2C%22Gyro%20yaw%22%2C%22Mag%20X%22%2C%22Mag%20Y%22%2C%22Mag%20Z%22%2C%22Compass%22%5D%0A%20%0AUTC%3DNone%0A%20%0A%23global%20counter%20used%20for%20waiting%20for%20GPS.%20Will%20make%20undated%20logfile%20if%20not%20connected%20within%2010%20minutes%3F%0Acounter%3D1%0Await_for_GPS%3DTrue%20%23Wait%2010%20min%20after%20boot%20then%20make%20alternative%20CSV%20if%20no%20connection.%0Await_for_min%3DTrue%20%23%20Wait%20until%20current%20Min%20is%20equal%20to%20min%20at%20boot%20time%0A%20%0A%23Time%0Amin_boot%20%3D%20str(time.strftime%20(%22%25M%22))%20%23Minute%20at%20boot%0Amin_count%3DNone%20%23Minutes%20counting%200-9%0Amin_last%3DNone%20%23Value%20last%20time%20minute%20was%20registered%0Amin_prev%3DNone%20%23Value%20previous%20minute%0Aweb_update%3DTrue%20%23For%20controlling%20updates%20of%20website%20data%0A%20%0A%23Rotation%0Arot%3D180%0Asense.set_rotation(rot)%20%23So%20power%20cable%20is%20upwards%0A%20%0A%23Pressure%0Aplast%3D1999%20%23default%20value%20for%20last%20pressure%20reading%2010%20mins%20ago%0Aplast_read%3DTrue%20%23Determines%20if%20last%20pressure%20(plast)%20should%20be%20opened%20for%20reading%0Apress_rising%3DTrue%20%23If%20good%20weather%20is%20on%20its%20way%20(pressure%20is%20rising)%0Apress_diff%3DNone%20%23For%20showing%20movements%20in%20pressure%20the%20web%20page%0A%20%0A%23%20GPS%20commands%0Agpsd%20%3D%20None%20%23seting%20the%20global%20variable%0ATIMEZ%20%3D%202%20%23Offsetting%20GPS%20UTC%20time%20to%20local%20timezone%201%3Dwinther%3B%202%3Dsummer%0A%20%0A%23Something%20with%20colors%0ATXBR%3D50%20%23Text%20brightness%0ATXCO%3D%5BTXBR%2C%20TXBR%2C%20TXBR%5D%20%23Scroll%20text%20default%20color%20white%0AR%20%3D%20(255%2C%200%2C%200)%0AG%20%3D%20(0%2C%20255%2C%200)%0AB%20%3D%20(0%2C%200%2C%20255)%0AY%20%3D%20(0%2C%20255%2C%20255)%0AM%20%3D%20(255%2C%20255%2C%200)%0AC%20%3D%20(255%2C%200%2C%20255)%0AO%20%3D%20(0%2C%200%2C%200)%0A%20%0Amaya_logo%20%3D%20%5B%0AR%2C%20O%2C%20R%2C%20O%2C%20O%2C%20O%2C%20B%2C%20O%2C%0AR%2C%20R%2C%20R%2C%20O%2C%20O%2C%20B%2C%20B%2C%20B%2C%0AR%2C%20O%2C%20R%2C%20O%2C%20O%2C%20B%2C%20O%2C%20B%2C%0AR%2C%20O%2C%20R%2C%20O%2C%20O%2C%20B%2C%20O%2C%20B%2C%0AO%2C%20Y%2C%20O%2C%20O%2C%20O%2C%20O%2C%20G%2C%20O%2C%0AO%2C%20Y%2C%20O%2C%20O%2C%20O%2C%20G%2C%20G%2C%20G%2C%0AO%2C%20Y%2C%20O%2C%20O%2C%20O%2C%20G%2C%20O%2C%20G%2C%0AO%2C%20Y%2C%20O%2C%20O%2C%20O%2C%20G%2C%20O%2C%20G%2C%0A%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0Aclass%20GpsPoller(threading.Thread)%3A%0A%20%20def%20__init__(self)%3A%0A%20%20%20%20threading.Thread.__init__(self)%0A%20%20%20%20global%20gpsd%20%23bring%20it%20in%20scope%0A%20%20%20%20gpsd%20%3D%20gps(mode%3DWATCH_ENABLE)%20%23starting%20the%20stream%20of%20info%0A%20%20%20%20self.current_value%20%3D%20None%0A%20%20%20%20self.running%20%3D%20True%20%23setting%20the%20thread%20running%20to%20true%0A%20%20%0A%20%20def%20run(self)%3A%0A%20%20%20%20global%20gpsd%0A%20%20%20%20while%20gpsp.running%3A%0A%20%20%20%20%20%20gpsd.next()%20%23this%20will%20continue%20to%20loop%20and%20grab%20EACH%20set%20of%20gpsd%20info%20to%20clear%20the%20buffer%0A%20%0Adef%20Counter()%3A%0A%20%20%20%20global%20counter%0A%20%20%20%20counter%3Dcounter%2B1%0A%23%20%20%20%20print%20counter%0A%23%20%20%20%20sleep%20(1)%0A%20%0Adef%20Compass()%3A%0A%20%20%23sense.show_message(%22Compass%20%25s%20%22%20%25%20%22%7B%3A.0f%7D%22.format(compass)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22Kompas%20%25s%20%22%20%25%20compass%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20print%20%22Kompasset%20viser%22%2C%20compass%0A%20%0Adef%20DateAndTime()%3A%0A%20%20timenow%3Dstr(datetime.now())%0A%20%20timenow_formatted%20%3D%20%22%7B%3A.16%7D%22.format(timenow)%0A%20%20sense.show_message(timenow_formatted%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20%0Adef%20GPSdata()%3A%0A%20%20global%20TXCO%0A%20%20sense.show_message(%22Br%20%25s%20%22%20%25%20%22%7B%3A.6%7D%22.format(lati)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22Lgd%20%25s%20%22%20%25%20%22%7B%3A.6%7D%22.format(longi)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%23%20%20fart%3Dgpsspeed%20%2F%201.852%20%23speed%20in%20knots%0A%20%20sense.show_message(%22Fart%20%25s%20knob%22%20%25%20gpsspeed%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22Kurs%20%25s%20%22%20%25%20kurs%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20Graphics()%3A%0A%20%20v%3DNone%20%23Variable%2C%20pos%201%0A%20%20n%3DNone%20%23Min%20in%20range%2C%20pos%202%0A%20%20a%3DNone%20%23Max%20in%20range%2C%20pos%203%0A%20%20l%3DNone%20%23Color%20of%20bar%2C%20pos%205%0A%20%20d%3DNone%20%23Delta%20-%20difference%20between%20min%20and%20max%20(a-n)%0A%20%20i%3DNone%20%23Difference%20between%20reading%20and%20minimum%20value%20(v-n)%0A%20%20c%3DNone%20%23Compare%3A%20diff%20versus%20delta%20(d-i)%0A%20%0A%23%20%20for%20i%20in%20range%20(8)%3A%0A%20%0A%20%20for%20x%20in%20range%20(8)%3A%0A%20%20%20%20%20%20for%20y%20in%20range%20(8)%3A%0A%20%20%20%20%20%20%20%20v%3Dfloat(var_range%5Bx%5D%5B1%5D)%20%23Read%20variable%20current%20value%0A%20%20%20%20%20%20%20%20n%3Dfloat(var_range%5Bx%5D%5B2%5D)%20%23Read%20Minimum%20in%20range%0A%20%20%20%20%20%20%20%20a%3Dfloat(var_range%5Bx%5D%5B3%5D)%20%23Read%20Maximum%20in%20range%0A%20%20%20%20%20%20%20%20l%3D(var_range%5Bx%5D%5B5%5D)%20%23Read%20color%0A%20%20%20%20%20%20%20%20d%3Da-n%0A%20%20%20%20%20%20%20%20i%3Dv-n%0A%20%20%20%20%20%20%20%20c%3D8*i%2Fd%0A%20%20%20%20%20%20%20%20if%20y%20%3C%20c%3A%0A%20%20%20%20%20%20%20%20%20%20l%3Dl%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20l%3DO%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20sense.set_pixel(x%2C%20y%2C%20l)%0A%20%20time.sleep(1)%0A%20%0Adef%20Gyroscope()%3A%0A%20%20sense.show_message(%22Pitch%20%25s%20uT%22%20%25%20%22%7B%3A.0%7D%22.format(pit)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22Roll%20%25s%20uT%22%20%25%20%22%7B%3A.0%7D%22.format(rol)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22Yaw%20%25s%20uT%22%20%25%20%22%7B%3A.0%7D%22.format(yaw)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20Humidity()%3A%0A%20%20sense.show_message(%22Fugt%20%25s%20pct%22%20%25%20%22%7B%3A.0f%7D%22.format(humi)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20log_create(timestamp)%3A%0A%20%20%20%20global%20logname%0A%20%20%23Creating%20new%20file%20after%20GPS%20time%20is%20received%20and%20inserting%20header%0A%20%20%20%20logname%3Dstr(‘%2Fhome%2Fpi%2FDesktop%2Fcsv%2F’%20%2B%20timestamp%20%2B%20′.csv’)%0A%20%20%20%20with%20open(logname%2C%22w%22)%20as%20f%3A%0A%20%20%20%20%20%20%20%20f.write(%22%2C%22.join(str(value)%20for%20value%20in%20header)%2B%20%22%5Cn%22)%0A%20%20%20%20print%20%22New%20log%20created%3A%20%22%20%2B%20logname%0A%20%0Adef%20log_update()%3A%0A%20%20global%20UTC%0A%20%20with%20open(logname%2C%22a%22)%20as%20f%3A%0A%20%20%20%20f.write(%22%2C%22.join(str(value)%20for%20value%20in%20log_data)%2B%20%22%5Cn%22)%0A%20%20%23write%20the%20file%20for%20use%20at%20the%20web%20server%0A%20%0Adef%20log_website()%3A%0A%20%20l%20%3D%20open(‘%2Fhome%2Fpi%2FDesktop%2Fcsv%2Flognow.csv’%2C%20’w’)%0A%20%20for%20i%20in%20range(len(header))%3A%20%23Order%20data%20vertically%0A%20%20%20%20%20%20l.write(str(header%5Bi%5D)%2B%20%22%2C%22%20%2B%20str(log_data%5Bi%5D)%20%2B%20%22%5Cn%22)%0A%23%20%20l.write(str(header)%20%2B%20%22%5Cn%22%20%2B%20str(log_data))%0A%20%20l.close()%0A%20%0Adef%20Magnetic()%3A%0A%20%20sense.show_message(%22MagneticX%20%25s%20gr%22%20%25%20%22%7B%3A.0f%7D%22.format(magX)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22MagneticY%20%25s%20gr%22%20%25%20%22%7B%3A.0f%7D%22.format(magY)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%20sense.show_message(%22MagneticZ%20%25s%20gr%22%20%25%20%22%7B%3A.0f%7D%22.format(magZ)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20Message(besked)%3A%0A%20%20sense.show_message(besked%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20Orientation()%3A%0A%20%20sense.show_message(%22p%3A%20%7Bpitch%7D%2C%20r%3A%20%7Broll%7D%2C%20y%3A%20%7Byaw%7D%22.format(**orien)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20Pressure()%3A%0A%20%20if%20press_rising%3D%3DFalse%3A%0A%20%20%20%20sense.show_message(%22Tryk%20%25s%20mb%22%20%25%20%22%7B%3A.0f%7D%22.format(press)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3D%5BTXBR%2C%200%2C%200%5D)%20%20%20%20%0A%20%20else%3A%0A%20%20%20%20sense.show_message(%22Tryk%20%25s%20mb%22%20%25%20%22%7B%3A.0f%7D%22.format(press)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20Temperature()%3A%0A%20%20sense.show_message(%22Temp%20%25s%20gr.%22%20%25%20%22%7B%3A.0f%7D%22.format(temph)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%23%20%20sense.show_message(%22TempP%20%25s%20gr.C%22%20%25%20%22%7B%3A.0f%7D%22.format(tempp)%2C%20scroll_speed%3DSCSP%2C%20text_colour%3DTXCO)%0A%20%0Adef%20var_read(var)%3A%20%23For%20reading%20single%20variables%20that%20are%20stored%20for%20later%20comparison%0A%20%20try%3A%0A%20%20%20%20t%20%3D%20open(‘%2Fhome%2Fpi%2FDesktop%2Fvar%2F’%20%2B%20str(var)%20%2B%20′.txt’%2C%20’r’)%0A%20%20%20%20return%20float(t.read())%0A%20%20%20%20t.close()%0A%20%20except%3A%0A%20%20%20%20Message(%20%22%20File%20read%20problem%20%22)%0A%20%0Adef%20var_write(varname%2C%20value)%3A%20%23For%20storing%20single%20variables%20for%20later%20comparison%0A%20%20try%3A%0A%20%20%20%20t%20%3D%20open(‘%2Fhome%2Fpi%2FDesktop%2Fvar%2F’%20%2B%20str(varname)%20%2B%20′.txt’%2C%20’w’)%0A%20%20%20%20t.write%20(str(value))%0A%20%20%20%20t.close()%0A%20%20except%3A%0A%20%20%20%20Message%20(%22File%20write%20problem%20%22)%0A%20%0A%23%23%23%23%23%23%23%23%23%23%20%20START%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20%20%0Aj%20%3D%20var_read(%22joystick%22)%20%23read%20joystick%20position%20before%20last%20shutdown%0Aprint%20%22Datetime%3A%22%2C%20datetime.now()%0Aprint%20%22Loop%20sequence%20starting%22%0A%20%0Asense.set_pixels(maya_logo)%0Atime.sleep(2)%0Afor%20x%20in%20range%20(8)%3A%0A%20%20%20%20for%20y%20in%20range%20(8)%3A%0A%20%20%20%20%20%20sense.set_pixel(x%2C%20y%2C%20O)%0A%20%0A%23sense.low_light%20%3D%20True%0A%20%0Aif%20__name__%20%3D%3D%20’__main__’%3A%0A%20%20%20%20gpsp%20%3D%20GpsPoller()%20%23%20create%20the%20thread%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20gpsp.start()%20%23%20start%20it%20up%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20b%3Dthreading.Thread(target%3DCounter)%0A%20%20%20%20%20%20%20%20%20%20%20%20b.start()%0A%20%20%20%20%20%20%20%20%20%20%20%20temph%20%3D%20sense.get_temperature_from_humidity()%0A%20%20%20%20%20%20%20%20%20%20%20%20tempp%20%3D%20sense.get_temperature_from_pressure()%0A%20%20%20%20%20%20%20%20%20%20%20%20press%20%3D%20sense.get_pressure()%0A%20%20%20%20%20%20%20%20%20%20%20%20humi%20%3D%20sense.get_humidity()%0A%20%20%20%20%20%20%20%20%20%20%20%20lati%3Dstr(%22%7B%3A.7%7D%22.format(gpsd.fix.latitude))%0A%20%20%20%20%20%20%20%20%20%20%20%20longi%3Dstr(%22%7B%3A.7%7D%22.format(gpsd.fix.longitude))%0A%20%20%20%20%20%20%20%20%20%20%20%20gpstime%3Dgpsd.utc%0A%20%20%20%20%20%20%20%20%20%20%20%20gpsspeed%3Dstr(%22%7B%3A3.1f%7D%22.format(gpsd.fix.speed%20*%203.6%20%2F%201.852))%20%23set%20to%20knots%20instead%20of%20m%2Fs%20%0A%20%20%20%20%20%20%20%20%20%20%20%20kurs%3Dstr(%22%7B%3A3.0f%7D%22.format(gpsd.fix.track))%0A%20%20%20%20%20%20%20%20%20%20%20%20gyro%20%3D%20sense.get_gyroscope()%0A%20%20%20%20%20%20%20%20%20%20%20%20pit%20%3D%20%22%7Bpitch%7D%22.format(**gyro)%0A%20%20%20%20%20%20%20%20%20%20%20%20rol%20%3D%20%22%7Broll%7D%22.format(**gyro)%0A%20%20%20%20%20%20%20%20%20%20%20%20yaw%20%3D%20%22%7Byaw%7D%22.format(**gyro)%0A%20%20%20%20%20%20%20%20%20%20%20%20mag%20%3D%20sense.get_compass_raw()%0A%20%20%20%20%20%20%20%20%20%20%20%20magX%20%3D%20mag%5B%22x%22%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20magY%20%3D%20mag%5B%22y%22%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20magZ%20%3D%20mag%5B%22z%22%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20orien%20%3D%20sense.get_orientation_degrees()%0A%20%20%20%20%20%20%20%20%20%20%20%20comp%20%3D%20sense.get_compass()%0A%20%20%20%20%20%20%20%20%20%20%20%20compass%3Dstr(%22%7B%3A3.0f%7D%22.format(comp))%0A%20%20%20%20%20%20%20%20%20%20%20%20tnow%3Dstr(datetime.now())%0A%20%20%20%20%20%20%20%20%20%20%20%20timenow%20%3D%20%22%7B%3A.19%7D%22.format(tnow)%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20log_data%20%3D%20%5BUTC%2C%20timenow%2Cgpsspeed%2C%20kurs%2C%20lati%2C%20longi%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20temph%2C%20tempp%2C%20press%2C%20press_diff%2C%20humi%2C%20pit%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rol%2C%20yaw%2C%20magX%2C%20magY%2C%20magZ%2C%20compass%5D%0A%20%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%23Array%20setting%20the%20data%20range%20and%20color%20for%20each%20sensor%3A%20Name%2C%20Var%2C%20Min%2C%20Max%2C%20Column%2C%20Color%0A%20%20%20%20%20%20%20%20%20%20%20%20var_range%20%3D%20%5B%22Pressure%22%2C%20press%2C%20%22960%22%2C%20%221080%22%2C%20%220%22%2C%20R%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Temperature%22%2C%20temph%2C%20%220%22%2C%20%2240%22%2C%20%221%22%2C%20G%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Heading%22%2C%20kurs%2C%20%220%22%2C%20%22360%22%2C%20%222%22%2C%20B%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Speed%22%2C%20gpsspeed%2C%20%220%22%2C%20%2210%22%2C%20%223%22%2C%20Y%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Pitch%22%2C%20pit%2C%20%220%22%2C%20%22360%22%2C%20%224%22%2C%20M%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Roll%22%2C%20rol%2C%20%220%22%2C%20%22360%22%2C%20%225%22%2C%20C%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Yaw%22%2C%20yaw%2C%20%220%22%2C%20%22360%22%2C%20%226%22%2C%20G%5D%2C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22Compass%22%2C%20comp%2C%20%220%22%2C%20%22360%22%2C%20%227%22%2C%20B%5D%2C%5C%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Wait%20for%20the%20UTC%20time%20from%20GPS%0A%20%20%20%20%20%20%20%20%20%20%20%20%23if%20counter%3C40%3A%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20gpstime%20!%3D%20None%20and%20gpstime%20!%3D%20”%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20GPStime_updated%3D%3DFalse%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23Update%20system%20time%20with%20GPS%20time%20and%20create%20new%20logfile%20with%20timestamp%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20%22GPS%20UTC%20time%3A%22%2C%20gpstime%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20UTC%20%3D%20gpstime%5B0%3A4%5D%20%2B%20gpstime%5B5%3A7%5D%20%2B%20gpstime%5B8%3A10%5D%20%2B%20’%20’%20%2B%20gpstime%5B11%3A13%5D%20%2B%20gpstime%5B13%3A19%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tzhour%20%3D%20int(gpsd.utc%5B11%3A13%5D)%2BTIMEZ%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(tzhour%3E23)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tzhour%20%3D%20(int(gpstime%5B11%3A13%5D)%2BTIMEZ)-24%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20%22TZhour%3A%22%2C%20tzhour%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20%22Datetime%3A%22%2C%20datetime.now()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20utctime_converted%20%3D%20gpstime%5B0%3A4%5D%20%2B%20gpstime%5B5%3A7%5D%20%2B%20gpstime%5B8%3A10%5D%20%2B%20’%20’%20%2B%20str(tzhour)%20%2B%20gpstime%5B13%3A19%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20%22GPS%20time%20corrected%22%2C%20utctime_converted%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’Setting%20system%20time%20to%20local%20time…’%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20os.system(‘sudo%20date%20–set%3D%22%25s%22’%20%25%20utctime_converted)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20%22New%20System%20time%22%2C%20datetime.now()%20%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20GPStime_updated%3DTrue%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23Create%20new%20logfile%20when%20time%20is%20updated%20and%20converted%20(only%20once%20per%20session)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20logfile_created%3D%3DFalse%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20timenow%20%3D%20str(utctime_converted)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log_create(timenow)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logfile_created%3DTrue%0A%23%20%20%20%20%20%20%20%20%20%20%20%20else%3A%20%20%20%20%20%20%20%20%20%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20logfile_created%3D%3DFalse%3A%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20timenow%3Dstr(datetime.now())%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20newlogname%20%3D%20str(%22no%20GPS%20%22%20%2B%20timenow)%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log_create%20(newlogname)%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logfile_created%3DTrue%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%23Controlling%20scroll%20colors%20depending%20on%20status%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20GPStime_updated%3D%3DTrue%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXCO%3D%5B0%2C%200%2C%20TXBR%5D%20%23Scroll%20text%20color%20to%20blue%20and%20check%20for%20changes%20in%20lumination%20%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20logfile_created%3D%3DTrue%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXCO%3D%5BTXBR%2C%200%2C%20TXBR%5D%20%23Scroll%20text%20color%20green%20until%20GPS%20is%20working%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXCO%3D%5BTXBR%2C%20TXBR%2C%200%5D%20%23set%20text%20color%20to%20yellow%20until%20a%20new%20logfile%20has%20been%20created%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20hour_count%20%3D%20str(time.strftime%20(%22%25H%22))%20%23Updating%20hours%0A%20%20%20%20%20%20%20%20%20%20%20%20min_count%20%3D%20str(time.strftime%20(%22%25M%22))%23%20Updating%20minutes%20for%20triggering%20saving%20of%20data%20-%20especially%20%22pressure%22%0A%20%20%20%20%20%20%20%20%20%20%20%20sec_count%20%3D%20str(time.strftime%20(%22%25S%22))%20%23Updating%20seconds%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20min_last!%3Dmin_count%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20min_prev%3Dmin_last%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20logfile_created%3D%3DTrue%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log_update()%20%23updating%20the%20CSV%20log%20every%20minute%20with%20all%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20min_last%3Dmin_count%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%23TXCO%3D%5B0%2C%200%2C%20TXBR%5D%20%23Scroll%20text%20color%0A%20%0A%20%20%20%20%20%20%20%20%23Check%20if%20pressure%20is%20going%20down%20or%20up%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20min_count%5B-1%3A%5D%20%3D%3D%20%225%22%3A%20%23Look%20up%2C%20Update%20and%20save%20Pressure%20every%2010%20minutes%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20plast_read%20%3D%3D%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20plast%20%3D%20var_read(%22pressure%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20press_diff%20%3D%20press%20-%20plast%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20press%20%3E%20plast%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20press_rising%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20press_rising%20%3D%20False%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var_write(%22pressure%22%2C%20press)%20%23saves%20new%20value%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20plast_read%20%3D%3D%20False%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20min_count%5B-1%3A%5D%20%3D%3D%20%220%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20plast_read%20%3D%20True%20%23End%20every%2010%20min%20cycle%20with%20reset%20of%20all%20reading%20variables%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%23if%20sec_count%5B-1%3A%5D%20%3D%3D%20%227%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%20%20%20if%20web_update%20%3D%3D%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20log_website()%20%23Update%20CSV%20file%20for%20website%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%20%20%20%20%20%20%20web_update%20%3D%3D%20False%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20sec_count%5B-1%3A%5D%20%3D%3D%20%220%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20web_update%20%3D%20True%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20events%20%3D%20sense.stick.get_events()%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20event%20in%20events%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20event.action%20!%3D%20%22released%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20event.direction%20%3D%3D%20%22right%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3Djmin%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20j%3Djmax%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20j%3Dj-1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var_write(%22joystick%22%2C%20j)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20elif%20event.direction%20%3D%3D%20%22left%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3Djmax%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20j%3Djmin%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20j%3Dj%2B1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var_write(%22joystick%22%2C%20j)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20elif%20event.direction%20%3D%3D%20%22down%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(TXBR%20%3C%20201)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXBR%3DTXBR%2B50%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXBR%3DTXBR%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20elif%20event.direction%20%3D%3D%20%22up%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(TXBR%20%3E%2099)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXBR%3DTXBR-50%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TXBR%3DTXBR%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20elif%20event.direction%20%3D%3D%20%22middle%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Message%20(%22God%20tur%20%3A-)%22)%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D1%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Message(%22MAIA%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DateAndTime()%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Temperature()%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Pressure()%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Humidity()%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20GPSdata()%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Graphics()%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Compass()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20GPSdata()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D3%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Pressure()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D4%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Humidity()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D5%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Temperature()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D6%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DateAndTime()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D7%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Graphics()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D8%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Compass()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D9%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Gyroscope()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D10%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Magnetic()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%3D%3D19%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Orientation()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20”’%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20os.system(‘clear’)%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’%20GPS%20reading’%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20′—————————————-‘%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’latitude%20%20%20%20’%20%2C%20gpsd.fix.latitude%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’longitude%20%20%20’%20%2C%20gpsd.fix.longitude%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’time%20utc%20%20%20%20’%20%2C%20gpsd.utc%2C’%20%2B%20’%2C%20gpsd.fix.time%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’altitude%20(m)’%20%2C%20gpsd.fix.altitude%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’eps%20%20%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.eps%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’epx%20%20%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.epx%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’epv%20%20%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.epv%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’ept%20%20%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.ept%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’speed%20(m%2Fs)%20’%20%2C%20gpsd.fix.speed%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’climb%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.climb%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’track%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.track%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’mode%20%20%20%20%20%20%20%20’%20%2C%20gpsd.fix.mode%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20’sats%20%20%20%20%20%20%20%20’%20%2C%20gpsd.satellites%0A%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20time.sleep(5)%20%23set%20to%20whatever%0A%20%20%20%20%20%20%20%20”’%0A%20%20%20%20except%20(KeyboardInterrupt%2C%20SystemExit)%3A%20%23when%20you%20press%20ctrl%2Bc%0A%20%20%20%20%20%20%20%20print%20%22%5CnKilling%20Thread…%22%0A%20%20%20%20%20%20%20%20gpsp.running%20%3D%20False%0A%20%20%20%20%20%20%20%20gpsp.join()%20%23%20wait%20for%20the%20thread%20to%20finish%20what%20it’s%20doing%0A%20%20%20%20print%20%22Done.%5CnExiting.%22%0A%20%0A%20%20%20%20time.sleep(1)” message=”” highlight=”” provider=”manual”/]