Aide vocabulaire


#1

Yo les gens,

Désolé pour le pavé …

En qualité de bidouilleur, j’arrive à faire des choses sans savoir les réaliser réellement.
Et je manque de connaissances, ne serait-ce qu’en vocabulaire.
Alors même que le vocabulaire idoine permet la recherche adaptée.

Je viens donc, pour une fois, demander de l’aide.
En effet, je ne trouve pas car je crois que je ne sais pas nommer ce que je cherche :sunglasses:

Prenons un exemple.
Je fais un script python
J’ai une boucle While (car ça doit tourner indéfiniment)
Ça affiche un accueil (une image et du texte en surimpression)
Ça passe en attente d’un appui sur le GPIO 24 (bouton noir)
Si 24 n’est pas pressé, rien ne se passe
Si 24 est pressé,
alors :

  • prise d’une photo
  • renommage et enregistrement de la photo
  • affichage de la photo
  • impression de la photo
  • affichage de l’accueil

Ce déroulement est logique et simple ; je sais faire ; ça fonctionne.

Maintenant,
Je tente une boucle While qui affiche un accueil (une image et du texte en surimpression)
ça passe en attente d’un appui sur le GPIO 24 (bouton noir)
Si 24 n’est pas pressé, rien ne se passe
Si 24 est pressé,
alors :

  • prise d’une photo
  • renommage et enregistrement de la photo
  • affichage de la photo
    –> mise en pause de la boucle initiale pour entrer dans une autre boucle (boucle2)
    Affichage du texte “enregistrer+imprimer photo ; oui=blanc / non=rouge”
    1 - oui (GPIO26 pressé), alors
  • impression de la photo
  • sortie de la boucle2
  • affichage de l’accueil (retour dans la boucle initiale)
    2 - non (GPIO18 pressé), alors
  • Effacement de la photo
  • sortie de la boucle2
  • affichage de l’accueil (retour dans la boucle initiale)

Pour le moment, je n’ai pas réussi.
je peux bloquer une boucle lancée par GPIO24 en attendant un appui sur GPIO26 puis GPIO18 avant de revenir à la boucle, mais c’est une enchaînement bête alors que je voudrais du conditionnel.
Par exemple, j’ai fais un script simpliste :
Au lancement du script, affichage d’un écran d’accueil
si 24 pressé, alors j’ai une image d’un bouton noir
ça reste là
Si j’appuie sur 24 ou 26 = rien
Si j’appuie sur 18 = image d’un bouton rouge
ça reste là
Si j’appuie sur 18 ou 24 = rien
Si j’appuie sur 26 = image d’un bouton blanc
ça reste là
Si j’appuie sur 24 ça recommence.
J’ai donc une boucle mais sans les “conditions différentielles” ; juste en “suites”(termes appropriés ???)

Question :
Comment s’appelle réellement ce que je cherche à faire ?
Des conditions en cascade ?
Des conditions imbriquées ?
Autre terme ?

Merci pour vos lumières,
(vous me connaissez, je cherches des pistes ; pas des solutions toutes faites sans explications :wink: )

++


#2

Salut,
Ce que tu as besoin, c’est de programmer une machine d’état, ou state machine en anglais


#3

Salut @tynnor

Merci pour ton intervention.

Je venais de faire un script un peu moins pire avec du

  • While
    • if (24)
      • if (18)
      • esle (26)

Au lancement du script, affichage d’un écran d’accueil
si 24 pressé, alors j’ai une image d’un bouton noir
ça reste là
Si j’appuie sur 24 ou 26 = rien
Si j’appuie sur 18 = image d’un bouton rouge
ça reste là
Si j’appuie sur 18 ou 26 = rien
(mais je vois dans le terminal que ma boucle reprend)
Si j’appuie sur 24 = image d’un bouton noir
Et Ceatera
donc, ce n’est pas ça :slight_smile:

Merci pour ton axe de recherche sur machine d’état ou state machine.
Bon, j’arrête pour ce soir (faut être raisonnable, sinon, je me connais, je vais pousser jusqu’à demain matin :slight_smile: )

++


#4

Yo @Nabla

Ta syntaxe de code en Français suit une logique implacable.:sunglasses:

Tu pourrais afficher ton code Python sur le fofo ?
Genre comme celui ci :

