Démo Lego

Dans la grande majorité des cas, un workflow K2 démarre suite à la saisie d’un formulaire K2, mais ça n’est pas le seul point d’entrée possible ! Un workflow K2 peut se déclencher de manière planifié, suite à une capture d’événement SharePoint ou plus généralement par appel à nos API Rest depuis n’importe quel outils tiers.

Et effectivement, le champ des possibles est énorme avec les API Rest. Pour ma part j’ai par exemple eu l’occasion dernièrement de créer un processus de validation de factures suite à une étape de reconnaissance de caractères par ABBYY, ou encore de créer un boîtier connecté pour simuler un processus de gestion des incidents lors de l’appui sur l’interrupteur d’arrêt d’urgence d’une ligne de production.

Après quelques photos de cette dernière démo sur Twitter, le monde entier m’a réclamé un article expliquant ce projet… voici donc un billet fleuve expliquant comment j’ai procédé.

La simulation de notre chaîne de production en Lego

Présentation générale

Ce projet a fait suite à un hackathon interne où il était question de sortir des démos classiques et assez administratives pour illustrer l’usage de K2 qui est fait par nos clients dans la vie réelle. Un événement (Microsoft Envision pour ne pas le citer) se profilait et nous nous retrouvions dans la zone “industrie”… présenter une gestion des entrées/sorties de collaborateurs, une demande d’investissement, d’achat ou de congés était à exclure.

Nous avons donc travaillé sur une application de gestion des incidents dont le déclenchement était externe.

Comme vous pouvez le voir sur la photo ci-dessus, la démo se compose de 3 éléments principaux :

  • Une maquette (en Lego Technic) de tapis roulant, animée par un petit moteur à courant continu.
  • Un boîtier (complètement standard) avec deux boutons, un interrupteur coup de poing, et un bouton vert, transformé en objet connecté (IoT) grâce au module ci-dessous.
  • Une boîte (en Lego Classic), qui contient un ordinateur monocarte, en l’occurrence un Raspberry Pi 4 et son module caméra.

Le fonctionnement de la démo est on ne peut plus simple, à chaque bouton correspond une action possible :

  • Lorsqu’on appuie sur le l’interrupteur coup de poing, le tapis roulant arrête d’avancer, une photo est prise grâce au module caméra du Raspberry Pi, puis un processus K2 de gestion des incidents est démarré sur notre tenant K2 Cloud.
  • Le bouton vert, quant à lui, déclenche un autre processus K2, qui n’a pas d’influence sur la maquette Lego et sur lequel je ne m’attarderai pas dans cet article.

Choix des composants

Toute l’intelligence de la maquette est gérée par le Raspberry Pi. Les principales raisons qui nous ont poussé vers la plateforme Raspberry Pi sont :

  • Les dimensions minimalistes de cet ordinateur.
  • Ses broches GPIO (General Purpose Input / Output) nous permettant de piloter une infinité de composants électroniques en lecture (par exemple pour surveiller l’état d’un capteur) ou en écriture (allumer une LED, actionner un relais…).
  • Très économique. Nous avons opté pour le modèle le plus puissant produit par la Raspberry Pi Foundation, valant une soixantaine d’euros, pour nous laisser la possibilité à l’avenir de créer d’autres démonstrations plus gourmandes en puissance de calcul, mais dans le cas de cette démo un Raspberry Pi Zero W à 10€ ferait amplement l’affaire ! Avec un peu plus d’efforts, il serait même probablement possible de réaliser ce projet avec un Arduino.
  • Possibilité d’y brancher une caméra gérée nativement par l’ordinateur.
  • Possibilité de se connecter à internet grâce à sa puce Wifi intégrée.
  • Une grosse communauté autour des produits Raspberry Pi, permettant de trouver beaucoup de ressources et d’aide, enk2besoin 🙂

En ce qui concerne la maquette Lego, nous avons détourné un kit Lego Technic permettant normalement de créer une pelleteuse, mais nous l’avons détourné pour faire de ses chenilles un tapis roulant, comme on pourrait en voir sur une ligne de production, et qui transporte des billes du bas vers le haut. Une fois arrivées en haut, les billes tombent dans une rigole qui les ramène en bas pour qu’elles puissent repartir pour un tour.  Ce genre de machines Lego parfaitement inutiles et donc totalement indispensables est ce qu’on appelle un module GBC pour Great Ball Contraption, ou Grand Bidule à Balles en français. Là encore, il y a une communauté très active autour de ce genre de machines, ce qui nous a permis de trouver des plans tout faits pour réaliser notre tapis roulant. Les seules adaptations que nous avons faites par rapport au plan sont l’ajout de la rampe de retour des billes et l’utilisation d’un autre moteur qu’un Lego Technic.

