def check_gom(): try: gom = Gomspace() hk = gom.get_health_data(level="eps") except Exception as e: log_error(e) logger.error( f"GOM init failed. Is it charged above 7.0V? Check SDA/SCL (with an oscilloscope if need be)" ) else: logger.info( f"GOM initialization successful. Battery voltage: {hk.vbatt}")
def init_sensors(self): self.radio = Radio() self.gom = Gomspace(self.parameters) self.gyro = GyroSensor() self.adc = ADC(self.gyro) self.rtc = RTC() # self.pressure_sensor = PressureSensor() # pass through self so need_to_burn boolean function # in pressure_sensor (to be made) can access burn queue""" # initialize the cameras, select a camera logger.info("Creating camera mux...") self.mux = camera.CameraMux() self.camera = camera.Camera() logger.info("Selecting a camera...") # select camera before reboot so that we will detect cam on reboot self.mux.selectCamera(random.choice([1, 2, 3]))
from drivers.gom import Gomspace import drivers.power.power_structs as ps from time import sleep from utils.log import get_log logger = get_log() gom = Gomspace() while True: choice = int( input("Choose an option:\n" "0: Display Housekeeping Data" "1: Receiving Amplifier (LNA)\n" "2: Glowplug 1\n" "3: Glowplug 2\n" "4: Burnwire\n" "5: Solenoid\n" "6: Electrolyzer\n" "7: Transmitting Amplifier (PA)\n" "999: Turn OFF all controllable outputs\n")) if choice == 999: gom.all_off() ps.displayHk2(gom.get_health_data(level="eps")) if choice == 0: ps.displayHk2(gom.get_health_data(level='eps')) if choice in [1, 4, 6, 7]: duration = int(input("Duration (integer seconds):\n")) assert 0 < duration < 15
from communications.satellite_radio import Radio from drivers.gom import Gomspace import utils.parameters as params from time import sleep radio = Radio() gom = Gomspace() electrolyzing = False interval = 3 # Number of seconds between each transmission repetitions = 5 # Number of total times you want to transmit the pattern downlink = bytes( input("Enter signal you want to downlink (e.g '\\x08\\x07\\x00\\x00)':"), encoding='utf-8') downlink = downlink.decode('unicode-escape').encode('ISO-8859-1') #––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– # Enter Transmit Mode #Stop electrolyzing if gom.is_electrolyzing(): electrolyzing = True gom.set_electrolysis(False) print('Electrolyzers turned off') #Set RF receiving side to low gom.rf_receiving_switch(receive=False) print('RF Receiving set to low') #Turn off LNA gom.lna(False)
class MainSatelliteThread(Thread): def __init__(self): super().__init__() logger.info("Initializing...") self.init_parameters() self.command_queue = Queue() self.downlink_queue = Queue() self.FMQueue = Queue() self.commands_to_execute = [] self.downlinks_to_execute = [] self.telemetry = Telemetry(self) self.burn_queue = Queue() self.reorientation_queue = Queue() self.reorientation_list = [] self.maneuver_queue = Queue() # maneuver queue self.opnav_queue = Queue() # determine state of opnav success # self.init_comms() self.command_handler = CommandHandler() self.downlink_handler = DownlinkHandler() self.command_counter = 0 self.downlink_counter = 0 self.command_definitions = CommandDefinitions(self) self.last_opnav_run = datetime.now() # Figure out what to set to for first opnav run self.log_dir = LOG_DIR self.logger = get_log() self.attach_sigint_handler() # FIXME self.need_to_reboot = False self.gom = None self.gyro = None self.adc = None self.rtc = None self.radio = None self.mux = None self.camera = None self.init_sensors() # Telemetry self.tlm = Telemetry(self) # Opnav subprocess variables self.opnav_proc_queue = Queue() self.opnav_process = Process() # define the subprocess if os.path.isdir(self.log_dir): self.flight_mode = RestartMode(self) else: os.makedirs(CISLUNAR_BASE_DIR, exist_ok=True) os.mkdir(LOG_DIR) self.flight_mode = BootUpMode(self) self.create_session = create_sensor_tables_from_path(DB_FILE) def init_comms(self): self.comms = CommunicationsSystem( queue=self.command_queue, use_ax5043=False ) self.comms.listen() def init_parameters(self): with open(PARAMETERS_JSON_PATH) as f: json_parameter_dict = load(f) try: for parameter in utils.parameters.__dir__(): if parameter[0] != '_': utils.parameters.__setattr__(parameter, json_parameter_dict[parameter]) except: raise Exception( 'Attempted to set parameter ' + str(parameter) + ', which could not be found in parameters.json' ) def init_sensors(self): try: self.gom = Gomspace() except: self.gom = None logger.error("GOM initialization failed") else: logger.info("Gom initialized") try: self.gyro = GyroSensor() except: self.gyro = None logger.error("GYRO initialization failed") else: logger.info("Gyro initialized") try: self.adc = ADC(self.gyro) self.adc.read_temperature() except: self.adc = None logger.error("ADC initialization failed") else: logger.info("ADC initialized") try: self.rtc = RTC() except: self.rtc = None logger.error("RTC initialization failed") else: logger.info("RTC initialized") try: self.nemo_manager = NemoManager(data_dir=NEMO_DIR, reset_gpio_ch=16) except: self.nemo_manager = None logger.error("NEMO initialization failed") else: logger.info("NEMO initialized") try: self.radio = Radio() except: self.radio = None logger.error("RADIO initialization failed") else: logger.info("Radio initialized") # initialize the Mux, select a camera try: self.mux = camera.CameraMux() self.mux.selectCamera(1) except: self.mux = None logger.error("MUX initialization failed") else: logger.info("Mux initialized") cameras_list = [0, 0, 0] # initialize cameras only if not a hard boot (or first boot) if not hard_boot() and os.path.isdir(self.log_dir): try: self.camera = camera.Camera() for i in [1, 2, 3]: try: self.mux.selectCamera(i) f, t = self.camera.rawObservation(f"initialization-{i}-{int(time())}") except Exception as e: logger.error(f"CAM{i} initialization failed") cameras_list[i - 1] = 0 else: logger.info(f"Cam{i} initialized") cameras_list[i - 1] = 1 if 0 in cameras_list: raise e except: self.camera = None logger.error(f"Cameras initialization failed") else: logger.info("Cameras initialized") else: self.need_to_reboot = True # make a bitmask of the initialized sensors for downlinking sensors = [self.gom, self.radio, self.gyro, self.adc, self.rtc, self.mux, self.camera] sensor_functioning_list = [int(bool(sensor)) for sensor in sensors] sensor_functioning_list.extend(cameras_list) sensor_bitmask = ''.join(map(str, sensor_functioning_list)) logger.debug(f"Sensors: {sensor_bitmask}") return int(sensor_bitmask, 2) def handle_sigint(self, signal, frame): self.shutdown() sys.exit(0) def attach_sigint_handler(self): signal.signal(signal.SIGINT, self.handle_sigint) def poll_inputs(self): self.flight_mode.poll_inputs() #Telemetry downlink if (datetime.today() - self.radio.last_telemetry_time).total_seconds()/60 >= params.TELEM_DOWNLINK_TIME: telemetry = self.command_definitions.gather_basic_telem() telem_downlink = ( self.downlink_handler.pack_downlink(self.downlink_counter, FMEnum.Normal.value, NormalCommandEnum.BasicTelem.value, **telemetry)) self.downlink_queue.put(telem_downlink) self.radio.last_telemetry_time = datetime.today() # Listening for new commands newCommand = self.radio.receiveSignal() if newCommand is not None: try: unpackedCommand = self.command_handler.unpack_command(newCommand) if unpackedCommand[0] == MAC: if unpackedCommand[1] == self.command_counter + 1: self.command_queue.put(bytes(newCommand)) self.command_counter += 1 else: logger.warning('Command with Invalid Counter Received. Counter: ' + str(unpackedCommand[1])) else: logger.warning('Unauthenticated Command Received') except: logger.error('Invalid Command Received') else: logger.debug('Not Received') def replace_flight_mode_by_id(self, new_flight_mode_id): self.replace_flight_mode(build_flight_mode(self, new_flight_mode_id)) def replace_flight_mode(self, new_flight_mode): self.flight_mode = new_flight_mode self.logger.info(f"Changed to FM#{self.flight_mode.flight_mode_id}") def update_state(self): fm_to_update_to = self.flight_mode.update_state() # only replace the current flight mode if it needs to change (i.e. dont fix it if it aint broken!) if fm_to_update_to is None: pass elif fm_to_update_to != NO_FM_CHANGE and fm_to_update_to != self.flight_mode.flight_mode_id: self.replace_flight_mode_by_id(fm_to_update_to) def clear_command_queue(self): while not self.command_queue.empty(): command = self.command_queue.get() logger.debug(f"Throwing away command: {command}") def reset_commands_to_execute(self): self.commands_to_execute = [] # Execute received commands def execute_commands(self): assert ( len(self.commands_to_execute) == 0 ), "Didn't finish executing previous commands" while not self.command_queue.empty(): self.commands_to_execute.append(self.command_queue.get()) self.flight_mode.execute_commands() def read_command_queue_from_file(self, filename="communications/command_queue.txt"): """A temporary workaround to not having radio board access""" # check if file exists if os.path.isfile(filename): text_file = open(filename, "r") for hex_line in text_file: self.command_queue.put(bytes.fromhex(hex_line)) text_file.close() # delete file os.remove(filename) # Run the current flight mode def run_mode(self): with self.flight_mode: self.flight_mode.run_mode() # Wrap in try finally block to ensure it stays live def run(self): """This is the main loop of the Cislunar Explorers and runs constantly during flight.""" try: while True: sleep(5) # TODO remove when flight modes execute real tasks self.poll_inputs() self.update_state() self.read_command_queue_from_file() self.execute_commands() # Set goal or execute command immediately self.run_mode() # Opnav subprocess management # TODO: This all needs to be moved to the OpNav Flight mode, and should not be in main!!! finally: # TODO handle failure gracefully if FOR_FLIGHT is True: self.replace_flight_mode_by_id(FMEnum.Safety.value) self.run() else: self.shutdown() def shutdown(self): if self.gom is not None: self.gom.all_off() if self.nemo_manager is not None: self.nemo_manager.close() logger.critical("Shutting down flight software")
def init_sensors(self): try: self.gom = Gomspace() except: self.gom = None logger.error("GOM initialization failed") else: logger.info("Gom initialized") try: self.gyro = GyroSensor() except: self.gyro = None logger.error("GYRO initialization failed") else: logger.info("Gyro initialized") try: self.adc = ADC(self.gyro) self.adc.read_temperature() except: self.adc = None logger.error("ADC initialization failed") else: logger.info("ADC initialized") try: self.rtc = RTC() except: self.rtc = None logger.error("RTC initialization failed") else: logger.info("RTC initialized") try: self.nemo_manager = NemoManager(data_dir=NEMO_DIR, reset_gpio_ch=16) except: self.nemo_manager = None logger.error("NEMO initialization failed") else: logger.info("NEMO initialized") try: self.radio = Radio() except: self.radio = None logger.error("RADIO initialization failed") else: logger.info("Radio initialized") # initialize the Mux, select a camera try: self.mux = camera.CameraMux() self.mux.selectCamera(1) except: self.mux = None logger.error("MUX initialization failed") else: logger.info("Mux initialized") cameras_list = [0, 0, 0] # initialize cameras only if not a hard boot (or first boot) if not hard_boot() and os.path.isdir(self.log_dir): try: self.camera = camera.Camera() for i in [1, 2, 3]: try: self.mux.selectCamera(i) f, t = self.camera.rawObservation(f"initialization-{i}-{int(time())}") except Exception as e: logger.error(f"CAM{i} initialization failed") cameras_list[i - 1] = 0 else: logger.info(f"Cam{i} initialized") cameras_list[i - 1] = 1 if 0 in cameras_list: raise e except: self.camera = None logger.error(f"Cameras initialization failed") else: logger.info("Cameras initialized") else: self.need_to_reboot = True # make a bitmask of the initialized sensors for downlinking sensors = [self.gom, self.radio, self.gyro, self.adc, self.rtc, self.mux, self.camera] sensor_functioning_list = [int(bool(sensor)) for sensor in sensors] sensor_functioning_list.extend(cameras_list) sensor_bitmask = ''.join(map(str, sensor_functioning_list)) logger.debug(f"Sensors: {sensor_bitmask}") return int(sensor_bitmask, 2)
# from utils.constants import BURNWIRE_DURATION def gyro_thread(gyro_freq: int): gyro_data = [] logger.info("Reading Gyro data (rad/s)") for i in range(2000): gyro_reading = gyro.get_gyro() gyro_time = time() gyro_list = list(gyro_reading) gyro_list.append(gyro_time) gyro_data.append(gyro_list) sleep(1.0 / gyro_freq) # writes gyro data to gyro_data.txt. Caution, this file will be overwritten with every successive test logger.info("Writing gyro data to file") with open('gyro_data.txt', 'w') as filehandle: filehandle.writelines("%s\n" % line for line in gyro_data) if __name__ == '__main__': logger = get_log() gyro = GyroSensor() gom_controller = Gomspace() # start new thread to log gyro data gyro_threader = threading.Thread(target=gyro_thread) gyro_threader.start() gom_controller.burnwire2(2)
# Testing all untested and new Gom-related commands from drivers.gom import Gomspace, logger from drivers.power.power_structs import displayHK, displayHk2, displayStruct from time import sleep test = Gomspace() # testing all HK functions hkdata = test.get_health_data() displayStruct(hkdata) sleep(2) hkdata = test.get_health_data(level="eps") displayStruct(hkdata) sleep(2) hkdata = test.get_health_data(level="vi") displayStruct(hkdata) sleep(2) hkdata = test.get_health_data(level="out") displayStruct(hkdata) sleep(2) hkdata = test.get_health_data(level="wdt") displayStruct(hkdata) sleep(2) hkdata = test.get_health_data(level="basic") displayStruct(hkdata)
class MainSatelliteThread(Thread): def __init__(self): super().__init__() logger.info("Initializing...") self.init_parameters() self.command_queue = Queue() self.downlink_queue = Queue() self.FMQueue = Queue() self.commands_to_execute = [] self.downlinks_to_execute = [] self.telemetry = Telemetry(self) self.burn_queue = Queue() self.reorientation_queue = Queue() self.reorientation_list = [] self.maneuver_queue = Queue() # maneuver queue # self.init_comms() self.command_handler = CommandHandler() self.downlink_handler = DownlinkHandler() self.command_counter = 0 self.downlink_counter = 0 self.command_definitions = CommandDefinitions(self) self.init_sensors() self.last_opnav_run = datetime.now() # Figure out what to set to for first opnav run self.log_dir = LOG_DIR self.logger = get_log() self.attach_sigint_handler() # FIXME if os.path.isdir(self.log_dir): self.flight_mode = RestartMode(self) else: os.makedirs(CISLUNAR_BASE_DIR) os.mkdir(LOG_DIR) self.flight_mode = BootUpMode(self) self.create_session = create_sensor_tables_from_path(DB_FILE) def init_comms(self): self.comms = CommunicationsSystem( queue=self.command_queue, use_ax5043=False ) self.comms.listen() def init_parameters(self): with open(PARAMETERS_JSON_PATH) as f: json_parameter_dict = load(f) self.parameters = json_parameter_dict # try: # for parameter in self.parameters.__dir__(): # if parameter[0] != '_': # self.parameters[parameter] = json_parameter_dict[parameter] # except: # raise Exception( # 'Attempted to set parameter ' + str(parameter) + # ', which could not be found in parameters.json' # ) def init_sensors(self): self.radio = Radio() self.gom = Gomspace(self.parameters) self.gyro = GyroSensor() self.adc = ADC(self.gyro) self.rtc = RTC() # self.pressure_sensor = PressureSensor() # pass through self so need_to_burn boolean function # in pressure_sensor (to be made) can access burn queue""" # initialize the cameras, select a camera logger.info("Creating camera mux...") self.mux = camera.CameraMux() self.camera = camera.Camera() logger.info("Selecting a camera...") # select camera before reboot so that we will detect cam on reboot self.mux.selectCamera(random.choice([1, 2, 3])) def handle_sigint(self, signal, frame): self.shutdown() sys.exit(0) def attach_sigint_handler(self): signal.signal(signal.SIGINT, self.handle_sigint) def poll_inputs(self): # self.tlm.poll() self.flight_mode.poll_inputs() # Telemetry downlink if (datetime.today() - self.radio.last_telemetry_time).total_seconds() / 60 >= self.parameters[ "TELEM_DOWNLINK_TIME"]: self.enter_transmit_safe_mode() telemetry = self.command_definitions.gather_basic_telem() telem_downlink = ( self.downlink_handler.pack_downlink(self.downlink_counter, FMEnum.Normal.value, NormalCommandEnum.BasicTelem.value, **telemetry)) self.downlink_queue.put(telem_downlink) # Listening for new commands newCommand = self.radio.receiveSignal() if newCommand is not None: try: unpackedCommand = self.command_handler.unpack_command(newCommand) if unpackedCommand[0] == MAC: if unpackedCommand[1] == self.command_counter + 1: print('hello') self.command_queue.put(bytes(newCommand)) self.command_counter += 1 else: print('Command with Invalid Counter Received. ' + 'Counter: ' + str(unpackedCommand[1])) else: print('Unauthenticated Command Received') except: print('Invalid Command Received') else: print('Not Received') def enter_transmit_safe_mode(self): # TODO: Make sure that everything else is turned off before transmitting pass def replace_flight_mode_by_id(self, new_flight_mode_id): self.replace_flight_mode(build_flight_mode(self, new_flight_mode_id)) def replace_flight_mode(self, new_flight_mode): self.flight_mode = new_flight_mode self.logger.info(f"Changed to FM#{self.flight_mode.flight_mode_id}") def update_state(self): fm_to_update_to = self.flight_mode.update_state() # only replace the current flight mode if it needs to change (i.e. dont fix it if it aint broken!) if fm_to_update_to is None: pass elif fm_to_update_to != NO_FM_CHANGE and fm_to_update_to != self.flight_mode.flight_mode_id: self.replace_flight_mode_by_id(fm_to_update_to) def clear_command_queue(self): while not self.command_queue.empty(): command = self.command_queue.get() print(f"Throwing away command: {command}") def reset_commands_to_execute(self): self.commands_to_execute = [] # Execute received commands def execute_commands(self): assert ( len(self.commands_to_execute) == 0 ), "Didn't finish executing previous commands" while not self.command_queue.empty(): self.commands_to_execute.append(self.command_queue.get()) self.flight_mode.execute_commands() def execute_downlinks(self): self.enter_transmit_safe_mode() while not self.downlink_queue.empty(): self.radio.transmit(self.downlink_queue.get()) self.downlink_counter += 1 sleep(self.parameters["DOWNLINK_BUFFER_TIME"]) def read_command_queue_from_file(self, filename="communications/command_queue.txt"): """A temporary workaround to not having radio board access""" # check if file exists if os.path.isfile(filename): text_file = open(filename, "r") for hex_line in text_file: self.command_queue.put(bytes.fromhex(hex_line)) text_file.close() # delete file os.remove(filename) # Run the current flight mode def run_mode(self): with self.flight_mode: self.flight_mode.run_mode() # Wrap in try finally block to ensure it stays live def run(self): """This is the main loop of the Cislunar Explorers and runs constantly during flight.""" try: while True: sleep(5) # TODO remove when flight modes execute real tasks self.poll_inputs() self.update_state() self.read_command_queue_from_file() self.execute_commands() # Set goal or execute command immediately self.execute_downlinks() self.run_mode() finally: self.replace_flight_mode_by_id(FMEnum.Safety.value) # TODO handle failure gracefully if FOR_FLIGHT is True: self.run() else: self.gom.all_off() def shutdown(self): self.gom.all_off() logger.critical("Shutting down...")