Outils pour utilisateurs

Outils du site


staublivissage


TP Robot Staubli à l'IUT

Présentation du projet

L'objectif de ce projet est de vous familiariser avec l'outils Staubli Robotic Suite afin de programmer une tâche robotique sur un robot manipulateur 6 axes. La tâche consiste à saisir un bouchon de bouteille et à venir le visser sur le goulot d'une bouteille. Afin de réaliser cette tâche, il aura fallu procéder à l'intégration d'une infrastructure de capteurs communicants comportant notamment:

  1. Un capteur de couple (déjà étudié dans le module capteur) permettant la mesure du couple de serrage
  2. Un système de vision 2D composé d'une caméra et d'un ordinateur sur carte Raspberry Pi permettant la localisation du bouchon dans l'espace de travail du robot.

Pour le développement de cette tâche, vous procéderez d'abord à la configuration d'un projet et de la cellule robotique. Ensuite vous développerez votre programme en réalisant des simulations, et utiliserez à cette occasion des logiciels fournis pour simuler les capteurs, puis finalement vous pourrez tester sur le robot réel en fin de projets afin de procéder aux réglages fins permettant d'adapter les mouvements du robots à la configuration spatiale des éléments dans la cellule.

Dans un premier temps, vous programmerez le robot sans utiliser les capteurs. Le capteur de couple sera intégré dans le cadre de ce projet dans un second temps et le capteur de vision sera intégré plus tard dans le cadre d'une séance dédiée.

Dans le cadre de ce projet, les communications entre le robot et l'infrastructure se feront via des Sockets TCP et UDP à l'aide de chaînes de caractères ASCII et les autres entrées/sorties numériques et analogiques ne seront pas utilisées.

Il faut que le dongle USB de licence monoposte (VERT) soir installé sur le poste près du robot et que le dongle de licence multiposte (ROUGE) soit installé sur un des postes étudiants avant que les étudiants ouvrent le projet avec SRS sinon les éléments 3D de la scène n’apparaissent pas.

Vidéo de la simulation sur un autre robot: https://youtu.be/o6v0avbkwQ4 <html> <iframe width=“560” height=“315” src=“https://www.youtube.com/embed/o6v0avbkwQ4” frameborder=“0” allow=“accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture” allowfullscreen></iframe> </html>

Planning prévisionnel

planning 2022:

durée Tâches
2h Présentation de la manip et organisation en différentes étapes:
-Vissage en boucle ouverte avec un préhenseur type pince.
-Vissage en boucle fermée en utilisant un préhenseur doté d'un capteur de couple.
-Intégration de la vision pour localiser le bouchon à saisir.
Lecture de la documentation du langage VAL3: types et différentes fonctions à utiliser dans le projet.
4h Configuration du projet, import et placement des éléments de la cellule (préhenseur et différents objets), positionnement et configuration du robot en Programmation Hors Ligne pour qu'il puisse faire la tâche.
Simultanément, démonstration (en petits groupes) par l'enseignant de la commande manuelle du robot réel en articulaire et en cartésien à l'aide du pendant, détermination des repères World et Flange, présentation des modes (manuel, auto et auto déporté) et des éléments de sécurité (détection ouverture de portes). Discussion au sujet des différentes entrées/sorties.
Programmation du mouvement de saisie du bouchon et de transport jusqu'au goulot de la bouteille à l'aide d'un mouvement de type 'cycle en U' utilisant les modes de mouvement point à point et linéaire.
Utilisation du simulateur pour exécution en continu ou en mode Débug pas à pas.
Tests sur le robot réel des mouvements de saisie et de vissage saccadé et apprentissage des points dans l'environnement réel.
4h Poursuite du développement.
Installation et configuration de l'application simulant un capteur, explication du serveur de capteur et des fonctions de communication par socket en VAL3.
Développement et intégration du capteur de couple.
4h Ajout d'une tâche parallèle à l’exécution des mouvements du robot pour envoyer la configuration du robot en temps réel (il se comporte alors comme un capteur).
Modification du programme pour des mouvements non saccadés en utilisant la File d'ordres et l'interruption/vidage lorsque le couple de vissage est atteint.
Intégration d'une position variable pour la saisie du bouchon dans un premier temps issue d'un simulateur de capteur (en préparation de la localisation par vision industrielle). Pour cela, utilisation de fonctions VAL3 permettant de tester si la tâche est réalisable.
4h Terminer le travail des séances précédentes
Optimisation des temps de cycles en adaptant les descripteurs de mouvements.
Petits projets personnalisés.

Consignes pour l'évaluation du projet

