Lier Python et Arduino

Bonjour, je travaille sur un projet de scanner 3D et j'ai à réaliser une interface graphique en python. J'aimerai donc qu'il y ai sur cette interface plusieurs boutons qui lancent des fonctions arduino.
Par exemple, un bouton "Lancer l'acquisition" enverrai une valeur sur le port série et Arduino de son côté s'occuperait de lancer le scan si la bonne donnée est reçue. Je ne sais pas trop comment m'y prendre, voici mon code:

#include <Arduino.h>
#include "BasicStepperDriver.h"
#include "MultiDriver.h"
#include "SyncDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200

// Target RPM for X axis motor
#define MOTOR_X_RPM 750
// Target RPM for Y axis motor
#define MOTOR_Y_RPM 2000

// Y motor
#define DIR_Y 48
#define STEP_Y 46
#define SLEEP_Y 62
#define ENDSTOP_Y 18

// X motor
#define DIR_X 55
#define STEP_X 54
#define SLEEP_X 38
#define ENDSTOP_X 3


#define MICROSTEPS 2

int Capteur_distance = A5;  

int x=0;
int y=0;

int DemandeScan = 0;

BasicStepperDriver stepperX(MOTOR_STEPS, DIR_X, STEP_X, SLEEP_X);
BasicStepperDriver stepperY(MOTOR_STEPS, DIR_Y, STEP_Y, SLEEP_Y);


void setup() {
    stepperX.begin(MOTOR_X_RPM, MICROSTEPS);
    stepperY.begin(MOTOR_Y_RPM, MICROSTEPS);
    stepperX.setEnableActiveState(LOW);
    stepperY.setEnableActiveState(LOW);
    Serial.begin(9600);
    pinMode(ENDSTOP_X, INPUT_PULLUP);
    pinMode(ENDSTOP_Y, INPUT_PULLUP);
    
}


void loop() {
  Serial.println("-------Bienvenue-------");
  delay(2000);
  Serial.println("-------Calibrage en cours-------");
  
  int EtatX=digitalRead(ENDSTOP_X);
  int EtatY=digitalRead(ENDSTOP_Y);
  
  if(EtatX == HIGH){
     retourX();

  }
  
   if(EtatY == HIGH){
     retourY();

  }
  
  Serial.println("-------Calibrage effectué-------");
  Serial.println("-------En attente de scan-------");
  delay(2000);
  while(DemandeScan ==0){
  delay(50);
  }
  scan();
}

void retourX(){
     stepperX.setEnableActiveState(LOW);
     stepperX.enable();

    while(digitalRead(ENDSTOP_X) == HIGH)
    {   
        stepperX.move(MOTOR_STEPS*MICROSTEPS);
    }
    stepperX.move(-MOTOR_STEPS*MICROSTEPS*4);
    stepperX.disable();
    stepperX.setEnableActiveState(HIGH);
    x=0;
}


void retourY(){
     stepperY.setEnableActiveState(LOW);
     stepperY.enable();
    
     while(digitalRead(ENDSTOP_Y) == HIGH){
        stepperY.move(MOTOR_STEPS*MICROSTEPS);
    }
    
    stepperY.disable();
    stepperY.setEnableActiveState(HIGH);
    y=0;
}

void scan(){
  Serial.println("-------Scan debuté-------");
  for (int i = 0; i < 31; i=i+1){
  for (int i = 0; i < 31; i=i+1){
    float volts = analogRead(Capteur_distance)  * 0.0048828125; 
    float distance = ((2.31584292213234-volts)/0.034554240563698);
    Serial.print("X= ");
    Serial.print(x);
    Serial.print(" Y= ");
    Serial.print(y);
    Serial.print("  Z=");
    Serial.println(distance);
    stepperX.setEnableActiveState(LOW);
    stepperX.enable();
    stepperX.move(-MOTOR_STEPS*MICROSTEPS);
    stepperX.disable();
    stepperX.setEnableActiveState(HIGH);
    delay(500);
    x=x+1;
  }

  retourX();
    
  stepperY.setEnableActiveState(LOW);
  stepperY.enable();
  stepperY.move(-MOTOR_STEPS*MICROSTEPS*536);
  stepperY.disable();
  stepperY.setEnableActiveState(HIGH);
  delay(500);
  y=y+1;
}
    retourY();
    DemandeScan =0;
    Serial.println("-------Scan fini-------");
}

Merci

J'ai réalisé une alimentation pilotable en PYTHON dernièrement : alimentation-37v-numerique

Le code ARDUINO :
3.7v-power-supply.ino

La fonction commandShell() est un interpréteur de commande.
Il te suffit de l'appeler dans la loop() et de remplacer le code de chaque commande.

      if (!strncmp(buf, "ACQ", 3)) {
        // lancer acquisition
      }
      else if (!strncmp(buf, "AUTRE", 5)) {
        // faire autrechose
      }
      else if (!strncmp(buf, "GET", 3)) {
        // récupérer un argument integer
        char s[CMD_MAX];
        int in;
        if (sscanf(buf, "%s %d", s, &in) != 2) {
          // argument manquant : erreur
          Serial.println("EINVAL");
          return true;
        }
        // faire qq chose avec l'argument
      }

