@@ -0,0 +1,125 @@ | |||
/***************************************************************************************************************************** | |||
Auteur : FDES et LilianRM | |||
Pour LowTech Bordeaux | |||
Exemple de fichier Arduino pour 5 capteurs: | |||
- 1 capteur multicanaux, I2C (4 capteurs) | |||
- 1 capteur O2, analogique | |||
- 1 capteur CO2 MH-Z19B, UART (+ température intégrée) | |||
- 1 thermocouple, lecture analogique | |||
- 1 sonde de température Onewire, numérique. | |||
*****************************************************************************************************************************/ | |||
// setup des librairies et des variables globales | |||
#include <Arduino.h> | |||
#include <High_Temp.h> | |||
#include <OneWire.h> | |||
#include <DallasTemperature.h> | |||
#include <Multichannel_Gas_GMXXX.h> | |||
#include <Wire.h> | |||
GAS_GMXXX<TwoWire> gas; | |||
#include <SoftwareSerial.h> | |||
#include <MHZ.h> | |||
int MHZ19B_PREHEATING_TIME = 3 * 60; | |||
#define O2_WIRE A2 | |||
#define ONE_WIRE_BUS 2 | |||
HighTemp ht(A1, A0); | |||
OneWire oneWire(ONE_WIRE_BUS); | |||
DallasTemperature dallasTemp(&oneWire); | |||
uint8_t tempAddress[8] = {0x28,0x46,0xBF,0x31,0x08,0,0,0x1B}; | |||
char data_sent[100]; | |||
char incomingInt; | |||
String data_string; | |||
MHZ co2capt(4,5, MHZ19B); // RX, TX, type | |||
// fonctions de conversion | |||
int Float2Int(float number){ | |||
return (int)number/1; | |||
} | |||
int Coma2Int(float number, int nbAfterComa){ | |||
number = number - (int)number; | |||
if(number < 0){ | |||
return (int)((-number)*pow(10, nbAfterComa)/1); | |||
}else{ | |||
return (int)(number*pow(10, nbAfterComa)/1); | |||
} | |||
} | |||
void setup() // setup des capteurs | |||
{ | |||
delay(20000); | |||
for(int i = 0;i<10;i++){ | |||
co2capt.calibrate400ppm(); | |||
delay(10); | |||
} | |||
gas.begin(Wire, 0x08); // use the hardware I2C | |||
ht.begin(); | |||
dallasTemp.begin(); | |||
dallasTemp.setResolution(12); | |||
delay(10000); | |||
Serial.begin(9600); | |||
delay(20); | |||
Serial.println('0'); | |||
} | |||
void loop() { | |||
if(Serial.available() > 0){ // wait for serial to have data | |||
incomingInt = Serial.read() - '0'; | |||
if(incomingInt == 1){ // read data from captors and construct string | |||
Serial.flush(); | |||
// GM102B NO2 sensor | |||
int val102 = gas.getGM102B(); | |||
// GM102B alcool? sensor | |||
int val302 = gas.getGM302B(); | |||
// GM502B VOC sensor | |||
int val502 = gas.getGM502B(); | |||
// GM702B CO sensor | |||
int val702 = gas.getGM702B(); | |||
int valOxygen = analogRead(O2_WIRE); | |||
int gazco2ppm = co2capt.readCO2UART(); | |||
int tempco2ppm = co2capt.getLastTemperature(); | |||
float thermoCpl = ht.getThmc(); | |||
dallasTemp.requestTemperatures(); | |||
int onewireTemp = dallasTemp.getTemp(tempAddress); | |||
data_string = String(valOxygen) + "," | |||
+ String(val102) + "," | |||
+ String(val302) + "," | |||
+ String(val502) + "," | |||
+ String(val702) + "," | |||
+ String(gazco2ppm) + "," | |||
+ String(tempco2ppm) + "," | |||
+ String(Float2Int(thermoCpl)) + "." + String(Coma2Int(thermoCpl,1)) + "," | |||
+ String(Float2Int(onewireTemp)); | |||
data_string.toCharArray(data_sent, 100); | |||
}else if(incomingInt == 2){ // send data | |||
delay(10); | |||
Serial.flush(); | |||
Serial.println(data_sent); | |||
}else if(incomingInt == 0){ // send ready signal | |||
Serial.flush(); | |||
Serial.println('0'); | |||
}else{ | |||
Serial.flush(); | |||
} | |||
} | |||
} |
@@ -121,13 +121,13 @@ class Arduino_data(): | |||
"""Lecture d'une ligne envoyée par Arduino, et parsing des données | |||
par rapport aux virgules dans un tableau""" | |||
coma = "," | |||
coma_places = raw_data_txt.find(coma) | |||
coma_places = fc.find_all(raw_data_txt, coma) | |||
if(type(coma_places) == type(int())): | |||
coma_places = [coma_places] | |||
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) | |||
raw_data_temp[0,0] = float(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.") | |||
@@ -138,7 +138,7 @@ class Arduino_data(): | |||
coma_places.insert(0,-1) | |||
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]+1:coma_places[i+1]]) | |||
self.raw_data_temp[0,i] = float(raw_data_txt[coma_places[i]+1:coma_places[i+1]]) | |||
self.data_array = np.append(self.data_array, self.raw_data_temp, axis=0) | |||
def create_data_file(self): | |||
@@ -55,7 +55,7 @@ class Figures(): | |||
if(nb_plots > 6): | |||
for i in range(6,nb_plots): | |||
# parcours des cases de la figure de droite à gauche puis de haut en bas, suivant la grille | |||
self.repartition.append(self.repartition[i%self.nb_curves]) | |||
self.repartition.append(self.repartition[((i+1)%6)-1]) | |||
def create_figure(self, titles_list): | |||
"""Creation de la fenêtre contenant les plots. | |||
@@ -64,8 +64,8 @@ class Figures(): | |||
actualiser les données.""" | |||
plt.ion() | |||
self.fig, self.axes = plt.subplots(self.plots_grid[0], self.plots_grid[1]) | |||
if(self.plots_grid[0] < 2): # si 1 seule ligne, empaqueter dans une liste pour | |||
# y acceder de la meme facon dans tous les cas | |||
if(self.plots_grid[0] < 2): # si 1 seule ligne de figures, empaqueter dans une | |||
# liste pour y acceder de la meme facon dans tous les cas | |||
self.axes = [self.axes] | |||
for j in range(self.plots_grid[0]): | |||
for i in range(self.plots_grid[1]): | |||
@@ -83,7 +83,7 @@ class Figures(): | |||
self.axes[i//100-1][(i//10)%10-1].clear() | |||
self.axes[i//100-1][(i//10)%10-1].title.set_text(self.titles[(i//100-1)*self.plots_grid[1]+(i//10)%10-1]) | |||
for i in range(self.nb_curves): | |||
self.axes[self.repartition[i]//100-1][(self.repartition[i]//10)%10-1].scatter(self.time, data_array_t[i]) | |||
self.axes[self.repartition[i]//100-1][(self.repartition[i]//10)%10-1].scatter(self.time, data_array_t[i], marker = '.') | |||
plt.show() | |||
plt.pause(0.05) | |||
@@ -53,3 +53,21 @@ def read_line_file(path): | |||
line = file.readline() #lis la 1e ligne | |||
file.close() #fermer avant de renvoyer la valeur | |||
return line | |||
def find_all(string, substring): | |||
""" Méthode find mais retourne toutes les occurences au lieu d'une seule.""" | |||
if(string.count(substring) == 0): | |||
return -1 | |||
else: | |||
if(string.count(substring) == 1): | |||
return string.find(substring) | |||
else: | |||
result = [string.find(substring)] | |||
for i in range(string.count(substring)-1): | |||
temp_string = string[result[-1]+1:] | |||
temp_string.find(substring) | |||
temp = temp_string.find(substring) + result[-1]+1 | |||
result.append(temp) | |||
return result |
@@ -12,6 +12,10 @@ parameters_path = os.path.abspath(os.path.dirname(__file__)) + "/parameters.txt" | |||
data_nb = 10 | |||
captors_path = os.path.abspath(os.path.dirname(__file__)) + "/captors.txt" | |||
serial_path = fc.read_line_file(parameters_path) | |||
#si '\n' a l'interieur du lien, peut ne pas fonctionner, donc a enlever | |||
bad_path_enter_place = serial_path.find("\n") | |||
if(bad_path_enter_place > 0): | |||
serial_path = serial_path[0:bad_path_enter_place]+serial_path[bad_path_enter_place+2:] | |||
#Variables cachees | |||
@@ -20,7 +24,20 @@ data_buff_max = 10 | |||
data_buff_nb = 0 | |||
data_buff = "" | |||
pressed_key = '' | |||
flag_state = 1 # etat neutre | |||
flag_erreur_serial = -1 | |||
flag_afficher_menu = 1 | |||
flag_enregistrer = 2 | |||
flag_afficher_ss_menu = 3 | |||
flag_choix_menu_principal = 4 | |||
flag_choix_ss_menu = 5 | |||
flag_init_arduino = 6 | |||
flag_state = 6 # etat initialisation, puis etat neutre (1) | |||
#Programme principal | |||
@@ -31,40 +48,49 @@ 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 (actuel : "+ serial_path+").") | |||
flag_state = -1 | |||
flag_state = flag_erreur_serial | |||
exit() | |||
else: | |||
arduino_data = data.Arduino_data() | |||
arduino_data.add_captors_from_file(captors_path) | |||
print("PoDoCor est pret a enregistrer les donnees") | |||
print("\nPoDoCor a initialisé la communication avec l'Arduino.") | |||
while(flag_state > 0): | |||
if(flag_state == 1): #afficher le menu | |||
if(flag_state == flag_init_arduino): #initialisation de l'arduino | |||
print("\nInitialisation des capteurs Arduino, veuillez patienter.") | |||
arduino_ser.flushInput() | |||
arduino_ser.write(bytes('0','utf-8')) | |||
time.sleep(5) | |||
test = arduino_ser.readline() | |||
print("Initialisation terminée, enregistrement possible.") | |||
flag_state = flag_afficher_menu | |||
arduino_ser.flushInput() | |||
if(flag_state == flag_afficher_menu): #afficher le menu | |||
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 = 4 | |||
time.sleep(2) # attente de la bonne communication avec Arduino | |||
elif(flag_state == 4): # appui clavier pour les choix du menu principal | |||
flag_state = fc.press_key('XPN', [0, 2, 3], flag_state) #detection de touche pressee (demarrage procedure acquisition) | |||
flag_state = flag_choix_menu_principal | |||
elif(flag_state == flag_choix_menu_principal): # appui clavier pour les choix du menu principal | |||
flag_state = fc.press_key('XPN', [0, flag_enregistrer, flag_afficher_ss_menu], flag_state) #detection de touche pressee (demarrage procedure acquisition) | |||
elif(flag_state == 3): # afficher le ss-menu capteurs | |||
elif(flag_state == flag_afficher_ss_menu): # afficher le ss-menu capteurs | |||
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 = 5 | |||
elif(flag_state == 5): # apui clavier pour les choix du ss-enu capteurs | |||
flag_state = fc.press_key('AETUQ', [31, 32, 33, 34, 1], flag_state) #detection de touche pressee (demarrage procedure acquisition) | |||
flag_state = flag_choix_ss_menu | |||
elif(flag_state == flag_choix_ss_menu): # appui clavier pour les choix du ss-enu capteurs | |||
flag_state = fc.press_key('AETUQ', [31, 32, 33, 34, flag_afficher_menu], flag_state) #detection de touche pressee (demarrage procedure acquisition) | |||
if(flag_state == 31): | |||
arduino_data.add_captor_manually(captors_path) | |||
flag_state = 3 | |||
flag_state = flag_afficher_ss_menu | |||
elif(flag_state == 32): | |||
arduino_data.del_captor(captors_path) | |||
flag_state = 3 | |||
flag_state = flag_afficher_ss_menu | |||
elif(flag_state == 33): | |||
arduino_data.change_captors_order(captors_path) | |||
flag_state = 3 | |||
flag_state = flag_afficher_ss_menu | |||
elif(flag_state == 34): | |||
arduino_data.captors_print_list(captors_path) | |||
flag_state = 3 | |||
flag_state = flag_afficher_ss_menu | |||
elif(flag_state == 2): # enregistrement des données | |||
elif(flag_state == flag_enregistrer): # enregistrement des données | |||
titles_list = [] | |||
for i in range(arduino_data.nb_captor_signals): | |||
titles_list.append(arduino_data.captors[i].captor_name) | |||
@@ -72,8 +98,10 @@ while(flag_state > 0): | |||
figures.create_figure(titles_list) | |||
data_buff_nb = 0 | |||
arduino_data.create_data_file() | |||
arduino_ser.flushInput() | |||
print("Enregistrement en cours. Arrêtez avec MAJ + P.\n") | |||
time_0 = time.time()-1 | |||
while(flag_state == 2): #boucle de reception des donnees | |||
while(flag_state == flag_enregistrer): #boucle de reception des donnees | |||
time_0 = time_0+1 | |||
time_1 = time_0+0.6 | |||
arduino_ser.write(bytes('1','utf-8')) #envoi de '1' a l'Arduino (acquisition donnees) | |||
@@ -81,15 +109,15 @@ while(flag_state > 0): | |||
arduino_ser.write(bytes('2','utf-8')) #envoi de '2' (réception donnees) | |||
time.sleep(0.05) | |||
raw_data_txt = arduino_ser.readline() #format des donnees: data1,data2,data3\n | |||
#print(str(raw_data_txt)[2:-5]) | |||
if(raw_data_txt == ''): # si aucune donnée reçue | |||
print("Arduino n'envoie aucune donnee, veuillez verifier le code televerse.") | |||
flag_state = -1 | |||
flag_state = flag_erreur_serial | |||
data_buff_nb = 0 | |||
else: | |||
data_buff_nb +=1 | |||
data_buff = data_buff + str(raw_data_txt)[2:-5] + "\n" #add 1 data line in buffer | |||
#procedure extraction donnees pour affichage | |||
#print(str(raw_data_txt)) | |||
arduino_data.extract_data_to_array(str(raw_data_txt)[2:-5]) | |||
@@ -101,7 +129,8 @@ while(flag_state > 0): | |||
# plot | |||
figures.plot_data(arduino_data.data_array) | |||
flag_state = fc.press_key_timeout('P', [1], flag_state) | |||
flag_state = fc.press_key_timeout('P', [flag_afficher_menu], flag_state) | |||
time.sleep(max(time_0+1-time.time(), 0)) | |||
# while end | |||