A l’origine nous avions prévu d’utiliser un moteur récupéré d’un pistole Nerf cassé (oui, nous sommes de grands enfants chez K2 :)), mais nous nous sommes finalement tournés vers un moteur plus adapté qui nous aura coûté la somme extravagante de 6€50. En effet, le moteur Nerf avait une vitesse de rotation bien trop élevée pour notre usage, avec comme conséquence un faible couple, exactement l’inverse de ce dont nous avions besoin. De plus il avait une fâcheuse tendance à surchauffer lors d’un usage prolongé. Tous ces soucis se sont évanouis avec notre autre moteur.

Branchements

Voilà à quoi ressemble le circuit électronique servant à relier les boutons, le moteur et l’ordinateur. Sur la droite du circuit vous pouvez voir les fameuses broches GPIO du Pi. Pour réaliser cette modélisation, j’ai utilisé le logiciel KiCad qui a le mérite d’être open source et néanmoins très complet.

Modélisation du circuit électronique

Comme vous pouvez le constater, il s’agit d’un schéma relativement simple, mais si vous êtes un peu rouillé de vos cours de techno ou que vous n’avez jamais fait d’électronique, je vais me fendre d’une explication !

La première chose qui pourrait vous interloquer sur ce diagramme, c’est le fait qu’il y ait 3 interrupteurs (les symboles libellés Circuit Breaker CB1, CB2 et CB3) dessus, alors que la maquette n’a que deux boutons. Bien vu ! En réalité, chacun des boutons sur le boîtier que nous utilisons sur la maquette comporte deux interrupteurs : un normalement ouvert (NO) et un normalement fermé (NF ou normally closed NC). Pour le bouton vert, puisqu’il n’a aucune interaction avec la maquette Lego, je n’utilise que son interrupteur normalement ouvert. Si on appuie dessus, du courant est transmis à la broche GPIO 11 du Pi, programmée pour déclencher un workflow lorsqu’elle est sous tension. En revanche pour le bouton coup de poing, j’ai bien besoin des deux interrupteurs :

  • Comme pour le bouton vert, j’utilise l’interrupteur NO pour y brancher la broche GPIO 7 du Pi. Quand le bouton coup de poing est enfoncé, la broche se retrouve sous tension et le Pi prend une photo puis déclenche le process de gestion des incidents via un appel aux API Rest de notre tenant K2 Cloud.
  • L’interrupteur NC sert quant à lui à alimenter le moteur à courant continu qui fait tourner le tapis roulant en Lego. Lorsque le bouton coup de poing est enfoncé, cette partie du circuit électronique se retrouve donc hors tension et le tapis s’arrête.

La deuxième chose qui pourrait vous intriguer sur le circuit sont les connexions entre les broches GPIO 7 et 11 du Pi et la masse (là où sont les résistances R2 et R3). Pourquoi ne pas directement brancher ces broches aux interrupteurs ? Il s’agit de résistances de « pull down ». Sans ces dernières, lorsque les interrupteurs restent ouverts, les broches GPIO sont « flottantes », c’est-à-dire qu’elles peuvent aussi bien détecter qu’elles sont sous tension ou au contraire hors tension, nous retournant donc des valeurs aléatoires. Le fait de les relier à la masse nous permet donc d’être sûr d’obtenir une tension nulle lorsque les interrupteurs sont ouverts. Et dans le cas où les boutons sont appuyés, les résistances de 10k Ohms nous garantissent que le courant, qui emprunte toujours le chemin avec la plus faible résistance, ira bien aux broches GPIO plutôt que de retourner directement à la masse.

Résistance “pull down”

Le dernier point qui pourrait retenir votre attention ici est la diode D2, qui semble à contre-courant du circuit. C’est bien entendu voulu : ce type de diode montée en parallèle d’un moteur s’appelle une diode « fly-back ». Elle permet au courant encore présent dans le moteur lors de l’ouverture du circuit de se dissiper sans remonter à l’alimentation, ce qui risquerait d’endommager le Raspberry Pi.

Diode “fly back”

Voilà pour la théorie ! Une fois ce circuit modélisé, je l’ai ensuite réalisé sur une planche de prototypage ou breadboard en anglais, ce qui m’a permis de valider son bon fonctionnement en conditions réelles. C’est même dans cet état que la maquette était visible au salon Microsoft Envision au mois de Novembre dernier !

Le prototype

Evidemment, même à court terme ce mode de fonctionnement est problématique pour une démo qui doit être déplacée régulièrement pour des salons et conférences. Nous avons donc pris le temps de modéliser un vrai circuit imprimé, afin de le faire fabriquer et disposer d’une partie électronique beaucoup plus commode à déplacer et qui ne risque pas de se débrancher à moindre mouvement.

