diff --git a/Ground Station/dropstar_gui/app.py b/Ground Station/dropstar_gui/app.py
index fff5f0f..9757a37 100644
--- a/Ground Station/dropstar_gui/app.py
+++ b/Ground Station/dropstar_gui/app.py
@@ -49,14 +49,15 @@ async def status() -> Tuple[Mapping[str, str | int | None], int]:
Returns a tuple containing the status and the HTTP status code.
"""
- motor_speed, sound_card_status, camera_status, LO, SOE, SODS, error_code = await asyncio.gather(
+ motor_speed, sound_card_status, camera_status, LO, SOE, SODS, error_code, led_status = await asyncio.gather(
experiment_status.get_motor_speed(),
experiment_status.get_sound_card_status(),
experiment_status.get_camera_status(),
experiment_status.get_LO_signal(),
experiment_status.get_SOE_signal(),
experiment_status.get_SODS_signal(),
- experiment_status.get_errors()
+ experiment_status.get_errors(),
+ experiment_status.get_led_status()
)
status = {
@@ -66,7 +67,8 @@ async def status() -> Tuple[Mapping[str, str | int | None], int]:
'LO_status': LO,
'SOE_status': SOE,
'SODS_status': SODS,
- 'errors': error_code
+ 'errors': error_code,
+ 'led_status': led_status
}
return status, 200
diff --git a/Ground Station/dropstar_gui/controllers/figures.py b/Ground Station/dropstar_gui/controllers/figures.py
index 3244a7c..30cd81e 100644
--- a/Ground Station/dropstar_gui/controllers/figures.py
+++ b/Ground Station/dropstar_gui/controllers/figures.py
@@ -1,8 +1,7 @@
-from cProfile import label
import io
-import numpy as np
import matplotlib
import asyncio
+import logging
from matplotlib import pyplot as plt
@@ -11,6 +10,8 @@
matplotlib.use('agg')
+logging.basicConfig(level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s')
FIGURES = ["temperature", "pressure"]
@@ -23,25 +24,25 @@ async def get_temp_plot(img: io.BytesIO) -> None:
"""
time_range_of_plot = 60 # This value determines the time range of the plot
- sensor1, sensor2, sensor3 = await asyncio.gather(
+ sensor1_data, sensor2_data, sensor3_data = await asyncio.gather(
get_temperature("sensor1", time_range_of_plot),
get_temperature("sensor2", time_range_of_plot),
get_temperature("sensor3", time_range_of_plot)
)
- # FIXME: This can probably be done in one line for every sensor so that we don't have to repeat the code
- x_1 = [i/3 for i in range(len(sensor1))]
- x_2 = [i/3 for i in range(len(sensor2))]
- x_3 = [i/3 for i in range(len(sensor3))]
-
figure, ax = plt.subplots()
- ax.plot(x_1, sensor1, label="Sensor 1")
- ax.plot(x_2, sensor2, label="Sensor 2")
- ax.plot(x_3, sensor3, label="Sensor 3")
+ logging.debug(f"Sensor 1 data: {sensor1_data}")
+ logging.debug(f"Sensor 2 data: {sensor2_data}")
+ logging.debug(f"Sensor 3 data: {sensor3_data}")
+
+ ax.plot(*sensor1_data, label="Right Sensor")
+ ax.plot(*sensor2_data, label="Left Sensor")
+ ax.plot(*sensor3_data, label="Sound Card")
ax.set_title("Temperature Plot")
ax.set_xlabel("Time (s)")
ax.set_ylabel("Temperature (C)")
+ ax.legend()
ax.grid()
figure.savefig(img, format='png')
plt.close(figure)
diff --git a/Ground Station/dropstar_gui/controllers/status.py b/Ground Station/dropstar_gui/controllers/status.py
index 436b32a..47989b3 100644
--- a/Ground Station/dropstar_gui/controllers/status.py
+++ b/Ground Station/dropstar_gui/controllers/status.py
@@ -1,5 +1,6 @@
import aiosqlite as sql
import logging
+import datetime
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
@@ -57,7 +58,7 @@ async def get_camera_status() -> bool:
return status
-async def get_temperature(sensor: str, time: int) -> list[int]:
+async def get_temperature(sensor: str, time: int) -> tuple[list[int], list[float]]:
"""Gets the temperature from the db.
Args:
@@ -65,7 +66,7 @@ async def get_temperature(sensor: str, time: int) -> list[int]:
time (int): The time for which the temperature will be read.
Returns:
- list: The temperature values for the given time.
+ tuple[list[float], list[float]]: A list of tuples containing the time and temperature.
"""
async with sql.connect('file:GS_data.db?mode=ro', timeout=10, isolation_level=None, uri=True) as db:
if sensor == 'sensor1':
@@ -77,22 +78,41 @@ async def get_temperature(sensor: str, time: int) -> list[int]:
else:
raise ValueError('Invalid sensor name')
- results = await db.execute(f'''SELECT {col}
+ # This query gets the last 180 temperature readings which we assume is about 1 minute of data because we have 3.3 Hz sampling rate
+ results = await db.execute(f'''SELECT time, {col}
FROM GS_data
- WHERE time >= DATETIME('now', '-{time} seconds')
+ WHERE {col} IS NOT NULL
ORDER BY time DESC
+ LIMIT 180
''')
- temperature = await results.fetchall()
+ time_to_temperature = await results.fetchall() # This is a list of tuples
- temp_list = [x for (x,) in temperature]
- temp_list.reverse()
+ # I need to convert the list of tuples into a tuple of lists
+ # I think this is returning a tuple of tuples instead of a tuple of lists but I'm not sure
+ temp_tuple = tuple(zip(*time_to_temperature))
+ if len(temp_tuple) == 0:
+ return ([], [])
- logging.debug(f'Got temperature: {temp_list}')
+ temp_tuple = (list(temp_tuple[0]), list(temp_tuple[1]))
- if len(temp_list) == 0:
- temp_list = [-1]
+ # I need to reverse the lists so that the time is in ascending order
+ temp_tuple[0].reverse()
+ temp_tuple[1].reverse()
- return temp_list
+ returned_times = []
+ returned_temps = []
+
+ for time_before_format, temp in zip(temp_tuple[0], temp_tuple[1]):
+ formated_time = datetime.datetime.strptime(
+ time_before_format, '%Y-%m-%d %H:%M:%S.%f')
+ returned_times.append(formated_time)
+ returned_temps.append(temp)
+
+ temp_tuple = (returned_times, returned_temps)
+
+ logging.debug(f'Got times: {temp_tuple[0]}')
+ logging.debug(f'Got temperatures: {temp_tuple[1]}')
+ return temp_tuple # type: ignore
async def get_LO_signal() -> bool:
@@ -169,3 +189,22 @@ async def get_errors() -> int | None:
error_code = None
return error_code
+
+
+async def get_led_status() -> int | None:
+ """Gets the led status from the db.
+
+ Returns:
+ int: The led status.
+ """
+ async with sql.connect('file:GS_data.db?mode=ro', timeout=10, isolation_level=None, uri=True) as db:
+ result = db.execute(
+ 'SELECT led_status FROM GS_data ORDER BY time DESC LIMIT 1')
+ status = await result
+ status = await status.fetchone()
+ try:
+ status = status[0] # type: ignore
+ except TypeError:
+ status = None
+
+ return status
diff --git a/Ground Station/dropstar_gui/static/js/utilities.js b/Ground Station/dropstar_gui/static/js/utilities.js
index 78840be..e2fb4b4 100644
--- a/Ground Station/dropstar_gui/static/js/utilities.js
+++ b/Ground Station/dropstar_gui/static/js/utilities.js
@@ -1,21 +1,16 @@
-function setMotorStatus(motor, speed){
- if (speed == 0){
- $(motor).html(`Stopped \t\t (${speed})`)
+function setMotorStatus(motor, status){
+ if (status == 0){
+ $(motor).html("OFF")
$(motor).removeClass()
$(motor).addClass("text-danger")
}
- else if (speed == 255){
- $(motor).html(`Max Speed \t\t (${speed})`)
+ else if (status == 1){
+ $(motor).html("ON")
$(motor).removeClass()
$(motor).addClass("text-success")
}
- else if (speed > 0){
- $(motor).html(`Speed Up \t\t (${speed})`)
- $(motor).removeClass()
- // $(motor).addClass("text-primary") // This is the default color which is blue
- }
else {
- $(motor).html(`Error \t\t (${speed})`)
+ $(motor).html(`Error \t\t (${status})`)
$(motor).removeClass()
$(motor).addClass("text-warning")
$(motor).addClass("text-dark")
@@ -23,13 +18,18 @@ function setMotorStatus(motor, speed){
}
function setSoundCardStatus(soundCard, status){
- if (status == false){
- $(soundCard).html("OFF")
+ if (status == 0){
+ $(soundCard).html("FINISHED")
$(soundCard).removeClass()
$(soundCard).addClass("text-danger")
}
- else if (status == true){
- $(soundCard).html("ON")
+ else if (status == 1){
+ $(soundCard).html("ON / IVED OFF")
+ $(soundCard).removeClass()
+ $(soundCard).addClass("text-primary") // This is the default color which is blue
+ }
+ else if (status == 2){
+ $(soundCard).html("ON / IVED RECORDING")
$(soundCard).removeClass()
$(soundCard).addClass("text-success")
}
@@ -42,13 +42,18 @@ function setSoundCardStatus(soundCard, status){
}
function setCameraStatus(camera, status){
- if (status == false){
- $(camera).html("OFF")
+ if (status == 0){
+ $(camera).html("FINISHED")
$(camera).removeClass()
$(camera).addClass("text-danger")
}
- else if (status == true){
- $(camera).html("ON")
+ else if (status == 1){
+ $(camera).html("ON / STANDBY")
+ $(camera).removeClass()
+ $(camera).addClass("text-primary")
+ }
+ else if (status == 2){
+ $(camera).html("RECORDING")
$(camera).removeClass()
$(camera).addClass("text-success")
}
@@ -60,60 +65,41 @@ function setCameraStatus(camera, status){
}
}
-function setLOStatus(lo, status){
- if (status == false){
- $(lo).html("OFF")
- $(lo).removeClass()
- $(lo).addClass("text-danger")
- }
- else if (status == true){
- $(lo).html("ON")
- $(lo).removeClass()
- $(lo).addClass("text-success")
- }
- else {
- $(lo).html(`Error \t\t (${status})`)
- $(lo).removeClass()
- $(lo).addClass("text-warning")
- $(lo).addClass("text-dark")
+function setLEDStatus(led, status){
+ if (status == 0){
+ $(led).html("OFF")
+ $(led).removeClass()
+ $(led).addClass("text-danger")
}
-}
-
-function setSOEStatus(soe, status){
- if (status == false){
- $(soe).html("OFF")
- $(soe).removeClass()
- $(soe).addClass("text-danger")
- }
- else if (status == true){
- $(soe).html("ON")
- $(soe).removeClass()
- $(soe).addClass("text-success")
+ else if (status == 1){
+ $(led).html("ON")
+ $(led).removeClass()
+ $(led).addClass("text-success")
}
else {
- $(soe).html(`Error \t\t (${status})`)
- $(soe).removeClass()
- $(soe).addClass("text-warning")
- $(soe).addClass("text-dark")
+ $(led).html(`Error \t\t (${status})`)
+ $(led).removeClass()
+ $(led).addClass("text-warning")
+ $(led).addClass("text-dark")
}
}
-function setSODSStatus(sods, status){
+function setSignalStatus(element, status){
if (status == false){
- $(sods).html("OFF")
- $(sods).removeClass()
- $(sods).addClass("text-danger")
+ $(element).html("OFF")
+ $(element).removeClass()
+ $(element).addClass("text-danger")
}
else if (status == true){
- $(sods).html("ON")
- $(sods).removeClass()
- $(sods).addClass("text-success")
+ $(element).html("ON")
+ $(element).removeClass()
+ $(element).addClass("text-success")
}
else {
- $(sods).html(`Error \t\t (${status})`)
- $(sods).removeClass()
- $(sods).addClass("text-warning")
- $(sods).addClass("text-dark")
+ $(element).html(`Error \t\t (${status})`)
+ $(element).removeClass()
+ $(element).addClass("text-warning")
+ $(element).addClass("text-dark")
}
}
diff --git a/Ground Station/dropstar_gui/telecoms/rxsm_receiver.py b/Ground Station/dropstar_gui/telecoms/rxsm_receiver.py
index ef25b2f..9dc9c8a 100644
--- a/Ground Station/dropstar_gui/telecoms/rxsm_receiver.py
+++ b/Ground Station/dropstar_gui/telecoms/rxsm_receiver.py
@@ -3,7 +3,9 @@
import serial
import sqlite3 as sql
-port = "COM6" # NOTE: This port may change depending on the computer
+from telecoms.telecom_util import coalesce_data, get_previous_row_values, format_data
+
+port = "COM5" # NOTE: This port may change depending on the computer
def receive_data():
@@ -17,21 +19,25 @@ def receive_data():
data_has_been_received = False
- try:
- while True:
+ while True:
+ try:
data = connection.readline()
if data:
logging.info(f"Received data: {data}")
- insert_data_in_db(deserialize_data(data))
+ try:
+ insert_data_in_db(deserialize_data(data))
+ except Exception as e:
+ logging.error(f"Error in inserting data: {e}")
data_has_been_received = True
else:
if not data_has_been_received:
logging.warning(
"No data received. Experiment is probably still off or there is something wrong in the connection...")
- logging.debug("No data received")
- except Exception as e:
- logging.error(f"Error in receiving data: {e}")
+ continue
+ logging.warning("No data received")
+ except Exception as e:
+ logging.error(f"Error in receiving data: {e}")
@cache
@@ -44,7 +50,26 @@ def deserialize_data(data: bytes) -> tuple:
Returns:
tuple: The deserialized data.
"""
- return tuple(data.decode().split(','))
+ deserialized_data = data.decode().split(',')
+
+ def omit_none_values(x):
+ return x if x != 'None' else None
+
+ def omit_values_with_endline(x):
+ if x is None:
+ return x
+ if x.endswith('\n'):
+ return x[:-1]
+ return x
+
+ try:
+ deserialized_data = map(omit_values_with_endline, deserialized_data)
+ deserialized_data = map(omit_none_values, deserialized_data)
+ except Exception as e:
+ logging.error(f"Error in deserializing data: {e}")
+ raise e
+
+ return tuple(deserialized_data)
def insert_data_in_db(data: tuple):
@@ -53,10 +78,22 @@ def insert_data_in_db(data: tuple):
Args:
data (tuple): The data to be inserted into the database.
"""
+ data = format_data(data)
+
with sql.connect('GS_data.db', timeout=10) as db:
cursor = db.cursor()
+ try:
+ previous_row = get_previous_row_values(cursor)
+ if len(previous_row) == 0:
+ previous_row = (None,)*len(data)
+ coalesced_data = coalesce_data(data, previous_row)
+ except Exception as e:
+ logging.error(f"Error in coalescing data: {e}")
+ raise e
+
cursor.execute('''
INSERT INTO GS_DATA (
+ time,
motor_speed,
sound_card_status,
camera_status,
@@ -66,11 +103,12 @@ def insert_data_in_db(data: tuple):
LO_signal,
SOE_signal,
SODS_signal,
- error_code
- ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- ''', data)
+ error_code,
+ led_status
+ ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ''', coalesced_data)
db.commit()
- logging.info(f'Inserted data: {data} in the database')
+ logging.info(f'Inserted data: {coalesced_data} in the database')
def create_db():
@@ -84,19 +122,18 @@ def create_db():
-- TODO: Add contraints in the values of the columns where needed
CREATE TABLE GS_DATA (
- time DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
- motor_speed INTEGER, -- The speed of the motor in (rpm?)
- sound_card_status INTEGER, -- The status of the sound card. Possible values: 0 = OFF, 1 = ON, 2 = RECORDING, 3 = ERROR
- camera_status INTEGER, -- The status of the camera. Possible values: 0 = OFF, 1 = ON, 2 = RECORDING, 3 = ERROR
+ time DATETIME,
+ motor_speed INTEGER, -- The speed of the motor. Possible values: 0 = OFF, 1 = ON
+ sound_card_status INTEGER, -- The status of the sound card. Possible values: 0 = FINISHED, 1 = STANDBY, 2 = RECORDING, 3 = ERROR
+ camera_status INTEGER, -- The status of the camera. Possible values: 0 = FINISHED, 1 = STANDBY, 2 = RECORDING, 3 = ERROR
temp_1 REAL, -- The temperature of the first sensor in (Celsius?)
temp_2 REAL, -- The temperature of the second sensor in (Celsius?)
temp_3 REAL, -- The temperature of the sound card sensor in (Kelvin)
- -- Add sensors here if needed
LO_signal BOOLEAN, -- The status of the LO signal. Possible values: 0 = OFF, 1 = ON
SOE_signal BOOLEAN, -- The status of the SOE signal. Possible values: 0 = OFF, 1 = ON
SODS_signal BOOLEAN, -- The status of the SODS signal. Possible values: 0 = OFF, 1 = ON
error_code INTEGER, -- The error code of the system in case of an error. Possible values: TBD
- PRIMARY KEY (time)
+ led_status INTEGER -- The status of the LED. Possible values: 0 = OFF, 1 = ON
);
''')
db.commit()
diff --git a/Ground Station/dropstar_gui/telecoms/telecom_util.py b/Ground Station/dropstar_gui/telecoms/telecom_util.py
new file mode 100644
index 0000000..04694a3
--- /dev/null
+++ b/Ground Station/dropstar_gui/telecoms/telecom_util.py
@@ -0,0 +1,111 @@
+import sqlite3 as sql
+from typing import Tuple
+from math import log
+import logging
+
+logging.basicConfig(level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s')
+
+
+def coalesce_data(data: Tuple, previous_row_values: Tuple) -> Tuple:
+ """Coalesces the data with the previous non-null values.
+
+ Args:
+ data (Tuple): The data to be coalesced.
+ previous_row_values (Tuple): The previous non-null values.
+
+ Returns:
+ Tuple: The coalesced data.
+ """
+ def coalesce(x, y):
+ return x if x is not None else y
+
+ if len(previous_row_values) != len(data):
+ raise ValueError(
+ f"The length of the previous row values ({len(previous_row_values)}) is different from the length of the data ({len(data)}).")
+
+ return tuple(map(coalesce, data, previous_row_values))
+
+
+def get_previous_row_values(cursor: sql.Cursor) -> Tuple:
+ """Gets values of the previous row.
+
+ Args:
+ cursor (sql.Cursor): The cursor to the database.
+
+ Returns:
+ Tuple: The values of the previous row.
+ """
+ cursor.execute('''
+ SELECT * FROM GS_DATA
+ ORDER BY time DESC
+ LIMIT 1
+ ''')
+ previous_row = cursor.fetchone()
+
+ if previous_row is None:
+ return ()
+
+ return previous_row
+
+
+def format_data(data: Tuple) -> Tuple:
+ """Formats the data into their proper type.
+
+ Args:
+ data (Tuple): The data to be formatted.
+
+ Returns:
+ Tuple: The formatted data.
+ """
+ def format_signals(x):
+ if x is None:
+ return x
+ if x == 0 or x == '0':
+ return False
+ if x == 1 or x == '1':
+ return True
+ return x
+
+ return (
+ str(data[0]) if data[0] is not None else None,
+ int(data[1]) if data[1] is not None else None,
+ int(data[2]) if data[2] is not None else None,
+ int(data[3]) if data[3] is not None else None,
+ convert_thermistor_values(
+ float(data[4])) if data[4] is not None else None,
+ convert_thermistor_values(
+ float(data[5])) if data[5] is not None else None,
+ float(data[6]) if data[6] is not None else None,
+ format_signals(data[7]) if data[7] is not None else None,
+ format_signals(data[8]) if data[8] is not None else None,
+ format_signals(data[9]) if data[9] is not None else None,
+ int(data[10]) if data[10] is not None else None,
+ int(data[11]) if data[11] is not None else None,
+ )
+
+
+def convert_thermistor_values(thermistor_value: float) -> float:
+ """Kanei convert ta voltages twn thermistors se thermokrasies
+ To voltage που παιρνουμε ειναι της αντίστασης όχι του θερμίστορ
+ Args:
+ thermistor_value (float): to ekastote voltage apo to ekastote thermistor
+ """
+ r0 = 10000 # temperature at 25 Celcious
+ B = 3984 # Beta value
+
+ T: float = 0
+
+ try:
+ Rth = (5 - thermistor_value) / 43.6e-5
+
+ logging.debug(f"Rth: {Rth}")
+ logging.debug(f"thermistor_value: {thermistor_value}")
+ logging.debug(f"Rth/r0: {Rth/r0}")
+
+ TK = 1 / ((log(Rth/r0) / B)+(1/298.15))
+ T = TK - 273.5
+ except Exception as e:
+ logging.error("Error in converting thermistor values")
+ logging.error(e)
+ return T
diff --git a/Ground Station/dropstar_gui/templates/downlink.j2 b/Ground Station/dropstar_gui/templates/downlink.j2
index 5457eb0..e9d5c63 100644
--- a/Ground Station/dropstar_gui/templates/downlink.j2
+++ b/Ground Station/dropstar_gui/templates/downlink.j2
@@ -15,6 +15,9 @@
+
@@ -56,9 +59,10 @@
setMotorStatus("#motorStatus", data.motor_speed);
setSoundCardStatus("#soundCardStatus", data.sound_card_status);
setCameraStatus("#cameraStatus", data.camera_status);
- setLOStatus("#LOStatus", data.LO_status);
- setSOEStatus("#SOEStatus", data.SOE_status);
- setSODSStatus("#SODSStatus", data.SODS_status);
+ setLEDStatus("#ledStatus", data.led_status);
+ setSignalStatus("#LOStatus", data.LO_status);
+ setSignalStatus("#SOEStatus", data.SOE_status);
+ setSignalStatus("#SODSStatus", data.SODS_status);
setErrors("#errors", data.errors);
});
}, 500); // twice per second
diff --git a/Rocket/app/Camera/CameraController.py b/Rocket/app/Camera/CameraController.py
index 23fb528..c2a4843 100644
--- a/Rocket/app/Camera/CameraController.py
+++ b/Rocket/app/Camera/CameraController.py
@@ -4,9 +4,12 @@
import threading
from Enums.TimelineEnum import TimelineEnum
+from Enums.PinsEnum import PinsEnum
from DataStorage import DataStorage
from Camera.camera_driver import start_recording
import Camera.led_driver as led_driver
+from Telecoms.Signals import signal_utils
+
logging.basicConfig(
level=logging.INFO,
@@ -14,27 +17,33 @@
)
-async def run_camera_cycle(starting_time: float):
+async def run_camera_cycle():
"""Runs the camera cycle according to the timeline.
-
- Args:
- starting_time (float): The time at which the program started.
"""
logging.info("Starting camera cycle")
- while (time.perf_counter() - starting_time < TimelineEnum.SODS_ON.adapted_value):
- await DataStorage().save_camera_status(0)
- logging.debug("Camera is OFF")
+ while True:
+ if signal_utils.get_status_of_signal(PinsEnum.SODS):
+ break
+
+ await DataStorage().save_camera_status(1)
+ logging.info("Camera is on STANDBY")
+
+ logging.info("LEDS are OFF")
+ await DataStorage().save_led_status(0)
+
await asyncio.sleep(0.3)
led_driver.turn_on_led()
logging.info("LEDS are ON")
- # await DataStorage().save_led_status(1) # TODO: Implement this functionality
+ await DataStorage().save_led_status(1)
# NOTE: With the current fps reach this will use about 1.1GB of storage # IDK what timeline this followed
# This means that we can perform the full experiment cycle about 80 times before running out of storage
record_for = TimelineEnum.SODS_OFF.value - TimelineEnum.SODS_ON.value
+ time_when_started_recording = time.perf_counter()
+
try:
threading.Thread(
target=start_recording,
@@ -46,10 +55,15 @@ async def run_camera_cycle(starting_time: float):
await DataStorage().save_camera_status(3)
return
- while (time.perf_counter() - starting_time < TimelineEnum.SODS_OFF.adapted_value):
+ while (time.perf_counter() - time_when_started_recording < record_for):
await DataStorage().save_camera_status(2)
- logging.debug("Camera is RECORDING")
+ logging.info("Camera is RECORDING")
+
+ logging.info("LEDS are ON")
+ await DataStorage().save_led_status(1)
+
await asyncio.sleep(0.3)
+ await DataStorage().save_camera_status(0)
logging.info("Camera has STOPPED RECORDING")
logging.info("Finished camera cycle")
diff --git a/Rocket/app/DataStorage.py b/Rocket/app/DataStorage.py
old mode 100644
new mode 100755
index 9492dba..b15e99c
--- a/Rocket/app/DataStorage.py
+++ b/Rocket/app/DataStorage.py
@@ -43,9 +43,9 @@ def _create_db(self):
CREATE TABLE ROCKET_DATA (
time DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
- motor_speed INTEGER, -- The speed of the motor in (rpm?)
- sound_card_status INTEGER, -- The status of the sound card. Possible values: 0 = OFF, 1 = ON, 2 = RECORDING, 3 = ERROR
- camera_status INTEGER, -- The status of the camera. Possible values: 0 = OFF, 1 = ON, 2 = RECORDING, 3 = ERROR
+ motor_speed INTEGER, -- The speed of the motor. Possible values: 0 = OFF, 1 = ON
+ sound_card_status INTEGER, -- The status of the sound card. Possible values: 0 = FINISHED, 1 = STANDBY, 2 = RECORDING, 3 = ERROR
+ camera_status INTEGER, -- The status of the camera. Possible values: 0 = FINISHED, 1 = STANDBY, 2 = RECORDING, 3 = ERROR
temp_1 REAL, -- The temperature of the first sensor in (Celsius?)
temp_2 REAL, -- The temperature of the second sensor in (Celsius?)
temp_3 REAL, -- The temperature of the sound card sensor in (Kelvin)
@@ -54,6 +54,7 @@ def _create_db(self):
SOE_signal BOOLEAN, -- The status of the SOE signal. Possible values: 0 = OFF, 1 = ON
SODS_signal BOOLEAN, -- The status of the SODS signal. Possible values: 0 = OFF, 1 = ON
error_code INTEGER, -- The error code of the system in case of an error. Possible values: TBD
+ led_status INTEGER, -- The status of the LED. Possible values: 0 = OFF, 1 = ON
PRIMARY KEY (time)
);
''')
@@ -144,30 +145,29 @@ async def save_error_code(self, error_code: int):
await sqlu.add_error_code(cursor, error_code)
await db.commit()
- async def get_motor_speed(self) -> int | None:
- """Gets the speed of the motor from the database.
+ async def save_led_status(self, led_status: int):
+ """Adds the status of the LED to the database.
- Returns:
- int: The speed of the motor in (rpm?)
+ Args:
+ led_status (int): The status of the LED. Possible values: 0 = OFF, 1 = ON
"""
async with sql.connect(self.db_filename, timeout=10) as db:
cursor = await db.cursor()
- speed = await sqlu.get_motor_speed(cursor)
+ await sqlu.add_led_status(cursor, led_status)
await db.commit()
- return speed
-
- async def motor_has_been_activated_before(self) -> bool:
- """Checks if the motor has been activated before.
+ async def get_motor_speed(self) -> int | None:
+ """Gets the speed of the motor from the database.
Returns:
- bool: True if the motor has been activated before, False otherwise.
+ int: The speed of the motor in (rpm?)
"""
async with sql.connect(self.db_filename, timeout=10) as db:
cursor = await db.cursor()
- status = await sqlu.motor_has_been_activated_before(cursor)
+ speed = await sqlu.get_motor_speed(cursor)
+ await db.commit()
- return status
+ return speed
async def get_sound_card_status(self) -> int | None:
"""Gets the status of the sound card from the database.
@@ -182,23 +182,6 @@ async def get_sound_card_status(self) -> int | None:
return status
- async def get_temp_of_sensor_for_the_last_x_secs(self, sensor_num: int, secs_ago: int = 1) -> Iterable[Row] | None:
- """Gets the temperature of a specified sensor from the database.
-
- Args:
- sensor_num (int): The number of the sensor to get the temperature from.
- secs_ago (int, optional): The number of seconds ago to get the temperature from. Defaults to 1.
-
- Returns:
- float: The temperature of the specified sensor.
- """
- async with sql.connect(self.db_filename, timeout=10) as db:
- cursor = await db.cursor()
- temp = await sqlu.get_temp_of_sensor_for_the_last_x_secs(cursor, sensor_num, secs_ago)
- await db.commit()
-
- return temp
-
async def get_error_code(self) -> int | None:
"""Gets the error code of the system from the database.
diff --git a/Rocket/app/Enums/MotorSpeedsEnum.py b/Rocket/app/Enums/MotorSpeedsEnum.py
deleted file mode 100644
index d237980..0000000
--- a/Rocket/app/Enums/MotorSpeedsEnum.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from enum import Enum
-
-
-class MotorSpeedsEnum(Enum):
- """An enum to store the motor_util speeds."""
-
- STOP = 0
- FULL_SPEED = 255
-
-
-class MotorPWMSpeeds(Enum):
- """An enum to store the motor_util speeds."""
-
- STOP = 65535
- HALF_SPEED = 32768
- FULL_SPEED = 0
diff --git a/Rocket/app/Motor/MotorController.py b/Rocket/app/Motor/MotorController.py
new file mode 100644
index 0000000..8bb047f
--- /dev/null
+++ b/Rocket/app/Motor/MotorController.py
@@ -0,0 +1,64 @@
+import asyncio
+import time
+import logging
+import threading
+
+from Enums.TimelineEnum import TimelineEnum
+from Enums.PinsEnum import PinsEnum
+from DataStorage import DataStorage
+from Telecoms.Signals import signal_utils
+from Motor.motor_driver import run_motor
+
+
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
+ filename='rocket.log',
+ encoding='utf-8',
+ filemode='a'
+)
+
+
+async def run_motor_cycle():
+ """Runs the motor cycle according to the timeline.
+ """
+ logging.info("Starting motor cycle")
+
+ while True:
+ if signal_utils.get_status_of_signal(PinsEnum.LO):
+ break
+
+ await DataStorage().save_motor_speed(0)
+ logging.info("Motor is OFF")
+ await asyncio.sleep(0.3)
+
+ wait_for = TimelineEnum.START_MOTOR.value - TimelineEnum.LIFT_OFF.value
+
+ time_when_received_LO = time.perf_counter()
+
+ while (time.perf_counter() - time_when_received_LO < wait_for):
+ await DataStorage().save_motor_speed(0)
+ logging.info("Motor is OFF")
+ await asyncio.sleep(0.3)
+
+ run_motor_for = TimelineEnum.SOE_ON.value - TimelineEnum.START_MOTOR.value
+ logging.info(f"Motor will run for {run_motor_for} seconds")
+ await DataStorage().save_motor_speed(1)
+
+ threading.Thread(
+ target=run_motor,
+ args=(run_motor_for,),
+ daemon=True
+ ).start()
+
+ time_when_motor_started = time.perf_counter()
+
+ while (time.perf_counter() - time_when_motor_started < run_motor_for):
+ await DataStorage().save_motor_speed(1)
+ logging.info("Motor is ON")
+ await asyncio.sleep(0.3)
+
+ while (time.perf_counter() - time_when_received_LO < TimelineEnum.SODS_OFF.value):
+ await DataStorage().save_motor_speed(0)
+ logging.info("Motor is OFF")
+ await asyncio.sleep(0.3)
diff --git a/Rocket/app/Motor/motor_driver.py b/Rocket/app/Motor/motor_driver.py
new file mode 100644
index 0000000..6f0b6eb
--- /dev/null
+++ b/Rocket/app/Motor/motor_driver.py
@@ -0,0 +1,56 @@
+import logging
+import time
+import Jetson.GPIO as GPIO
+
+from Enums.PinsEnum import PinsEnum
+
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
+ filename='rocket.log',
+ encoding='utf-8',
+ filemode='a'
+)
+
+
+def run_motor(run_for: float):
+ """Runs the motor cycle.
+
+ Args:
+ run_for (float): The time to run the motor for.
+ """
+ logging.info("Starting motor cycle")
+
+ GPIO.setmode(GPIO.BOARD)
+
+ GPIO.setup(PinsEnum.MOTOR_CONTROL.value, GPIO.OUT)
+
+ time_passed = 0
+
+ while time_passed < run_for:
+ turn_on_motor()
+ time.sleep(0.5)
+ if time_passed + 0.5 > run_for:
+ turn_off_motor()
+ break
+ time_passed += 0.5
+
+ turn_off_motor()
+
+
+def turn_on_motor() -> None:
+ try:
+ GPIO.output(PinsEnum.MOTOR_CONTROL.value, GPIO.HIGH)
+ except Exception as e:
+ logging.error("An Error has occured in the LED Driver")
+ logging.error(e)
+ raise e
+
+
+def turn_off_motor() -> None:
+ try:
+ GPIO.output(PinsEnum.MOTOR_CONTROL.value, GPIO.LOW)
+ except Exception as e:
+ logging.error("An Error has occured in the LED Driver")
+ logging.error(e)
+ raise e
diff --git a/Rocket/app/SoundCard/SoundCardController.py b/Rocket/app/SoundCard/SoundCardController.py
index 948f8f2..893f704 100644
--- a/Rocket/app/SoundCard/SoundCardController.py
+++ b/Rocket/app/SoundCard/SoundCardController.py
@@ -6,29 +6,26 @@
from Enums.TimelineEnum import TimelineEnum
from DataStorage import DataStorage
-from SoundCard.motor_driver import run_motor_cycle_labjack, run_motor_cycle
from SoundCard.sound_card_driver import start_recording
-from Enums.MotorSpeedsEnum import MotorSpeedsEnum
from Enums.PinsEnum import PinsEnum
from Telecoms.Signals import signal_utils
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
+ filename='rocket.log',
+ encoding='utf-8',
+ filemode='a'
)
SCAN_FREQUENCY = 48000 # Hz
-async def run_sound_card_cycle(starting_time: float):
+async def run_sound_card_cycle():
"""Runs the sound card cycle according to the timeline.
This function is responsible for the control of the sound card which in turn controls:
- - The motor
- The thermistors
- The I-VED technique
-
- Args:
- starting_time (float): The time at which the program started.
"""
logging.info("Starting sound card cycle")
@@ -62,7 +59,44 @@ async def run_sound_card_cycle(starting_time: float):
await DataStorage().save_sound_card_status(3)
return
- while (time.perf_counter() - starting_time < TimelineEnum.SODS_OFF.adapted_value):
+ while True:
+ temperature_of_card = card.getTemperature() - 273.15 # Convert to Celsius
+
+ # FIXME: This is voltage and it needs to be converted to temperature by using the utils.thermistor_util
+ temperature_of_thermistor1 = card.getAIN(2)
+ temperature_of_thermistor2 = card.getAIN(3)
+
+ await DataStorage().save_temperature_of_sensor(temperature_of_card, 3)
+ await DataStorage().save_temperature_of_sensor(temperature_of_thermistor1, 1)
+ await DataStorage().save_temperature_of_sensor(temperature_of_thermistor2, 2)
+
+ await DataStorage().save_sound_card_status(1)
+ logging.info("I-VED is OFF")
+
+ await asyncio.sleep(0.3)
+
+ if signal_utils.get_status_of_signal(PinsEnum.SODS):
+ break
+
+ logging.info(
+ "Received SODS signal so now we will continue working for 380 seconds")
+
+ time_when_started_recording = time.perf_counter()
+
+ await DataStorage().save_sound_card_status(2)
+
+ record_for = TimelineEnum.SODS_OFF.adapted_value - \
+ TimelineEnum.SODS_ON.adapted_value
+
+ threading.Thread(
+ target=start_recording,
+ args=(card, record_for),
+ daemon=True
+ ).start()
+
+ logging.info("I-VED is ON and the sound card is RECORDING")
+
+ while (time.perf_counter() - time_when_started_recording < record_for):
temperature_of_card = card.getTemperature() - 273.15 # Convert to Celsius
@@ -74,52 +108,7 @@ async def run_sound_card_cycle(starting_time: float):
await DataStorage().save_temperature_of_sensor(temperature_of_thermistor1, 1)
await DataStorage().save_temperature_of_sensor(temperature_of_thermistor2, 2)
- ived_status = await DataStorage().get_sound_card_status()
- if time.perf_counter() - starting_time > TimelineEnum.SODS_ON.adapted_value and ived_status != 2:
- await DataStorage().save_sound_card_status(2)
-
- record_for = TimelineEnum.SODS_OFF.adapted_value - \
- TimelineEnum.SODS_ON.adapted_value
-
- threading.Thread( # TODO: Configure this
- target=start_recording,
- args=(card, record_for),
- daemon=True
- ).start()
-
- logging.info("I-VED is ON and the sound card is RECORDING")
- elif time.perf_counter() - starting_time < TimelineEnum.SODS_ON.adapted_value or time.perf_counter() - starting_time > TimelineEnum.SODS_OFF.adapted_value:
- await DataStorage().save_sound_card_status(1)
- logging.info("I-VED is OFF")
-
- motor_has_been_activated_before = await DataStorage().motor_has_been_activated_before()
- if time.perf_counter() - starting_time > TimelineEnum.START_MOTOR.adapted_value and not motor_has_been_activated_before:
- if signal_utils.get_status_of_signal(PinsEnum.LO):
- await DataStorage().save_motor_speed(MotorSpeedsEnum.FULL_SPEED.value)
-
- run_motor_for = TimelineEnum.SOE_ON.value - TimelineEnum.START_MOTOR.value
-
- # NOTE: This is the Electrical's PCB implementation
- threading.Thread(
- target=run_motor_cycle_labjack,
- args=(run_motor_for, card),
- daemon=True
- ).start()
-
- # NOTE: This is the Jim's PCB implementation
- # threading.Thread(
- # target=run_motor_cycle,
- # args=(run_motor_for,),
- # daemon=True
- # ).start()
-
- logging.info("Motor is ON and running at FULL_SPEED")
- else:
- await DataStorage().save_motor_speed(MotorSpeedsEnum.STOP.value)
- logging.info("LO signal is OFF, motor will not start")
- elif time.perf_counter() - starting_time < TimelineEnum.START_MOTOR.adapted_value or time.perf_counter() - starting_time > TimelineEnum.SOE_ON.adapted_value:
- await DataStorage().save_motor_speed(MotorSpeedsEnum.STOP.value)
- logging.info("Motor is OFF or has STOPPED")
+ await DataStorage().save_sound_card_status(2)
await asyncio.sleep(0.3)
diff --git a/Rocket/app/SoundCard/motor_driver.py b/Rocket/app/SoundCard/motor_driver.py
index a0cfa1f..e69de29 100644
--- a/Rocket/app/SoundCard/motor_driver.py
+++ b/Rocket/app/SoundCard/motor_driver.py
@@ -1,88 +0,0 @@
-import logging
-import u3
-import time
-import Jetson.GPIO as GPIO
-
-from Enums.MotorSpeedsEnum import MotorPWMSpeeds
-from Enums.PinsEnum import PinsEnum
-
-logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
-)
-
-
-def run_motor_cycle_labjack(run_for: float, device: u3.U3):
- """Runs the motor cycle.
-
- Args:
- starting_time (float): The time at which the program started.
- device (u3.U3): The device to run the motor cycle on (the sound card).
- """
- logging.info("Starting motor cycle")
- value = MotorPWMSpeeds.HALF_SPEED.value # 50% duty cycle
-
- config = u3.Timer1Config # Timer1Config is a class
-
- logging.info("Starting PWM at 50% duty cycle")
- device.getFeedback(config(TimerMode=1, Value=value))
-
- # Ramp up the motor speed slowly starting from 50% duty cycle so that we don't draw too much current
- for _ in range(4):
- time.sleep(0.5)
- value = int(value/4)
- device.getFeedback(config(TimerMode=1, Value=value))
- logging.info(
- f"Speed: {100 - int(value/MotorPWMSpeeds.STOP.value*100)} %")
-
- logging.info("Starting PWM at 100% duty cycle")
- device.getFeedback(config(TimerMode=1, Value=0))
-
- # 20 seconds of emulsification + 2 seconds of ramping up
- time.sleep(run_for - 2)
-
- logging.info("Stopping PWM")
- device.getFeedback(config(TimerMode=1, Value=MotorPWMSpeeds.STOP.value))
-
-
-def run_motor_cycle(run_for: float):
- """Runs the motor cycle.
-
- Args:
- run_for (float): The time to run the motor for.
- """
- logging.info("Starting motor cycle")
-
- GPIO.setmode(GPIO.BOARD)
-
- GPIO.setup(PinsEnum.MOTOR_CONTROL.value, GPIO.OUT)
-
- time_passed = 0
-
- while time_passed < run_for:
- turn_on_motor()
- time.sleep(0.5)
- if time_passed + 0.5 > run_for:
- turn_off_motor()
- break
- time_passed += 0.5
-
- turn_off_motor()
-
-
-def turn_on_motor() -> None:
- try:
- GPIO.output(PinsEnum.MOTOR_CONTROL.value, GPIO.HIGH)
- except Exception as e:
- logging.error("An Error has occured in the LED Driver")
- logging.error(e)
- raise e
-
-
-def turn_off_motor() -> None:
- try:
- GPIO.output(PinsEnum.MOTOR_CONTROL.value, GPIO.LOW)
- except Exception as e:
- logging.error("An Error has occured in the LED Driver")
- logging.error(e)
- raise e
diff --git a/Rocket/app/Telecoms/CommunicationsController.py b/Rocket/app/Telecoms/CommunicationsController.py
index 419aac0..eb583fa 100644
--- a/Rocket/app/Telecoms/CommunicationsController.py
+++ b/Rocket/app/Telecoms/CommunicationsController.py
@@ -8,6 +8,9 @@
from DataStorage import DataStorage
from Enums.ErrorCodesEnum import ErrorCodesEnum
from Enums.TimelineEnum import TimelineEnum
+from Enums.PinsEnum import PinsEnum
+import Telecoms.Signals.signal_utils as signal_utils
+
logging.basicConfig(
level=logging.INFO,
@@ -23,7 +26,7 @@
logging.info(f"Running on Jetson Nano and using {port}")
-async def run_telecoms_cycle(starting_time: float):
+async def run_telecoms_cycle():
"""Send and receive data from the serial port.
Args:
@@ -32,24 +35,53 @@ async def run_telecoms_cycle(starting_time: float):
_, writer = await open_serial_connection(url=port, baudrate=38400)
try:
+
while True:
- # Send the last saved data to the serial port
+ if signal_utils.get_status_of_signal(PinsEnum.LO):
+ break
+
data_to_send = await DataStorage().get_last_row_of_all_data()
- if data_to_send:
- logging.info(f"Sending data: {data_to_send}")
- writer.write(format_data_to_send(*data_to_send))
- await writer.drain()
+ try:
+ if data_to_send:
+ logging.info(f"Sending data: {data_to_send}")
+ writer.write(format_data_to_send(*data_to_send))
+
+ await writer.drain()
+
+ except Exception as e:
+ logging.error(f"Error in telecoms cycle: {e}")
+ await DataStorage().save_error_code(ErrorCodesEnum.CONNECTION_ERROR.value)
+ raise e
await asyncio.sleep(0.3) # 3 times per second
- if time.perf_counter() - starting_time > TimelineEnum.SODS_OFF.adapted_value:
- logging.info("Stopping the telecoms cycle...")
- break
+ logging.info(
+ "Received LO signal so now we will continue working for 380 seconds")
+
+ time_when_received_LO = time.perf_counter()
+
+ while (time.perf_counter() - time_when_received_LO < TimelineEnum.SODS_OFF.value):
+ data_to_send = await DataStorage().get_last_row_of_all_data()
+
+ try:
+ if data_to_send:
+ logging.info(f"Sending data: {data_to_send}")
+ writer.write(format_data_to_send(*data_to_send))
+
+ await writer.drain()
+
+ except Exception as e:
+ logging.error(f"Error in telecoms cycle: {e}")
+ await DataStorage().save_error_code(ErrorCodesEnum.CONNECTION_ERROR.value)
+ raise e
+
+ await asyncio.sleep(0.3) # 3 times per second
- except Exception as e:
- logging.error(f"Error in telecoms cycle: {e}")
- await DataStorage().save_error_code(ErrorCodesEnum.CONNECTION_ERROR.value)
+ finally:
+ logging.info("Finished telecoms cycle")
+ writer.close()
+ await writer.wait_closed()
@cache
diff --git a/Rocket/app/Telecoms/SignalsController.py b/Rocket/app/Telecoms/SignalsController.py
index 9480d50..9f819f2 100644
--- a/Rocket/app/Telecoms/SignalsController.py
+++ b/Rocket/app/Telecoms/SignalsController.py
@@ -12,16 +12,31 @@
)
-async def run_rocket_signals_cycle(starting_time: float):
+async def run_rocket_signals_cycle():
"""Runs the rocket signals cycle.
-
- Args:
- starting_time (float): The time at which the program started.
"""
logging.info("Starting rocket signals cycle")
- while time.perf_counter() - starting_time < TimelineEnum.SODS_OFF.adapted_value:
+
+ while True:
+ LO, SOE, SODS = signal_utils.get_signals()
+ await DataStorage().save_signals(LO, SOE, SODS)
+ logging.info(f"LO: {LO}, SOE: {SOE}, SODS: {SODS}")
+
+ await asyncio.sleep(0.3)
+
+ if LO == 1:
+ break
+
+ logging.info(
+ "Received LO signal so now we will continue working for 380 seconds")
+
+ time_when_received_LO = time.perf_counter()
+
+ while (time.perf_counter() - time_when_received_LO < TimelineEnum.SODS_OFF.value):
LO, SOE, SODS = signal_utils.get_signals()
await DataStorage().save_signals(LO, SOE, SODS)
logging.info(f"LO: {LO}, SOE: {SOE}, SODS: {SODS}")
await asyncio.sleep(0.3)
+
+ logging.info("Finished rocket signals cycle")
diff --git a/Rocket/app/__init__.py b/Rocket/app/__init__.py
old mode 100644
new mode 100755
diff --git a/Rocket/app/main.py b/Rocket/app/main.py
old mode 100644
new mode 100755
index 7c09193..fc1e177
--- a/Rocket/app/main.py
+++ b/Rocket/app/main.py
@@ -2,9 +2,9 @@
import asyncio
import logging
-import time
from Camera.CameraController import run_camera_cycle
+from Motor.MotorController import run_motor_cycle
from SoundCard.SoundCardController import run_sound_card_cycle
from Telecoms.CommunicationsController import run_telecoms_cycle
from Telecoms.SignalsController import run_rocket_signals_cycle
@@ -16,8 +16,6 @@
async def main():
- # NOTE: This should be the same as POWER_ON during flight_mode or we should sync them up somehow
- time_at_start_of_program = time.perf_counter()
logging.info('''
========================================
@@ -25,10 +23,11 @@ async def main():
========================================''')
await asyncio.gather(
- run_rocket_signals_cycle(time_at_start_of_program),
- run_sound_card_cycle(time_at_start_of_program),
- run_camera_cycle(time_at_start_of_program),
- run_telecoms_cycle(time_at_start_of_program),
+ run_rocket_signals_cycle(),
+ run_sound_card_cycle(),
+ run_camera_cycle(),
+ run_telecoms_cycle(),
+ run_motor_cycle()
)
diff --git a/Rocket/app/utils/data_handling_utils.py b/Rocket/app/utils/data_handling_utils.py
index 456b431..e69de29 100644
--- a/Rocket/app/utils/data_handling_utils.py
+++ b/Rocket/app/utils/data_handling_utils.py
@@ -1,23 +0,0 @@
-import asyncio
-import numpy as np
-import logging
-
-from DataStorage import DataStorage
-
-logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
-)
-
-logging.captureWarnings(True)
-
-
-async def get_avg_temp_of_sensors() -> tuple[float, float]:
- """Returns the average temperature of the two temperature sensors.
-
- Returns:
- float: The average temperature of the two temperature sensors.
- """
- temp0_list, temp1_list = await asyncio.gather(*[DataStorage().get_temp_of_sensor_for_the_last_x_secs(i) for i in range(1, 3)])
-
- return np.average(temp0_list), np.average(temp1_list)
diff --git a/Rocket/app/utils/sql_utils.py b/Rocket/app/utils/sql_utils.py
index 14662e5..b138fa4 100644
--- a/Rocket/app/utils/sql_utils.py
+++ b/Rocket/app/utils/sql_utils.py
@@ -8,7 +8,7 @@
format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
)
-accepted_signal_names = ['LO', 'SOE', 'SODS', 'PO']
+accepted_signal_names = ['LO', 'SOE', 'SODS']
async def add_motor_speed(cursor: aiosqlite.Cursor, motor_speed: int):
@@ -180,120 +180,6 @@ async def add_camera_status(cursor: aiosqlite.Cursor, camera_status: int):
f"Updated the timestamp '{earliest_time}' with camera status: {camera_status}")
-async def add_cell_heater_status(cursor: aiosqlite.Cursor, cell_heater_status: bool):
- """Adds the heater status to the database by first checking when the heater status has been added in the last second.
- If it hasn't been added in the last second, it inserts a new row with the new heater status. If it has been added in the last second,
- it updates the earliest row with the new heater status.
-
- Args:
- cursor (aiosqlite.Cursor): The cursor of the database.
- cell_heater_status (bool): The heater status to be added to the database.
- """
- results = await cursor.execute("""
- SELECT cell_heater_status, time
- FROM rocket_data
- WHERE strftime('%s', time) = strftime('%s', 'now')
- ORDER BY time DESC
- """)
-
- results = await results.fetchall()
-
- if not results:
- await cursor.execute("""
- INSERT INTO rocket_data (cell_heater_status) VALUES (?)
- """, (cell_heater_status,))
- logging.debug(
- f'Added a new row with heater status: {cell_heater_status}')
- else:
-
- # This variable will declare the earliest time in which the heater status was None.
- earliest_time = None
-
- for row in results:
- prev_cell_heater_status, last_time = row
-
- if prev_cell_heater_status is not None:
- if earliest_time is not None:
- await cursor.execute("""
- UPDATE rocket_data SET cell_heater_status = ? WHERE time = ?
- """, (cell_heater_status, earliest_time))
- logging.debug(
- f"Updated the timestamp '{earliest_time}' with heater status: {cell_heater_status}")
- break
- await cursor.execute("""
- INSERT INTO rocket_data (cell_heater_status) VALUES (?)
- """, (cell_heater_status,))
- logging.debug(
- f'Added a new row with heater status: {cell_heater_status}')
- break
- else:
- earliest_time = last_time
- continue
- else:
- await cursor.execute("""
- UPDATE rocket_data SET cell_heater_status = ? WHERE time = ?
- """, (cell_heater_status, earliest_time))
- logging.debug(
- f"Updated the timestamp '{earliest_time}' with heater status: {cell_heater_status}")
-
-
-async def add_electronics_heater_status(cursor: aiosqlite.Cursor, electronics_heater_status: bool):
- """Adds the heater status to the database by first checking when the heater status has been added in the last second.
- If it hasn't been added in the last second, it inserts a new row with the new heater status. If it has been added in the last second,
- it updates the earliest row with the new heater status.
-
- Args:
- cursor (aiosqlite.Cursor): The cursor of the database.
- electronics_heater_status (bool): The heater status to be added to the database.
- """
- results = await cursor.execute("""
- SELECT electronics_heater_status, time
- FROM rocket_data
- WHERE strftime('%s', time) = strftime('%s', 'now')
- ORDER BY time DESC
- """)
-
- results = await results.fetchall()
-
- if not results:
- await cursor.execute("""
- INSERT INTO rocket_data (electronics_heater_status) VALUES (?)
- """, (electronics_heater_status,))
- logging.debug(
- f'Added a new row with heater status: {electronics_heater_status}')
- else:
-
- # This variable will declare the earliest time in which the heater status was None.
- earliest_time = None
-
- for row in results:
- prev_electronics_heater_status, last_time = row
-
- if prev_electronics_heater_status is not None:
- if earliest_time is not None:
- await cursor.execute("""
- UPDATE rocket_data SET electronics_heater_status = ? WHERE time = ?
- """, (electronics_heater_status, earliest_time))
- logging.debug(
- f"Updated the timestamp '{earliest_time}' with heater status: {electronics_heater_status}")
- break
- await cursor.execute("""
- INSERT INTO rocket_data (electronics_heater_status) VALUES (?)
- """, (electronics_heater_status,))
- logging.debug(
- f'Added a new row with heater status: {electronics_heater_status}')
- break
- else:
- earliest_time = last_time
- continue
- else:
- await cursor.execute("""
- UPDATE rocket_data SET electronics_heater_status = ? WHERE time = ?
- """, (electronics_heater_status, earliest_time))
- logging.debug(
- f"Updated the timestamp '{earliest_time}' with heater status: {electronics_heater_status}")
-
-
async def add_temp_to_sensor(cursor: aiosqlite.Cursor, temp: float, sensor_num: int):
"""Adds the temperature of a specified sensor to the database by first checking when the temperature of that sensor has been added in the last second.
If it hasn't been added in the last second, it inserts a new row with the new temperature. If it has been added in the last second,
@@ -351,64 +237,6 @@ async def add_temp_to_sensor(cursor: aiosqlite.Cursor, temp: float, sensor_num:
f"Updated the timestamp '{earliest_time}' with temperature of sensor {sensor_num}: {temp}")
-async def add_pressure_to_sensor(cursor: aiosqlite.Cursor, pressure: float, sensor_num: int):
- """Adds the pressure of a specified sensor to the database by first checking when the pressure of that sensor has been added in the last second.
- If it hasn't been added in the last second, it inserts a new row with the new pressure. If it has been added in the last second,
- it updates the earliest row with the new pressure.
-
- Args:
- cursor (aiosqlite.Cursor): The cursor of the database.
- pressure (float): The pressure of the sensor to be added to the database.
- sensor_num (int): The number of the sensor to be added to the database.
- """
- results = await cursor.execute("""
- SELECT pressure_{}, time
- FROM rocket_data
- WHERE strftime('%s', time) = strftime('%s', 'now')
- ORDER BY time DESC
- """.format(sensor_num))
-
- results = await results.fetchall()
-
- if not results:
- await cursor.execute("""
- INSERT INTO rocket_data (pressure_{}) VALUES (?)
- """.format(sensor_num), (pressure,))
- logging.debug(
- f'Added a new row with pressure of sensor {sensor_num}: {pressure}')
- else:
-
- # This variable will declare the earliest time in which the pressure of the sensor was None.
- earliest_time = None
-
- for row in results:
- prev_pressure, last_time = row
-
- if prev_pressure is not None:
- if earliest_time is not None:
- await cursor.execute("""
- UPDATE rocket_data SET pressure_{} = ? WHERE time = ?
- """.format(sensor_num), (pressure, earliest_time))
- logging.debug(
- f"Updated the timestamp '{earliest_time}' with pressure of sensor {sensor_num}: {pressure}")
- break
- await cursor.execute("""
- INSERT INTO rocket_data (pressure_{}) VALUES (?)
- """.format(sensor_num), (pressure,))
- logging.debug(
- f'Added a new row with pressure of sensor {sensor_num}: {pressure}')
- break
- else:
- earliest_time = last_time
- continue
- else:
- await cursor.execute("""
- UPDATE rocket_data SET pressure_{} = ? WHERE time = ?
- """.format(sensor_num), (pressure, earliest_time))
- logging.debug(
- f"Updated the timestamp '{earliest_time}' with pressure of sensor {sensor_num}: {pressure}")
-
-
async def add_signal_status(cursor: aiosqlite.Cursor, signal_status: bool, signal_name: str):
"""Adds the status of a specified signal to the database by first checking when the status of that signal has been added in the last second.
If it hasn't been added in the last second, it inserts a new row with the new signal status. If it has been added in the last second,
@@ -483,6 +311,58 @@ async def add_error_code(cursor: aiosqlite.Cursor, error_code: int):
logging.debug(f'Added a new row with error code: {error_code}')
+async def add_led_status(cursor: aiosqlite.Cursor, led_status: int):
+ """Adds the status of the LED to the database.
+
+ Args:
+ cursor (aiosqlite.Cursor): The cursor of the database.
+ led_status (int): The status of the LED. Possible values: 0 = OFF, 1 = ON
+ """
+ results = await cursor.execute("""
+ SELECT led_status, time
+ FROM rocket_data
+ WHERE strftime('%s', time) = strftime('%s', 'now')
+ ORDER BY time DESC
+ """)
+ results = await results.fetchall()
+
+ if not results:
+ await cursor.execute("""
+ INSERT INTO rocket_data (led_status) VALUES (?)
+ """, (led_status,))
+ logging.debug(f'Added a new row with LED status: {led_status}')
+ else:
+
+ # This variable will declare the earliest time in which the LED status was None.
+ earliest_time = None
+
+ for row in results:
+ prev_led_status, last_time = row
+
+ if prev_led_status is not None:
+ if earliest_time is not None:
+ await cursor.execute("""
+ UPDATE rocket_data SET led_status = ? WHERE time = ?
+ """, (led_status, earliest_time))
+ logging.debug(
+ f"Updated the timestamp '{earliest_time}' with LED status: {led_status}")
+ break
+ await cursor.execute("""
+ INSERT INTO rocket_data (led_status) VALUES (?)
+ """, (led_status,))
+ logging.debug(f'Added a new row with LED status: {led_status}')
+ break
+ else:
+ earliest_time = last_time
+ continue
+ else:
+ await cursor.execute("""
+ UPDATE rocket_data SET led_status = ? WHERE time = ?
+ """, (led_status, earliest_time))
+ logging.debug(
+ f"Updated the timestamp '{earliest_time}' with LED status: {led_status}")
+
+
async def get_motor_speed(cursor: aiosqlite.Cursor) -> int | None:
"""Returns the motor speed from the database.
@@ -517,45 +397,6 @@ async def get_sound_card_status(cursor: aiosqlite.Cursor) -> int | None:
return status
-async def motor_has_been_activated_before(cursor: aiosqlite.Cursor) -> bool:
- """Returns True if the motor has been activated before, False otherwise.
-
- Args:
- cursor (aiosqlite.Cursor): The cursor of the database.
-
- Returns:
- bool: True if the motor has been activated before, False otherwise.
- """
- results = await cursor.execute("""
- SELECT motor_speed FROM rocket_data WHERE motor_speed <> 0
- """)
- results = await results.fetchall()
- return True if results else False
-
-
-async def get_temp_of_sensor_for_the_last_x_secs(cursor: aiosqlite.Cursor, sensor_num: int, secs_ago: int = 1) -> Iterable[Row] | None:
- """Returns the temperature of the specified sensor from the database.
-
- Args:
- cursor (aiosqlite.Cursor): The cursor of the database.
- sensor_num (int): The number of the sensor to be added to the database.
- secs_ago (int, optional): The number of seconds ago to get the temperature from. Defaults to 1.
-
- Returns:
- float: The temperature of the specified sensor from the database.
- """
- results = await cursor.execute(f"""
- SELECT temp_{sensor_num}
- FROM rocket_data
- WHERE temp_{sensor_num} IS NOT NULL
- AND time > datetime('now', '-{secs_ago} seconds')
- ORDER BY time DESC
- """)
- results = await results.fetchall()
- temp = results if results is not None else None
- return temp
-
-
async def get_error_code(cursor: aiosqlite.Cursor) -> int | None:
"""Returns the error code from the database.
diff --git a/Rocket/archive/test_thermi.py b/Rocket/archive/test_thermi.py
new file mode 100644
index 0000000..d9c1035
--- /dev/null
+++ b/Rocket/archive/test_thermi.py
@@ -0,0 +1,24 @@
+from math import exp, log
+
+
+def theoretic_resistance(T: float):
+
+ r0 = 10000 # temperature at 25 Celcious
+ B = 3984 # Beta value
+ TK = T + 273.5
+ # θεωρητικη τιμη αντιστασης
+ resistance_th = r0 * exp(B*((1/TK)-(1/298.15)))
+
+ return resistance_th
+
+
+def convert_volt_temp(voltage1: float):
+
+ r0 = 10000 # temperature at 25 Celcious
+ B = 3984 # Beta value
+
+ Rth = (5 - voltage1) / 43.6e-5
+ TK = 1 / ((log(Rth/r0) / B)+(1/298.15))
+ T = TK - 273.5
+
+ return T