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:
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 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. |
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.
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
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é.
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
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
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
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:
Il faut maintenant configurer l'outils du robot, pour cela:
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:
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).
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.
Récupérer le modèle: https://bvdp.inetdoc.net/files/iut/staubli/stl/cellule_simplifiee.wrl
Editer la position absolue suivante:
63.3 -68.2 550.45 0 0 -90
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:
Ensuite il faut associer l'outils à la variable tTool, pour cela:
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:
Pour ajouter un objet dans l'espace de travail du robot:
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:
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.
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).
Dans la fenêtre cellule→Controller1→Projet…→
<?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…→
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…
Vous veillerez à respecter les règles de nommages des variables en fonction de leurs types (voici ce que nous manipulerons dans le projet):
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.
Présentation au tableau de la gestion du temps par le contrôleur du robot.
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:
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.
La simulation peut se faire en mode “exécution continue” ou en 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:
Pour lancer le Debug du programme
Pour éxecuter en pas à pas:
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”
Pour arrêter un Debug en cours et recommencer:
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.
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.
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)
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.
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.
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).
Pour déplacer le robot à une configuration articulaire donnée:
Pour déplacer le robot à une configuration cartésienne donnée:
Vous pouvez vous entraîner à faire ces opérations sur le PC de développement en simulation à l'aide du pendant virtuel:
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:
//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=
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)
Vous devriez obtenir un affichage identique à:
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)
#!/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.
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:
//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:
//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:
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.
La variable socket est normalement déjà configurée, mais il est possible la configurer au début du programme à l'aide de:
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:
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.
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()
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.
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.
1: Configurer le projet SRS et insérer les éléments 3D dans l'environnement du robot.
2: Programmer le mouvement pour faire sortir le bras de la configuration singulière (2 positions du robot en articulaire: jBrasLeve et jBrasBaisse).
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.
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.
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.
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)
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é.
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.
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.
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.
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.
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.
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.
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.
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.
#!/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")
IP du cs9: 172.16.8.250 utilisateur: default mdp: default
<?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>
<?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>
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).
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”:
Dans la fenêtre d'édition de données:
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…)
//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
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
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
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
à dézipper sur D:
https://bvdp.inetdoc.net/files/softs/SRS%202019%20fonctionnel%20u2.zip
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.
sujet: https://bvdp.inetdoc.net/files/iut/PHL/01%20LP%20ROB%20TP%20PHL%20SRS.pdf#PAGE=4
support: https://bvdp.inetdoc.net/files/iut/PHL/support%20Kapla%20horizontal.pdf
Fichiers CAD à récupérer:
https://bvdp.inetdoc.net/files/iut/staubliiut/kapla/kapla.scad
https://bvdp.inetdoc.net/files/iut/staubliiut/kapla/kapla.stl
https://bvdp.inetdoc.net/files/iut/staubliiut/kapla/support_kapla.stl