def setup(self): self.logger.info("--------------------------------------") self.logger.info(" Balloon Mission Computer V4.01 ") self.logger.info("--------------------------------------") self.logger.debug("setup") # setup with open('data/config.json') as fin: self.config = json.load(fin) self.images_dir = self.config["directories"][ "images"] if "directories" in self.config and "images" in self.config[ "directories"] else "./images" self.tmp_dir = self.config["directories"][ "tmp"] if "directories" in self.config and "tmp" in self.config[ "directories"] else "./tmp" if not os.path.exists(self.tmp_dir): os.makedirs(self.tmp_dir) if not os.path.exists(self.images_dir): os.makedirs(self.images_dir) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme GPIO.setup(self.config['pins']['BUZZER'], GPIO.OUT) GPIO.setup(self.config['pins']['LED1'], GPIO.OUT) GPIO.setup(self.config['pins']['LED2'], GPIO.OUT) GPIO.output(self.config['pins']['LED1'], GPIO.HIGH) self.aprs = APRS(self.config['callsign'], self.config['ssid'], "idoroseman.com") self.modem = AFSK() self.gps = Ublox() self.gps.start() self.radio = Dorji(self.config['pins']) self.radio.init() self.radio_q = queue.Queue() self.radio_thread = threading.Thread(target=self.radio_worker) self.radio_thread.start() self.timers = Timers(self.config['timers']) self.sensors = Sensors() self.cam = Camera() self.ssdv = SSDV(self.config['callsign'], self.config['ssid']) self.sstv = SSTV() self.webserver = WebServer() self.radio_queue(self.config['frequencies']['APRS'], 'data/boatswain_whistle.wav') for item in ["APRS", "APRS-META", "Imaging", 'Capture']: self.timers.handle({item: self.config['timers'][item] > 0}, []) self.timers.handle({"Buzzer": False}, []) self.ledState = 1 self.imaging_counter = 1 self.state = "init" self.min_alt = sys.maxsize self.max_alt = 0 self.prev_alt = 0 self.send_bulltin() GPIO.output(self.config['pins']['LED1'], GPIO.LOW)
def test_parse_gngga(self): gps = Ublox() test_input = [ '$GNGGA,130706.00,3203.82887,N,03452.29882,E,1,08,1.79,99.4,M,17.4,M,,', '$GNGGA,130702.00,3203.82879,N,03452.29869,E,1,07,1.79,99.9,M,17.4,M,,', '$GNGGA,124436.00,3203.8585,N,03452.29945,E,1,12,0.91,87.6,M,17.4,M3', '$GNGGA,115233.003203.82821,N,03452.30067,E,1,12,1.41,89.4,M17.4,M,,' ] for line in test_input: tokens = line.split(',') try: rv = gps.parse_gngga(tokens) except: self.fail()
class BalloonMissionComputer(): # --------------------------------------------------------------------------- def __init__(self): if not os.path.exists('tmp/'): os.makedirs('tmp/') logging.basicConfig( format='%(asctime)s %(levelname)s %(name)s: %(message)s', level=logging.DEBUG, datefmt='%Y-%m-%d %H:%M:%S') self.logger = logging.getLogger(__name__) hdlr = logging.FileHandler('tmp/program.log') formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') hdlr.setFormatter(formatter) self.logger.addHandler(hdlr) #--------------------------------------------------------------------------- def handle_log(self, msg): self.webserver.log(msg) #--------------------------------------------------------------------------- def calc_status_bits(self, gpsdata, sensordata): bits = [ True, False, sensordata['cam2'] == "ok", sensordata['cam1'] == "ok", gpsdata['status'] == "fix", gpsdata['status'] == "lost", gpsdata['status'] == "comm error", gpsdata['status'] == "i2c error" ] return ''.join(['1' if val else '0' for val in bits]) status_names = [ 'gps i2c err', "gps comm err", "gps no fix", "gps ok", "cam1 ok", "cam2 ok" ] # --------------------------------------------------------------------------- def calc_balloon_state(self, gpsdata): current_alt = float(gpsdata['alt']) if self.state == "init" and current_alt > 0: self.state = "ground" self.send_bulltin() if self.state == "ground" and current_alt > self.min_alt + 2000: self.state = "ascent" self.send_bulltin() if self.state == "ascent" and current_alt < self.max_alt - 2000: self.state = "descent" self.send_bulltin() if self.state == "descent" and current_alt < 2000: self.state = "landed" self.send_bulltin() self.timers.set_state('BUZZER', True) if current_alt > self.max_alt: self.max_alt = current_alt if current_alt > 0 and current_alt < self.min_alt: self.min_alt = current_alt self.prev_alt = current_alt # --------------------------------------------------------------------------- def update_system_datetime(self, gpsdata): if gpsdata['status'] != "fix": return if 'date' not in gpsdata: return now = datetime.datetime.now() gpstime = datetime.datetime.strptime( gpsdata['date'] + " " + gpsdata['fixTimeStr'], "%d%m%y %H:%M:%S") diff = int(abs((now - gpstime).total_seconds() / 60)) if diff > 100: self.logger.info("system time %s" % now) self.logger.info("gps time %s" % gpstime) self.logger.info("updating") # os.system('date -s %s' % gpstime.isoformat()) proc = subprocess.Popen( ["date", "-s %s" % gpstime.isoformat()], stdout=subprocess.PIPE, shell=True) (out, err) = proc.communicate() self.logger.info("program output:" % out) self.logger.info("program error:" % err) #todo: verify we have premissions # --------------------------------------------------------------------------- def send_bulltin(self): try: self.logger.info("state changed to %s" % self.state) frame = self.aprs.create_message_msg( "BLN1BALON", "changed state to %s" % self.state) self.modem.encode(frame) self.modem.saveToFile(os.path.join(self.tmp_dir, 'aprs.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join(self.tmp_dir, 'aprs.wav')) except: pass # --------------------------------------------------------------------------- def capture_image(self, archive=True): # self.logger.debug("capture start") self.cam.capture() if archive: self.cam.archive() # self.logger.debug("capture end") # --------------------------------------------------------------------------- def prep_image(self, id, gpsdata, sensordata): self.logger.debug("image manutulation start") self.cam.select(id) self.cam.resize((320, 256)) self.cam.overlay(self.config['callsign'], gpsdata, sensordata) self.cam.saveToFile(os.path.join(self.tmp_dir, "image.jpg")) self.logger.debug("image manipulation end") # --------------------------------------------------------------------------- def process_ssdv(self): self.logger.debug("process ssdv start") self.logger.debug("jpg->ssdv") self.ssdv.convert('tmp/image.jpg', 'tmp/image.ssdv') self.logger.debug("ssdv->aprs") packets = self.ssdv.prepare(os.path.join(self.tmp_dir, "image.ssdv")) self.logger.debug("aprs->wav") self.ssdv.encode(packets, 'tmp/ssdv.wav') self.timers.trigger("PLAY-SSDV") self.logger.debug("process ssdv end") # --------------------------------------------------------------------------- def process_sstv(self): self.logger.debug("process sstv start") self.sstv.image = self.cam.image self.sstv.process() self.sstv.saveToFile(os.path.join(self.tmp_dir, 'sstv.wav')) self.timers.trigger("PLAY-SSTV") self.logger.debug("process sstv end") # --------------------------------------------------------------------------- def gps_reset(self): self.logger.warning("reset gps") GPIO.setup(self.config['pins']['GPS_RST'], GPIO.OUT) GPIO.output(self.config['pins']['GPS_RST'], GPIO.LOW) time.sleep(1) GPIO.output(self.config['pins']['GPS_RST'], GPIO.HIGH) # --------------------------------------------------------------------------- def setup(self): self.logger.info("--------------------------------------") self.logger.info(" Balloon Mission Computer V4.01 ") self.logger.info("--------------------------------------") self.logger.debug("setup") # setup files and directories with open('data/config.json') as fin: self.config = json.load(fin) self.images_dir = self.config["directories"][ "images"] if "directories" in self.config and "images" in self.config[ "directories"] else "./images" self.tmp_dir = self.config["directories"][ "tmp"] if "directories" in self.config and "tmp" in self.config[ "directories"] else "./tmp" if not os.path.exists(self.tmp_dir): os.makedirs(self.tmp_dir) if not os.path.exists(self.images_dir): os.makedirs(self.images_dir) # setup gpio GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme GPIO.setup(self.config['pins']['BUZZER'], GPIO.OUT) GPIO.setup(self.config['pins']['LED1'], GPIO.OUT) GPIO.setup(self.config['pins']['LED2'], GPIO.OUT) GPIO.output(self.config['pins']['LED1'], GPIO.HIGH) # modules self.aprs = APRS(self.config['callsign'], self.config['ssid'], "idoroseman.com") self.modem = AFSK() try: self.gps = Ublox() self.gps.start() except: pass self.radio = Dorji(self.config['pins']) self.radio.init() self.radio_q = queue.Queue() self.radio_thread = threading.Thread(target=self.radio_worker) self.radio_thread.start() self.timers = Timers(self.config['timers']) self.sensors = Sensors() self.cam = Camera() self.ssdv = SSDV(self.config['callsign'], self.config['ssid']) self.sstv = SSTV() self.webserver = WebServer() self.radio_queue(self.config['frequencies']['APRS'], 'data/boatswain_whistle.wav') self.syslog = logging.getLogger() kh = MyLogHandler() kh._listeners.append(self.handle_log) kh.setLevel(logging.DEBUG) formatter2 = logging.Formatter('%(levelname)s: %(name)s - %(message)s') kh.setFormatter(formatter2) self.syslog.addHandler(kh) # timers for item in ["APRS", "APRS-META", "Imaging", 'Capture']: self.timers.set_state(item, self.config['timers'][item] > 0) self.timers.set_state("Buzzer", False) # lets go self.ledState = 1 self.imaging_counter = 1 self.state = "init" self.min_alt = sys.maxsize self.max_alt = 0 self.prev_alt = 0 self.send_bulltin() GPIO.output(self.config['pins']['LED1'], GPIO.LOW) # --------------------------------------------------------------------------- def run(self): self.logger.debug("run") telemetry = {} telemCoef = { 'SatCount': 1, 'outside_temp': 10, 'inside_temp': 10, 'barometer': 1, 'battery': 100 } exitFlag = False self.prev_gps_status = "" while not exitFlag: try: # blink self.ledState = 1 - self.ledState GPIO.output(self.config['pins']['LED1'], GPIO.HIGH) watchdog = Watchdog(60) # gps self.gps.loop() gpsdata = self.gps.get_data() self.calc_balloon_state(gpsdata) if gpsdata['status'] == "fix" and gpsdata['alt'] > 0: self.sensors.calibrate_alt(gpsdata['alt']) if gpsdata['status'] != "fix": gpsdata['alt'] = self.sensors.read_pressure() # sensors sensordata = self.sensors.get_data() sensordata.update(self.cam.status) status_bits = self.calc_status_bits(gpsdata, sensordata) telemetry[ 'Satellites'] = gpsdata['SatCount'] * telemCoef['SatCount'] telemetry['outside_temp'] = sensordata[ 'outside_temp'] * telemCoef['outside_temp'] telemetry['inside_temp'] = sensordata[ 'inside_temp'] * telemCoef['inside_temp'] telemetry['barometer'] = sensordata['barometer'] * telemCoef[ 'barometer'] telemetry[ 'battery'] = sensordata['battery'] * telemCoef['battery'] if gpsdata['status'] != self.prev_gps_status: frame = self.aprs.create_telem_data_msg( telemetry, status_bits, gpsdata['alt']) self.modem.encode(frame) self.modem.saveToFile( os.path.join(self.tmp_dir, 'aprs.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join(self.tmp_dir, 'aprs.wav')) self.prev_gps_status = gpsdata['status'] # UI self.webserver.update(gpsdata, sensordata, self.state) self.update_system_datetime(gpsdata) if self.timers.expired("APRS"): if gpsdata['status'] == "fix": self.logger.debug("sending location") frame = self.aprs.create_location_msg( gpsdata, telemetry, status_bits) else: self.logger.debug("sending only telemetry") frame = self.aprs.create_telem_data_msg( telemetry, status_bits, gpsdata['alt']) self.modem.encode(frame) self.modem.saveToFile( os.path.join(self.tmp_dir, 'aprs.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join(self.tmp_dir, 'aprs.wav')) with open(os.path.join(self.tmp_dir, "flight.log"), 'a+') as f: merged = dict() merged.update(gpsdata) merged.update(sensordata) merged['datatime'] = datetime.datetime.now().isoformat( ) f.write(json.dumps(merged, indent=2)) f.write(',\n') if self.timers.expired("APRS-META"): frame = self.aprs.create_telem_name_msg( telemetry, self.status_names) self.modem.encode(frame) self.modem.saveToFile( os.path.join(self.tmp_dir, 'aprs.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join(self.tmp_dir, 'aprs.wav')) frame = self.aprs.create_telem_eqns_msg(telemCoef) self.modem.encode(frame) self.modem.saveToFile( os.path.join(self.tmp_dir, 'coef.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join(self.tmp_dir, 'coef.wav')) if self.timers.expired("Capture"): self.capture_image() if self.timers.expired("Snapshot"): self.imaging_counter += 1 cam_select = self.imaging_counter % CAMERAS self.capture_image(archive=False) self.prep_image(cam_select, gpsdata, sensordata) self.webserver.snapshot() if self.timers.expired("Imaging"): self.imaging_counter += 1 cam_select = self.imaging_counter % CAMERAS cam_system = self.imaging_counter % (CAMERAS + 1) self.logger.info("imageing trigger") self.logger.debug("cam %s system %s" % (cam_select, cam_system)) self.capture_image(archive=False) self.prep_image(cam_select, gpsdata, sensordata) self.webserver.snapshot() if cam_system == 0: self.logger.info("->sstv") _thread.start_new_thread(self.process_sstv, ()) else: self.logger.info("->ssdv") _thread.start_new_thread(self.process_ssdv, ()) if self.timers.expired("PLAY-SSDV"): self.logger.debug("sending ssdv") self.radio_queue(self.config['frequencies']['APRS'], os.path.join("data", 'starting_ssdv.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join("data", 'habhub.wav')) self.radio_queue(self.config['frequencies']['APRS'], os.path.join(self.tmp_dir, 'ssdv.wav')) if self.timers.expired("PLAY-SSTV"): self.logger.debug("sending sstv") self.radio_queue( self.config['frequencies']['APRS'], os.path.join("data", 'switching_to_sstv.wav')) self.radio_queue(self.config['frequencies']['SSTV'], os.path.join("data", 'starting_sstv.wav')) self.radio_queue(self.config['frequencies']['SSTV'], os.path.join(self.tmp_dir, 'sstv.wav')) if self.timers.expired("Buzzer"): for i in range(3): GPIO.output(self.config['pins']['BUZZER'], GPIO.HIGH) time.sleep(0.5) GPIO.output(self.config['pins']['BUZZER'], GPIO.LOW) time.sleep(0.5) GPIO.output(self.config['pins']['LED1'], GPIO.LOW) watchdog.stop() time.sleep(1) except Watchdog: self.logger.error("task timedout!") except KeyboardInterrupt: # If CTRL+C is pressed, exit cleanly exitFlag = True self.gps.stop() break except Exception as x: self.logger.exception(x) self.logger.info("Done.") # --------------------------------------------------------------------------- def radio_queue(self, freq, filename): self.radio_q.put({'freq': freq, 'filename': filename}) # --------------------------------------------------------------------------- def radio_worker(self): while True: item = self.radio_q.get() self.radio.play(item['freq'], item['filename']) self.radio_q.task_done()
def setup(self): self.logger.info("--------------------------------------") self.logger.info(" Balloon Mission Computer V4.01 ") self.logger.info("--------------------------------------") self.logger.debug("setup") # setup files and directories with open('data/config.json') as fin: self.config = json.load(fin) self.images_dir = self.config["directories"][ "images"] if "directories" in self.config and "images" in self.config[ "directories"] else "./images" self.tmp_dir = self.config["directories"][ "tmp"] if "directories" in self.config and "tmp" in self.config[ "directories"] else "./tmp" if not os.path.exists(self.tmp_dir): os.makedirs(self.tmp_dir) if not os.path.exists(self.images_dir): os.makedirs(self.images_dir) # setup gpio GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme GPIO.setup(self.config['pins']['BUZZER'], GPIO.OUT) GPIO.setup(self.config['pins']['LED1'], GPIO.OUT) GPIO.setup(self.config['pins']['LED2'], GPIO.OUT) GPIO.output(self.config['pins']['LED1'], GPIO.HIGH) # modules self.aprs = APRS(self.config['callsign'], self.config['ssid'], "idoroseman.com") self.modem = AFSK() try: self.gps = Ublox() self.gps.start() except: pass self.radio = Dorji(self.config['pins']) self.radio.init() self.radio_q = queue.Queue() self.radio_thread = threading.Thread(target=self.radio_worker) self.radio_thread.start() self.timers = Timers(self.config['timers']) self.sensors = Sensors() self.cam = Camera() self.ssdv = SSDV(self.config['callsign'], self.config['ssid']) self.sstv = SSTV() self.webserver = WebServer() self.radio_queue(self.config['frequencies']['APRS'], 'data/boatswain_whistle.wav') self.syslog = logging.getLogger() kh = MyLogHandler() kh._listeners.append(self.handle_log) kh.setLevel(logging.DEBUG) formatter2 = logging.Formatter('%(levelname)s: %(name)s - %(message)s') kh.setFormatter(formatter2) self.syslog.addHandler(kh) # timers for item in ["APRS", "APRS-META", "Imaging", 'Capture']: self.timers.set_state(item, self.config['timers'][item] > 0) self.timers.set_state("Buzzer", False) # lets go self.ledState = 1 self.imaging_counter = 1 self.state = "init" self.min_alt = sys.maxsize self.max_alt = 0 self.prev_alt = 0 self.send_bulltin() GPIO.output(self.config['pins']['LED1'], GPIO.LOW)
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # Set baudrate import logging from ublox import Ublox if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('baudRate', type=int, choices=[9600, 115200], help='Specify the baudrate. Must be 9600 or 115200') parser.add_argument('--device', '-d', help='Specify the serial port device to communicate with. e.g. /dev/ttyO5') parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--debug', action='store_true') args = parser.parse_args() if args.debug: logging.basicConfig(level=logging.DEBUG) elif args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.ERROR) ublox = Ublox(args.device) ublox.setBaudRate(args.baudRate)
def main(args): """ Main execution method to log u-blox RTK GPS data. Inputs: args - List of input arguments as taken from command line execution via sys.argv[1:]. Outputs: nav_data - Dictionary whose key-value pairs contain the data unpacked from the data file. """ # Parse input arguments parsed_args = parse_args(args) # Create PulsON440 object gps = Ublox() # Connect to the GPS gps.connect() # Log GPS data try: if parsed_args.return_data: data = gps.log(parsed_args.log_file, True) else: gps.log(parsed_args.log_file, False) except Exception as e: gps.disconnect() raise e # Disconnect GPS gps.disconnect() # Return data if requested if parsed_args.return_data: return data