import the necessary packages

from __future__ import print_function
import imutils
import cv2
 
# load the Tetris block image, convert it to grayscale, and threshold
# the image
print("OpenCV Version: {}".format(cv2.__version__))
image = cv2.imread("tetris.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 225, 255, cv2.THRESH_BINARY_INV)[1]
 
# check to see if we are using OpenCV 2.X
if imutils.is_cv2():
	(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
		cv2.CHAIN_APPROX_SIMPLE)
 
# check to see if we are using OpenCV 3
elif imutils.is_cv3():
	(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
		cv2.CHAIN_APPROX_SIMPLE)


# draw the contours on the image
cv2.drawContours(image, cnts, -1, (240, 0, 159), 3)
cv2.imshow("Image", image)
cv2.waitKey(0)

@++


#5

Salut,
Un post intéressant et qui sort de l’ordinaire, d’autant plus qu’on sort de la technique pure pour rentrer dans la structure de code, ce qui est très souvent un problème et un facteur limitant pour tous ceux qui ont une pratique peu expérimentée. Ce n’est ni un problème d’intelligence, ni de compétences techniques ou mathématiques, mais plutôt, oserai-je le dire, un problème d’expérience artisanale en quelque sorte. Pour moi, la bonne structure du code relève plus de l’expérience que de la science, un peu comme en soudure, en couture, ou en cuisine.
Parler d’une machine à états à propos de ton problème, c’est certainement scientifiquement correct (qui suis-je pour imaginer le contester…), mais ça n’apporte pas grand chose de concret. Si tu parles à des développeurs d’un problème de machine à état, la plupart vont te regarder avec de grands yeux, et beaucoup ne comprendront pas vraiment ce que tu cherches.
Je propose plutôt de parler de programmation événementielle. Ceci est venu à la mode avec l’arrivée des premiers systèmes graphiques (xerox d’abord, puis lisa et mac, et enfin windows). L’inconvénient d’une interface utilisateur moderne, c’est qu’il y a un grand nombre d’évènements possibles à gérer (clavier, souris, boutons, cases, gpios, timers, communications, et j’en passe). Impossible de programmer tout ça avec des boucles imbriquées, on arrive à des impossibilités. Dans ton exemple, le traitement des boutons G26 et G18 est imbriqué dans celui du G24. Comment feras-tu si tu veux imbriquer dans un bouton G25 ? Tu seras obligé de créer des fonctions ou des classes et ceci ne règlera que partiellement le problème car tu pourrais très bien décider à un moment de faire le contraire et imbriquer le traitement du G24 dans le G26…
Une approche différente serait de gérer chaque évènement l’un à la suite de l’autre, avec une seule boucle (pas d’imbrication) et une série de tests qui se suivent pour savoir quel évènement on doit gérer.
Cela pourrait donner :

  • while True
    • afficher accueil ?
      • affiche accueil
      • sort de la boucle
    • GPIO 24 à traiter ?
      • photo, rename, affichage
      • génère évènement G26
      • sort de la boucle
    • GPIO 18 à traiter ?
      • efface
      • génère évènement affichage accueil
      • sort de la boucle
    • GPIO 26 à traiter ?
      • imprime
      • génère évènement affichage accueil
      • sort de la boucle
    • etc…

De cette manière, tes modules de code sont successifs, tu peux plus facilement les organiser en fonctions ou en méthodes de classes, ton script est carré, facile à maintenir pour un gars limité en neurones comme myself.
Ton post amène un autre problème, celui de la modélisation en pseudo-code. Le pseudo-code, c’est bien gentil, mais ça ne tourne pas. Et comme ça ne tourne pas, on peut toujours prétendre que ça marche, mais on ne peut pas en fournir la preuve. Autant modéliser directement en python, et faire tourner, c’est plus sûr. C’est très difficile de modéliser de façon fiable en pseudo-code. In fine, plus l’algorithme est complexe, plus le risque de faire des erreurs de conception très invalidantes est important.
Espérant t’avoir éclairé, je te souhaite bon courage pour tous tes projets…


#6

Yo,

Merci à tous

Effectivement, le pseudo code … reste … du pseudo code :smiley:

Combien de fois un pseudo code a été parfait aussi longtemps qu’il restait un pseudo code ??? :wink:
C’est là le pb pour un mec possiblement logique mais non codeur …

Le script (un des scripts :smiley: ) :

#!/usr/bin/python3
# -*- coding: utf-8 -*

#on importe les modules nécessaires
import RPi.GPIO as GPIO
import time
from datetime import datetime
from PIL import Image
import pygame
from pygame.locals import *
import os

#on initialise les GPIO en écoute
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)

