diff --git a/tx/shssp.py b/tx/shssp2017.py similarity index 100% rename from tx/shssp.py rename to tx/shssp2017.py diff --git a/tx/shssp2018.py b/tx/shssp2018.py new file mode 100644 index 0000000..06da3be --- /dev/null +++ b/tx/shssp2018.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +# +# SHSSP Payload Main Loop - 2018 Version +# +# Requires: +# - PiCamera +# - uBlox GPS Unit, available at /dev/ublox +# - Bosch BNO055 Absolute Orientation Sensor, available at /dev/bno +# - Wenet TX Shield, available on /dev/ttyAMA0 +# +# Mark Jessop +# + +import PacketTX +import WenetPiCam +import ublox +import json +import argparse +import time +import traceback +import datetime +import os +from BNO055 import WenetBNO055 +from threading import Thread + +# Payload Callsigns +global_callsign = "SHSSP1" + +# Image capture directory +image_dir = "./tx_images/" + +# Log files. +text_telemetry_log = "ssp1_text.log" +bno_log = "ssp1_bno.log" +gps_log = "ssp1_gps.log" + +# Start up Wenet TX Object. +tx = PacketTX.PacketTX(serial_port='/dev/ttyAMA0', serial_baud=115200, callsign=global_callsign) +tx.start_tx() + +# Sleep for a second to let the transmitter fire up. +time.sleep(1) + + +# Initiaise BNO055. +# This will loop until it has connected to a BNO055. +bno = WenetBNO055(port='/dev/bno', + update_rate_hz = 5, + debug_ptr = tx.transmit_text_message, + log_file=bno_log) + +# Global variable to record if the GPS is giving valid time data. +# As the GPS can go back to a fix state of 0, yet still give valid time data (for our purposes anyway), +# We latch this variable to True as soon as we see any valid fix state. +gps_time_fix = False + +def handle_gps_data(gps_data): + """ Handle GPS data passed to us from a UBloxGPS instance """ + global tx, bno, gps_time_fix + + # Latch gps_time_fix if Fix is OK. + if gps_data['gpsFix'] > 0: + gps_time_fix = True + + # Grab a snapshot of orientation data. + orientation_data = bno.read_state() + + # Immediately generate and transmit a GPS packet. + tx.transmit_gps_telemetry(gps_data) + + # Now transmit an orientation telemetry packet. + tx.transmit_orientation_telemetry(gps_data['week'], gps_data['iTOW'], gps_data['leapS'], orientation_data) + + +# Try and start up the GPS rx thread. +# Note: The UBloxGPS constructor will continuously loop until it finds a GPS unit to connect to. +try: + gps = ublox.UBloxGPS(port='/dev/ublox', + dynamic_model = ublox.DYNAMIC_MODEL_AIRBORNE1G, + update_rate_ms = 1000, + debug_ptr = tx.transmit_text_message, + callback = handle_gps_data, + log_file = gps_log + ) +except Exception as e: + tx.transmit_text_message("ERROR: Could not Open GPS - %s" % str(e), repeats=5) + gps = None + +# Initialise the Camera Objects. + +# Initialise PiCam, using default capture and transmit resolution. +picam = WenetPiCam.WenetPiCam(callsign=global_callsign, + num_images=1, # Only capture one image at a time. + debug_ptr=tx.transmit_text_message, + vertical_flip=False, + horizontal_flip=False) + +# SSDV Image ID. +image_id = 0 + + +# Main 'loop'. +try: + while True: + # Grab current timestamp for image filenames. + gps_data = gps.read_state() + if gps_time_fix: + # The timestamp supplied within the gps data dictionary isn't suitable for use as a filename. + # Do the conversion from week/iTOW/leapS to UTC time manually, and produce a suitable timestamp. + epoch = datetime.datetime.strptime("1980-01-06 00:00:00","%Y-%m-%d %H:%M:%S") + elapsed = datetime.timedelta(days=(gps_data['week']*7),seconds=(gps_data['iTOW']+gps_data['leapS'])) + timestamp = epoch + elapsed + capture_time = timestamp.strftime("%Y%m%d-%H%M%SZ") + else: + # If we don't have valid GPS time, use system time. + capture_time = datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%SZ") + + # Generate output filenames. + vis_capture_filename = image_dir + "/%s_%d_visible.jpg" % (capture_time,image_id) + metadata_filename = image_dir + "/%s_%d_metadata.json" % (capture_time, image_id) + + # Capture an instantaneous snapshot of GPS and Orientation data. + gps_data = gps.read_state() + orientation_data = bno.read_state() + + # Capture picam image. + picam_capture_success = picam.capture(vis_capture_filename) + + # Transmit a summary of what images we were able to capture. + tx.transmit_text_message("Image %d Captured at %s (%s)" % ( + image_id, + capture_time, + "GPS" if gps_time_fix else "System") + ) + + # If we have images, convert to SSDV. + if picam_capture_success: + picam_ssdv_filename = picam.ssdvify(vis_capture_filename, image_id = image_id) + + + # Wait until the transmit queue is empty before pushing in packets. + tx.transmit_text_message("Waiting for SSDV TX queue to empty.") + while tx.image_queue_empty() == False: + time.sleep(0.1) # Sleep for a short amount of time. + + if picam_capture_success: + # Get file size in packets. + file_size = os.path.getsize(picam_ssdv_filename)/256 + + tx.transmit_text_message("Transmitting %d NIR SSDV Packets." % file_size) + + tx.queue_image_file(picam_ssdv_filename) + + # Transmit Image telemetry packet + tx.transmit_image_telemetry(gps_data, orientation_data, image_id, callsign=global_callsign) + + # Dump all the image metadata to a json blob, and write to a file. + metadata = {'gps': gps_data, 'orientation': orientation_data, 'image_id': image_id} + f = open(metadata_filename,'w') + f.write(json.dumps(metadata)) + f.close() + + # Increment image ID and loop! + image_id = (image_id + 1) % 256 + + +# Catch CTRL-C, and exit cleanly. +# Only really used during debugging. +except KeyboardInterrupt: + print("Closing") + bno.close() + gps.close() + picam.stop() + tx.close() + + + + + + + + + + + + + + + + +