@@ -6,12 +6,18 @@ Poeles-Dragon-Calculator (PoDoCor) est un logiciel d'expérimentation développ | |||
Pour l'instant il n'existe pas d'interface graphique, de plus il n'existe qu'en français. Cela sera développé plus tard. | |||
Ce logiciel est développé pour Linux avec python3 et un arduino. Les autres plateformes viendront plus tard. | |||
Ce logiciel est développé pour Linux avec python3 et Arduino. Les autres plateformes viendront plus tard. | |||
## Utilisation et fonctionnement | |||
Au démarrage, le logiciel crée un dossier "data" à la racine du dossier de PoDoCor, où se trouve le script principal; dans ce dossier se trouveront toutes les données au format CSV. | |||
Le logiciel extraie les données brutes que renvoie l'Arduino: si l'Arduino extraie la valeur 342 à la suite d'une conversion analogique-numérique, ce sera cette valeur qui sera transmise. Le CSV ne contient donc que des données qu'il est nécessaire de traiter, en particulier si les capteurs utilisés nécessitent l'utilisation d'une table de conversion ou d'un étalonnage, ces opérations devront être effectuées avant de lancer PoDoCor. Il est prévu néanmoins, dans une future version, d'inclure la phase d'initialisation dans le processus. | |||
Si aucun fichier n'est déjà créé, ou s'il ne contient aucune déclaration de capteur, le logiciel en demandera la création au démarrage. | |||
Le menu principal propose de commencer l'enregistrement des données ou de gérer les capteurs; le sous-menu permet d'afficher les capteurs enregistrés, d'en ajouter ou supprimer, et de changer l'ordre des capteurs pour correspondre à l'ordre des données envoyées par l'Arduino | |||
Pour que le logiciel fonctionne, il est nécessaire de déclarer les capteurs utilisés: leur nom, l'unité dans laquelle il mesure, et une variable (0 ou 1) pour savoir si l'Arduino envoie des données brutes de ce capteur (i.e. une simple conversion analogique-numérique, sans mapping des données acquises), ou si ce sont les données normalisées que renvoie l'Arduino (une température par exemple). Lors de cette création de capteurs, ne JAMAIS utiliser de virgule (","), sans quoi le logiciel s'arrêterait pour ses futures initialisations. | |||
Concernant les données simplement converties en numérique (si l'Arduino extraie la valeur 342 à la suite d'une conversion analogique-numérique par exemple), ce sera cette valeur qui sera transmise. Le CSV contient donc à la fois des données brutes et normalisées; les données brutes nécessiteront donc un traitement, en particulier si les capteurs utilisés nécessitent l'utilisation d'une table de conversion ou d'un étalonnage, ces opérations devront être effectuées avant de lancer PoDoCor. Il est prévu néanmoins, dans une future version, d'inclure la phase d'initialisation dans le processus. | |||
Une fois le logiciel démarré, le démarrage du processus d'enregistrement des données démarre en utilisant Shift+P; de même, ce processus s'arrête en utilisant Shift+P. |
@@ -10,7 +10,7 @@ class Arduino_data(): | |||
self.nb_captor_signals = 0 | |||
self.data_file_path = '' | |||
self.data_array = np.empty((1,1)) | |||
self.data_path_dir = os.path.abspath(os.path.dirname(__file__)) + "/data" | |||
self.data_path_dir = os.path.abspath(os.path.dirname(__file__)) + "/../data" | |||
if(not(os.path.isdir(self.data_path_dir))): #creer dossier si non existant | |||
os.mkdir(self.data_path_dir, 0o777) | |||
self.raw_data_temp = [[]] | |||
@@ -27,28 +27,101 @@ class Arduino_data(): | |||
else: | |||
lines = captors_file.readlines() | |||
self.nb_captor_signals = len(lines) | |||
if(self.nb_captor_signals == 0): | |||
captors_file.close() | |||
print("Ajoutez au moins 1 capteur avant de commencer:\n") | |||
self.add_captor_manually(file) | |||
captors_file = open(file, "r") | |||
lines = captors_file.readlines() | |||
self.nb_captor_signals = len(lines) | |||
self.data_array = np.empty((1,self.nb_captor_signals)) | |||
for i in range(self.nb_captor_signals): | |||
captor_line = lines[i] | |||
capt = Captor_data(); | |||
capt.read_captor(captor_line) | |||
captors_file.close() | |||
self.raw_data_temp = np.empty((1,self.nb_captor_signals)) | |||
def add_captor_manually(self, file): | |||
self.nb_captor_signals += 1 | |||
capt = Captor_data() | |||
coma = "," | |||
capt.captor_name = str(input("Nom du capteur : ")) | |||
while(capt.captor_name.find(coma) != -1): | |||
capt.captor_name = str(input("Nom du capteur ("," non accepté): ")) | |||
capt.unit = str(input("Unité : ")) | |||
while(capt.unit.find(coma) != -1): | |||
capt.unit = str(input("Unité (\",\" non accepté): ")) | |||
capt.data_type = -1 | |||
while(capt.data_type <= -1 or capt.data_type >= 2): | |||
capt.data_type = int(input("Type de données : 0 (raw) ou 1 (real): ")) | |||
captors_file = open(file, "a") | |||
captors_file.write(".\n") | |||
captors_file.write(capt.captor_file_line()) | |||
captors_file.close() | |||
self.raw_data_temp.append([]) | |||
np.append(self.raw_data_temp, []) | |||
self.data_array = np.empty((1,self.nb_captor_signals)) | |||
print("Capteur ajouté") | |||
def captors_print_list(self, file): | |||
captors_file = open(file, "r") | |||
print(" Nom Unit Type(raw/real)") | |||
for i in range(self.nb_captor_signals): | |||
print("Capteur n°" + str(i+1) + " : " + str(captors_file.readline())) | |||
captors_file.close() | |||
def extract_data_to_array(self, raw_data_txt): | |||
def del_captor(self, file): | |||
self.captors_print_list(file) | |||
captor_to_del = int(input("\nNumero du capteur a supprimer : "))-1 | |||
captors_file = open(file, "r") | |||
lines = captors_file.readlines(); | |||
captors_file.close() | |||
captors_file = open(file, "w") | |||
for i in range(self.nb_captor_signals): | |||
carac_coma_nb = 1 | |||
while((raw_data_txt[carac_coma_nb] != ',') or (raw_data_txt[carac_coma_nb:carac_coma_nb+2] != "\n")): #fin de la donnee ou de la ligne | |||
carac_coma_nb +=1 | |||
single_data = int(raw_data_txt[0:carac_coma_nb]) | |||
raw_data_txt = raw_data_txt[carac_coma_nb+1:] | |||
self.raw_data_temp[0,i] = single_data | |||
if(i != captor_to_del): | |||
captor_line = lines[i] | |||
captors_file.write(captor_line) | |||
else: | |||
break; | |||
captors_file.close() | |||
self.nb_captor_signals = self.nb_captor_signals-1 | |||
def change_captors_order(self, file): | |||
self.captors_print_list(file) | |||
captors_file = open(file, "r") | |||
lines = captors_file.readlines(); | |||
captors_file.close() | |||
captors_order = [] | |||
print("Assigner ligne par ligne les anciens numéros de capteur à leur nouvelle place:") | |||
for i in range(self.nb_captor_signals): | |||
captors_order.append(int(input("nouveau n°" + str(i+1) + " : ancien n° : "))) | |||
captors_file = open(file, "w") | |||
for i in range(self.nb_captor_signals): | |||
captor_line = lines[captors_order[i]-1] | |||
captors_file.write(captor_line) | |||
captors_file.close() | |||
print("\nNouvel ordre des capteurs") | |||
self.captors_print_list(file) | |||
def extract_data_to_array(self, raw_data_txt): | |||
coma = "," | |||
coma_places = raw_data_txt.find(coma) | |||
if(coma_places == -1 and len(raw_data_txt) < 2): | |||
print("Donnees non transmises par l'Arduino.") | |||
elif(coma_places == -1 and len(raw_data_txt) > 2): | |||
raw_data_temp[0,0] = int(raw_data_txt) | |||
if(len(coma_places) != self.nb_captor_signals-1): | |||
if(len(coma_places) < self.nb_captor_signals-1): | |||
print("Il y a moins de donnees transmises que de capteurs. Vérifiez les donnees transmises.") | |||
else: | |||
print("Il y a plus de donnees transmises que de capteurs.\nLes " + str(len(coma_places)-self.nb_captor_signals-1) + " donnees de fin seront supprimees") | |||
else: | |||
coma_places.insert(0,0) | |||
coma_places.append(len(raw_data_txt)) | |||
for i in range(min(len(coma_places)-1, self.nb_captor_signals)): | |||
self.raw_data_temp[0,i] = int(raw_data_txt[coma_places[i]:coma_places[i+1]]) | |||
np.append(self.data_array, raw_data_temp, axis=1) | |||
def create_data_file(self): | |||
@@ -60,3 +133,42 @@ class Arduino_data(): | |||
file = open(self.data_file_path,"a") #mode append | |||
file.write(data) | |||
file.close() | |||
class Captor_data(): | |||
def __init__(self): | |||
self.captor_name = "" | |||
self.unit = "" | |||
self.data_type = 0 #type possibles : donnee brute raw a convertir (0), donnees reelles utilisables en l'etat (1) | |||
def set_captor_name(self, name): | |||
self.captor_name = name | |||
def set_unit(self, unit): | |||
self.unit = unit | |||
def set_data_type(self, data_type): | |||
self.data_type = data_type | |||
def read_captor(self, line): | |||
for j in range(3): | |||
carac_coma_nb = 1 | |||
while((line[carac_coma_nb] != ',') and (line[carac_coma_nb:carac_coma_nb+2] != "\n")): #fin de la donnee ou de la ligne | |||
carac_coma_nb +=1 | |||
if(j == 0): | |||
self.captor_name = line[0:carac_coma_nb] | |||
elif(j == 1): | |||
self.unit = line[0:carac_coma_nb] | |||
elif(j == 2): | |||
self.data_type = int(line[0:carac_coma_nb]) | |||
line = line[carac_coma_nb+1:] | |||
def captor_string(self): | |||
type_txt = ["raw", "real"] | |||
return self.captor_name + "(" + self.unit + " " + type_txt[self.data_type] + ")" | |||
def captor_file_line(self): | |||
return self.captor_name + "," + self.unit + "," + str(self.data_type) + "\n" |
@@ -4,13 +4,13 @@ if(os.name == "posix"): | |||
else: | |||
import msvcrt as gt | |||
def press_key(caracter, actual_state, future_state): | |||
""" Cette fonction sert à détecter si le caractère est pressé, pour passer | |||
d'un état (ou boucle) à un autre.""" | |||
def press_key(caracters, numbers, actual): | |||
""" Cette fonction sert à détecter si un caractère est pressé, pour passer d'un | |||
état (numbers) à un autre.""" | |||
pressed_key = gt.getch() #detection de touche pressee (arret procedure acquisition) | |||
if(pressed_key == caracter): | |||
flag_data = future_state | |||
place = caracters.find(pressed_key) | |||
if(place == -1): | |||
return actual | |||
else: | |||
flag_data = actual_state | |||
return flag_data | |||
return numbers[place] |
@@ -2,102 +2,102 @@ import serial | |||
import numpy as np | |||
import matplotlib.pyplot as plt | |||
import os | |||
if(os.name == "posix"): | |||
import getch as gt #clavier | |||
else: | |||
import msvcrt as gts | |||
import time | |||
import bin.functions as fc | |||
import bin.data as data | |||
#Variables principales | |||
serial_path = '/dev/ttyUSB0' | |||
script_path = os.path.abspath(os.path.dirname(__file__)) | |||
data_path_dir = script_path + "/data" | |||
data_nb = 10 | |||
captors_path = os.path.abspath(os.path.dirname(__file__)) + "/captors.txt" | |||
#Variables cachees | |||
flag_data = 0 | |||
flag_data = False | |||
data_buff_max = 10 | |||
data_buff_nb = 0 | |||
data_buff = "" | |||
pressed_key = '' | |||
full_rec_data = np.empty((1,data_nb)) | |||
raw_data_temp = np.empty((1, data_nb)) | |||
flag_exception_serial = 0 | |||
flag_state = 1 # etat neutre | |||
#Programme principal | |||
#init | |||
#creer dossier si non existant | |||
if(not(os.path.isdir(data_path_dir))): | |||
os.mkdir(data_path_dir, 0o777) | |||
try: | |||
arduino_ser = serial.Serial(serial_path, 9600) #communication avec Arduino | |||
except serial.serialutil.SerialException: | |||
print("SerialException : la carte Arduino n'est pas connectee ou est connectee sur au autre port.\nFermeture du programme.") | |||
flag_exception_serial = 1 | |||
while(1 and flag_exception_serial == 0): | |||
pressed_key = gt.getch() #detection de touche pressee (demarrage procedure acquisition) | |||
if(pressed_key == 'P'): | |||
flag_data = 1 | |||
print("SerialException : la carte Arduino n'est pas connectee ou est connectee sur au autre port.") | |||
flag_state = -1 | |||
else: | |||
arduino_data = data.Arduino_data() | |||
arduino_data.add_captors_from_file(captors_path) | |||
print("PoDoCor est pret a enregistrer les donnees") | |||
while(flag_state > 0): | |||
if(flag_state == 1): | |||
print("_________________________________\n\nMAJ + P : Enregistrement des donnees\nMAJ + N : Gerer les capteurs\nMAJ + X : Arrêt du programme (ne fonctionne pas pendant l'enregistrement)\n_________________________________\n") | |||
flag_state = fc.press_key('XPN', [0, 2, 3], flag_state) #detection de touche pressee (demarrage procedure acquisition) | |||
elif(flag_state == 3): | |||
print(" _________________________________\n MAJ + U : Lister les capteurs\n MAJ + A : Ajouter un capteur\n MAJ + E : Supprimer un capteur\n MAJ + T : Changer l'ordre des capteurs\n MAJ + Q : Menu principal\n _________________________________\n") | |||
flag_state = fc.press_key('AETUQ', [31, 32, 33, 34, 1], flag_state) #detection de touche pressee (demarrage procedure acquisition) | |||
if(flag_state == 31): | |||
arduino_data.add_captor_manually(captors_path) | |||
flag_state = 3 | |||
elif(flag_state == 32): | |||
arduino_data.del_captor(captors_path) | |||
flag_state = 3 | |||
elif(flag_state == 33): | |||
arduino_data.change_captors_order(captors_path) | |||
flag_state = 3 | |||
elif(flag_state == 34): | |||
arduino_data.captors_print_list(captors_path) | |||
flag_state = 3 | |||
elif(flag_state == 2): | |||
data_buff_nb = 0 | |||
data_path_file = data_path_dir + "/" + time.asctime()+".csv" | |||
file = open(data_path_file, "w") | |||
file.close() | |||
else: | |||
flag_data = 0 | |||
while(flag_data == 1 and flag_exception_serial == 0): #boucle de reception des donnees | |||
arduino_ser.write(1) #envoi de '1' a l'Arduino | |||
raw_data_txt = arduino_ser.readline() #format des donnees: data1,data2,data3\n raw data | |||
#print(raw_data_txt) | |||
if(raw_data_txt == ''): # si aucune donnée reçue | |||
print("Arduino n'envoie aucune donnee, veuillez verifier le code televerse.") | |||
flag_data = 1 | |||
data_buff_nb = 0 | |||
else: | |||
data_buff_nb +=1 | |||
data_buff = data_buff + str(raw_data_txt) + "\n" #add 1 data line in buffer | |||
print("a\n"+data_buff) | |||
arduino_data.create_data_file() | |||
while(flag_state == 2): #boucle de reception des donnees | |||
time_0 = time.time() | |||
arduino_ser.write(1) #envoi de '1' a l'Arduino | |||
time.sleep(time_0+0.5-time.time()) | |||
time_1 = time_0+0.5 | |||
raw_data_txt = arduino_ser.readline() #format des donnees: data1,data2,data3\n raw data | |||
print(raw_data_txt) | |||
if(raw_data_txt == ''): # si aucune donnée reçue | |||
print("Arduino n'envoie aucune donnee, veuillez verifier le code televerse.") | |||
flag_state = -1 | |||
data_buff_nb = 0 | |||
else: | |||
data_buff_nb +=1 | |||
data_buff = data_buff + str(raw_data_txt) + "\n" #add 1 data line in buffer | |||
#procedure extraction donnees pour affichage | |||
for i in range(data_nb): | |||
carac_coma_nb = 1 | |||
while((raw_data_txt[carac_coma_nb] != ',') or (raw_data[carac_coma_nb:carac_coma_nb+2] != "\n")): #fin de la donnee ou de la ligne | |||
carac_coma_nb +=1 | |||
single_data = int(raw_data_txt[0:carac_coma_nb]) | |||
raw_data_txt = raw_data_txt[carac_coma_nb+1:] | |||
raw_data_temp[0,i] = single_data | |||
np.append(full_rec_data, raw_data, axis=1) | |||
raw_data_temp = raw_data*0 | |||
arduino_data.extract_data_to_array(raw_data_txt) | |||
# procedure d'ecriture fichier | |||
if(data_buff_nb == data_buff_max): | |||
file = open(data_path_file,"a") #mode append | |||
file.write(data_buff) | |||
file.close() | |||
arduino_data.append_data_to_file(data_buff) | |||
data_buff = "" #remise a zero | |||
data_buff_nb = 0 | |||
pressed_key = gt.getch() #detection de touche pressee (arret procedure acquisition) | |||
if(pressedKey == 'P'): | |||
flag_data = 0 | |||
else: | |||
flag_data = 1 | |||
flag_state = fc.press_key('P', [1], flag_state) | |||
time.sleep(time_1+0.5-time.time()) | |||
print(time.time()) | |||
# while end | |||
if(data_buff_nb > 0): #vidage du buffer | |||
arduino_data.ppend_data_to_file(self, data_buff) | |||
data_buff = "" | |||
data_buff_nb = 0 | |||
assert pressed_key != 'P' "Sortie de la boucle de reception des donnees" | |||
arduino_ser.close() | |||
assert flag_data == True, "Sortie de la boucle de reception des donnees" | |||
if(data_buff_nb > 0): | |||
file = open(file_name,"a") | |||
file.write(data_buff) | |||
file.close() | |||
data_buff = "" | |||
data_buff_nb = 0 | |||
arduino_ser.close() | |||
elif(flag_state == 0): | |||
break | |||
print("Fermeture du programme.") |