pygame.init()
#screen = pygame.display.set_mode((0,0),pygame.FULLSCREEN)
screen = pygame.display.set_mode((1920,1080),RESIZABLE)
width, height = screen.get_size()

def AfficherTexte(message): # Afficher un Texte en surimpression 
    font = pygame.font.SysFont("verdana", 50, bold=1)
    textsurface = font.render(message, 1, pygame.Color(100,150,200))
    screen.blit(textsurface,(35,40))
    pygame.display.update()

def AfficherPhoto(NomPhoto): # Afficher une image à l'écran
    print("loading image: " + NomPhoto)
    background = pygame.image.load(NomPhoto);
    background.convert_alpha()
    background = pygame.transform.scale(background,(width,height))
    screen.blit(background,(0,0),(0,0,width,height))
    pygame.display.flip()
    
while True : #boucle jusqu'a interruption
  try:
        print ("\n attente boucle")
        
        AfficherPhoto("/home/pi/test-script/accueil.png")
        AfficherTexte("Appuyez sur le bouton noir")

        
        #on attend que le bouton soit pressé
        GPIO.wait_for_edge(24, GPIO.FALLING)
        

        #on génère le nom de la photo avec heure_min_sec
        date_today = datetime.now()
        nom_image = date_today.strftime('%d_%m_%H_%M_%S')

        
        #on déclenche la prise de photo
        os.system('raspistill -w 800 -h 600 -o "/home/pi/test-script/photos/'+nom_image+'.jpeg" -q 100')

        AfficherPhoto("/home/pi/test-script/photos/"+nom_image+".jpeg")
        AfficherTexte("OK pour Test")
        time.sleep(5)
        
        GPIO.wait_for_edge(18, GPIO.FALLING)
        print ("18 ?")
        AfficherPhoto("/home/pi/test-script/accueil.png")
        AfficherTexte("GPIO 18 pressé")
        time.sleep(3)

        
        GPIO.wait_for_edge(26, GPIO.FALLING)
        print ("26 ?")
        AfficherPhoto("/home/pi/test-script/accueil.png")
        AfficherTexte("GPIO 26 pressé")
        time.sleep(3)



        if (GPIO.input(24) == 0): #Appui long durant la séquence = sortie de la boucle)
              print ("Arrêt script demandé")
              break  
 

  except KeyboardInterrupt:
    print ('sortie du programme!')
    raise

GPIO.cleanup()           # reinitialisation GPIO

Ce script fonctionne bien
Appui sur 24 = prise de la photo et affichage avec “Test OK” puis ça attend

Si 24 ou 26 appuyé = rien
Obligé d’appuyer sur 18 qui enclenche bien le fond + “GPIO 18 pressé”
Puis ça attend

Si 24 ou 18 appuyé = rien
Obligé d’appuyer sur 26 qui ré-enclenche bien le fond + “GPIO 26 pressé”
Et retour au début

L’idée étant d’avoir un choix appuyez sur 18 ou 26 si vous m’avez suivi :wink:

++


#7

Re,

Pas pu vraiment lire ni tester pour le moment.
Mais je tente par à-coups

#!/usr/bin/python3
# -*- coding: utf-8 -*

#on importe les modules nécessaires
import RPi.GPIO as GPIO
import time
from datetime import datetime
from PIL import Image
import pygame
from pygame.locals import *
import os

#on initialise les GPIO en écoute
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)

pygame.init()
#screen = pygame.display.set_mode((0,0),pygame.FULLSCREEN)
screen = pygame.display.set_mode((1360,768),RESIZABLE)
width, height = screen.get_size()

def AfficherTexte(message): # Afficher un Texte en surimpression 
    font = pygame.font.SysFont("verdana", 50, bold=1)
    textsurface = font.render(message, 1, pygame.Color(100,150,200))
    screen.blit(textsurface,(35,40))
    pygame.display.update()