Durant le projet, vous travaillerez en binôme, et serez normalement évalués conjointement, à moins que l'enseignant juge que le travail n'a pas été réparti équitablement. Vous devrez produire un rapport avec le code commenté (notamment par des messages affichés sur l'interface utilisateur) et des captures d'écran (Pour faire des captures d'écran avec Windows 10: SHIFT+WINDOWS+S ). Vous fournirez également une archive zip du projet contenant les informations de suivi de version GIT. Vous veillerez à ne pas casser le matériel et dans le cas contraire, cela pourra être pris en compte dans la notation.

Informations sur la structure d'un programme VAL3 et sur les types utilisés

L'enseignant vous guidera au cours du projet dans la lecture de la documentation du langage VAL3 utilisé par SRS pour programmer le robot. Ouvrez cette documentation dans une autre fenêtre de navigateur pour la consulter pendant tout le TP, elle est disponible à l'adresse: https://bvdp.inetdoc.net/files/iut/staubli/documentations/Val3.PDF

Informations sur l'infrastructure de capteurs communicants

Outil de gestion de versions GIT

Durant le projet, nous utiliserons un outils pour suivre les changements effectués sur les fichiers au fur et à mesure du développement. Ceci nous permettra éventuellement de revenir en arrière en cas de problème et vous montrera le code nécessaire pour chaque nouvelle fonctionnalité.

Installation de GIT en version portable pour Windows et configuration

Récupérer et exécuter: https://github.com/git-for-windows/git/releases/download/v2.35.0.windows.1/PortableGit-2.35.0-64-bit.7z.exe

Installer l'application dans le dossier D:\PortableGit

Créer dans D:\ un fichier alias.txt

alias.txt
git=D:\PortableGit\bin\git $*
gitk=D:\PortableGit\cmd\gitk

Charger ce fichier à chaque ouverture d'une console en copiant collant dans une fenêtre cmd

Doskey /MACROFILE=D:\alias.txt  

Pour lister les paramètres de configurations de l'outils, copier-coller dans une console Windows:

git config --list --show-origin

Pour configurer votre identité, copier-coller dans une console Windows en adaptant:

git config --global user.name "Bertrand Vandeportaele"
git config --global user.email secret@meninblack.jupiter

Consigne d'utilisation

Vous devrez d'abord faire ce qui est indiqué dans la partie “Récupération du projet SRS de départ et configuration” avant de faire ce qui est indiqué ici, mais les informations concernant GIT sont regroupées pour plus de lisibilité.

GIT sera utilisé depuis la console Windows (que vous garderez ouverte) en utilisant des copier-coller de commandes présentées ci dessous, que vous adapterez en fonction des besoins.

Vous pourrez, si vous le souhaitez, consulter les documentations: https://git-scm.com/book/fr/v2/D%C3%A9marrage-rapide-Param%C3%A9trage-%C3%A0-la-premi%C3%A8re-utilisation-de-Git https://www.atlassian.com/git/tutorials/gitk https://git-scm.com/download/gui/windows https://www.atlassian.com/fr/git/tutorials/undoing-changes

La commande git doit être lancée depuis un dossier contenant un dépôt (un ensemble de fichiers permettant le suivi). Dans notre cas ce dossier sera celui dans lequel vous aurez décompressé le projet SRS, pour aller dans ce dossier saisir à chaque début de séance (vous pourrez utiliser la touche Tabulation pour auto-compléter les noms de dossiers):

 R:
 cd R:\lprob\"nom_prenom"\CELL_IUT0 


La première fois, il faut initialiser le dépôt en copiant-collant:

git init

et créer une version initiale stockant l'état des fichiers tels que vous les aurez récupéré. Habituellement on ne fait pas l'ajout de tous les fichiers mais comme ici VAL3 est un langage interprété, on peut suivre tous les fichiers. Cette commande sera à refaire si vous ajoutez de nouveaux fichiers au projet:

git add * 

Ensuite, il faut enregistrer cette version en faisant un “commit”, associé à un commentaire qui vous permettra d'indiquer ce qu'il fait (voyez cela comme un commentaire temporel). La première fois, vous saisirez:

 git commit -m"ajout de tous les fichiers en version initiale"

Les fois suivantes, vous saisirez:

 git commit -a -m"Whaou! mon programme arrive à faire un truc super: l exercice 2!!!"

Vous utiliserez l'outils gitk (que vous garderez ouvert pendant toute la séance, en pressant “F5” pour rafraîchir l'affichage) pour visualiser les différentes version en copiant-collant:

gitk

En cas de problème, et après accord du professeur, pour ramener vos fichiers à l'état du dernier commit en annulant toutes les modifications locales non commitées, fermer SRS puis copier coller:

git reset --hard


Récupération du projet SRS de départ et configuration

Télécharger et décompresser le fichier: https://bvdp.inetdoc.net/files/iut/staubli/projets_SRS/Cellule_depart_staubli_vide.zip

Vous devez dézipper le dossier CELL_IUT0 afin qu'il soit dans le dossier R:\lprob\“votrelogin”\CELL_IUT0

Il est temps d'initialiser le dépot git tel que montré plus haut.

Ensuite, lancer le programme SRS en cliquant sur: Menu Démarrer→Tous les programmes→Staubli Robotic Suite 2019→Staubli Robotic Suite 2019.10.1

et ouvrir le projet.


Dans la vue 3D vous devez voir la cellule. Vous pouvez cliquer à gauche sur Cameras→Camera pour sélectionner la vue perspective telle que visible ci dessous:

Le contrôleur du robot est configuré dans le projet fourni, il faut maintenant créer une nouvelle application, pour cela:

  1. Choisir l'onglet Cellule dans la fenêtre de droite
  2. Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître “Controller1 [s8…]”
  3. Cliquer droit sur “Controller1 [s8…]” puis cliquer gauche sur “Nouvelle application”
  4. Saisir un nom: “Projet” suivi d'un numéro sur 2 chiffres qui vous sera attribué en début de séance et que vous conserverez durant toutes les séances. Il est important que vous ayez chacun un nom de projet différent pour pouvoir identifier votre programme une fois chargé sur le contrôleur du robot!
  5. Cliquer sur Ok

Il faut maintenant configurer l'outils du robot, pour cela:

  1. Choisir l'onglet Géométrie dans la fenêtre de droite
  2. Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître “Controller1 [s8…]” puis faire de même pour votre Projet
  3. Cliquer droit sur “Flange” (qui signifie Bride en français, soit l'emplacement où fixer l'outils) puis cliquer gauche sur “Nouvelle donnée”
  4. Saisir un nom pour l'outils, ou laisser le nom par défaut (tTool) puis cliquer sur Ok
  5. Vérifier que tTool apparaît maintenant en cliquant sur la flèche à coté de “flange[0]”

Edition du programme

  1. Cliquer sur l'onglet “Accueil” puis sur “Afficher la vue 3D”
  2. Choisir l'onglet Cellule dans la fenêtre de droite
  3. Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître “Controller1 [s8…]” puis “Projet” puis double cliquer sur “start()” pour ouvrir la fenêtre d'édition du programme.

Afin d'organiser la disposition des sous fenêtres pour permettre de voir simultanément le programme et le simulateur 3D du robot, cliquer gauche longuement sur l'onglet Projet-start puis, tout en maintenant le clic déplacer la flèche vers le carré de droite qui vient d'apparaître, relâcher alors le clic gauche. Vous devriez obtenir un affichage ressemblant à:

La vue 3D utilise les mêmes principes que Catia pour naviguer:

  • molette vers le haut pour dézoomer et vers le bas pour zoomer (ils sont tordus les mécanos…)
  • clic molette maintenu pour déplacer la caméra
  • clic molette + clic droit maintenus pour orienter la caméra

En fonction de la position de départ du mouvement de souris, la rotation obtenue n'est pas la même. Pour afficher le disque délimitant les zones de départ, il faut cliquer sur l'icone rotation en bas à droite à coté de zoom.

Il peut être nécessaire de désactiver l'affichage du plancher car il fait buguer l'application. Pour cela, cliquer droit sur la vue 3D, “réglages affichage” et décocher “afficher plancher”.

Le programme propose par défaut un certain nombres de vues (de face, de coté, etc…). Il peut être intéressant d'ajouter des caméras fixes dans l'environnement pour observer les mouvements du robot depuis des points de vues particuliers. Pour cela, configurer la vue à l'aide de la souris puis dans l'arbre à gauche de la vue 3D, cliquer droit sur la vue 3D et sélectionner Caméras→ajouter une camera pour la vue courante. Il suffira de double cliquer sur la caméra créée dans l'arbre pour revenir sur cette vue.

Dans certains cas l'affichage de trièdres est trop petit pour être visible. Pour changer leur taille, aller dans l'onglet Simulation→réglage affichage→taille des trièdres (en pixel).

Lorsqu'il est nécessaire de définir un repère à l'aide de clics de souris, l'ordre de clics des points définit l'orientation du 3° axe par la règle de la main droite (aussi appelée du tire-bouchon).

Modification de la configuration du robot

Pour modifier la configuration du robot, double cliquer sur Scène→Robot→Controller dans l'arbre, ce qui fait apparaître des disques permettant de contrôler chaque articulation. Cliquer gauche maintenu sur un des disque pour faire tourner l'articulation. Il est également possible de modifier la configuration du robot en cartésien en jouant sur le trièdre placé au niveau de la bride du robot. Cliquer droit sur le robot pour faire apparaître le menu et clic gauche sur “déplacement manuel” pour faire apparaître la fenêtre de configuration du robot qui permet un réglage fin et la visualisation des valeurs extrémales atteintes par chaque articulation et le pilotage manuel en cartésien:

L'affichage de l'espace de travail (righty ou lefty) est obtenu en sélectionnant Scène→Robot→Controller dans l'arbre, puis clic droit sur le robot et afficher l'espace de travail… Il s'agit du volume atteignable par le milieu de l'axe 5 du robot, ce sont juste 2 sphères calculées statiquement à partir du modèle du robot, mais elle permette de se faire un idée pour positionner les différents éléments dans la cellule.

Configuration de la cellule

Import du modèle 3D de la cellule

Récupérer le modèle: https://bvdp.inetdoc.net/files/iut/staubli/stl/cellule_simplifiee.wrl

  1. Importer le modèle dans le projet
  2. Onglet Modeleur→Ajouter un modèle CAO
  3. Chercher le fichier cellule_simplifiee.wrl à l'aide du bouton …
  4. Régler la résolution sur Standard et cocher l'option “Copier et insérer le fichier” et “importer comme un assemblage”
  5. Dans la vue 3D, dans Scène→Géométrie→cellule_simplifiee_1.wrl, clic droit puis “éditer la postion”

Editer la position absolue suivante:

63.3
-68.2
550.45 
0
0
-90

Import du modèle de pince

Récupérer le modèle STL de la pince Schunk et du préhenseur de bouchon: https://bvdp.inetdoc.net/files/iut/staubli/stl/adaptateur_pince_bouchon_iut2021_open.stl

Le modèle téléchargé est déjà référencé correctement pour faciliter le positionnement du Handler (point saisisseur) et du Handle (base: point de saisie). La bride du robot (Flange) est un Handler en Val3, et nous allons connecter ce Handler au Handle de l'outils pince. Il est important de respecter scrupuleusement les étapes suivantes sinon l'outils ne sera pas correctement ajouté au robot!

L'image suivante montre le repère du handler du robot c'est à dire sa bride (Flange en anglais):

Pour ajouter la pince au robot:

  1. Si un outils est déjà attaché au handler du robot: Scene→Robot→Controleur→Base→Controleur click droit et Détacher
  2. masquer le robot→ cliquer droit sur l'arborescence de scène sur Controller et décocher “Afficher le robot”
  3. Onglet Modeleur→Ajouter un modèle CAO
  4. choisir Copier et insérer le fichier
  5. l'objet apparaît dans l'arbre en tant que Géométrie, cliquer droit dessus et faire “nouvel outils”
  6. NE PAS déplacer l'outils (car il est normalement bien positionné)
  7. choisir dans l'arbre l'outils et son handle
  8. cliquer sur “Edition” sous la barre de menu
  9. cliquer droit sur handle et “Editer la position”
  10. Régler tout à 0 dans la position absolue
  11. cliquer droit sur handler et “Editer la position”
  12. Régler tout à 0 dans la position absolue sauf Z à 140.00
  13. Sortir du mode Edition
  14. Cliquer droit sur Tool1 dans l'arborescence, attacher à et choisir le handler du robot
  15. réactiver l'affichage du robot

Ensuite il faut associer l'outils à la variable tTool, pour cela:

  1. Sélectionner le Tool1 dans l'arborescence puis faire CTRL+C
  2. pour utiliser un outils de la géométrie graphique vers une variable val3, il faut clic gauche sur le handler de l'outils, CTRL+C et coller dans la ligne de la variable tTool[0] dans l'onglet données. Vous devriez obtenir un vecteur dont toutes les composantes sont à 0 à l’exception du champ Z à 140.00.

Ensuite, cliquer droit sur le handler de l'outils puis définir comme TCP (Tool Center Point= Centre De l'Outils) pour pouvoir déplacer l'outils.

Vous devriez voir la pince solidaire de la bride du robot, comme sur la figure suivante, dans laquelle le repère du haut est le handler du robot connecté au handle de la pince (sur la bride), alors que le repère du bas est le handler de la pince, situé au centre des mors:


Ajout des éléments dans la cellule