Le code PYTHON :
test.py

La fonction sendReply() envoie une commande à l'ARDUINO.
Tout en bas, le code pour ouvrir la ligne série.
Si tu es sous Windows remplace '/dev/ttyUSB1' par 'COMX', X étant le numéro du port.

N'hésite pas à poser des questions.

Merci pour ta réponse.
J'ai regardé les 2 prog et je t'avoue que je n'ai pas tout compris

Je ne comprends pas comment envoyer une donnée à l'arduino par python

Merci

La fonction sendReply envoie la commande :

	def sendReply(self, request):
		global ser
		ser.write(request+'\r\n')          # envoi commande
		answer = ser.read_until('\n')    # réception réponse
		print answer,
		return answer.strip('\r\n')

La requête est terminée par '\r \n' pour que l'ARDUINO sache que c'est la fin de la requête.
Et elle renvoie la réponse de l'ARDUINO à l'appelant.

Côté ARDUINO :

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Boot message"));
}

void loop() {
  commandShell();
  // autres traitements
}

#define CMD_MAX               100

bool commandShell(void)
{
  static char buf[CMD_MAX];
  static int i;

  if (!Serial.available()) {
    return false;
  }
  int c = Serial.read();
  if (c != -1) {
    if (c == '\n') {
      if (strlen(buf) == 0) {
        return;
      }
      // exécution de la commande
      Serial.println(strlwr(buf));
      // -------------------------
      buf[i] = 0;
      i = 0;
      return true;
    }
    if (c != '\r') {
      if (i < CMD_MAX - 1) {
        buf[i++] = c;
        buf[i] = '\0';
      }
      else {
        Serial.println("ETOOBIG");
      }
    }
  }
  return true;
}

Côté PYTHON :

#!/usr/bin/env python

import time, serial

def sendReply(request):
	global ser
	ser.write(request+'\r\n')
	answer = ser.read_until('\n')
	return answer.strip('\r\n')

if __name__ == "__main__":
	ser = serial.Serial('/dev/ttyUSB1', baudrate=115200)
	ser.timeout = 3
	time.sleep(1)
	ser.read_until('\n') # read boot message
	answer = sendReply('COMMANDE')
	print "answer:", answer

L'ARDUINO renvoie simplement la commande reçue après l'avoir convertie en minuscules.
On peut difficilement faire plus simple.

Quelques commandes avec ou sans arguments (string, integer) :

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Boot message"));
}

void loop() {
  commandShell();
  // autres traitements
}

#define CMD_MAX               100

bool commandShell(void)
{
  static char buf[CMD_MAX];
  static int i;

  if (!Serial.available()) {
    return false;
  }
  int c = Serial.read();
  if (c != -1) {
    if (c == '\n') {
      if (strlen(buf) == 0) {
        return;
      }
// exécution de la commande
      if (!strncmp(buf, "HELLO", 4)) {
        Serial.println("HELLO");
      }
      else if (!strncmp(buf, "UPPER", 5)) {
        char s[20];
        char arg[20];
        if (sscanf(buf, "%s %s", s, arg) != 2) {
          // invalid arguments
          Serial.println("EINVAL");
          return true;
        }
        Serial.println(strupr(arg));
      }
      else if (!strncmp(buf, "LOWER", 5)) {
        char s[20];
        char arg[20];
        if (sscanf(buf, "%s %s", s, arg) != 2) {
          // invalid arguments
          Serial.println("EINVAL");
          return true;
        }
        Serial.println(strlwr(arg));
      }
      else if (!strncmp(buf, "ADD", 3)) {
        char s[20];
        int a, b;
        if (sscanf(buf, "%s %d %d", s, &a, &b) != 3) {
          // invalid arguments
          Serial.println("EINVAL");
          return true;
        }
        Serial.println(a + b);
      }
      else {
        // command not supported
        Serial.println("WHAT'UP DOC ?");
      }
// -------------------------
      buf[i] = 0;
      i = 0;
      return true;
    }
    if (c != '\r') {
      if (i < CMD_MAX - 1) {
        buf[i++] = c;
        buf[i] = '\0';
      }
      else {
        Serial.println("ETOOBIG");
      }
    }
  }
  return true;
}
#!/usr/bin/env python

import time, serial

def sendReply(request):
	global ser
	ser.write(request+'\r\n')
	answer = ser.read_until('\n')
	return answer.strip('\r\n')

if __name__ == "__main__":
	ser = serial.Serial('/dev/ttyUSB1', baudrate=115200)
	ser.timeout = 3
	time.sleep(1)
	ser.read_until('\n') # read boot message
	answer = sendReply('HELLO')
	print "answer:", answer
	answer = sendReply('UPPER azertyuiop')
	print "answer:", answer
	answer = sendReply('LOWER AZERTYUIOP')
	print "answer:", answer
	answer = sendReply('ADD 12 13')
	print "answer:", answer
	answer = sendReply('blabla')
	print "answer:", answer
riton@alpha:~/sources/arduino/samples/serial-python$ ./serial-python.py 
answer: HELLO
answer: AZERTYUIOP
answer: azertyuiop
answer: 25
answer: WHAT'UP DOC ?
riton@alpha:~/sources/arduino/samples/serial-python$