def AfficherPhoto(NomPhoto): # Afficher une image à l'écran
    print("loading image: " + NomPhoto)
    background = pygame.image.load(NomPhoto);
    background.convert_alpha()
    background = pygame.transform.scale(background,(width,height))
    screen.blit(background,(0,0),(0,0,width,height))
    pygame.display.flip()
    
while True : #boucle jusqu'a interruption
  try:
        print ("\n attente boucle")
        
        AfficherPhoto("/home/pi/test-script/accueil_1360x765.png")
        AfficherTexte("Appuyez sur le bouton noir")

        
        #on attend que le bouton soit pressé
        GPIO.wait_for_edge(24, GPIO.FALLING)
        

        #on génère le nom de la photo avec heure_min_sec
        date_today = datetime.now()
        nom_image = date_today.strftime('%d_%m_%H_%M_%S')

        
        #on déclenche la prise de photo
        os.system('raspistill -w 1360 -h 768 -o "/home/pi/test-script/photos/'+nom_image+'.jpeg" -q 100')

        AfficherPhoto("/home/pi/test-script/photos/"+nom_image+".jpeg")
        AfficherTexte("imprimer ? rouge=oui blanc=non")
        time.sleep(5)
        
        if GPIO.wait_for_edge(18, GPIO.FALLING):
          print ("18 ?")
          AfficherPhoto("/home/pi/test-script/accueil_1360x765.png")
          AfficherTexte("impression ok - GPIO 18 pressé")
          time.sleep(3)
        
        elif GPIO.wait_for_edge(26, GPIO.FALLING):
          print ("26 ?")
          AfficherPhoto("/home/pi/test-script/accueil_1360x765.png")
          AfficherTexte("photo annulée - GPIO 26 pressé")
          time.sleep(3)
          
        else:
          AfficherPhoto("/home/pi/test-script/accueil_1360x765.png")
          AfficherTexte("on recommence")



        if (GPIO.input(24) == 0): #Appui long durant la séquence = sortie de la boucle)
              print ("Arrêt script demandé")
              break  
 

  except KeyboardInterrupt:
    print ('sortie du programme!')
    raise

GPIO.cleanup()           # reinitialisation GPIO

Là, j’ai bien l’invitation pour appuyez sur 24 (débuter la boucle)
Une fois 24 pressé, j’ai prise de photo puis affichage photo avec “imprimer ? rouge=oui blanc=non”

Mais je ne peux faire que un appui sur 18 (bouton rouge)
Un appui sur 26 (blanc) ne lance rien.

Une fois 18 pressé, j’ai bien “impression ok - GPIO 18 pressé” qui s’affiche 3 seconde et je repasse au début de la boucle

Bref, tout ce qui suit soit

elif GPIO.wait_for_edge(26, GPIO.FALLING):
  print ("26 ?")
  AfficherPhoto("/home/pi/test-script/accueil_1360x765.png")
  AfficherTexte("photo annulée - GPIO 26 pressé")
  time.sleep(3)
  
else:
  AfficherPhoto("/home/pi/test-script/accueil_1360x765.png")
  AfficherTexte("on recommence")

est non pris en compte.


#8

@tynnor
Et ?

Beaucoup de monde, ici, connaît la traduction en anglais de state machine.

Mais si tu n’exposes pas de façon explicite ce qu’est la programmation, sur une macchina di stato,
les membres du forum seront un peu perdus.

Je ne vois pas ce que tu apportes de concret sur le sujet. A moins d’allez plus loin dans ton argumentation. Comme expliquer pour les néophytes, ce que c’est une “state machine”…

Désolé pour toi, mais ici le sujet concerne un problème relatif a la syntaxe Python.

Mais soyons constructif.
Postes un sujet concret autour du Raspberry, avec un langage de bas ou haut niveau, peu importe.

De plus, tu peux contacter @Nabla, qui gere son blog autour de la PI, histoire de lui exposer tes projets.

P.S @Nabla je t’envoi une patate chaude :wink:


#9

Yo,

Ne pouvant “travailler” que par à-coups, je ne suis pas très productif.
J’ai tenté des modifications de code sur des codes clonés et je me perds (faut que je passe à GitHub).
Pour les states Machines, ça semble intéressant, au moins dans la théorie :