Pour ajouter un objet dans l'espace de travail du robot:

  1. Onglet Modeleur→Ajouter un modèle CAO
  2. Télécharger le fichier et aller le chercher dans l'arborescence avec le bouton “…”
  3. Choisir Copier et insérer le fichier
  4. L'objet apparaît dans l'arbre en tant que Géométrie

Insérer dans l'espace de travail du robot:

Vous devez positionner les éléments pour obtenir une configuration proche de celle du robot réel (vous adapterez les positions plus tard en relevant avec le pendant la configuration cartésienne du robot lorsqu'il est en position de saisie et de dépose du bouchon). Vous devez obtenir un espace de travail tel que celui visible sur la figure suivante:


Configuration de l'outils

Dans le données, sélectionner la variable tTool de type tool, et double cliquer pour l'éditer. Vérifiez que vous avez bien comme changement de repère {0,0,140,0,0,0}, et que le gripper est bien réglé à FastIO\fOut1 . Saisir 1 pour les 2 champs suivants qui permettent de régler les durées de délais en seconde(s) pour que la pince s'ouvre et se ferme après que la commande lui soit envoyée.

Activation de la détection de collision

Pour activer la détection de collisions dans le simulateur, il faut griser le bouton Simulation→Collision + choisir les événements qui déclenchent les collisions + activer la gestion des collisions dans chaque objet (Propriétés F4).

Ajout d'un sous programme d'affichage bien pratique

Dans la fenêtre cellule→Controller1→Projet…→

  • clic droit et “Ajouter nouveau programme”
  • Nom: logMsgBlock
  • Sauver tout (icone à plusieurs disques)
  • Télécharger le fichier suivant dans le dossier CELL_IUT0\Controller1\usr\usrapp\ en écrasant le fichier qui vient d'être créé par SRS
logMsgBlock.pgx
<?xml version="1.0" encoding="utf-8"?>
<Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
  <Program name="logMsgBlock" access="public">
    <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
      <Parameter name="x_sString" type="string" xsi:type="element" />
      <Parameter name="x_bBool" type="bool" xsi:type="element" />
    </Parameters>
    <Code><![CDATA[begin
  //attend que le robot arrive à la position souhaitée si demandé
  if x_bBool==true
    waitEndMove() 
  endIf
  //assure l'affichage du message
  while logMsg(x_sString)==false
    delay(0) 
  endWhile
end]]></Code>
  </Program>
</Programs>

Dans la fenêtre cellule→Controller1→Projet…→

  • cliquer droit sur Projet…
  • cliquer gauche sur “recharger l'application”
  • vous devriez voir apparaître le programme ainsi que ses paramètres

Démarche de développement et de simulation

Structure du programme

Vous veillerez à bien structurer votre programme en utilisant des sous programmes lorsque cela est judicieux. Au démarrage de votre programme, le fichier “start.pgx” et exécuté. Vous veillerez à informer l'utilisateur du pendant de l'état de votre programme à l'aide de d'appel de fonction d'affichage, afin d'être capable d'identifier facilement la partie du programme en cours d’exécution etc…

Nommage des variables

Vous veillerez à respecter les règles de nommages des variables en fonction de leurs types (voici ce que nous manipulerons dans le projet):

  • variable bool (booléen) commençant par b
  • variable frame (repère) commençant par f
  • variable jointRx (configuration en articulaire) commençant par j
  • variable pointRx (configuration en cartésien) commençant par p
  • variable mdesc (descripteur de mouvement) commençant par m
  • variable num (valeur numérique) commençant par n
  • variable string (chaine de caractères) commençant par s
  • variable tool (outils) commençant par t
  • variable trsf (transformation) commençant par tr
  • variable sio (ressource de communication) commençant par si

Ceci permettra notamment d'ajouter automatiquement une variable à partir du code en faisant clic droit sur la variable puis “ajouter donnée”. Le type de la variable est alors inféré d'après la convention de nommage.

Les noms des variables locales sont de plus préfixés par l_ à ajouter en tant que nouvelle variable locale (pas donnée) et les nom des paramètres sont préfixés par x_. Nous Utiliserons les variables locales pour les variables qui n'ont pas à être réglées depuis le pendant (par exemple les variables numériques de compteurs). Dans le projet, les variables locales n'apparaissent pas dans les “Données” mais dans “Cellule”→Controller1→Projet→start()→Variables locales.

Gestion du temps

Présentation au tableau de la gestion du temps par le contrôleur du robot.


Programmation des mouvements de saisie et de transport du bouchon

Nous allons mettre en place un mouvement semblable à celui présenté page 144 de la documentation pour saisir le bouchon et l'amener en face du goulot de la bouteille. Les fonctions de mouvement utilisables sont:

  • movej(): mouvement en point à point, la trajectoire entre les points optimise la vitesse de déplacement en interpolant sur le coordonnées articulaires
  • movel(): mouvement linéaire dans l'espace de travail
  • movec(): mouvement circulaire dans l'espace de travail

Selon le descripteur de mouvement passé en paramètre à la fonction move, un lissage est possible, et celui-ci peut se faire en interpolant sur les coordonnées articulaires ou cartésiennes.

Simulation

La simulation peut se faire en mode “exécution continue” ou en mode “Debug”.

Mode "Debug"

Dans le mode “Debug”, il est possible de positionner des points d'arrêt dans le programme, d’exécuter des instructions en pas à pas, ou fonction par fonction, et d'espionner la valeurs de variables.

Presser la touche F9 pour activer ou désactiver un point d'arrêt sur une ligne d'un programme. Un point rouge apparaît à gauche de la ligne pour indiquer la présence du point d'arrêt.

Pour synchroniser l'affichage 3D avec le simulateur:

  1. Onglet “Simulation”, cliquer sur icone “PLAY” triangle bleu (Démarrer la synchro)

Pour lancer le Debug du programme

  1. Dans l'onglet Cellule, ouvrir le Controller1→Projet et cliquer gauche sur “start()” pour choisir le programme
  2. Onglet “Val3”, cliquer sur “Démarrer et Debugguer l'application” (CTRL+R,D). On doit alors observer une flêche jaune sur la ligne du premier point d'arrêt visité

Pour éxecuter en pas à pas:

  1. Onglet “Déboguer”, “Pas principal” (raccourci F10)

Observer dans la fenêtre “Emulator Controller” les affichages utilisateurs (au besoin cliquer sur l'onglet “User”)

Amener la souris sur le “?” de la fenêtre de l'émulateur pour voir les raccourcis clavier.

Arrivé à l’exécution de l'instruction WaitEndMove(), le simulateur semble bloqué, ceci est dû au fait que le robot est par défaut en mode “Hold”

  1. Dans la fenêtre “Emulator Controller”, il faut:
  2. Choisir le mode automatique en cliquant sur le bouton rond blanc jusqu'à ce que l'icone “auto” soit en bleu
  3. Mettre le robot sous puissance: cliquer sur le bouton rond avec un trait noir vertical pour le faire devenir vert
  4. cliquer sur l'onglet “Move” (qui devient “Hold”) (SHIFT+F7) pour autoriser le robot à bouger

Pour arrêter un Debug en cours et recommencer:

  1. Onglet “Deboguer” Arrêt du débogueur. (CTRL+D,S abbrégé de Débugguer Stop) .
  2. Onglet Val3, cliquer sur “Démarrer et Debugguer l'application” (CTRL+R,D abbrégé de Run Débugguer )
  3. Fenêtre “Emulator Controller”, cliquer sur “Move”


Mode "Exécution continue"

L’exécution en mode “exécution continue” est accessible depuis le bouton “Démarrer l'application” dans l'onglet “VAL3” ( raccourci (CTRL+R,X)).

A part cela, la synchronisation avec l'affichage 3D et l'émulateur de contrôleur se passent comme pour le mode “Debug”. Les points d'arrêt éventuellement présents dans le programme sont ignorés.

Réglage manuel de la configuration du robot

Pour pouvoir configurer la pose du robot en cliquant sur la vue 3D il faut cliquer sur Onglet Simulation, icone “STOP” afin d’arrêter la synchronisation entre de simulateur et la vue 3D. Dans le cas contraire, c'est le programme qui pilote le robot.

Affichage d'informations pour l'utilisateur du robot

Vous veillerez à afficher avec call logMsgBlock(sString “…”,bBool block) ce que fait le robot après chaque commande move?() pour pouvoir le visualiser sur le pendant. Nous pourrions utiliser le mode debug pas à pas sur le pendant mais ce n'est pas pratique pour le test sur le robot réel. De plus ces commandes d'affichage permettent de documenter le code.

Les affichages sont faits dans l'onglet Journal/Info du pendant (ne sélectionner que Info et désélectionner Critique,Erreur et Attention). Pour afficher une valeur numérique, vous pourrez la convertir en chaîne et la concaténer à une autre chaîne en faisant par exemple:

call logMsgBlock("prise numéro:"+toString(".3",nprise),true)

Utilisation du mode automatique déporté

Il est également possible d'utiliser le mode automatique déporté (remote) pour simuler l'application. Dans ce mode, le bouton de mise en marche de la puissance du robot du pendant n'est pas utilisable. Pour débugger, dans le pendant virtuel, changer le mode en automatique déporté à l'aide du bouton blanc. Une tentative d'exécution de votre programme provoquera l'affichage d'une erreur “Demande de mise sous puissance du bras refusée: la baie est en mode déporté ou invalide”. Pour débloquer cette situation, il suffit d'appeler la fonction VAL3 enablePower() au début de votre programme. Grâce à cela vous n'aurez plus à agir sur le bouton “Move/Hold” et mise sous puissance du pendant virtuel.


Intégration des capteurs

La communication via Socket proposée par SRS ne fait pas de distinction entre les numéros de ports local et distant. Il n'est donc pas possible de faire communiquer directement l'émulateur de robot tournant sur votre PC de développement avec une application émulant un capteur sur le même PC. Nous utiliserons donc une autre machine (dotée d'une adresse IP permettant de l'identifier) appelée “serveur de capteurs” qui sera en charge de centraliser les données issues des différents capteurs réels ou simulés. SRS pourra communiquer avec ce serveur car il dispose d'une adresse IP différente de celle de votre PC. De plus la lecture de données via socket depuis SRS fonctionne de manière bloquante avec timeout, donc le fait d'avoir le pc serveur qui puisse répondre à des requêtes même si le capteur n'a pas fourni de valeur permet par exemple d'indiquer qu'il n'y a pas de donnée disponible rapidement sans que le robot soit bloqué en attente du capteur.

Python 3.9.7 est installé sur les PC Windows. Vous devrez télécharger/modifier un programme python émulant un capteur à l'aide d'une interface graphique.



Adaptation du robot pour la scène réelle

Télécharger votre application vers l'armoire de commande. L'adaptation consiste à déplacer manuellement le robot à l'aide du pendant et à affecter des valeurs “correctes” aux variables de votre programme.

Il faut tout d'abord ouvrir l'application avec le pendant EN MODE MANUEL (sélectionné avec la clef).

Apprentissage d'une configuration articulaire

Pour déplacer le robot à une configuration articulaire donnée:

  • arrêter l'application en cours
  • aller dans le menu Jog
  • choisir le mode “Joint”
  • régler une vitesse faible à l'aide de la touche +/- du haut, surtout si une partie du robot est proche d'un obstacle.
  • utiliser les autres touches +/- pour modifier la position de chaque articulation
  • relever les valeurs pour les écrire dans votre programme ( il est également possible d'enregistrer la configuration dans une variable puis de la rapatrier sur le PC de développement)

Apprentissage d'une configuration cartésienne

Pour déplacer le robot à une configuration cartésienne donnée:

  • arrêter l'application en cours
  • aller dans le menu Jog
  • choisir le mode “Outil”
  • régler une vitesse faible à l'aide de la touche +/- du haut, surtout si une partie du robot est proche d'un obstacle.
  • par défaut, le pendant en mode outils utilise l'outils flange[0] (bride), il faut gérer la translation en z pour avoir le repère du handler de l'outils.
  • Pour choisir le projet, en haut cliquer sur les 3 petits traits à droite de l'outils
  • Pour choisir l'outils dans ce projet, cliquer sur les 3 petits traits en dessous et sélectionner tTool[0]
  • Pour choisir le repère de référence , cliquer en dessous sur les petits traits pour sélectionner le repère world[0] du projet
  • Vous devez voir les coordonnées de tTool[0] exprimées dans le repère world[0]
  • utiliser les autres touches +/- pour modifier la position/orientation du repère outils (dessiné sur la pince)
  • relever les valeurs pour les écrire dans votre programme ( il est également possible d'enregistrer la configuration dans une variable puis de la rapatrier sur le PC de développement)

Vous pouvez vous entraîner à faire ces opérations sur le PC de développement en simulation à l'aide du pendant virtuel:

Rapatriement des données apprises de l'armoire de commande vers le projet SRS

Dans le gestionnaire de téléchargement, cocher à droite Projet→Projet→Données et faire télécharger. Le fichier Projet.dtx (xml) est mis à jour sur le PC mais SRS ne s'en rend pas compte, il faut faire clic droit dans l'onglet “Données”→Cell2→Controller1→Projet puis “Recharger l'application”.

L'enseignant expliquera en séance la démarche de pilotage manuel du robot et de mise à jour des variables du programme ainsi que du téléversement des valeurs numériques vers le programme. En cas de problème pour récupérer ces valeurs, il sera possible de relever manuellement les configurations du robot et de les affecter dans les variables correspondantes du programme (c'est l'approche préférée par l'enseignant car les informations apparaissent dans le code) avec des instructions telles que:

conf
   //configuration des points en articulaire par programme
  //position bras levé
  jBrasHaut={0,	0,	0,	0,	0,	0}
  //position bras vers le bas
  jBrasBas=
 
  //exemple d'affichage
   call logMsgBlock((" déplacement vers jBrasBas: "+toString(".3",jBrasBas.j1)+" , "+ toString(".3",jBrasBas.j2)+" , "+toString(".3",jBrasBas.j3)+" , "+toString(".3",jBrasBas.j4)+" , "+toString(".3",jBrasBas.j5)+" , "+toString(".3",jBrasBas.j6),true)
  delay(3)  
 
  //définition des position des points en cartésien
  //en une ligne
  pSaisieBouchon={{0,0,0,0,0,0},{sfree,efree,wfree}}
  //ou champ par champ
  pSaisieBouchon.trsf.x=
  pSaisieBouchon.trsf.y=
  pSaisieBouchon.trsf.z=
  pSaisieBouchon.trsf.rx=
  pSaisieBouchon.trsf.ry=
  pSaisieBouchon.trsf.rz=
  pSaisieBouchon.config.shoulder=
  pSaisieBouchon.config.wrist=
  pSaisieBouchon.config.elbow=
 
  pVissageBouchon.trsf.x=
  pVissageBouchon.trsf.y=
  pVissageBouchon.trsf.z=
  pVissageBouchon.trsf.rx=
  pVissageBouchon.trsf.ry=
  pVissageBouchon.trsf.rz=
  pVissageBouchon.config.shoulder=
  pVissageBouchon.config.wrist=
  pVissageBouchon.config.elbow=
 


Communication via Sockets


Dans ce projet, l'échange d'information entre le contrôleur du robot et son environnement (notamment des capteurs) est réalisé par réseau ethernet et wifi à l'aide des Sockets. Vous devez dans un premier temps configurer deux sockets dans votre projet SRS pour pouvoir dialoguer (et nous utiliserons ici deux types de sockets, qui seront illustrés en cours de réseau)

Création et configuration des sockets dans le projet

Socket UDP

  1. cliquer sur le contrôleur dans l'arborescence du projet
  2. cliquer sur l'onglet Accueil
  3. cliquer sur l'onglet IO Physiques
  4. clic droit sur “Sockets” puis gauche sur “Editer la carte”
  5. clic gauche sur “+”
  6. choisir “UDP”
  7. régler les paramètres et valider
    1. Nom: siSocketUDP
    2. Port: 10000
    3. Description: Emission etat robot
    4. Timeout: 1
    5. Fin de chaine: 13
    6. IP du serveur: 172.16.6.59
  8. créer une nouvelle donnée de type sio nommée siSocketUDP

Socket TCP

  1. cliquer sur le contrôleur dans l'arborescence du projet
  2. cliquer sur l'onglet Accueil
  3. cliquer sur l'onglet IO Physiques
  4. clic droit sur “Sockets” puis gauche sur “Editer la carte”
  5. clic gauche sur “+”
  6. choisir “TCP client”
  7. régler les paramètres et valider
    1. Nom: siSocketTCP
    2. Port: 30000
    3. Description: requete donnee capteur
    4. Timeout: 1
    5. Fin de chaine: 13
    6. IP du serveur: 172.16.6.59
  8. créer une nouvelle donnée de type sio nommée siSocketTCP

Association des variables Val3 sio aux Sockets

  1. cliquer sur l'onglet Accueil
  2. cliquer sur l'onglet IO Physiques
  3. cliquer sur le petit “+” à gauche de “Sockets” pour faire apparaître le détail des sockets
  4. glisser/déposer chacune des variables sio pour l'associer au Socket correspondant (en déposant la variable dans la colonne VAL3 et en attendant que l'icone “Link with” apparaisse avant de relâcher le bouton (Si cela ne marche toujours pas après 10 secondes, changer de marque de robot ou de métier.)

Vous devriez obtenir un affichage identique à:

Programme python de simulation d'un capteur

Nous allons maintenant ajouter un capteur simulé (via un programme) afin que vous puissiez l'utiliser depuis votre PC et accéder à ces données depuis SRS.

Pour cela, enregistrer dans le dossier R:\lprob\“nom_prenom” le code du programme suivant (en faisant clic droit sur le nom puis enregistrer sous)

simu_sensor_2_joystick_qt5.py
#!/usr/bin/python3
# -*- coding: utf-8 -* 
#Bertrand Vandeportaele 2022
import os
import sys
 
debug=True
 
global numeroPremiereDonneeCapteur
#TODO: donner une valeur à cette variable en fonction de votre numéro d'étudiant
numeroPremiereDonneeCapteur=156
 
global destIP
global portOut
 
global etatBouton
etatBouton=0
global slider1Value
slider1Value=0
global slider2Value
slider2Value=0
 
global led0Button
 
 
 
########################################
#https://stackoverflow.com/questions/1051254/check-if-python-package-is-installed
#install automatically watchdog if not already installed
import subprocess
import sys
 
reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
installed_packages = [r.decode().split('==')[0] for r in reqs.split()]
 
if 'PyQt5' in installed_packages:
  if debug: print('PyQt5 pip package already installed')
else: 
  if debug: print('PyQt5 pip package missing, lets install it')
  import pip
  pip.main(['install','PyQt5'])
 
########################################
 
from PyQt5.QtGui import *
from PyQt5.QtNetwork import *
from PyQt5.QtCore import *
 
from PyQt5.QtWidgets import *
 
from PyQt5 import *
 
 
 
import re #pour découpage chaine comme sur https://stackoverflow.com/questions/2175080/sscanf-in-python
 
 
 
################################################################################
def close():
  print('close')
  exit(0)
################################################################################
def commutTimer():
  global timer
  print('commutTimer')
  if timer.isActive():
     timer.stop()
     commutTimerButton.setText('start stream sensor')
  else:
     timer.start()
     commutTimerButton.setText('stop stream sensor')
################################################################################
def slider1ValueChanged( value ):
  #label.setText( str( value )
  global numeroPremiereDonneeCapteur
  global labelSlider1Value
  global slider1Value
  slider1Value=value
  labelSlider1Value.setText( str( numeroPremiereDonneeCapteur+5)+" :  {:6d}".format(slider1Value) ) 
  #print('changed')
################################################################################
def slider2ValueChanged( value ):
  #label.setText( str( value )
  global numeroPremiereDonneeCapteur  
  global labelSlider2Value
  global slider2Value
  slider2Value=value
  labelSlider2Value.setText( str( numeroPremiereDonneeCapteur+6)+" : {:6d}".format(slider2Value) )
  #print('changed')
################################################################################
def bouton0():
  global numeroPremiereDonneeCapteur 
  global labelButtonValue
  global led0Button
  global  etatBouton 
  etatBouton=(etatBouton+1)%2
  if etatBouton==0:
    led0Button.setText('Activer la sortie TOR')
  else:
    led0Button.setText('Desactiver la sortie TOR')
  labelButtonValue.setText( str( numeroPremiereDonneeCapteur+2)+" : {:6d}".format(etatBouton) ) 
  print('etatBouton: '+ str(etatBouton) +" \n");
 
################################################################################
def sendUDP(i):
  global udpSocket
  global destIP
  global portOut
  DestIP = QHostAddress(destIP);
  global slider1Value
  global slider2Value
  global etatBouton
  global numeroPremiereDonneeCapteur
#  chaine=str(slider1Value)+ " " + str(slider2Value) 
#ajout @MAC bidon
#  chaine="00:00:00:00:00:00 "+str(slider1Value)+ " " + str(slider2Value) 
#ajout champs vides pour être compatible avec le joystick wifi
#@MAC: BC:DD:C2:FE:6F:F0 num: 0 0 -> 529.0 , 1 -> 534.0 , 2 -> 0.0 , 3 -> 0.0 , 4 -> 0.0 , 5 -> -73.0 , 6 -> 63.0 , 
  chaine="00:00:00:00:00:00 "+str(numeroPremiereDonneeCapteur)+" 0 0 "+str(etatBouton)+" 0 0 "+str(slider1Value)+ " " + str(slider2Value) 
 
#chaines bidons pour générer erreur de parsing sur le serveur
#  chaine="00:00:00:00:00:00 0 0 0 "+"687f"+" 0 0 "+str(slider1Value)+ " " + str(slider2Value) 
 
  chaine=chaine+chr(13)+chr(10)
  print("la chaine envoyée vers ip: "+str(destIP)+":"+str(portOut) +" est: "+chaine)
  udpSocket.writeDatagram(chaine.encode('utf-8'),DestIP, portOut);
 
################################################################################
def timerUpdate():
  sendUDP(0)
################################################################################ 
 
global led0Button
#destIP='192.168.1.50' #pc simulateur
#destIP='192.168.0.112' #pc simulateur
#destIP='192.168.1.49' #pc serveur rapid connecté en filaire à réseau AIP
#destIP='127.0.0.1' #pc serveur sur la boucle locale
#destIP='192.168.3.5' #pc serveur rapid connecté en wifi à réseau AIP
#destIP='192.168.3.4' #pc serveur rapid connecté en ethernet à réseau AIP
#destIP='127.0.0.1' #ip locale
#destIP='10.6.11.62' #un pc de la salle u2 IUT
 
destIP='172.16.6.59' #rapid connecté sur gommette bleu
 
 
 
 
portOut=10000
posx=100
posy=100
sizex=500
sizey=150
################################################################################ 
app = QApplication(sys.argv)
w=QDialog() 
statusLabel =QLabel('En attente de datagrammes UDP depuis le PIC32')
commutTimerButton=QPushButton('stop stream sensor')
quitButton = QPushButton('&Quit')
led0Button = QPushButton('Activer la sortie TOR')
 
udpSocket =QUdpSocket()
udpSocket.bind(portOut, QUdpSocket.ShareAddress) 
 
quitButton.clicked.connect(close)
commutTimerButton.clicked.connect(commutTimer)
led0Button.clicked.connect(bouton0)
#led1Button.clicked.connect(bouton1)
#led2Button.clicked.connect(bouton2)
 
#app.connect(quitButton,QtCore.SIGNAL('clicked()'), close)
#app.connect(commutTimerButton,  QtCore.SIGNAL('clicked()'), commutTimer)
#app.connect(led0Button,QtCore.SIGNAL('clicked()'), bouton0)
 
buttonLayout =QHBoxLayout()
buttonLayout.addStretch(1)
buttonLayout.addWidget(quitButton)
buttonLayout.addWidget(commutTimerButton)
buttonLayout.addStretch(1)
 
global labelButtonValue
labelButtonValue=QLabel( )
labelButtonValue.setGeometry(250, 50, 50, 35)
#labelButtonValue.setText( "x: "+str(0 ) )  
labelButtonValue.setText( str( numeroPremiereDonneeCapteur+2)+" : {:6d}".format(0) ) 
 
button1Layout =QHBoxLayout()
button1Layout.addStretch(1)
button1Layout.addWidget(labelButtonValue)
button1Layout.addStretch(1)
button1Layout.addWidget(led0Button)
button1Layout.addStretch(1)
 
 
####################################################"" 
#http://koor.fr/Python/CodeSamplesQt/PyQtSlider.wp
slider1 = QSlider(Qt.Horizontal);  
amplitude=1800;
slider1.setMinimum(int(-amplitude/2))
slider1.setMaximum(int(amplitude/2))
slider1.setGeometry( 10, 10, 600, 40 )
slider1.valueChanged.connect(slider1ValueChanged )
slider1.setValue( 0 )
global labelSlider1Value
labelSlider1Value=QLabel( )
labelSlider1Value.setGeometry(250, 50, 50, 35)
#labelSlider1Value.setText( "x: "+str(0 ) )
labelSlider1Value.setText( str( numeroPremiereDonneeCapteur+5)+" : {:6d}".format(0) ) 
slider1Layout =QHBoxLayout()
slider1Layout.addWidget(labelSlider1Value)
slider1Layout.addWidget(slider1)
 
 
#labelSlider1Value=QLabel( )
#labelSlider1Value.setGeometry(250, 50, 50, 35)
#labelSlider1Value.setText( str( slider1.getValue() ) )
sliderLayout =QHBoxLayout()
sliderLayout.addStretch(1)
sliderLayout.addWidget(slider1)
sliderLayout.addStretch(1)
#sliderLayout.addWidget(labelSlider1Value)
#sliderLayout.addStretch(1)
 
 
slider2 = QSlider(Qt.Horizontal); 
slider2.setMinimum(int(-amplitude/2))
slider2.setMaximum(int(amplitude/2))
 
slider2.setGeometry( 10, 10, 600, 40 )
slider2.valueChanged.connect(slider2ValueChanged )
slider2.setValue( 0 )
global labelSlider2Value
labelSlider2Value=QLabel( )
labelSlider2Value.setGeometry(250, 50, 50, 35)
#labelSlider2Value.setText( "Y: "+str(0 ) )
labelSlider2Value.setText( str( numeroPremiereDonneeCapteur+6)+" : {:6d}".format(0) ) 
slider2Layout =QHBoxLayout()
slider2Layout.addWidget(labelSlider2Value)
slider2Layout.addWidget(slider2)
 
sliderLayout.addWidget(slider2)
sliderLayout.addStretch(1)
 
mainLayout = QVBoxLayout()
mainLayout.addLayout(buttonLayout)
mainLayout.addLayout(button1Layout)
mainLayout.addLayout(slider1Layout)
mainLayout.addLayout(slider2Layout)  
 
mainLayout.addWidget(statusLabel)
w.setLayout(mainLayout)
chaine='@BVDP2022: Port Em '+str(portOut) +' vers IP: '+str(destIP)
print(chaine)
w.setWindowTitle(chaine)
 
#timer adapted from example 1 of https://www.programcreek.com/python/example/52106/PyQt4.QtCore.QTimer
timer = QtCore.QTimer()
#app.connect(timer,  QtCore.SIGNAL('timeout()'), timerUpdate)
timer.timeout.connect(timerUpdate)
timer.setInterval(100)
timer.start()
 
w.setGeometry(posx,posy,sizex,sizey)
#donne le focus au bouton 1
led0Button.setDefault(True)
 
w.show()
app.exec_()

Sauver ce fichier sur le disque R:\ dans le dossier R:\lprob\nom_prenom

Exécuter une première fois ce programme pour télécharger les librairies en copiant collant dans une console:

R:
cd lprob
cd nom_prenom
python simu_sensor_2_joystick_qt5.py

Editer ce fichier avec idle pour l'adapter selon les consignes données en séance en modifiant la variable numeroPremiereDonneeCapteur au début du programme pour qu'elle vaille 100x le numéro du projet qui a été attribué à votre binome, en tapant dans la commande windows:

C:\"Program Files"\Python39\Lib\idlelib\idle simu_sensor_2_joystick_qt5.py

Après édition, sauver le fichier et quitter idle puis lancer ce programme en faisant Touche Windows+R puis taper “cmd” et entrée, puis saisir en adaptant les lignes suivantes:

R:
cd R:\lprob\nom_prenom 
py simu_sensor_2_joystick_qt5.py

Si besoin, à la première utilisation, exécuter deux fois la dernière commande puis ignorer les messages de pare feu!

Agir sur les curseurs et bouton de l'application et observé dans la fenêtre de texte les chaines de caractères émises via Socket.

Le robot en tant que capteur

Nous allons maintenant faire en sorte que le robot se comporte comme un capteur qui informe de son état (articulaire et cartésien). Pour cela, il va envoyer via socket UDP des chaines de caractères comme le fait l'application python. Ceci va être réalisé par une tâche périodique en VAL3 qui envoie en UDP la pose courante du robot T,R, et joint à intervalle régulier dans un programme qui s’exécute en parallèle du programme start.

Présentation au tableau de la gestion de l'émission de l'état du robot via socket UDP.

La variable socket est normalement déjà configurée, mais il est possible la configurer au début du programme à l'aide de:

configsocketUDP.pgx
  //configuration du socket UDP
  clearBuffer(siSocketUDP)    
  if(sioCtrl(siSocketUDP, "target", "172.16.6.59")!=0)  
    call logMsgBlock("probleme sioCtrl(siSocketUDP, target, 172.16.6.59)", true)
  endIf
  //"endOfString" num (Pour ligne série, client et serveur UDP) Code ASCII pour le caractère de fin de chaîne à utiliser avec les opérateurs '=' (dans la plage [0, 255]) 
  if(sioCtrl(siSocketUDP, "endOfString", 13)!=0)
    call logMsgBlock("probleme sioCtrl(siSocketUDP, endOfString, 13)",true)
  endIf
  //port 10000 utilisé par socket UDP
  if(sioCtrl(siSocketUDP, "port", 10000)!=0)
    call logMsgBlock("probleme sioCtrl(siSocketUDP, port, 10000)",true)
  endIf
  //0 pour configurer les lectures sur socket bloquante,
  //une autre valeur en seconde sinon
  if(sioCtrl(siSocketUDP, "timeout",1)!=0 )
    call logMsgBlock("probleme sioCtrl(siSocketUDP, timeout,1)",true)
  endIf

La programmation de la tache périodique doit être faite une fois dans le programme start avec:

ajouttacheperiodique.pgx
//programmation de la tache périodique
  //emissionEtat est un programme créé, et exécuté à une périodicité de 0.1s
  taskCreateSync "emissionEtat",.1,bOverRun,emissionEtat()
  call logMsgBlock("Tache periodique emission Etat lancee",true)

Ajouter la variable bOverRun en tant que nouvelle donnée.

Ensuite, ajouter un programme dans le projet: Cellule→Projet→clic droit→Ajouter→Nouveau programme. Saisir le nom “emissionEtat”

puis y copier le code suivant:

emissionEtat.pgx
begin
  //il faut une boucle car taskCreateSync ne réappelle pas le programme, juste il lui donne la main périodiquement
  while true
    l_pHereEtat=here(tTool,world)
    l_jHereEtat=herej()
 
    //déclarer une variable string et utiliser la fonction tostring pour formater
    //adresse mac puis numéro de la première donnée capteur émise 
    l_sEtat="DC:4F:22:00:00:00 50"
    l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].trsf.x)
    l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].trsf.y)
    l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].trsf.z)
    l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].trsf.rx)
    l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].trsf.ry)
    l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].trsf.rz)
    //l_sEtat=l_sEtat+" "+toString(".6",l_pHereEtat[0].config.shoulder) 
    //shoulder n'est pas un numero, si je veux l'envoyer il faut faire une correspondante avec numéros
    siSocketUDP=l_sEtat
 
    //envoi en 2 temps de la config du robot, car sinon la chaine est tronquée car trop longue (>128 octets)
    //envoyer les paramètres suivants avec un offset par rapport aux précédents
    //adresse mac puis numéro de la première donnée capteur émise 
    l_sEtat="DC:4F:22:00:00:00 56"
    l_sEtat=l_sEtat+" "+toString(".6",l_jHereEtat[0].j1)
    l_sEtat=l_sEtat+" "+toString(".6",l_jHereEtat[0].j2)
    l_sEtat=l_sEtat+" "+toString(".6",l_jHereEtat[0].j3)
    l_sEtat=l_sEtat+" "+toString(".6",l_jHereEtat[0].j4)
    l_sEtat=l_sEtat+" "+toString(".6",l_jHereEtat[0].j5)
    l_sEtat=l_sEtat+" "+toString(".6",l_jHereEtat[0].j6)
    siSocketUDP=l_sEtat
 
    //en cas de doute décommenter la ligne suivante pour afficher des messages indiquant l'exécution de la tache periodique
    //popUpMsg("emissionEtat") 
 
    //Il faut un delay de la periodicité de la tâche sinon les données s'accumulent dans la variable l_sEtat et le controleur plante
    delay(0.1)  
  endWhile
