Go Down

Topic: Simple "Serial_Com" arduino raspberry pi (Read 4424 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
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy