Go Down

Topic: Simple "Serial_Com" arduino raspberry pi (Read 4273 times) previous topic - next topic

cutprod

Feb 27, 2013, 09:53 pm Last Edit: Mar 06, 2013, 10:03 pm by cutprod Reason: 1
Bonjour a tous,
voila je partage mon protocole de communication entre arduino et raspberry pi.
Deux petits scripts bien commenté pour aider les novices...
- Python 2.7 et lib "Serial" coté raspi
- IDE arduino 1.0.3
Code pas ou peu optimisé, pas de bug majeur mais, vos remarques seront les bien venu.
Par exemple le cpu de la raspberry mouline plein pot :smiley-mr-green: si quelqu'un a une solution...

Principe :
- carte arduino et raspberry pi relier par câble usb.
- les scripts intègre dans leur boucle une fonction qui li le port série, stocke les msg vérifie leur intégrité (simple présence de "char" spécifiques au début et a la fin, il faudrait faire un checksum...)
- si le msg est entier envoi un accuser de réception (sinon l' émetteur recommence l'envoi un max de 5 fois avant abandon)
- exécute une action en fonction du msg reçu

Ici les msg entre cartes sont de type "String".
Le script python contient une fonction date_time pour un fichier log que je vous épargne.

Arduino =
Code: [Select]
/*programme qui envoi  un msg sur le port serie a destination
d'une carte raspberry pi qui elle attend ce msg pour declencher
une action et renvoi sur le port serie un accuser de reception
send_data_to_raspi("donne_teleinfo") #exemple d' envoi de data vers raspberry
*/
//##############################
//variable data port serie
char data_port_serie = '\0';//char de reception "serial.read()"
char data[256] = "";//tableau de stockage des char reçu par le port serie
String str_data_serial;//data recu transformer en string
int i = 0;//incremente le tableau de char
boolean accuser_de_reception = false;//etat de l'accuser de recption
//##############################
//variable chronos attente accuser de reception
unsigned long start_chrono;
unsigned long stop_chrono;
unsigned long total_chrono;
//###############################################################
//###############################################################
//###############################################################

void setup()
{
 Serial.begin(9600);  
 Serial.println("Demarrage programme");
}//fin setup
//###############################################################
void loop()
{
 
 serial_port_watcher();//li les data du port serie(raspi) si data dispo
 
}//fin loop
//###############################################################
void serial_port_watcher()
{
 memset(data,0,256);//vide le tableau des data precedents
 str_data_serial = "";//raz du string data reçu
 i=0;
 
 if (Serial.available())//attend reception data
   
  {
    delay(100); //important! laisse le temps de charger le buffer          
    while (Serial.available() > 0) //tant qu' il ya des data en reception
      {
         data_port_serie = Serial.read();//stock dans une varible chaque char reçu
         data[i++] = data_port_serie;//on ajoute au tableau les char reçu
      }
   
    data[i++] = '\0';//on fini le tableau par un char nul pour construire un string
    str_data_serial = data;//transforme le tableau en string  
   
  }//fin if serial.avaible

//#####################
//verifi l'integrité du msg
  if (str_data_serial.startsWith("<") and str_data_serial.endsWith(">"))
   {
    //#####################
      //execute en fonction du msg reçu
      if (str_data_serial == "<donne_teleinfo>")
       {
         send_accuser_de_reception();//envoi accuser de reception
         //action ...
       }
      else if (str_data_serial == "<ok>")
       {
         accuser_de_reception = true;
       }
    }//fin de if startsWith...
//#####################
}//fin serial_port_watcher
//###############################################################
void send_data_to_raspi(String data_to_send)
{
 //fonction qui envoi des data sur le port serie,attend un accuser de reception (string "ok")
 //si pas reçu recommence l'envoi des meme data et cela un nombre de fois defini(variable "try_to_send")
 
 accuser_de_reception = false;
 long interval = 1000;//temps d'attende pour renvoi des data si pas de reponse accuser de reception
 byte try_to_send = 0;//nombre de tentative d'envoi des data
   
   while(try_to_send < 5)//boucle de tentative d'envoi retente jusqu'a x fois
     {
       
       start_chrono = millis();//demarre un chrono pour attente rx
       ++ try_to_send;//incremente le nombre de tentative
     
       Serial.println("<" +data_to_send+ ">");//envoi du msg(string passer en parametre) avec ajout des balises de debut et fin du msg pour verifier son integrité a la reception
       
        while (1)//attente reception de data pour accuser reception
          {
             //####################
             //li le port serie pour rx l'accuser de recep du raspi ("ok")
             serial_port_watcher();
             if(accuser_de_reception == true)
               {
                 return;//sort de la fonction si accuser de reception
               }
            //####################
            //verifie si le temps d'attente de reponse est depasser
            stop_chrono = millis();
            if(stop_chrono - start_chrono > interval)
            {
              break;//si temps d'attente accuser de reception ecouler on sort de la boucle pour re envoyer le msg
            }  
              //####################
          }//fin  while 1 (boucle attente reception accuser de reception)

     }//fin boucle de tentative d'envoi
           
}//fin ecrit data raspi
//###############################################################
void send_accuser_de_reception()
{
 Serial.println("<ok>");
}
//##########################################################################################


Je met le script raspberry dans le post suivant car "The message exceeds the maximum allowed length (9500 characters). "