end

Remplacer les valeurs 50 et 56 de ce programme par les valeurs de numeroProjet*100+10 et numeroProjet*100+16, par exemple 910 et 916 pour le projet numéro 9.

Ajouter les variables nécessaires dans votre projet en tant que variables LOCALES pour que ce nouveau programme puisse fonctionner.

Tester le programme et vérifier avec l'enseignant que l'état de votre robot est bien envoyé au serveur.

Récupération des données capteurs depuis le serveur via Socket TCP

La variable socket est normalement déjà configurée, mais il est possible la configurer au début du programme à l'aide de:

config_socket.val3
    clearBuffer(siSocketTCP)    
    if(sioCtrl(siSocketTCP, "target", "172.16.6.59")!=0)
      call logMsgBlock("probleme sioCtrl(siSocketTCP, target, 172.16.6.59)",true)
    endIf    
    //"endOfString" num (Pour ligne série, client et serveur TCP) Code ASCII pour le caractère de fin de chaîne à utiliser avec les opérateurs '=' (dans la plage [0, 255]) 
    if(sioCtrl(siSocketTCP, "endOfString", 13)!=0)
      call logMsgBlock("probleme sioCtrl(siSocketTCP, endOfString, 13)",true)
    endIf
    //port 30000 utilisé par socket TCP
    if(sioCtrl(siSocketTCP, "port", 30000)!=0)
      call logMsgBlock("probleme sioCtrl(siSocketTCP, port, 30000)",true)
    endIf
    //0 pour configurer les lectures sur socket bloquante,
    //une autre valeur en seconde sinon
  if(sioCtrl(siSocketTCP, "timeout",1)!=0 )
    call logMsgBlock("probleme sioCtrl(siSocketTCP, timeout,1)",true)
  endIf