State machines are especially interesting because, among other things, they provide well-defined scenarios and list out the conditions to get to them. This makes it very easy to scope out edge cases and how to handle them, as we are forced to consider every possible scenario our code must fall within.

Et c’est bien ce que je veux : des scénarios bien définis et des conditions pour y accéder.

Il me reste du chemin cependant.
Là, j’exploire les boucles car j’avais dans l’idée ce que proposait @jmbc avec

Mais en fait, je crois que je pèche sur la syntaxe car c’est un échec (partiel, pas total).
Comme dirait @jelopo : RTFM :wink:

++


#10

Il n’est pas vraiment question de programmation événementielle ici. On pourrait toujours adopter une structure de la sorte mais ça sera lourd pour pas grand chose.

Effectivement ce genre de problème se rencontre assez rapidement quand on commence à coder. Heureusement, dans l’orienté objet, il existe un tas de solution pour résoudre ce genre de soucis d’architecture du code : on appelle ça des design pattern ou patron de conception, sujet très documenté sur internet

Pour l’instant je n’ai pas le temps donner un exemple de code, je le ferais peut-être ce soir. (mais ce sera pas du Python). Mais voici un peu de doc sur le sujet :

Tout plein d’exemple de design pattern :
https://www.tutorialspoint.com/design_pattern/state_pattern.htm


#11

Voilà un exemple simpliste d’une machine d’état en C ou C++. En suivant un tel modèle, tu arriveras (peut-être sans soucis) à tes fins.
Les noms des états sont évidemment mal choisis ! A toi de l’adapter en fonction de l’application

//déclaration des différents états de la machine d'état
enum STATE{
	STATE_1,
	STATE_2,
	STATE_3,
	STATE_4,
	STATE_5,
	STATE_LAST
};



//contient l'état en cours de la machine d'état
STATE state = STATE_1;

int main(){

	
	while(state != STATE_LAST){

		switch(state){


			case STATE_1:
			{
				afficherAccueil();
				state = STATE_2;
			}
			break;

			case STATE_2:
			{
				//attente appuie sur le bouton
				if(getPressedKey() == GPIO_24){
					state = STATE_3;
				}
			}
			break;


			case STATE_3:
			{
				takePicture();
				pictureProcessing();
				

				//on pose la question à l'utilisateur
				string answer = showText();
				if(getPressedKey() == YES)
					state  = STATE_4;
				else
					state = STATE_5;


			}
			break;


			case STATE_4:
			{
				printPicture();

				//retour au début
				state  = STATE_1;
			}
			break;

			case STATE_5:
			{
				deletePicture();
				state = STATE_1;
			}
			break;

			case STATE_LAST:
			{
				
			}
			break;

		}



	}



	return 0;
}

Bon courage :wink:


#12

Hello,
Je suis sûr qu’une âme charitable va m’expliquer pourquoi ce n’est pas de la programmation événementielle…
Pour ce qui est des design patterns, je suis curieux de savoir lequel s’applique au cas présent, et pendant qu’on y est, un exemple serait bien venu.
Du concret quoi, pas simplement des affirmations.


#13

Si tu avais lu les réponses précédentes ou fais des recherches sur le sujet, tu aurais vu que la machine d’état est un design pattern et qu’il y a un exemple concret …
Je ne donne pas de mon temps pour faire ton apprentissage mais pour donner un coup de main à ceux qui on fait un effort.

Programmation événementielle ça veut tout et rien dire, le pattern observer je le considère comme événementiel. Lorsqu’un événement dans ton code survient, il appelle une fonction dit fonction de callback. Quand on parle de callback, je pense qu’on peut parler de programmation événementiel. Ce mécanisme est utilisé à gogo dans les interfaces graphiques


#14

Yo,

Désolé, je bosse sur des projets variés qui me prennent pas mal de temps et j’ai dû laisser ce sujet (et le forum) de côté.

Je remercie tout le monde pour les avis et pistes.
Connaissant les pédigrées de certains d’entre vous, je me permets de dire que vos compétences ne sont plus à prouver donc je saupoudre de modération :wink:

Mon message était posté dans le but d’avancer et de profiter à tous.
Ok pour du débat, mais en aucun cas ce post ne doit être sujet à “partir en vrille” :sunglasses:

++