cutprod


Raspberry pi =
Code: [Select]
# -*- coding: cp1252 -*-

#programme qui envoi  un msg sur le port serie a destination
#d'une carte arduino qui elle attend ce msg pour declencher
#une action et renvoi sur le port serie un accuser de reception
#exemple d' envoi de data vers arduino = send_data_to_arduino("donne_teleinfo")

import serial
import time #fonction heure_date + chrono
import threading #utilisation multi-threading

#########################################################################
##########                      Class                          ##########
#########################################################################

class Serial_Port_Watcher(threading.Thread): #thread qui li le port serie

   
    def __init__(self):
        threading.Thread.__init__(self)
        self.running = False#continu ou stop le thread
        self.accuser_de_reception = False#stop les tentative d'envoi de msg si bien reçut
       
    def run(self):
        self.running = True
        while self.running:# scrutation du buffer d'entree

            try:
                if serial_port.inWaiting():#inWaiting vient de "pyserial"
                    li_data_port_com()#appel la foction qui lit et verifie les datas
            except:
                pass
           
    def stop(self):
        self.running = False


###########################################################################
#############                    Fonctions                 ################
###########################################################################

def li_data_port_com():
       
    global msg_port_serie
       
    msg_port_serie = serial_port.readline()
    if (msg_port_serie != ""):
        msg_port_serie = msg_port_serie.rstrip() #on enleve le "\n" et le char null
        #print("msg => " + msg_port_serie) #debug du msg recu
       
        if(msg_port_serie.startswith("<") & msg_port_serie.endswith(">")): #on verifie l' integrité du msg (commence et fini par les balises "<...>"
            msg_is_ok(msg_port_serie) #appel la fonction de traitement du msg si celui ci et "entier"
           
        else:
            print("Erreur lecture port com = " + msg_port_serie)
            #log_serial_data("Erreur lecture port com = " + msg_port_serie)

    #serial_port.flushInput()
    #serial_port.flushOutput()

########################

def msg_is_ok(msg_ok):
#gestion des data recut sur le port serie (Arduino "UNO")
   
    print("RX serial port => " + msg_ok)#debug

    if (msg_ok != "<ok>"):
        send_accuser_de_reception()#vu que le msg est entier (et != accuser de reception venant de arduino) on accuse reception
       
    if (msg_ok == "<ok>"):
        data_watcher.accuser_de_reception = True#stop le ré-envoi du msg
        print("RX serial port => accuser de reception")
       
########################
         
def send_data_to_arduino(data_to_send):
#fonction qui envoi des data sur le port serie,attend un accuser de reception (string "ok")
#si pas reçu recommence l'envoi des meme data et cela un nombre de fois defini(variable "try_to_send")
    data_watcher.accuser_de_reception = False
    try_to_send = 0#raz nombre de tentative d'envoi des data

    while(try_to_send < 5):#boucle de tentative d'envoi retente jusqu'a x fois
       
        serial_port.write("<" + data_to_send + ">")
        try_to_send += 1 #incremente le nombre de tentative
        print("TX ok... try_to_send = " + str(try_to_send))
        time.sleep(1)#laisse le temps de recevoir accuser de recption

        if (data_watcher.accuser_de_reception == True):
            return#sort de la fonction si le msg est bien envoyer

########################

def send_accuser_de_reception():
    serial_port.write("<ok>")#envoi accuse reception
    print("TX serial port => accuser de reception")

########################

def connexion_arduino():

    global etat_connexion_arduino
    global serial_port

    try:
        serial_port = serial.Serial("COM3")#("/dev/ttyUSB0")
        serial_port.baudrate=9600
        etat_connexion_arduino = True
        print("connexion arduino ok")
       
    except:
        etat_connexion_arduino = False
        print("Erreur connexion arduino")
        pass
 
########################

def date():

    if time.localtime().tm_mday < 10 :
        day = str(0) + str(time.localtime().tm_mday)
    else:
        day = str(time.localtime().tm_mday)
       
    if time.localtime().tm_mon < 10:
        mon = str(0) + str(time.localtime().tm_mon)
    else:
        mon = str(time.localtime().tm_mon)

    date = day + "/" + mon + "/" + str(time.localtime().tm_year)
    return date

########################

def heure():
   
    if time.localtime().tm_hour < 10 :
        hh = str(0) + str(time.localtime().tm_hour)
    else:
        hh = str(time.localtime().tm_hour)
       
    if time.localtime().tm_min < 10:
        mm = str(0) + str(time.localtime().tm_min)
    else:
        mm = str(time.localtime().tm_min)

    if time.localtime().tm_sec < 10:
        sec = str(0) + str(time.localtime().tm_sec)
    else:
        sec = str(time.localtime().tm_sec)
                 
    heure = hh + ":" + mm + ":" + sec
    return heure

 
########################

def stop_prog():
   
    data_watcher.stop()
    serial_port.close()#ferme port ouvert dans connexion ardino
    print("stop programme")

#########################################################################
##########                       Main                          ##########
#########################################################################

print("Demarrage programme")
connexion_arduino()

#initialyse les objets
data_watcher = Serial_Port_Watcher()

#démarre les threads
data_watcher.start()

time.sleep(15)#tempo auto stop a virer dans votre prog
stop_prog()

Go Up