Outils pour utilisateurs

Outils du site


staubli

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
Dernière révision Les deux révisions suivantes
staubli [2019/07/10 10:17]
bvandepo
staubli [2020/02/03 13:23]
bvandepo
Ligne 1: Ligne 1:
-=====Staubli AIP===== 
  
  
-{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​SRS1.png}} 
  
 +=====TP Robot Staubli à l'​AIP=====
 +
 +====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:
 +  - Un capteur de couple (déjà étudié dans le module capteur) permettant la mesure du couple de serrage
 +  - Un système de vision 3D Intel Realsense 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 cet 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 Socket TCP à l'aide de chaînes de caractères ASCII et les autres entrées/​sorties numériques et analogiques ne seront pas utilisées.
 +<ifauth @prof>
 +TODO: lien vers vidéo
 +</​ifauth>​
 +
 +Le logiciel SRS étant payant, vous ne pourrez malheureusement pas reproduire la manip en dehors de l'AIP.
 +l'AIP dispose de 9 licences de SRS 2016 permettant à 8 postes + celui connecté au robot d'​utiliser le logiciel simultanément. ​
 +
 +
 +====Planning prévisionnel====
 +^  durée ^ Tâches^
 +|  30min   ​|Présentation de la manip et organisation en différentes étapes:​| ​
 +|     ​|-Vissage en boucle ouverte avec un préhensseur 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.|  ​
 +|  2h |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 sujets des différentes entrées/​sorties.|
 +|Pause| |
 +|1h30 |Lecture de la documentation du langage VAL3: types et différentes fonctions à utiliser dans le projet.|
 +|Pause| |
 +|  2h |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 continue ou en mode Débug pas à pas.|
 +|  2h |Poursuite du développement.|
 +|     ​|Tests sur le robot réel des mouvements de saisie et de vissage saccadé et apprentissage des points dans l'​environnement réel.|
 +|Pause| |
 +| 1h30  |Installation et configuration de l'​application simulant un capteur, explication du serveur de capteur et des fonctions de communication par socket en VAL3.|
 +| 2h30  |Développement et intégration du capteur de couple.|
 +| Pause | |
 +| 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'​ordre 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.|
 +
 +
 +====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. Cette documentation est disponible à l'​adresse:​ http://​homepages.laas.fr/​bvandepo/​files/​staubli/​documentations/​Val3.PDF
 +
 +
 +
 +====Informations sur l'​infrastructure de capteurs communicants===
 +
 +
 +
 +
 +=====Configuration d'un projet de départ=====
 +
 +<color red> ​
 +Durant tous le projet, vous travaillerez sur des fichiers stockés en réseau sur le disque L: afin de pouvoir y accéder depuis différents ordinateurs.
 +</​color>​
 +
 +
 +Ouvrir le programme SRS en cliquant sur:
 +Menu Démarrer->​Tous les programmes->​Staubli Robotic Suite 2016->​Staubli Robotic Suite 2016.6.1
 +
 +
 +====Création d'un projet utilisant les IO physiques de l'​armoire de commande===
 +L'​armoire de commande dispose de cartes d'​entrées/​sorties (IO, liens série, lien sockets etc...). Pour que ces cartes soient accessibles depuis le projet, il faut que le projet soit configuré lors de la création de la cellule en récupérant les informations matérielles depuis l'​armoire de commande.
 +
 +  - Dans SRS, cliquer en haut à gauche sur l'​icone de bras jaune.
 +  - Cliquer sur "​Nouvelle->​ Assistant nouvelle cellule"​
 +  - Donner un nom au projet, ici vous utiliserez "​CellStaubliAIP"​ suivi d'un numéro qui vous sera attribué en début de séance et que vous conserverez durant toutes les séances
 +  - S'​assurer que l'​armoire de commande est sous tension et démarrée depuis 2 minutes
 +  - Cliquer sur "A partir d'un contrôleur distant"​
 +  - Choisir l'​adresse IP de l'​armoire de commande: 192.168.0.112
 +  - La version de l'​émulateur s7.9.1 n'est pas installée, il faut donc sélectionner ​ la 7.10
 +  - Cliquer sur "​Suivant"​
 +
 +<ifauth @prof>
 +Si problème lors du téléchargement des infos depuis le controleur à la création de la cellule, il faut faire le ménage sur le controleur avec FTP et ne laisser que camera, cognex, cognexComm7en,​ commCamera2 et EntreeSortie.
 +TODO: automatiser le ménage (sauvegarde et effacement)
 +</​ifauth>​
 +
 +En cas de problème pour créer la cellule, vous pouvez, après accord de l'​enseignant,​ télécharger le fichier zip suivant en remplacement: ​ http://​homepages.laas.fr/​bvandepo/​files/​staubli/​projets_SRS/​CellStaubliAIPVide.zip
 +
 +
 +Toutes les cartes ne sont pas automatiquement ajoutées au projet. Il faut: 
 +  - Choisir l'​onglet Cellule dans la fenêtre de droite
 +  - Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître "​Controller1 [s7.10]"​
 +  - Cliquer droit sur "​Controller1 [s7.10]"​ puis cliquer gauche sur "​Configuration du contrôler"​
 +  - Sélectionner le bon type de bras (sinon par défaut un Scara sera choisi). Choisir "​RX60B,​ Fixation Sol, Horizontal base cable outlet, UL Certified arm power on light"
 +  - cliquer sur l'​onglet I/O et cocher "​BIO"​ ainsi que "​BIO2/​MIO",​ puis "​Ok"​
 +  - Si l'​onglet "IO physiques-Controller1"​ est ouvert, il faut le fermer et l'​ouvrir à nouveau pour que les modifications soient visibles.
 +
 +
 +
 + 
 +Maintenant que le contrôleur est configuré, il faut créer une nouvelle application,​ pour cela:
 +  - Choisir l'​onglet Cellule dans la fenêtre de droite
 +  - Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître "​Controller1 [s7.10]"​
 +  - Cliquer droit sur "​Controller1 [s7.10]"​ puis cliquer gauche sur "​Nouvelle application"​
 +  - Saisir un nom, par exemple "​Projet",​ puis Ok
 +
 +Il faut maintenant configurer l'​outils du robot, pour cela:
 +  - Choisir l'​onglet Géométrie dans la fenêtre de droite
 +  - Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître "​Controller1 [s7.10]"​ puis faire de même pour votre Projet
 +  - Cliquer droit sur "​Flange"​ (qui signifie Bride en français, soit l'​emplacement où fixer l'​outils) puis cliquer gauche sur "​Nouvelle donnée"​
 +  - Saisir un nom pour l'​outils,​ ou laisser le nom par défaut (tTool) puis cliquer sur Ok
 +  - Vérifier que tTool apparaît maintenant en cliquant sur la flèche à coté de "​flange[0]"​
 +
 +===Edition du programme===
 +  - Cliquer sur l'​onglet "​Accueil"​ puis sur "​Afficher la vue 3D"
 +  - Choisir l'​onglet Cellule dans la fenêtre de droite
 +  - Cliquer sur la flèche à gauche du nom de la cellule pour faire apparaître "​Controller1 [s7.10]"​ 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,​ relacher alors le clic gauche. Vous devriez obtenir un affichage ressemblant à:
 + 
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS-disposition.PNG}}
 +
 +===Navigation dans la vue 3D===
 +
 +La vue 3D utilise les mêmes principes que Catia pour naviguer:
 +  * 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 parfois falloir 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 "​position articulaire"​ 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:​
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_articulaire.PNG}}
 +
 +
 +Le pilotage manuel en cartésien se fait à l'aide de la fenêtre:
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_cartesienne.PNG}}
 +
 +
 +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====
 +Les différents fichiers STL des objets à insérer sont disponibles à l'​adresse: ​
 + ​https://​homepages.laas.fr/​bvandepo/​files/​staubli/​stl/​
 +
 +
 +===Import du modèle de pince===
 +Récupérer le modèle STL de la pince Schunk: https://​homepages.laas.fr/​bvandepo/​files/​staubli/​stl/​pince_schunk_staubli_ouverte.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.
 +
 +
 +Pour ajouter la pince au robot:
 +  - masquer le robot-> cliquer droit sur l'​arborescence de scène sur Controller et décocher "​Afficher le robot"
 +  - Onglet Modeleur->​Ajouter un modèle CAO
 +  - choisir Copier et insérer le fichier
 +  - l'​objet apparaît dans l'​arbre en tant que Géométrie,​ cliquer droit dessus et faire "​nouvel outils" ​
 +  - NE PAS déplacer l'​outils (car il est normalement bien positionné)
 +  - choisir dans l'​arbre l'​outils et son handle
 +  - cliquer sur "​Edition"​ sous la barre de menu
 +  - cliquer droit sur handle et "​Editer la position"​
 +  - Régler tout à 0 dans la position absolue
 +  - cliquer droit sur handler et "​Editer la position"​
 +  - Régler tout à 0 dans la position absolue sauf Z à 117.25
 +  - Sortir du mode Edition
 +  - Cliquer droit sur Tool1 dans l'​arborescence,​ attacher à et choisir le handler du robot
 +  - réactiver l'​affichage du robot
 +
 +
 +Vous devriez obtenir un affichage tel que:
 +{{https://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_pince.PNG}} ​
 +
 +
 +Ensuite il faut associer l'​outils à la variable tTool, pour cela:
 +  - Sélectionner le Tool1 dans l'​arborescence puis faire CTRL+C ​
 +  - 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 à 117.25.
 +
 +
 +
 +cliquer droit sur le handler de l'​outils puis définir comme TPC (Tool Center Point= Centre De l'​Outils) pour pouvoir déplacer l'​outils.
 +
 +
 +
 +Vous devriez obtenir des repères de handle et de handler tels que visible sur les images suivantes:
 +
 +
 +{{https://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_handle.PNG}} {{https://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_handler.PNG}} ​
 +
 +
 +
 +Optionnel: importer le modèle de gripper adapté au bouchon depuis ​ https://​homepages.laas.fr/​bvandepo/​files/​staubli/​stl/​adaptateur_pince_bouchon_ouvert.stl et le rajouter à la pince en configurant son handler et son handle correctement. Pour cet outils, le handler et le handle doivent être distant de 10mm selon Z. Faire clic droit sur l'​adaptateur puis "​attacher à" et sélectionner le handler du Tool1. Après avoir attaché ce nouvel outils au précédent,​ vous devriez obtenir:
 +
 +{{https://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_adaptateur_pince_bouchon_ouvert.PNG}} ​
 +
 +
 +
 +===Ajout des éléments dans la cellule===
 +
 +
 +Pour ajouter un objet dans l'​espace de travail du robot:
 +  - Onglet Modeleur->​Ajouter un modèle CAO
 +  - Télécharger le fichier et aller le chercher dans l'​arborescence avec le bouton "​..."​
 +  - Choisir Copier et insérer le fichier
 +  - L'​objet apparaît dans l'​arbre en tant que Géométrie
 +
 +Insérer dans l'​espace de travail du robot:
 +  - le support de bouteille: https://​homepages.laas.fr/​bvandepo/​files/​staubli/​stl/​support_bouteille_cristaline_lr.stl
 +  - la bouteille: https://​homepages.laas.fr/​bvandepo/​files/​staubli/​stl/​bouteille_cristaline.stl
 +  - le bouchon: https://​homepages.laas.fr/​bvandepo/​files/​staubli/​stl/​bouchon_cristaline.stl
 +
 +
 +Vous devez positionner les éléments pour obtenir une configuration proche de celle visible sur la figure suivante (respecter le positionnement du robot indiqué par les câbles):
 +
 +{{https://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_espace_travail.PNG}} ​
 +===Activation de la détection de collision===
 +
 +Pour activer la détection de collision dans le simulateur, il faut griser le bouton Simulation->​Collision + choisir les événements qui déclenchent les collisions + activer la gestion des collision dans chaque objet (Propriétés F4).
 +
 +=====Démarche de développement et de simulation=====
 +
 +
 +====Structure du programme====
 +
 +Il sera peu fait usage de la notion de sous programme dans la suite, la plus grande partie de votre programme résidera dans le fichier "​start"​.
 +Vous veillerez à informer l'​utilisateur du pendant de l'​état de votre programme à l'aide 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 commençant par bBool
 +  * variable frame commençant par fFrame
 +  * variable jointRx commençant par jJointRx
 +  * variable mdesc commençant par mMdesc
 +  * variable num commençant par nNum
 +  * variable pointRx commençant par pPointRx
 +  * variable string commençant par sString
 +  * variable tool commençant par tTool
 +  * variable trsf commençant par trTrsf
 +
 +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.
 +
 +Pour info, même si nous n'​utiliserons pas ces concepts dans le projet, les noms des variables locales sont 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_.
 +
 +
 +====Gestion du temps====
 +Présentation au tableau de la gestion du temps par le contrôleur du robot.
 +<ifauth @prof>
 +TODO: expliquer delay, waitEndMove,​ la file d'​ordre et le lissage de trajectoire
 +
 +dans un premier temps, mouvements saccadés puis lissés
 +</​ifauth>​
 +
 +
 +
 +
 +====Programmation des mouvements de saisie et de transport du bouchon====
 +Nous allons mettre en place un mouvement semblable à celui présenté page 145 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
 +  * movel(): ​ mouvement linéaire dans l'​espace de travail (en interpolant sur les articulations ou en cartésien selon le mdesc)
 +  * movec(): ​ mouvement circulaire dans l'​espace de travail (en interpolant sur les articulations ou en cartésien selon le mdesc)
 +
 +====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:
 +  - Onglet "​Simulation",​ cliquer sur icone "​PLAY"​ triangle bleu (Démarrer la synchro)
 +
 +Pour lancer le Debug du programme
 +  - Dans l'​onglet Cellule, ouvrir le Controller1->​Projet et cliquer gauche sur "​start()"​ pour choisir le programme
 +  - 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:
 +  - 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"​
 +  - Dans la fenêtre "​Emulator Controller",​ il faut:
 +  - Choisir le mode automatique en cliquant sur le bouton rond blanc jusqu'​à ce que l'​icone "​auto"​ soit en bleu
 +  - Mettre le robot sous puissance: cliquer sur le bouton rond avec un trait noir vertical pour le faire devenir vert
 +  - cliquer sur l'​onglet "​Move"​ (qui devient "​Hold"​) (SHIFT+F7) pour autoriser le robot à bouger
 +
 +
 +
 +Pour arrêter un Debug en cours et recommencer:​
 +  - Onglet "​Deboguer"​ Arrêt du débogueur. ​ (CTRL+D,​S ​ abbrégé de Débugguer Stop) .
 +  - Onglet Val3, cliquer sur "​Démarrer et Debugguer l'​application" ​ (CTRL+R,​D ​ abbrégé de Run Débugguer )
 +  - Fenêtre "​Emulator Controller",​ cliquer sur "​Move"​
 +
 +<ifauth @prof>
 +TODO : expliquer espions sur variables locales et globales
 +/ifauth>
 +===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 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.
 +
 +
 +
 +===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, 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.
 +
 +
 +
 +====Configuration du robot pour permettre le vissage====
 +Le poignet du robot est configuré par défaut avec des butées logicielles pour pouvoir tourner le poignet de plus de -270° à +270°, afin de ne pas détériorer les flexibles pneumatiques permettant de piloter la pince. Dans notre manip, nous débrancherons ces flexibles et utiliserons un plus grand débattement pour le poignet, qu'il va falloir configurer, sur le pendant virtuel ainsi que sur le pendant réel (sur ce dernier, ce sera fait par l'​enseignant). Le poignet du robot RX60 peut faire une rotation de +- 18000°.
 +
 +Afin d'​accéder à la configuration du pendant, il faut utiliser le "​profil de maintenance":​
 +
 +sur l'​émulateur,​ presser: SHIFT + F11 + F3
 +
 +
 +sur le vrai pendant, presser: SHIFT+USER
 +
 +
 +choisir "​maintenance"​ (au lieu de "​staubli",​ en faisant entrée puis en sélectionnant avec les flêches), mot de passe: spec_cal, (caractère "​_"​ obtenu par SHIFT+M) puis F8 pour OK
 +
 +
 +Il faut ensuite régler les butées du bras et de la cellule. cela va modifier les fichiers arm.cfx et cell.cfx
 +
 +Pour cela, aller dans Menu->​tableau de bord->​Etat du contrôleur->​Limites bras, et régler J6min à -18000 et J6max à +18000 ​ puis F8
 +
 +L'​image suivante montre la configuration des butées sur le pendant virtuel:
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_limites.PNG}}
 +
 +Revenir au profil "​staubli"​ après que la modification ait été effectuée.
 +
 +Pour que la modification soit prise en compte, il faut que le programme soit en cours d'​exécution mais  que le robot ne soit pas en train de bouger. On peut pour cela par exemple exécuter le programme en mode debug, avec un  point d'​arrêt actif dans le programme ​ sur un appel à la fonction delay(...)
 +
 +Les limites de la cellule sont automatiquement mises à jour à partir des limites du bras.
 +
 +
 +
 +
 +
 +====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 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.
 +Dn 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 fournit de valeur permet par exemple d'​indiquer qu'il n'y a pas de donnée disponible sans bloquer le robot.
 +
 +
 +<ifauth @prof>
 +NOTES PERSOS:
 +Problème, je ne peux pas lancer un programme python qui communique via UDP avec le simulateur sur le même pc car il n'y a qu'un numéro de port (local=distant) pour les sockets créées par VAL3 et donc si l'IP est la même, le simulateur reçoit les données qu'il envoie.
 +donc il faut passer par un serveur (avec une ip différente) qui centralise les données capteurs; l'​appli Qt sur le pc étudiant envoie des demandes au pc serveur et SRS communique avec le serveur qui centralise les données capteurs. ​
 +</​ifauth>​
 +
 +  ​
 +  ​
 +  ​
 +  ​
 +Python 3.4.1 est installé sur les PC Windows. Vous devrez installer un paquet de librairie et télécharger/​modifier un programme python émulant un capteur à l'aide d'une interface graphique.
 +
 +===Installation de pyQT sur les postes étudiants===
 +Télécharger le fichier suivant: https://​download.lfd.uci.edu/​pythonlibs/​q4hpdf1k/​PyQt4-4.11.4-cp37-cp37m-win_amd64.whl sur le Bureau, Puis saisir dans un terminal en faisant Touche Windows+R puis taper “cmd” et entrée, puis copier coller la ligne suivante:
 +  pip install Desktop\PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
 +  ​
 +  ​
 +<ifauth @prof>
 +En cas de problème (par exemple pyqt4 déjà installé par un autre utilisateur sur la machine), on peut le désinstaller en faisant:
 +  pip uninstall Desktop\PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
 +
 +</​ifauth>  ​
 +===Exécution du programme python de simulation d'un capteur===
 +Voici le code du programme émulant un capteur:  ​
 +<file python simu_sensor_2_joystick.py>​
 +#​!/​usr/​bin/​python3
 +# -*- coding: utf-8 -* 
 +#Bertrand Vandeportaele 2019
 +import os
 +import sys
 +from PyQt4.QtGui import *
 +from PyQt4.QtNetwork import *
 +from PyQt4.QtCore import *
 +from PyQt4 import *
 +import re #pour découpage chaine comme sur https://​stackoverflow.com/​questions/​2175080/​sscanf-in-python
 + 
 +global etatBouton
 +etatBouton=0
 +global slider1Value
 +slider1Value=0
 +global slider2Value
 +slider2Value=0
 +
 +global led0Button
 +################################################################################​
 +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 slider1Value
 +  slider1Value=value
 +  print('​changed'​)
 +################################################################################​
 +def slider2ValueChanged( value ):
 +  #​label.setText( str( value )
 +  global slider2Value
 +  slider2Value=value
 +  print('​changed'​)
 +################################################################################​
 +def bouton0():
 +  global led0Button
 +  global ​ etatBouton ​
 +  etatBouton=(etatBouton+1)%2
 +  if etatBouton==0:​
 +    led0Button.setText('​Appuyer sur le bouton'​)
 +  else:
 +    led0Button.setText('​Relacher le bouton'​)
 +  print('​etatBouton:​ '+ str(etatBouton) +" \n");
 +################################################################################​
 +def sendUDP(i):
 +  global udpSocket
 +  global destIP
 +  global portOut
 +  DestIP = QHostAddress(destIP);​
 +  global slider1Value
 +  global slider2Value
 +  global etatBouton
 +#  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 0 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 est: "​+chaine)
 +  udpSocket.writeDatagram(chaine,​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
 +
 +
 +portOut=10000
 +posx=10
 +posy=10
 +sizex=500
 +sizey=150
 +################################################################################ ​
 +app = QApplication(sys.argv)
 +w=QDialog() ​
 +statusLabel =QLabel('​En attente de datagrammes UDP depuis le PIC32'​)
 +commutTimerButton=QPushButton('​start clignote LED0')
 +quitButton = QPushButton('&​Quit'​)
 +led0Button = QPushButton('​Appuyer sur le bouton'​) ​
 +
 +udpSocket =QUdpSocket()
 +udpSocket.bind(portOut,​ QUdpSocket.ShareAddress) ​
 +
 +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)
 +button1Layout =QHBoxLayout()
 +button1Layout.addStretch(1)
 +button1Layout.addWidget(led0Button)
 +button1Layout.addStretch(1)
 +
 +
 +#​http://​koor.fr/​Python/​CodeSamplesQt/​PyQtSlider.wp
 +slider1 = QSlider(Qt.Horizontal); ​
 +
 +amplitude=1800;​
 +
 +slider1.setMinimum(-amplitude/​2)
 +slider1.setMaximum(amplitude/​2)
 +slider1.setGeometry( 10, 10, 600, 40 )
 +slider1.valueChanged.connect(slider1ValueChanged )
 +slider1.setValue( 0 )
 +
 +
 +
 +#​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(-amplitude/​2)
 +slider2.setMaximum(amplitude/​2)
 +
 +slider2.setGeometry( 10, 10, 600, 40 )
 +slider2.valueChanged.connect(slider2ValueChanged )
 +slider2.setValue( 0 )
 +
 +
 +sliderLayout.addWidget(slider2)
 +sliderLayout.addStretch(1)
 +
 +mainLayout = QVBoxLayout()
 +mainLayout.addLayout(buttonLayout)
 +mainLayout.addLayout(button1Layout)
 +mainLayout.addLayout(sliderLayout)
 +mainLayout.addWidget(statusLabel)
 +w.setLayout(mainLayout)
 +chaine='​@BVDP2019:​ Port Em '​+str(portOut) +' vers IP: '​+str(destIP)
 +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.setInterval(100)
 +timer.start()
 +
 +w.setGeometry(posx,​posy,​sizex,​sizey)
 +#donne le focus au bouton 1
 +led0Button.setDefault(True)
 +
 +w.show()
 +app.exec_()
 +</​file>​
 +
 +Sauver ce fichier sur le Bureau puis le lancer en faisant Touche Windows+R puis taper "​cmd"​ et entrée, puis copier coller la ligne suivante:
 +  C:​\RoboDK\Python37\python.exe Desktop\simu_sensor_2_joystick.py
 +
 +
 +Editer ce fichier avec Notepad++ pour l'​adapter selon les consignes données en séance.
 +
 +
 +
 +====Le robot en tant que capteur====
 +Présentation au tableau de la gestion de l'​émission de l'​état du robot via socket UDP.
 +<ifauth @prof>
 +TODO:  faire une tâche périodique en VAL3 qui envoie en UDP la pose courante du robot T,R, et joint comme n'​importe quel capteur.
 +/ifauth>
 +
 +=====Mise en oeuvre sur le robot=====
 + 
 +Le chargement du programme sur le robot se fait depuis le poste situé à coté du robot.
 +
 +====Mise sous tension de l'​armoire de commande===
 +
 +Fermer les différents portes équipées de capteur d'​ouverture (sinon il y aura un message User ES1-2 indiquant que le capteur porte ouverte empêche le robot de démarrer)
 +
 +
 +Mettre l'​interrupteur rotatif gris clair à gauche de l'​armoire de commande en position "​flêche vers le haut" pour alimenter le robot.
 +
 +<ifauth @prof>
 +TODO: mettre les 2 photos de la façade
 +</​ifauth>​
 +
 +Ne surtout jamais rallumer le robot juste après l'​avoir éteint sans attendre au moins une dizaine de secondes.
 +
 +
 +Choisir parmi les 3 modes en tournant la clef:
 +  - En mode manuel, le robot s'​arrête si l'​utilisateur n'​exerce pas de pression sur le bouton de l'​homme mort et qu'il ne presse pas en continu le bouton Move/Hold. Ce sera le mode à utiliser pendant les tests et réglages sur le robot afin de pouvoir ​
 +  - En mode automatique... ​
 +<ifauth @prof>
 +... TODO: expliquer les 3 positions de clef
 +</​ifauth>​
 +
 +===Cas particulier du retour de vacances====
 +Si l'​alimentation de l'​armoire a été coupée pendant longtemps, la batterie de l'​armoire n'est pas suffisante pour conserver les paramètres de calibrage du robot, il faut donc refaire le calibrage. ​
 +Pour cela, amener le robot en position de référence (les marqueurs traits noirs des différentes articulations doivent être en face les uns par rapport aux autres) en utilisant les mouvements manuels en mode Joint et faire sur le pendant:
 +
 +  - Bouton Menu
 +  - Calibrage
 +  - Presser le bouton Cal
 +  - Presser le bouton Ok
 +
 +
 +===Création d'une ressource Socket depuis le pendant===
 +Cette opération a déjà été réalisée par l'​enseignant mais est indiquée ici pour référence:​
 +Sur le pendant:
 +  - Tableau de bord
 +  - ES ->
 +  - Socket ->
 +  - Socket UDP, bouton "​Nouveau"​
 +  - donner un nom: "​udpsock"​ puis cliquer sur "​Ok"​
 +  - Editer, bouton "​entrée"​ pour choisir les paramètres à modifier
 +  - filtre IP: 192.168.1.49
 +  - port: 20000 
 +  -temps maxi: 5s   ​(permet de régler la durée au bout de laquelle une tentative de lecture sur la socket n'​ayant pas aboutie fera planter le programme VAL3
 +  - caractère fin de chaine: 13   ​(identifie le caractère ASCII devant se trouver à la fin de toutes les chaines échangées via sockets)
 +
 +<ifauth @prof>
 +TODO: Vérifier si il est possible d'​ajouter des sockets au projet SRS via le pendant virtuel????
 +</​ifauth>​
 +
 +====Chargement de l'​application dans l'​armoire de commande====
 +S'​assurer que l'​armoire de commande du robot est sous tension.
 +
 +  - Dans SRS, sélectionner la fenêtre du programme start
 +  - cliquer sur l'​onglet VAL3, puis cliquer sur le bouton Télécharger l'​application vers la cible
 +
 +La fenêtre suivante apparaît, indiquant l'​adresse IP et le numéro de port utilisé pour communiquer avec l'​armoire de commande:
 + ​{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS_prog_robot.PNG}}
 +  - Cliquer sur OK
 +  - Une fenêtre apparaît demandant si l'on souhaite écraser l'​ancien programme sur l'​armoire,​ cliquer sur Oui
 +
 +Avec le pendant:
 +  - Bouton "​Menu"​
 +  - Choisir "​Gestionnaire d'​applis"​ et valider avec le bouton Flèche droite
 +  - Choisir "​Application Val3" et valider avec le bouton Flèche droite
 +  - Choisir "​Disque"​ et valider avec le bouton Flèche droite
 +  - Choisir newProject1 (ou le nom de votre projet) et valider avec le bouton Ok
 +  - Pour que le  programme s’exécute,​ mettre le bras sous tension en appuyant sur le bouton vert de mise sous tension tout en exerçant une pression modérée sur la poignée de l'​homme mort
 +  - Pour autoriser les mouvements du robot, appuyer sur le bouton Move/Hold
 +  - Pour visualiser les messages utilisateurs sur l'​écran du pendant, appuyer sur le bouton User
 +
 +===Gestion des fichiers sur l'​armoire de commande avec winSCP ou FileZilla===
 +il est également possible d'​utiliser logiciel client FTP pour accéder aux fichiers du contrôleur (p15 de SRS-ManuelUtilisation2.PDF). L'​armoire de commande héberge les différents programmes sur un serveur FTP. Il est possible d'​utiliser un client FTP tel que winSCP (téléchargeable en version portable à l'​adresse:​ https://​winscp.net/​download/​WinSCP-5.15.9-Portable.zip )pour gérer les fichiers sur ce serveur. On pourra supprimer sur le contrôleur toutes les applications,​ sauf:
 +  Cognex
 +  CognexComm7en
 +  commCamera2
 +  EntreesSortie
 +
 +Il faut être connecté en filaire au réseau local (pas via passerelle wifi). La connexion se fait  à: 
 +  ftp://​defaut@192.168.0.112
 +  mot de passe vide
 +il faut accéder au dossier distant: ​
 +  /usr/
 +
 +===Redémarrage de l'​application===
 +Pour exécuter à nouveau le programme sur l'​armoire:​
 +  - Presser le bouton Stop
 +  - Presser le bouton Run
 +===Rechargement d'une application depuis le PC===
 +
 +Pour pouvoir recharger une application depuis le PC,  il faut tout d'​abord que l'​armoire de commande arrête son exécution. Pour cela, à l'aide du pendant:
 +  - Presser le bouton Stop
 +  - Presser le bouton Menu
 +  - choisir gestionnaire d'​applis
 +  - Presser le bouton Fer (F4)
 +
 +Ensuite charger la nouvelle version de l'​application en suivant les consignes de la section: "​Chargement de l'​application dans l'​armoire de commande"​
 +
 +===Arrêt de l'​application en cours d’exécution===
 +Pour arrêter l'​application en cours depuis le pendant:
 +  - bouton STOP
 +  - bouton Menu
 +  - Gestionnaire des tâches flêche droite
 +  - choisir la tache et cliquer sur "​Ter"​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +====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 (sur l'​armoire avec la clef et sur le pendant)!
 +Pour déplacer le robot à un point donné:
 +  * choisir mode Point, en dessous de "​Joint",​ "​Frame"​ et "​Tool"​
 +  * sélectionner le point dans la liste avec les flêches. ​
 +  * appuyer sur la poignée de l'​homme mort et mettre la puissance (bouton vert), régler la vitesse avec "​+/​-"​ à 10% puis maintenir pressé le bouton "​Move/​Hold"​ jusqu'​à ce que le robot ait atteint la consigne.
 +
 +Pour éditer le point, utiliser le pendant en mode "​Joint",​ "​Frame"​ et "​Tool"​et déplacer en ajustant Vitesse à 10% ou moins et X,Y,Z etc à la bonne valeur. Une fois l'​outil à la bonne position, cliquer sur "​Ici"​ puis sur "​Enr"​. ​
 +
 +==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 mise à 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 mettre dans les variables correspondantes du programme avec des instructions telles que:
 +
 +<file cpp conf>
 + //​configuration des points en articulaire par programme
 +  //position bras levé
 +  A={0,​ 0,​ 0,​ 0,​ 0,​ 0}
 +  //position bras vers le bas
 +  //​B={0,​ -50,​ -90,​ 0,​ -40,​ 0}
 +  //position bras vers le bas vers la fenêtre
 +   ​B={-50,​-50,​-60,​0,​-70,​0}
 +  ​
 +          put("​B[0]:​ ")
 +          put(B[0].j1)
 +          put(", ")
 +          put(B[0].j2)
 +          put(", ")
 +          put(B[0].j3)
 +          put(", ")
 +          put(B[0].j4)
 +          put(", ")
 +          put(B[0].j5)
 +          put(", ")
 +          put(B[0].j6)
 +          putln(" ​      "​)
 +          delay(3)
 +  ​
 +  ​
 +  pPointSaisieBou[0].trsf.x=-137.74
 +  pPointSaisieBou[0].trsf.y=510.87
 +  pPointSaisieBou[0].trsf.z=-303.78
 +  pPointSaisieBou[0].trsf.rx=-0.02
 +  pPointSaisieBou[0].trsf.ry=179.95
 +  pPointSaisieBou[0].trsf.rz=66.93
 +  ​
 +  pPointVisBou[0].trsf.x=72.04
 +  pPointVisBou[0].trsf.y=477.2
 +  pPointVisBou[0].trsf.z=-110.92
 +  pPointVisBou[0].trsf.rx=-0.02
 +  pPointVisBou[0].trsf.ry=179.94
 +  pPointVisBou[0].trsf.rz=66.93
 +</​file>​
 +
 +
 +=====Communication via socket=====
 +Tester le programme suivant en copiant collant le code au début de start. Il vous faut remplacer les numéros des champs dans la chaine par les champs que vous aurez réglé dans votre programme Python.
 +
 +<file cpp test.val3>​
 +begin
 +  cls()
 +  userPage()
 +  while(true)
 +    cClient_socket = "r 10 11 12"
 +    x_sMsg = cClient_socket  ​
 +    putln(x_sMsg)
 +  endWhile
 +</​file>​
 +
 +Créer les variables **cClient_socket** (de type sio) et **x_sMsg ** (de type string).
 +
 +Il faut ensuite associer la variable **cClient_socket** à la ressource sio, pour cela aller dans Accueil->​IO Physique->​Socket->​client_socket puis glisser déposer la variable **cClient_socket[0]** dans la colonne VAL3 du lien physique **client_socket**.
 +
 +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.
 +
 +
 +
 +La variable socket est normalement déjà configurée,​ mais il est possible la configurer dans le programme à l'aide de: 
 +<file cpp config_socket.val3>​
 +    clearBuffer(cClient_socket) ​   ​
 +    if(sioCtrl(cClient_socket,​ "​target",​ "​192.168.3.4"​)!=0)
 +      putln("​probleme sioCtrl(cClient_socket,​ "​target",​ "​192.168.3.4"​)"​)
 +    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(cClient_socket,​ "​endOfString",​ 13)!=0)
 +      putln("​probleme sioCtrl(cClient_socket,​ endOfString,​ 13)")
 +    endIf
 +    //port 30000 utilisé par socket UDP
 +    if(sioCtrl(cClient_socket,​ "​port",​ 30000)!=0)
 +      putln("​probleme sioCtrl(cClient_socket,​ port, 30000)"​)
 +    endIf
 +    //0 pour configurer les lectures sur socket bloquante,
 +    //une autre valeur en seconde sinon
 +    if(sioCtrl(cClient_socket,​ "​timeout",​1)!=0 )
 +      putln("​probleme sioCtrl(cClient_socket,​ timeout,​1)"​)
 +    endIf
 +</​file>​
 +
 +====Configuration à faire sur le contrôleur du robot====
 +Le PC sur lequel le serveur de capteur fonctionne n'est pas sur le réseau local du contrôleur du robot. Votre PC de développement et le simulateur du robot sont capables de communiquer avec le serveur car le PC connait le réseau local de l'AIP et les passerelles pour en sortir. Par contre, pour que le vrai robot soit capable de communiquer avec le serveur de capteurs, il faut configurer sur le contrôleur du robot une passerelle qui fait le lien entre les deux réseaux. Cela est normalement déjà réglé mais la procédure est indiquée ici pour référence: ​
 +  * Menu->​Tableau de bords->​Passerelles,​ puis
 +  * choisir destination,​ , faire "​entrée"​ puis saisir l'ip 192.168.3.4
 +  * choisir passerelle, faire "​entrée"​ puis saisir l'ip 192.168.0.13
 +
 +=====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 tel que:
 +  //il faut activer le lissage en mode '​joint'​ pour que les commandes s'​enchainent
 +  mdescA.blend=joint
 +  mdescA.leave=0
 +  mdescA.reach=0
 +
 +Ensuite, dans la boucle, vous devrez enchaîner les **movej()** ou **movel()** sans **waitEndMove()**.
 +
 +La fin du vissage programmé est alors détectée avec:
 +  // condition d'​arrêt si la fifo est vidée
 +  if isEmpty()
 +     ​bBoolVisFini=true ​
 +     ​putln("​arret vissage fin de mouvement!"​)
 +  endIf
 +
 +Pour déterminer quel ordre de mouvement le robot est en train d’exécuter:​
 +  nNumOrdreActuel[0]= getMoveId() ​         ​
 +  put("​nNumOrdreActuel:​ ")
 +  putln(nNumOrdreActuel[0])
 + 
 +Pour interompre les mouvements programmé (lorsque le capteur de couple indique un couple supérieur au seuil souhaité):
 +  stopMove()
 +  resetMotion() ​         ​
 +
 +
 +
 +=====Annexes=====
 +
 +====Informations réseau====
 +===IP et numéros de port===
 +  - IP pc rapid hébergeant le serveur de données capteurs en WIFI: 192.168.3.5
 +  - IP pc rapid hébergeant le serveur de données capteurs en filaire: 192.168.1.49
 +  - IP pc Windows à coté de l'​armoire de commande: 192.168.1.50
 +  - IP de l'​armoire de commande Staubli: 192.168.0.112
 +
 +
 +Configuration du pc Windows à coté de l'​armoire de commande:
 +  IP: 192.168.1.50
 +  Masque: 255.255.254.0
 +  Passerelle: 192.168.1.13
 +====Gestions des E/S TOR====
 +
 +L'​armoire est équipée de deux cartes DIO:
 +  -BASIC I/O
 +  -DIO MIO
 +
 +Pour les configurer dans le projet SRS: cliquer onglet cellule->​prog1->​Controller1,​ Acceuil, IO Physiques
 +  BasicIO-1
 +
 +cliquer gauche pour cocher Entrée digital %I13 puis cliquer gauche importer
 +
 +
 +dans l'​onglet Données, Projet->​dio doit contenir diB_13
 +
 +
 +
 +ATTENTION Problème de numérotation sur le bornier, car les indices commencent à 1
 +
 +Sortie doB_15 (numeroté 16) ne fonctionne pas
 +
 +   ​putln("​doB_12"​)
 +   while true
 +   ​doB_12[0]=true
 +   ​put("​1"​)
 +   ​delay(1)
 +   ​doB_12[0]=false
 +   ​put("​0"​)
 +   ​delay(1)
 +    ​
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS-ES.PNG}}
 +
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS-ES2.PNG}}
 +
 +
 +{{http://​homepages.laas.fr/​bvandepo/​files/​staubli/​images_wiki/​SRS-ES3.PNG}}
 +
 +
 +
 +===Alimentation pour les E/S 24V===
 +
 +Alimentation 24V pour les Entrées/​Sorties à allumer (en bas sur cloison à coté robot staubli)
 +
 +
 +<ifauth @prof>
 +
 +
 +=====ressources du net====
 +vidéos Tuto: https://​www.youtube.com/​playlist?​list=PLUDu1larmk8EB1ar2MTOhkf7iHOtTKb6j
 +
 +
 +https://​fr.readkong.com/​page/​tp-3-decouverte-du-robot-staubli-tx60-1715216
 +
 +
 +
 +TP d'​initiation robot staubli Picardie: https://​home.mis.u-picardie.fr/​~fabio/​Eng/​documenti/​Teaching/​INRO15-16/​InitRob_TP3.pdf
 +
 +
 +vidéo communication par socket: https://​slideplayer.fr/​slide/​2666058/​
 +
 +
 +l'​émulateur de pendant utilise les ports 850-853 et 5660-5680
 +
 +Socket\sCognex1
 +
 +faire une string pour stocker les messages
 +
 +
 +
 +
 +====Réflexion sur l'​infrastructure réseau====
 +
 +routeur wifi 
 +banana pi RP2 avec 4 interfaces filaires + WIFI
 +
 +
 +
 +ajout d'une variable sSio
 +ajout d'une variable string x_sMsg
 +
 +
 +
 +explication du protocole de comm cognex via socket dans le fichier
 +C:​\Users\bvande\Downloads\communication-EntreeSorties-mai2019_michel\communication-EntreeSorties-mai2019\Controller1\usr\usrapp\cognexComm7En\readme.pgx
 +
 +
 +---------------------------
 +  //  You must declare this socket in the control panel of the controller as
 +  //  followed :
 +  //    - a client socket for each camera with
 +  //    - IP address of camera
 +  //    - Port : 1023
 +  //    - time out = 0
 +  //    - line end char = 13
 +  ​
 +  chaque fichier .pgx est un sous programme ​
 +  ​
 +  example.pgx ​  
 +  //  This is an example for use this library.
 +  //  This example writes two numerical values (int num and float num) and
 +  //  reads a string value to/from three cells:
 +  ​
 +  ---------------------------
 +  sendCommand.pgx
 + 
 + call writeSocket(x_nCamID,​x_sCmd)
 +  call readSocket(x_nCamID,​l_sMsgError,​x_bError)
 +  call checkErrFormat(x_nCamID,​l_sMsgError,​l_bError)
 +  x_bError=l_bError
 +  if bDebugProgram
 +    //Displays error message
 +    //​getFullError() replace getErrorCode() and getErrorMessage()
 +    call getFullError(x_nCamID,​l_nErrorCode,​l_sMsgError)
 +    ? "​Cmd>​ "​+l_sMsgError
 +  endIf
 +  ​
 +  ​
 +  ​
 +  ---------------------------
 +  writeSocket.pgx
 +  ​
 +  for i=0 to (len(x_sMsg)-1)
 +    sioSet(cCamera[x_nCamID].sSocket,​asc(x_sMsg,​i))
 +  endFor
 +  sioSet(cCamera[x_nCamID].sSocket,​13)
 +  sioSet(cCamera[x_nCamID].sSocket,​10)
 +  if bDebugSocket
 +    ? "W Status code: "​+x_sMsg
 +  endIf
 +  ​
 +  ​
 +
 +
 +librairie récupérée de: 
 +C:​\Users\bvande\Documents\communication-EntreeSorties-mai2019_michel\communication-EntreeSorties-mai2019\Controller1\usr\usrapp\cognexComm7En
 +
 +
 +-----------------------------------------------
 +
 +
 +dans C:​\Users\bvande\Documents\communication-EntreeSorties-mai2019_michel\communication-EntreeSorties-mai2019\Controller1\usr\usrapp\cognexComm7En\login.pgx
 + 
 +
 +sioLink(cCamera[x_nCamID].sSocket,​x_sioSocket) ​    
 +
 +
 + call readSocket(x_nCamID,​l_sMsg,​x_bError) ​
 +                                               //​putln("​finreadsoc"​)
 +    // Send user name
 +    call readLogin(x_nCamID,​l_sMsg,​x_bError)
 +                                               //​putln("​readlogin"​)
 +    call writeSocket(x_nCamID,​x_sUser)
 +    // Send password
 +    call readLogin(x_nCamID,​l_sMsg,​x_bError)
 +    call writeSocket(x_nCamID,​x_sPassword)
 +       
 +    // Read login result
 +    call readSocket(x_nCamID,​l_sMsg,​x_bError)
 +    x_bError=find(l_sMsg,"​User Logged In"​)==-1
 +    if x_bError
 +      cCamera[x_nCamID].nErrorCode=1
 +      cCamera[x_nCamID].bConnected=false
 +      if bDebugProgram
 +        putln("​Login : failed"​) ​       ​
 +      endIf
 +
 +
 +------------------------------------------------------------------------
 +readsocket
 +x_sMsg=""​
 +  //​putln("​read socket"​)
 + 
 +  do
 +    l_nCount=sioGet(cCamera[x_nCamID].sSocket,​l_nChar)
 +    //-1 : timeout for input communication has been reached
 + //​putln("​sio"​)
 +    if (l_nCount>​-1) and (l_nChar>​=32)
 +      x_sMsg=x_sMsg+chr(l_nChar)
 +    endIf
 +    x_bError=l_nCount<​=-1
 +  until (l_nChar==13) or x_bError
 +  //Displays error message
 +  if bDebugSocket
 +    ? "R Status code> "​+x_sMsg
 +  endIf
 +
 +------------------------------------------------------------------------
 +writesocket
 +
 +  for i=0 to (len(x_sMsg)-1)
 +    sioSet(cCamera[x_nCamID].sSocket,​asc(x_sMsg,​i))
 +  endFor
 +  sioSet(cCamera[x_nCamID].sSocket,​13)
 +  sioSet(cCamera[x_nCamID].sSocket,​10)
 +  if bDebugSocket
 +    ? "W Status code: "​+x_sMsg
 +  endIf
 +
 +------------------------------------------------------------------------
 +
 +
 +
 +=====Python=====
 +Installation python sur machine windows:
 +
 +
 +https://​pypi.anaconda.org/​ales-erjavec/​simple/​pyqt4/​4.11.4/​PyQt4-4.11.4-cp34-none-win_amd64.whl
 +cd \Python34\Scripts
 +pip install QtGui 
 +pip3 install C:​\Users\bvande\Downloads\PyQt4-4.11.4-cp34-none-win_amd64.whl
 +
 +
 +
 +<file txt pip3.txt>​
 +C:​\Python34\Scripts>​pip3 install tk
 +Downloading/​unpacking tk
 +  Downloading tk-0.1.0-py3-none-any.whl
 +Installing collected packages: tk
 +Successfully installed tk
 +Cleaning up...
 +
 +C:​\Python34\Scripts>​pip3 install matplotlib
 +Downloading/​unpacking matplotlib
 +  Running setup.py (path:​C:​\Users\alimen\AppData\Local\Temp\pip_build_alimen\mat
 +plotlib\setup.py) egg_info for package matplotlib
 +
 +    Beginning with Matplotlib 3.1, Python 3.6 or above is required.
 +
 +    This may be due to an out of date pip.
 +
 +    Make sure you have pip >= 9.0.1.
 +
 +    Complete output from command python setup.py egg_info:
 +
 +
 +Beginning with Matplotlib 3.1, Python 3.6 or above is required.
 +
 +
 +
 +This may be due to an out of date pip.
 +
 +
 +
 +Make sure you have pip >= 9.0.1.
 +
 +----------------------------------------
 +Cleaning up...
 +Command python setup.py egg_info failed with error code 1 in C:​\Users\alimen\App
 +Data\Local\Temp\pip_build_alimen\matplotlib
 +Storing debug log for failure in C:​\Users\alimen\pip\pip.log
 +
 +C:​\Python34\Scripts>​
 +
 +</​file>​
 +
 +
 +=====Programmes Bertrand=====
 +
 +<file cpp start.c>
 +begin
 +  ​
 +  //​B.Vandeportaele 2019
 +  //​activation puissance pour mode deporte
 +  enablePower() ​
 +  //​effacement écran USER
 +  cls()  ​
 +  //selection écran USER
 +  userPage()
 +  //putln( "​démarrage application"​) ​
 +  put("​date:​ ")
 +  putln(getDate("​ %d/%m/%Y %H:​%M:​%S"​))
 +  ​
 +  nNum[0]=0
 +  put(nNum[0])
 + 
 +  //affichage compte à rebours
 +  gotoxy(0,1)
 +  put("​départ dans:   "​)
 +  for nNum[0]=1 to 0 step -1
 +    gotoxy(13,​1)
 +    put(nNum[0])
 +    putln("​ s   "​)
 +    delay(1)
 +  endFor
 +  ​
 +    ​
 +  nNum[0]=0
 +  gotoxy(0,2)
 +  putln("​ KABOUM2 !!!!!!! ​ ")
 +  ​
 +  ​
 +  //TODO faire un sous programme qui teste la communication ​
 +  //avec les différentes adresses (via timeout)
 +  call initSockets()
 +  ​
 +
 +  bOverRun=false
 +  //​emissionEtat est un programme créé, et éxecuté à une périodicité de 0.01s
 +  //​taskCreateSync "​emissionEtat",​.01,​bOverRun,​emissionEtat()
 +  taskCreateSync "​emissionEtat",​1,​bOverRun,​emissionEtat()
 +  putln("​Tache periodique emission Etat lancee"​)
 +
 +  ///////////////////////////////////////////////////////​
 +  //​configuration des points en articulaire par programme
 +  //position bras levé
 +  A={0,​ 0,​ 0,​ 0,​ 0,​ 0}
 +  //position bras vers le bas
 +  B={0,​ -50,​ -90,​ 0,​ -40,​ 0}
 +  ​
 +  //impose une vitesse faible pour les premiers déplacements du robot
 +  //on ne peut que ralentir la vitesse avec le programme, c'est à l'​utilisateur de l'​augmenter avec Emulator Controller ou avec le pendant
 +
 +  //attention cette vitesse est prise en compte par l'​armoire de commande en mode automatique
 +  //​setMonitorSpeed(10) ​
 +
 +    ​
 +  //​positionnement du bras dans une configuration initiale connue en donnant une consigne articulaire (joint)
 +  putln("​positionnement du bras dans une configuration initiale connue en donnant une consigne articulaire (joint) ")
 +  //bras vers le haut
 +  movej( A,tTool, mdescA)
 +  waitEndMove()
 +  //bras vers le bas
 +  movej( B,tTool, mdescA)
 +  ​
 +  waitEndMove()
 +  putln("​positionnement du bras atteinte"​)
 +  ///////////////////////////////////////////////////////​
 +
 +  if(true)
 +    //Cette instruction renvoie un point modifié par transformation géométrique. La transformation est définie par rapport aux axes du centre outil d'​entrée.
 +    //Le repère de référence et la configuration du point renvoyé sont ceux du point d'​entrée.
 +    //Une erreur d'​exécution est générée si aucun repère de référence n'est défini pour pPosition.
 +  ​
 +    // Approche :Mouvement d'​approche à 100 mm au-dessus du point (axe Z)
 +    // movej(appro(pDestination,​{0,​0,​-100,​0,​0,​0}),​ flange, mNomDesc)
 +    // Aller au pointmovel(pDestination,​ flange, mNomDesc)
 +  ​
 +  ​
 +    while(true)
 +      putln("​Approche pour la saisie du bouchon"​)
 +      movej(appro(pPointSaisieBou[0],​{0,​0,​-100,​0,​0,​0}),​ tTool, mdescA)
 +      //​waitEndMove()
 +      //Attendre que la position du robot se stabilise
 +      while(isSettled()==false)
 +        putln("​."​)
 +      endWhile
 +      ​
 +      ​
 +  ​
 +  ​
 +      putln("​saisie du bouchon"​)
 +      movej(pPointSaisieBou[0],​ tTool, mdescA)
 +    ​
 +      putln("​Eloignement après la saisie du bouchon"​)
 +      movej(appro(pPointSaisieBou[0],​{0,​0,​-100,​0,​0,​0}),​ tTool, mdescA)
 +      waitEndMove()
 +  ​
 +      putln("​Approche pour le vissage du bouchon"​) ​
 +      //100mm au dessus
 +      movej(appro(pPointVisBou[0],​{0,​0,​-100,​0,​0,​0}),​ tTool, mdescA)
 +      waitEndMove()
 +  ​
 +      //baisser la vitesse
 +      //​setMonitorSpeed(10)
 +      ​
 +      putln("​vissage du bouchon"​)
 +      mdescA.blend=off
 +      mdescA.leave=0
 +      mdescA.reach=0
 +      movej(pPointVisBou[0],​ tTool, mdescA)
 +    ​
 +      bBoolVisFini=false
 +    ​
 +      //il faut activer le lissage en mode '​joint'​ pour que les commandes s'​enchainent
 +      mdescA.blend=joint
 +      mdescA.leave=0
 +      mdescA.reach=0
 +      ​
 +      for nNum[0]=0 to 10 step 1 
 +        put("​itération:​ ")
 +        put(nNum[0])
 +        put(" ​ ->  ")
 +        movej(appro(pPointVisBou[0],​{0,​0,​nNum[0]*2.6*3/​8,​0,​0,​nNum[0]*45}),​ tTool, mdescA)
 +      endFor
 +      ​
 +      nNum[0]=0
 +      while bBoolVisFini==false
 +        //
 +        //      movej(appro(pPointVisBou[0],​{0,​0,​nNum[0]*1.2,​0,​0,​nNum[0]*90}),​ tTool, mdescA)
 +        //   ​waitEndMove()
 +      ​
 +        if(false)
 +          jJointActuel=herej()
 +          put("​jJointActuel[0]:​ ")
 +          put(jJointActuel[0].j1)
 +          put(", ")
 +          put(jJointActuel[0].j2)
 +          put(", ")
 +          put(jJointActuel[0].j3)
 +          put(", ")
 +          put(jJointActuel[0].j4)
 +          put(", ")
 +          put(jJointActuel[0].j5)
 +          put(", ")
 +          put(jJointActuel[0].j6)
 +          putln(" ​      "​)
 +        endIf
 +        ​
 +        // condition d'​arrêt si la fifo est vidée
 +        if isEmpty()
 +          bBoolVisFini=true ​
 +          putln("​arret vissage fin de mouvement!"​)
 +        endIf
 +     
 +        nNumOrdreActuel[0]= getMoveId() ​         ​
 +        put("​nNumOrdreActuel:​ ")
 +        putln(nNumOrdreActuel[0])
 +        ​
 +        //ajouter une condition sur le capteur de couple ​       ​
 +        //if nNum[0]>​=10
 +
 +        //émission chaine complète
 +        cClient_socket="​r 5 6 2"
 +        x_sMsg=cClient_socket
 +        putln("​chaine recue:"​)
 +        put(x_sMsg)
 +        x_sMsg= toNum(x_sMsg,​ nNum, bBool)
 +        x_sMsg= toNum(x_sMsg,​ nNum2, bBool)
 +        x_sMsg= toNum(x_sMsg,​ nNum3, bBool)
 +        if nNum3==1
 +          bBoolVisFini=true ​        
 +          stopMove()
 +          ​
 +          resetMotion() ​         ​
 +          putln("​arret vissage capteur!"​)
 +          ​
 +        endIf
 +    ​
 +        ​
 +        if bBoolVisFini==false
 +          nNum[0]=nNum[0]+1
 +        endIf
 +        ​
 +        //endFor
 +        ​
 +      endWhile
 +    ​
 +  ​
 +      //remonter la vitesse, ne fonctionne pas si l'​utilisateur peut régler manuellement la vitesse
 +      //​setMonitorSpeed(25)
 +      ​
 +      // il faut garder l'​angle de vissage sinon l'​outils va devisser en remontant
 +      putln("​Eloignement après le vissage du bouchon"​)
 +      //recupère la pose courante en cartésien
 +      pPointActuel[0]=here(tTool,​fFrame[0])
 +      //remonte de 100 par rapport à la position courante 100mm au dessus
 +      movej(appro(pPointActuel[0],​{0,​0,​-100,​0,​0,​0}),​ tTool, mdescA)
 +      waitEndMove()
 +      ​
 +      // problème, en cartésien, les tours faits pour le vissage ne sont pas défaits....
 +      putln("​Dévissage pour revenir au 0")
 +      jJointActuel=herej()
 +      jJointActuel[0].j6=0
 +      movej( jJointActuel[0],​ tTool, mdescA)
 +      waitEndMove()
 +  ​
 +    endWhile
 +  endIf
 + 
 +  ​
 +  ​
 +  if true
 +    while true
 +      put("​*"​)
 +    ​
 +      //​sioSet(cUdpsock,​asc(x_sMsg) ) 
 +      //​nNum[0]=ioStatus(cClient_socket)
 +      //0 L'​entrée-sortie fonctionne. ​
 +      //1 L'​entrée-sortie fonctionne mais elle est verrouillée par l'​opérateur. Les entrées ont alors une valeur fixe (contrôlée par l'​opérateur) qui peut être différente de la valeur matérielle. Les sorties ont alors une valeur
 +      //fixe contrôlée par l'​opérateur : l'​écriture sur la sortie n'a aucun effet. Le mode de verrouillage est un moyen de débogage. ​
 +      //2 L'​entrée-sortie est simulée (entrée-sortie logicielle, sans effet sur le matériel). ​
 +      //-1 L'​entrée-sortie ne fonctionne pas parce que le lien (adresse physique) n'est pas défini. ​
 +      //-2 L'​entrée-sortie ne fonctionne pas parce que le lien (adresse physique) ne correspond à aucune entrée-sortie du système. Le matériel correspondant à l'​adresse physique n'est pas installé ou n'a pas pu être initialisé. ​
 +      //-3 L'​entrée-sortie ne fonctionne pas parce que le dispositif d'​entrée-sortie est en erreur. ​
 +
 +      //​putln("​envoi"​)
 +      //émission chaine complète
 +      cClient_socket="​r 5 6 2"
 +      //​putln("​requete0"​)
 +      //émission chaine caractère par caractère
 +      //    for nNum[0]=0 to(len(x_sMsg)-1)
 +      //      sioSet(cUdpsock,​asc(x_sMsg, ​ nNum[0]))  ​
 +      //    endFor
 +      //    sioSet(cUdpsock,​13)
 +      //    sioSet(cUdpsock,​10)
 +    ​
 +      //tentative de reception d'un caractère, bloquant jusqu'​au timeout
 +      //    nNum[0]=sioGet(cUdpsock,​ nCarRecu[0])
 +      //    if nNum[0]>​0
 +      //      put(chr(nCarRecu[0])) ​     ​
 +      //    endIf
 +
 +      //reception d'une chaine de caractère d'un seul coup, devant se terminer par "​endOfString"​
 +    ​
 +      x_sMsg=cClient_socket
 +      // x_sMsg="​70"​
 +      putln("​chaine recue:"​)
 +      put(x_sMsg)
 +
 +      if false
 +        ///pour débugage; affichage des codes ascii recus
 +        putln("​chaine en ascii decimal:"​)
 +        for nNum= 0 to len(x_sMsg)-1
 +          put(nNum)
 +          put(" : ")
 +          put(asc(x_sMsg,​nNum))
 +          putln(""​)
 +        endFor
 +      endIf
 +      ​
 +      //parsing, il ne faut pas que la chaine se termine par la valeur numérique à parser, ajouter un espace à la fin
 +      //  x_sMsg="​70"​
 +      //​x_sMsg=x_sMsg+"​. "
 +     
 +      ​
 +      ​
 +      x_sMsg= toNum(x_sMsg,​ nNum, bBool)
 +      if(bBool==true)
 +        put("​décodé:"​)
 +        put(nNum)
 +      else
 +        put("​erreur décodage"​)
 +      endIf
 +      putln(""​)
 +
 +
 +
 +      x_sMsg= toNum(x_sMsg,​ nNum2, bBool)
 +      if(bBool==true)
 +        put("​décodé:"​)
 +        put(nNum2)
 +      else
 +        put("​erreur décodage"​)
 +      endIf
 +      putln(""​)
 +
 +      x_sMsg= toNum(x_sMsg,​ nNum3, bBool)
 +      if(bBool==true)
 +        put("​décodé:"​)
 +        put(nNum3)
 +      else
 +        put("​erreur décodage"​)
 +      endIf
 +      putln(""​)
 +
 +
 +      //delay(1)
 +      //true pour commande en articulaire
 +      //false pour commande en cartesien
 +      if false   
 +        nNum=nNum/​100
 +        nNum2=nNum2/​100
 +        nNum3=nNum3*50
 +       
 +        //A[0]=nNum
 +        A={nNum,​ nNum2,​ nNum3,​ -0,​ 0,​ 0}
 +        //​vérification que le point visé soit atteignable pour 
 +        //ne pas faire planter dans le cas contraire
 +        if isInRange(A)
 +          putln("​atteignable ​   ")
 +          movej( A,​tTool,​mdescA)
 +          waitEndMove()  ​
 +        else
 +          putln("​non atteignable"​)
 +          //delay pour avoir le temps de voir
 +          delay(1)
 +        endIf
 +     
 +      else
 +     
 +        nNum=nNum/​10
 +        nNum2=nNum2/​10
 +        nNum3=nNum3*50
 +     
 +     
 +       
 +        // Aj[0]= ​  ​{157,​ 84,​ -50,​ -206,​ -41,​ -51}
 +  ​
 +        //MGD
 +        Ac[0]=jointToPoint(tTool,​fFrame[0], ​ B)
 +        put("​Ac[0]:​ ")
 +        put(Ac[0].trsf.x)
 +        put(", ")
 +        put(Ac[0].trsf.y)
 +        put(", ")
 +        put(Ac[0].trsf.z)
 +        put(", ")
 +        put(Ac[0].trsf.rx)
 +        put(", ")
 +        put(Ac[0].trsf.ry)
 +        put(", ")
 +        put(Ac[0].trsf.rz)
 +        putln(",​ ")
 +        if(Ac[0].config.shoulder==righty)
 +          put("​shoulder righty"​)
 +        endIf
 +        if(Ac[0].config.shoulder==lefty)
 +          put("​shoulder lefty"​)
 +        endIf
 +        //​put(pPointRx[0].config.shoulder)
 +        //​putln(",​ ")
 +        //​put(pPointRx[0].config.shoulder)
 +        //​putln(",​ ")
 +        //​put(pPointRx[0].config.wrist)
 +        //​putln(",​ ")
 +        //​put(pPointRx[0].config.elbow)
 +        putln(" ​      "​)
 +
 +
 +        //position de travail en articulaire
 +        //movej( B,tTool, mdescB)
 +        //​waitEndMove()  ​
 +    ​
 +        Ac=here(tTool,​fFrame[0])
 +        put("​pPointRx[0]:​ ")
 +        put(Ac[0].trsf.x)
 +        put(", ")
 +        put(Ac[0].trsf.y)
 +        put(", ")
 +        put(Ac[0].trsf.z)
 +        put(", ")
 +        put(Ac[0].trsf.rx)
 +        put(", ")
 +        put(Ac[0].trsf.ry)
 +        put(", ")
 +        put(Ac[0].trsf.rz)
 +        //​putln(",​ ")
 +        //​put(Ac[0].config.shoulder)
 +        //​putln(",​ ")
 +        //​put(Ac[0].config.shoulder)
 +        //​putln(",​ ")
 +        //​put(Ac[0].config.wrist)
 +        //​putln(",​ ")
 +        //​put(Ac[0].config.elbow)
 +        putln(" ​      "​)
 +     
 +     
 +     
 +
 +        //génère un nombre aléatoire suivant
 +        //call rand(0) ​   ​
 +        //​xObj=-200+seed%400
 +        //call rand(0) ​   ​
 +        //​yObj=-200+seed%400
 +      ​
 +        //injecte la consigne issue du capteur
 +        Ac[0].trsf.x=-400+nNum
 +        Ac[0].trsf.y=49+nNum2
 +        Ac[0].trsf.z=-116-nNum3
 +      ​
 +        //    Ac[0].trsf.x=Ac[0].trsf.x+1
 +    ​
 +    ​
 +        //​vérification que le point visé soit atteignable pour 
 +        //ne pas faire planter dans le cas contraire
 +        if pointToJoint(tTool,​herej(),​Ac[0],​B[0])
 +          putln("​atteignable ​   ")
 +          // if isInRange(()
 +    ​
 +    ​
 +          movej( Ac,tTool, mdescA)
 +          waitEndMove()  ​
 +        else
 +          putln("​non atteignable"​)
 +          //delay pour avoir le temps de voir
 +          delay(1)
 +        endIf
 +     
 +        //    pPointRx=here(tTool,​fFrame[0])
 +        //    put("​pPointRx[0]:​ ")
 +        //    put(pPointRx[0].trsf.x)
 +        //    put(", ")
 +        //    put(pPointRx[0].trsf.y)
 +        //    put(", ")
 +        //    put(pPointRx[0].trsf.z)
 +        //    put(", ")
 +        //    put(pPointRx[0].trsf.rx)
 +        //    put(", ")
 +        //    put(pPointRx[0].trsf.ry)
 +        //    put(", ")
 +        //    put(pPointRx[0].trsf.rz)
 +     
 +        putln(" ​      "​)
 +    ​
 +      endIf
 +      ​
 +    endWhile
 +  endIf
 +  ///////////////////////////////////////////​
 +  ​
 +  ​
 +    ​
 +  //test des sockets ​ UDP
 +  ​
 +  x_sMsg="​Bonjour de la part de RX60"
 +
 +  //"​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(cUdpsock,​ "​endOfString",​ 13)!=0)
 +    putln("​probleme D")
 +  endIf
 +  ​
 +  if(sioCtrl(cUdpsock,​ "​port",​ 20000)!=0)
 +    putln("​probleme A")
 +  endIf
 +  ​
 +  if(sioCtrl(cUdpsock,​ "​target",​ "​192.168.1.49"​)!=0)
 +    putln("​probleme B")
 +  endIf
 + 
 +  //0 pour configurer les lectures sur socket bloquantes,
 +  //une autre valeur en seconde sinon
 +  if(sioCtrl(cUdpsock,​ "​timeout",​ 10)!=0 )
 +    putln("​probleme C")
 +  endIf
 +  ​
 +  ​
 +  if true
 +    while true
 +      put("​."​)
 +    ​
 +      //​sioSet(cUdpsock,​asc(x_sMsg) ) 
 +      nNum[0]=ioStatus(cUdpsock)
 +      //0 L'​entrée-sortie fonctionne. ​
 +      //1 L'​entrée-sortie fonctionne mais elle est verrouillée par l'​opérateur. Les entrées ont alors une valeur fixe (contrôlée par l'​opérateur) qui peut être différente de la valeur matérielle. Les sorties ont alors une valeur
 +      //fixe contrôlée par l'​opérateur : l'​écriture sur la sortie n'a aucun effet. Le mode de verrouillage est un moyen de débogage. ​
 +      //2 L'​entrée-sortie est simulée (entrée-sortie logicielle, sans effet sur le matériel). ​
 +      //-1 L'​entrée-sortie ne fonctionne pas parce que le lien (adresse physique) n'est pas défini. ​
 +      //-2 L'​entrée-sortie ne fonctionne pas parce que le lien (adresse physique) ne correspond à aucune entrée-sortie du système. Le matériel correspondant à l'​adresse physique n'est pas installé ou n'a pas pu être initialisé. ​
 +      //-3 L'​entrée-sortie ne fonctionne pas parce que le dispositif d'​entrée-sortie est en erreur. ​
 +
 +      //émission chaine complète
 +      cUdpsock="​requete0"​
 +    ​
 +      //émission chaine caractère par caractère
 +      //    for nNum[0]=0 to(len(x_sMsg)-1)
 +      //      sioSet(cUdpsock,​asc(x_sMsg, ​ nNum[0]))  ​
 +      //    endFor
 +      //    sioSet(cUdpsock,​13)
 +      //    sioSet(cUdpsock,​10)
 +    ​
 +      //tentative de reception d'un caractère, bloquant jusqu'​au timeout
 +      //    nNum[0]=sioGet(cUdpsock,​ nCarRecu[0])
 +      //    if nNum[0]>​0
 +      //      put(chr(nCarRecu[0])) ​     ​
 +      //    endIf
 +
 +      //reception d'une chaine de caractère d'un seul coup, devant se terminer par "​endOfString"​
 +    ​
 +      x_sMsg=cUdpsock
 +      put(x_sMsg)
 +      //delay(1)
 +    endWhile
 +  endIf
 +  ​
 +  putln("​doB_15"​)
 +  while true
 +    doB_15[0]=true
 +    put("​1"​)
 +    delay(1)
 +    ​
 +    doB_15[0]=false
 +    put("​0"​)
 +    delay(1)
 +    ​
 +  endWhile
 +  ​
 +  if(false)
 +    putln("​lecture capteur par socket"​)
 +    while true
 +      put("​."​)
 +      //émission chaine complète
 +      cUdpsock="​lecture capteur 1"
 +      x_sMsg=cUdpsock
 +      put(x_sMsg)
 +    endWhile
 +
 +  else 
 +    putln("​lecture capteur par IO TOR diB_13"​)
 +    while true
 +      put("​."​)
 +      ​
 +      nNum[0]=ioStatus(diB_13,​ x_sMsg, x_sMsg2)
 +      put( "​ioStatus= ")
 +      putln (nNum[0])
 +      if nNum[0]<​0
 +        putln("​Signal "​+x_sMsg2+ "en erreur"​) ​
 +        putln("​Description :"​+x_sMsg)
 +      endIf
 +        ​
 +        ​
 +      if(diB_13==true)
 +        x_sMsg="​1"​
 +        doB_15=true
 +      else
 +        x_sMsg="​0"​
 +        doB_15=false
 +      endIf
 +      ​
 +      ​
 +      ​
 +      put(x_sMsg)
 +      delay(1)
 +    endWhile
 +  endIf
 +  //fermer la connexion ​ ??? (vider les buffers
 +  nNum[0]=clearBuffer(cUdpsock)
 +end
 +</​file>​
 +
 +<file cpp initSocket.c>​
 +begin
 +  bServeurTrouve=false
 +  ​
 +  //nombre de serveurs définis
 +  nNum=3 ​
 +  ​
 +  while bServeurTrouve==false
 +    ​
 +    ​
 +  ​
 +    clearBuffer(cClient_socket)
 +    //"​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(cClient_socket,​ "​endOfString",​ 13)!=0)
 +      putln("​probleme sioCtrl(cClient_socket,​ endOfString,​ 13)")
 +    endIf
 +    //port 30000 utilisé par socket UDP
 +    if(sioCtrl(cClient_socket,​ "​port",​ 30000)!=0)
 +      putln("​probleme sioCtrl(cClient_socket,​ port, 30000)"​)
 +    endIf
 +    //0 pour configurer les lectures sur socket bloquante,
 +    //une autre valeur en seconde sinon
 +    if(sioCtrl(cClient_socket,​ "​timeout",​1)!=0 )
 +      putln("​probleme sioCtrl(cClient_socket,​ timeout,​2)"​)
 +    endIf
 +  ​
 +    //  if(sioCtrl(cClient_socket,​ "​nagle",​false)!=0 )
 +    //    putln("​probleme sioCtrl(cClient_socket,​ nagle,​false)"​)
 +    // endIf
 +  ​
 +  ​
 +  ​
 +    if nNum==0
 +      putln("​Serveur NON TROUVE, on recommence le scan"​) ​       ​
 +      nNum=3
 +    endIf
 +    switch(nNum)
 +      //le scan fonctionne mais il faut que toutes les adresses soient joignables.
 +      //si une adresse balayée n'est pas joignable, une adresse suivante ne pourra pas être jointe
 +      //dans ce cas mettre manuellement l'​adresse du bon serveur en premier ​
 +      case 3
 +        //rapid en filaire à la maison et a l'aip (meme adresse)
 +        sAdrIPServeur="​192.168.1.49"  ​
 +        //​sAdrIPServeur="​192.168.1.254"  ​
 + 
 +        // sAdrIPServeur="​192.168.43.14" ​  
 +      break
 +      case 2
 +        //rapid en filaire ​
 +        //      sAdrIPServeur="​192.168.1.49"​
 +        //rapid en wifi à l'aip sur WIFI AIP ROBOT
 +        sAdrIPServeur="​192.168.3.5"​
 +     
 +
 +        //test bidon google
 +        //​sAdrIPServeur="​8.8.8.8"​
 +      break
 +   
 +      case 1
 +        //rapid en wifi via huawei GR5
 +        sAdrIPServeur="​192.168.43.14" ​  
 +      break
 +    endSwitch
 +    ​
 +    put("​essai serveur: ")
 +    putln(sAdrIPServeur)
 +    if(sioCtrl(cClient_socket,​ "​target",​ sAdrIPServeur)!=0)
 +      putln("​probleme sioCtrl(cClient_socket,​ target, sAdrIPServeur)"​)
 +    endIf
 +    ​
 +    delay(2)
 +    ​
 +    //nNum2=13
 +    //​if(sioSet(cClient_socket,​nNum2)==-1)
 +    //​if(sioSet(cClient_socket,​nNum2)<​1)
 +    ​
 +    //fait une requette bidon
 +    sEtat="​r 5 6 2"
 +    //​redimensionne nNum2 pour traduire la chaine vers un tableau de caractères
 +    resize(nNum2,​1,​len(sEtat)+1)
 +    for nNum3=0 to len(sEtat)
 +      nNum2[nNum3]=asc(sEtat,​nNum3)  ​
 +    endFor
 +    nNum2[len(sEtat)]=13
 +    // delay(1) ​
 +    ​
 +    ​
 +    //​resize(nNum2,​1,​128)
 +    nNum3=5
 +    //for nNum4=0 to 30
 +    while nNum3>0 and bServeurTrouve==false
 +      put("​tentative:​ ")
 +      putln(nNum3)
 +      if(sioSet(cClient_socket,​nNum2)!=-1)
 +        bServeurTrouve=true
 +        put("​serveur capteur trouve: ")
 +        putln(sAdrIPServeur)
 +        //delay(3)
 +      endIf
 +      nNum3=nNum3-1
 +    endWhile
 +    nNum=nNum-1
 +  endWhile
 +  ​
 +  ​
 +  //test des sockets ​ TCP
 +  ​
 +  x_sMsg="​Bonjour de la part de RX60"
 +
 +  /////// CONFIGURATION SOCKET UDP /////////
 +  ​
 +  ​
 +  //"​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(cUdpsock,​ "​endOfString",​ 13)!=0)
 +    putln("​probleme D")
 +  endIf
 +  ​
 +  if(sioCtrl(cUdpsock,​ "​port",​ 10000)!=0)
 +    putln("​probleme A")
 +  endIf
 +  ​
 +  if(sioCtrl(cUdpsock,​ "​target",​ sAdrIPServeur)!=0)
 +    putln("​probleme B")
 +  endIf
 + 
 +  //0 pour configurer les lectures sur socket bloquantes,
 +  //une autre valeur en seconde sinon
 +  if(sioCtrl(cUdpsock,​ "​timeout",​ 10)!=0 )
 +    putln("​probleme C")
 +  endIf
 +  ​
 +  ​
 +  ​
 +  ////  FIN CONFIGURATION SOCKET UDP ///////
 +
 +
 +end
 +</​file>​
 +
 +<file cpp emissionEtat.c>​
 +begin
 +  while true
 +    pHereEtat=here(tTool,​world)
 +    jHereEtat=herej()
 +    //    putln(pHereEtat[0].trsf.x)
 +    ​
 +    //émission chaine complète
 +    //déclarer une variable string et utiliser la fonction tostring pour formater
 +    //adresse mac???
 +    //​cUdpsock="​DC:​4F:​22:​00:​00:​00 0 191.000000 6 0"
 +    sEtat="​DC:​4F:​22:​00:​00:​00 100 " +toString("​.6",​pHereEtat[0].trsf.x)
 +    sEtat=sEtat+"​ "​+toString("​.6",​pHereEtat[0].trsf.y)
 +    sEtat=sEtat+"​ "​+toString("​.6",​pHereEtat[0].trsf.z)
 +    sEtat=sEtat+"​ "​+toString("​.6",​pHereEtat[0].trsf.rx)
 +    sEtat=sEtat+"​ "​+toString("​.6",​pHereEtat[0].trsf.ry)
 +    sEtat=sEtat+"​ "​+toString("​.6",​pHereEtat[0].trsf.rz)
 +    //​sEtat=sEtat+"​ "​+toString("​.6",​pHereEtat[0].config.shoulder) ​
 +    //ce n'est pas un numero
 +    cUdpsock=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
 +    sEtat="​DC:​4F:​22:​00:​00:​00 106 " +toString("​.6",​jHereEtat[0].j1)
 +    sEtat=sEtat+"​ "​+toString("​.6",​jHereEtat[0].j2)
 +    sEtat=sEtat+"​ "​+toString("​.6",​jHereEtat[0].j3)
 +    sEtat=sEtat+"​ "​+toString("​.6",​jHereEtat[0].j4)
 +    sEtat=sEtat+"​ "​+toString("​.6",​jHereEtat[0].j5)
 +    sEtat=sEtat+"​ "​+toString("​.6",​jHereEtat[0].j6)
 +    cUdpsock=sEtat
 +    ​
 +    delay(0)
 +    ​
 +   
 +  endWhile
 +end
 +
 +</​file>​
 +
 +
 +</​ifauth> ​
staubli.txt · Dernière modification: 2020/02/06 15:02 par bvandepo