Tester la boucle du programme suivant en la copiant collant avant la boucle de votre programme. Il vous faut remplacer les numéros des champs dans la chaîne par les numéros de champs de données émises par votre programme Python:

test.val3
begin 
  while(true)
    //exemple d'envoi d'une requete pour obtenir les donnees capteurs 10 11 et 12
    siSocketTCP = "r 10 11 12"
    //receptionne la reponse et la met dans la donnée sMsg, arrêt du programme si la reponse n'est pas recue avant le timeout
    l_sMsg = siSocketTCP  
    //affiche sur l'ecran la chaine recue
    call logMsgBlock(l_sMsg,true)
    //il vous reste a convertir les donnees depuis la chaine
  endWhile
end

Si vous ne l'avez pas déjà fait, créer la variable siSocketTCP (attention à bien choisir le type sio, car le type automatiquement choisi risque d'être string) et l'associer la variable à la ressource sio, pour cela aller dans Accueil→IO Physique→Socket→siSocketTCP puis glisser déposer la variable siSocketTCP[0] dans la colonne VAL3 du lien physique siSocketTCP.

Créer la variable locale l_sMsg (de type string).

Lancer le programme VAL3 alors que le programme python est lancé et vous devriez voir les valeurs des données capteurs s'afficher sur l'écran du pendant virtuel.