Ça tombe bien, KiCad dispose d’un module permettant d’assigner à chacun des composants d’un circuit ce qu’on appelle une empreinte, représentant en somme la place qu’ils prennent sur une carte électronique, ainsi que le besoin ou non de percer cette dernière pour pouvoir les y souder. Une fois ces empreintes assignées, en fonction des composants que nous avions à disposition (à savoir des composants traversant THT [through hole technology], nécessitant donc des perçages, par opposition à des composants dits de surface SMD / SMT [surface mount device / technology]), il ne reste plus qu’à disposer ces derniers sur une zone de dessin et de les relier entre eux par des traces de cuivre, qui font office de fils sur un circuit imprimé (PCB pour printed circuit board en anglais).

Modélisation du PCB

Cette modélisation génère un fichier qui est exploitable par les fabricants de PCB. Nous avons décidé de faire fabriquer le nôtre par OSHPark.

Rendu 3D du PCB

Après quelques semaines d’attente, la petite enveloppe tant espérée est bien arrivée, il ne restait plus qu’à souder tous les composants sur la carte, en se référant à la modélisation et en faisant bien attention de placer les diodes dans le bon sens !

Le PCB réalisé par OshPark, tout juste sorti de l’enveloppe
Le PCB après soudure
Et enfin… le PCB posé sur le Raspberry Pi

Partie Logicielle

La partie logicielle se décompose en 3 volets :

  • Une application K2 avec plusieurs formulaires, un workflow (deux si on compte celui du bouton vert, mais encore une fois je ne m’attarderai pas dessus aujourd’hui :)) et évidemment pas mal de SmartObjects.
  • Un script Python sur le Raspberry Pi qui permet de traiter l’appui sur les boutons et de démarrer les workflows associés via un appel aux API Rest de K2.
  • Un peu de paramétrage pour que le Raspberry Pi fonctionne sans écran, en lançant automatiquement le script Python mentionné dans le point précédent à son démarrage.

Workflow K2

Le workflow K2 qui est démarré lorsque le bouton coup de poing est enfoncé est le suivant :

Workflow “gestion des incidents”

Comme vous l’avez peut-être deviné à sa lecture, ce workflow peut démarrer automatiquement ou bien suite à la saisie d’un formulaire. Dans le cas d’un démarrage automatique, une tâche est envoyée au responsable de l’équipement qui a détecté un incident, pour lui demander de le qualifier.

Un formulaire responsive lui pose quelques questions simples, avec un minimum d’informations à saisir pour déterminer la suite du déroulement du processus, sans perdre de temps si urgence il y a.

Formulaire responsive vu depuis un smartphone
Photo prise par le Raspberry Pi et stockée dans SharePoint

Il a la possibilité d’ajouter des photos depuis son terminal à celle prise automatiquement par le Raspberry Pi.

Ensuite, en fonction des cases à cocher qu’il aura positionné à « Oui » sur le premier onglet du formulaire, les branches du workflow « Infirmerie », « Maintenance » et « Service client » s’exécuteront ou non, en parallèle. Donc si des blessés ont été signalés, une personne de l’infirmerie sera envoyée sur place pour prendre en charge ces derniers, mais si aucun retard ni dégât n’ont été constatés, alors ni la maintenance ni le service client ne seront impliqués dans le workflow.

Une fois ces étapes passées, une seconde tâche est envoyée au responsable afin qu’il saisisse un rapport de l’incident.

A chaque étape du processus, un message Teams est publié dans un canal dédié.

Publication automatique dans Teams

Script Python

Voilà le script Python qui permet de surveiller les broches 7 et 11 du Raspberry Pi et de démarrer les processus K2 associés. Il faudra évidemment l’adapter en fonction de vos environnements et nous n’avons pas trop travaillé sur la sécurité 😉

import RPi.GPIO as GPIO
import time
from datetime import datetime
from picamera import PiCamera
import requests
import base64
import os

# Broche GPIO des boutons
pinPunch = 7 # Bouton coup de poing (pour la ligne de production)
pinBatch = 11 # Bouton pour changement de lot

# Chemin où est enregistrée l'image capturée avant d'être transmise au webservice
path = '/home/pi/CameraImages/image.jpg'

# Valeurs à transmettre au webservice
K2RestAPIMethod = 'https://<cloudTenant>.onk2.com/Api/Workflow/V1/workflows/'
IncidentManagementProcessId = 160
NewBatchProcessId = 168
ProdLine = 'Raspberry Pi'
K2ProcessPriority = 0
Account = '<account>'
Password = '<pwd>'

# Initialisation GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pinPunch, GPIO.IN)
PunchCurrentValue = GPIO.input(pinPunch)
PunchPreviousValue = GPIO.input(pinPunch)
GPIO.setup(pinBatch, GPIO.IN)
BatchCurrentValue = GPIO.input(pinBatch)
BatchPreviousValue = GPIO.input(pinBatch)