Il vous reste maintenant à fusionner votre programme et cette boucle qui récupère les données capteurs pour que votre programme les utilise correctement.


Génération d'une trajectoire lisse pour le vissage

Il est nécessaire de configurer un descripteur de mouvement imposant de passer exactement par les points programmés avec lissage en mode 'off' pour que les commandes s’enchainent tel que:

mdescA.blend=off

ou

mdescA.leave=0
mdescA.reach=0

Ensuite, dans la boucle, vous devrez enchainer les movej() ou movel() sans waitEndMove().

La fin du vissage programmé est alors détectée non plus parce que les différentes itérations de la boucle qui génèrent les commandes move? ont été exécutées mais avec:

// condition d'arrêt si la FIFO est vidée
if isEmpty()
   bBoolVisFini=true 
   call logMsgBlock("arret vissage fin de mouvement!",false)
endIf

Pour déterminer quel ordre de mouvement le robot est en train d’exécuter (et quel pourcentage par rapport au point suivant):

nNumOrdreActuel[0]= getMoveId()     
call logMsgBlock("nNumOrdreActuel:"+toString(".3",nNumOrdreActuel[0]),false)     

Pour interrompre les mouvements programmés (lorsque le capteur de couple indique un couple supérieur au seuil souhaité):

stopMove()
resetMotion()          

Mesure des temps de cycles

Vous pouvez mesurer le temps en secondes entre l’exécution de deux lignes du programme avec:

//lecture de la date de départ: lancement chronomètre
l_ndebut=clock()
//instructions  dont on souhaite mesurer la durée d'exécution
//......
//lecture de la date de fin: arrêt du chronomètre et mesure de la durée écoulée
l_nduree=clock()-l_ndebut

Pour rappel, les instructions move. sont non bloquantes et leur durée d’exécution n'est pas la durée nécessaire au robot pour faire le mouvement. Pour mesurer le temps nécessaire au robot pour faire le mouvement, la lecture de date de fin doit être faite APRES une instruction waitEndMove().

Ceci peut être utilisé pour mesurer le temps d'un cycle et comparer plusieurs exécutions du programme en faisant varier des paramètres de la trajectoire.

Étapes de développement

Jusqu'à nouvel ordre, les commandes de mouvements doivent être suivies de waitEndMove() pour pouvoir tester en pas à pas et voir le robot effectuer les mouvements demandés.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 1: Configurer le projet SRS et insérer les éléments 3D dans l'environnement du robot.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 2: Programmer le mouvement pour faire sortir le bras de la configuration singulière (2 positions du robot en articulaire: jBrasLeve et jBrasBaisse).

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 3: Ajouter le cycle en U avec deux positions en cartésien (pSaisieBouchon et pDeposeBouchon), calculer les positions avec offset grâce à la fonction appro(…) 10cm au dessus des points.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 4: Préparer le vissage saccadé en boucle ouverte: définir deux variables nPasVissage (pas de vissage en mm/tour) et nDebAngulaire (débattement angulaire pour le vissage en degrés) Faire en sorte que le robot arrive au point d'approche pDeposeBouchon en contraignant l'articulation j6 pour qu'elle soit préparée pour le vissage en prédévissant la moitié de l'amplitude de vissage.


Adapter la commande de déplacement linéaire du cycle en U pour que le robot descende sur le point pDeposeBouchon en conservant l'orientation du poignet déterminée précédemment.

Ouvrir puis refermer la pince pour faire descendre le bouchon sur le pas de vis.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 5: Mettre en place le mouvement de vissage saccadé: Faire une boucle qui décompose en 8 étapes le vissage.

Utiliser la fonction appro() pour calculer des offsets en cartésien par rapport à la position initiale pDeposeBouchon.

Utiliser une boucle permettant de générer le mouvement interpolé en linéaire passant par ces 8 points à la suite.

A la fin ouvrir la pince.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 6: Mettre en place le mouvement du cycle en U lissé:

Régler le descripteur de mouvements pour autoriser le robot à approximer la trajectoire pour le cycle en U et à passer à 2cm des points fournis.

Commenter les waitEndMove() correspondant (ou mieux utiliser une variable booléenne bLisssage pour désactiver les waitEndMove() si la variable vaut true)

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 7: Mettre en place le mouvement de vissage lissé:

Régler le descripteur de mouvements pour obliger le robot à interpoler en cartésien et à passer exactement par les points fournis pour le vissage et retirer les waitEndMove() correspondant. La commande d'ouverture de la pince à la fin de la boucle contient un waitEndMove() et bloque donc l'exécution du programme jusqu'à ce que le mouvement soit achevé.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 8: Mettre en place la préparation d'une condition d'arrêt du vissage:

Après la boucle qui fournit au contrôleur les différents points pour le vissage, ajouter une autre boucle qui affiche en continu l'état d'avancement dans l’exécution de la trajectoire. La sortie de cette boucle est dans un premier temps effectuée lorsque la file d'ordres du contrôleur est vide.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 9: Intégrer le capteur simulé pour interrompre le vissage:

Installer et configurer l'application python émulant un capteur.

Configurer le projet SRS pour pouvoir communiquer via socket TCP.

Ajouter la condition d'arrêt correspondant au fait que le couple de serrage soit atteint, et dans ce cas interrompre l'exécution de la file d'ordre de mouvement du robot. Tester avec le préhenseur sans le capteur de couple et simuler le capteur de couple avec l'application python.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 10: Ajouter la tâche parallèle permettant au robot d'envoyer son état au serveur de données capteur.

Visualiser l'affichage du robot en 3D sur le PC de l'enseignant.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 11: Adapter les descripteurs de mouvements pour régler une vitesse de déplacement plus importante pendant le trajet cycle en U et moindre pendant la saisie et le vissage du bouchon. (100% pendant les déplacements rapide et 10% pendant la saisie du bouchon le vissage). Ne pas utiliser la fonction setMonitorSpeed() dans le code car nous réglerons ce paramètre à l'aide du pendant. Ajouter des points intermédiaires pour l'approche du bouchon et de la bouteille pour réduire la vitesse à 3cm des objets à saisir.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 12: Après accord de l'enseignant et vérification des vitesses de déplacement, exécuter le programme en mode automatique AVEC L'ENSEIGNANT. Ne pas dépasser 75% de la vitesse sur le pendant.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 13: Déterminer la valeur du capteur de couple réel correspondant à un bouchon bien vissé et adapter la condition de fin de vissage dans votre programme. Adapter également votre programme pour qu'il utilise la donnée issue du capteur réel plutôt que celle issue du simulateur.

Avec l'enseignant, monter le préhenseur doté du capteur de couple sur le robot.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 14: Utiliser le capteur de couple pour déterminer si le vissage a été bien effectué (couple de serrage atteint avant le débattement maximal) et indiquer sur le pendant l'information correspondante.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg 15: Utilisez ce que vous avez appris dans la formation PHL pour faire en sorte que la simulation permette d'animer le bouchon.


Bravo, vous êtes arrivé au bout de votre quête, Chevalier…. Maintenant il faut attendre la période suivante pour intégrer le capteur de vision au système afin de localiser automatiquement le bouchon.


Annexes



simu_client_srs_continu.py
#!/usr/bin/python3
import time   # https://docs.python.org/fr/3/library/time.html
 
#https://realpython.com/python-sockets/
 
import socket
 
HOST = '172.16.6.59'  # The server's hostname or IP address
PORT = 30000        # The port used by the server
 
########################################################################################################################
if __name__ == '__main__':
 
  try:
 
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
      s.connect((HOST, PORT))
      while True:
        s.sendall(b'r 1 2 3')
        data = s.recv(1024)
#	print('Received', repr(data))
        print(repr(data))
        time.sleep(0.01)
  except KeyboardInterrupt:
      print("bye")

Téléchargement sur le controleur du robot

IP du cs9: 172.16.8.250
utilisateur: default 
mdp: default

Sous programme pour tester si un point est atteignable