# Initialisation caméra
camera = PiCamera()
camera.resolution = (1024, 768) # faible résolution pour limiter la taille du JSON à transmettre au webservice K2
camera.start_preview()
time.sleep(2)

# Boucle principale
try:
    while(1):
        PunchCurrentValue = GPIO.input(pinPunch)
        BatchCurrentValue = GPIO.input(pinBatch)
        
        if PunchCurrentValue != PunchPreviousValue: # Changement d'état de l'interrupteur
            time.sleep(.5) # Temporisation pour éviter les rebonds de l'interrupteur qui provoquerait des changements supplémentaires et indésirables
            if PunchCurrentValue == GPIO.HIGH: # L'interrupteur coup de poing a été enfoncé
                # Prendre une photo
                camera.capture(path)
                image_64 = base64.b64encode(open(path, 'rb').read())
                DateDeclenchement = datetime.now()
                
                # Construire le JSON puis le transmettre à K2
                K2WebserviceJson = '{"priority":' + str(K2ProcessPriority) + ', "dataFields":{"Ligne de production":"' + ProdLine + '", "Image64":"' + image_64.decode('utf-8') + '"}}'
                resp = requests.post(K2RestAPIMethod + str(IncidentManagementProcessId), K2WebserviceJson, headers={'Content-Type':'application/json'}, auth=(Account, Password))
                
                # Supprimer l'image du système de fichiers
                os.remove(path)
            
            PunchPreviousValue = PunchCurrentValue
                
        if BatchCurrentValue != BatchPreviousValue: # Changement d'état de l'interrupteur
            time.sleep(.5) # Temporisation pour éviter les rebonds de l'interrupteur qui provoquerait des changements supplémentaires et indésirables
            if BatchCurrentValue == GPIO.HIGH: # Le bouton pour changement de lot a été pressé                
                # Démarrer le processus de changement de lot
                resp = requests.post(K2RestAPIMethod + str(NewBatchProcessId), '{}', headers={'Content-Type':'application/json'}, auth=(Account, Password))   
                
            BatchPreviousValue = BatchCurrentValue
finally:
    camera.stop_preview()
    GPIO.cleanup()

Le script est plutôt simple et assez commenté pour que je n’aie pas à m’étendre dessus, si ce n’est sur les temporisations que vous apercevez lorsqu’un changement d’état d’un des boutons est détecté time.sleep(.5). En effet, la boucle de ce script s’exécute des centaines de fois par seconde, donc sans ces temporisations de quelques millisecondes, nous risquerions de détecter plusieurs changements d’état pour un seul et même appui sur un bouton, parce l’interrupteur a tendance à « rebondir » lorsqu’on l’actionne. Cette temporisation n’empêche donc pas les interrupteurs de rebondir, mais laisse suffisamment de temps à ceux-ci de le faire avant que le script ne commence une nouvelle boucle et évite donc de détecter involontairement plusieurs actions au lieu d’une.

Mode Headless

Le mode headless est le jargon pour dire qu’on configure le Raspberry Pi pour fonctionner sans écran. Dans notre cas, je suis allé au plus simple en enregistrant le script Python à exécuter au démarrage du Pi sur le bureau de celui-ci.

Une fois enregistré, je n’ai plus eu qu’à ajouter la ligne de commande suivante dans le fichier /etc/rc.local : sudo python3 /home/pi/Desktop/IncidentManagement.py &

Pour les profanes de la ligne de commande Linux, quelques explications s’imposent :

  • sudo indique que l’on veut exécuter la commande en question avec les droits d’administrateur.
  • python3 est le programme que l’on souhaite exécuter. Python étant un langage interprété, il faut bien lui indiquer l’interpréteur que l’on souhaite utiliser pour exécuter un script, contrairement à un langage compilé.
  • /home/pi/Desktop/IncidentManagement.py est l’emplacement sur le système de fichiers du script que le programme python3 doit exécuter.
  • Enfin l’esperluette & de fin est ce qu’on appelle un fork, c’est-à-dire que cette ligne de commande va s’exécuter dans son propre processus, sans bloquer l’exécution du reste des lignes de commande du fichier rc.local. Dans notre cas, puisque notre script comporte une boucle infinie, c’est indispensable 🙂

Voilà chers lecteurs, je crois bien que j’ai fait le tour de ce qui a été mis en place pour réaliser cette démonstration. J’espère que vous aurez trouvé cet article intéressant et qu’il aura élargi votre vision du champ des possibilités de la plateforme K2. Un dernier mot pour vous dire que si vous voulez voir la démonstration tourner, nous avons également réalisé un webinar autour de celle-ci, que vous pouvez visionner sur notre chaîne Youtube :

A très bientôt pour un nouvel article !

Thomas

Chez K2 France depuis 2013, je ne suis pas magicien mais j'ai tout de même quelques tours dans mon sac en matière d'applications K2, dont je veux bien vous révéler les secrets ;-)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.