isReachable.pgx
<?xml version="1.0" encoding="utf-8"?>
<Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
  <Program name="isReachable">
    <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
      <Parameter name="x_pPointRx" type="pointRx" xsi:type="element" />
      <Parameter name="x_bBool" type="bool" xsi:type="element" use="reference" />
    </Parameters>
    <Locals>
      <Local name="l_bPointToJoint" type="bool" xsi:type="array" size="1" />
      <Local name="l_jResultat" type="jointRx" xsi:type="array" size="1" />
      <Local name="l_bIsInRange" type="bool" xsi:type="array" size="1" />
    </Locals>
    <Code><![CDATA[begin
 
  //bool pointToJoint(tool tOutil, joint jInitial, point pPosition,
 
  l_bPointToJoint= pointToJoint(tTool[0], herej(),x_pPointRx,l_jResultat)
  if l_bPointToJoint==false
    x_bBool=false
    return
  endIf
  //bool isInRange(joint jPosition)
 
  l_bIsInRange=isInRange(l_jResultat)
  if l_bIsInRange==false
    x_bBool=false
    return
  endIf   
 
  x_bBool=true
  return   
 
end]]></Code>
  </Program>
</Programs>

Sous programme afficher la valeur d'un point sur le pendant

logMsgBlockPoint.pgx
<?xml version="1.0" encoding="utf-8"?>
<Programs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Program/2">
  <Program name="logMsgBlockPoint">
    <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
      <Parameter name="x_pPointRx" type="pointRx" xsi:type="element" />
      <Parameter name="x_bBool" type="bool" xsi:type="element" />
    </Parameters>
    <Locals>
      <Local name="l_sString" type="string" xsi:type="array" size="1" />
    </Locals>
    <Code><![CDATA[begin
 
 
 
  l_sString="Point:"
 
 
  l_sString=l_sString+" "+toString(".6",x_pPointRx.trsf.x)
  l_sString=l_sString+" "+toString(".6",x_pPointRx.trsf.y)
  l_sString=l_sString+" "+toString(".6",x_pPointRx.trsf.z)
  l_sString=l_sString+" "+toString(".6",x_pPointRx.trsf.rx)
  l_sString=l_sString+" "+toString(".6",x_pPointRx.trsf.ry)
  l_sString=l_sString+" "+toString(".6",x_pPointRx.trsf.rz)
  if x_pPointRx.config.shoulder==lefty
    l_sString=l_sString+" "+"lefty"
  else
    l_sString=l_sString+" "+"righty"
  endIf
  if x_pPointRx.config.elbow==epositive
    l_sString=l_sString+" "+"epositive"
  else
    l_sString=l_sString+" "+"enegative"
  endIf
  if x_pPointRx.config.wrist==wpositive
    l_sString=l_sString+" "+"wpositive"
  else
    l_sString=l_sString+" "+"wnegative"
  endIf
 
 
  call logMsgBlock(l_sString,x_bBool)
end]]></Code>
  </Program>
</Programs>

Apprentissage de repère

Pour voir le repère world, il faut cacher le robot car il est à l'intersection de j1 et j2, dans le robot

On peut faire “aller à” à un repère (ou point) pour amener le repère outils à l'origine du repère

frame p127 p79 phl.pptx: un frame (bleu) et un point (rouge) relatif à ce frame, lorsque le frame est déplacé avec le Positionneur Cartésien, ses coordonnées sont mises à jour et le point se déplace avec le frame.

On peut donner une couleur aux points et frame dans la fenêtre propriétés

Clic gauche sur un frame ou un point puis clic droit puis “Gros plan” pour centrer la vue: Le gros plan permet de centrer la vue 3D sur une variable géométrique VAL 3, ainsi que de la sélectionner (pratique lorsque le point/frame vient d’être créé et se trouve au centre de l’épaule du robot)

Tous les Positionneurs d’objet peuvent ensuite être utilisés sur les points et frames VAL 3 pour les positionner graphiquement (exemple : la méthode Origine, X, Y permet de positionner un frame sur un objet 3D de manière identique à la méthode VAL 3 de définition de frame).

Frames

  1. Définir un Tableau de point pFrame1 de dimension 3
  2. On peut apprendre les points avec le pendant et récupérer les valeurs vers le projet SRS et on peut aussi le faire avec SRS en bougeant le robot et en faisant “ici” sur chaque case du tableau
  3. Créer une donnée fFrame1 tableau sans taille
  4. Dans données→frame, la variable frame a un Père (par exemple world)
  5. Pareil pour les données→pointRx, ils ont un père
  6. Le frame peut être déplacé manuellement, (ouvrir une fenêtre données pour voir les valeurs)
  7. Sélectionner le pFrame1[0] dans données, puis clic droit et gros plan, ensuite onglet modeleur →Origine X,Y et cliquer successivement sur les 3 points (Si le frame est déjà à la bonne position mais pas la bonne orientation, le déplacer manuellement avant)
  8. Créer un point pDansFrame1[0], puis AVANT DE L'EDITER, pour l'attacher au repère pFrame1[0]:
  9. Sélectionner la vue Géométrie (à coté de Cellule et Données), et glisser-déposer pDansFrame1 sur fFrame1[0], ceci permet de régler le parent à pFrame1[0], et pDansFrame1 apparait sous fFrame1[0] dans l'arborescence géométrie
  10. Déplacer pFrame1[0] déplace également les points de pDansFrame1
  11. Régler le point avec le robot avec “ici avec config”

NB: lors du changement de repère de référence pour un point dans l'arborescence de géométrie, le point est déplacé erratiquement. Il faut le régler APRES l'avoir lié à un repère.

Pour déplacer des points et frames, les sélectionner dans la vue géométrie et faire clic droit puis “Gros plan” ou sélectionner dans la vue 3D“.

Dans la fenêtre “Editer la position”:

  • position relative règle la position dans le repère du point (pas de son frame parent), ou du frame lui même pour un frame. La donnée est mise à jour et les cordonnées relatives remises à 0 quand on sélectionne à nouveau le point dans la vue 3D.
  • position absolue règle la position dans le repère cellule (-375mm en Z par rapport au repère robot)

Dans la fenêtre d'édition de données:

  • position du point ou du frame dans le frame parent

NB: c'est bizarre le repère world[0] devrait avoir sa position absolue en z=+375, or srs affiche 0…. (mais ce n'est pas éditable…)

Utilisation des frames pour points variables locales

frame.txt
  //avec la fonction appro:
  //la transformation est exprimée dans le repère de référence du point
  //pas besoin de calculer sa valeur dans world
  link(l_pVariableDansFrame1,fFrame1)
  movej(appro(l_pVariableDansFrame1,{0,0,0,0,0,0}),tTool,mNomSpeed)   
  waitEndMove()
 
  for l_nNum=0 to 100   
    movej(appro(l_pVariableDansFrame1,{(l_nNum%10)*10,roundDown(l_nNum/10)*10,0,0,0,0}),tTool,mNomSpeed)   
    if roundDown(l_nNum%10)==0
      waitEndMove()
    endIf
  endFor
 

Animer un déplacement de pièce

Bouger le robot pour libérer la vue 3D: ( Données→jBrasLeve[0]→Aller à )

Transformer un objet 3D en pièce: clic droit sur la pièce puis “Nouvelle pièce” pour promouvoir la géométrie en pièce qui peut être déplacée

Créer un handle pour une pièce:

Scene→.wrl→ clic droit éditer le repère de référence

Le faire correspondre avec le repère handle quand l'outil est sur la pièce

Puis Scene→.wrl→ clic droit éditer le repère de référence pour désactiver l'édition

Simulation→enregistrer toutes les positions initiales (il faut selectionner les pieces avec CTRL)

Pour tester, déplacer la piece puis “Amener tout sur les positions initiales”

Clic droit sur l'outil→configuration de l'outil

Créer une machine à état de pince sur Tool1.handler

Déclencheur→FastIO→sorties digitales→fOut1 (qui est liée à tTool[0]) et selectioner “On”

Dans la fenêtre configuration d'outil:

Handler→état de saisie→closed, tel quel, distance de saisie 10mm

Positionner etat 1:opened: correspond au déclencheur fOut1 à état On

Positionner etat 2:closed: correspond au déclencheur fOut1 à état Off

Délais de transition, mettre 500ms pour les 2

Raccourcis clavier utiles

F6 : vérifie syntaxe
CTRL+R X : Exécution

Pour le mode DEBUG:

F9 : (des)active un point d'arrêt sur la ligne courante
CTRL+R D : Run Debogueur
CTRL+S D : Stop Debogueur
F5 : continue jusqu'au point d'arrêt
F10 : exécute la ligne sans rentrer dans les appels
F11 : exécute la ligne en entrant dans les appels
SHIFT+F11 : exécute tout pour sortir de cet appel

Installer SRS 2019.10.1

Emulateur à installer dans SRS 2019

Il faut ajouter l'émulateur de controleur version s8.11Cs9_BS2229

Fichier→Aide→Ouvrir l'outils de mise à jour en ligne (afficher les mises à jour Emulateur/robot)

et télécharger +installer


Cours de robotique BUT2 AII

lien vers TP de PHL

Fichier zip pour réparer SRS

Logo BUTAII

https://bvdp.inetdoc.net/files/iut/staubli/stl/BUTAII.scad et https://bvdp.inetdoc.net/files/iut/staubli/stl/BUTAII.stl

Pour apprendre les points, utiliser le robot en le cachant, et en amenant le repère outils sur les points.

PHL Kapla

staublivissage.txt · Dernière modification : 2023/09/13 08:07 de bvandepo