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
staubli [2019/07/10 10:17]
bvandepo
staubli [2021/04/03 21:47] (Version actuelle)
bvandepo
Ligne 1: Ligne 1:
-=====Staubli AIP===== 
  
  
-{{http://homepages.laas.fr/bvandepo/files/staubli/SRS1.png}}+<ifauth @prof> 
 +2021/03/31:  Fabien a du réinstaller l'émulateur sur le poste étudiant en face du controleur, il avait été réglé en déporté.
  
 +2021/01/06 : problème de version du controleur en v7.9.1
 +tous mes projets sont en 7.10 et tous les postes étudiants sont aussi en 7.10
 +Fabien réinstalle l'émulateur en v7.10 sur le poste près du controleur robot.
 +on télécharge alors un projet en v7.10 vers le controleur en 7.6.9 (ce qui n'était pas possible avant), et a partir de la le controleur accepte les projets en 7.10 et les pc étudiants peuvent créer des projets en 7.10 à partir de la config du robot.
 +
 +réinitialisation de la config du controleur
 +je sauvegarde via filezilla l'arborescence du dossier /app/ du controleur dans  https://bvdp.inetdoc.net/files/staubli/backup_controlleur_janvier_2021_avant_remise_en_fonctionnement_suite_a_probleme_7.9.1.zip
 +
 +Puis remet ma version de sauvegarde (avec aucune application): https://bvdp.inetdoc.net/files/staubli/backup_controller_apres_purge.zip
 +
 +il manque la configuration d'une passerelle via le pendant telle que décrit plus bas vers 192.168.3.4 via 192.168.0.13
 +
 +
 +------------------------------------------
 +2021/01/07 réglage de la date et de l'heure sur le controleur: Tableau de bord->Date&heure
 +
 +
 +Adresse mac du controleur: 00:c0:3a:60:04:01 je voudrais bien que le serveur de données capteur indique qui fait les demandes de données mais il ne voit pas l'adresse mac du client (qui est sur un autre réseau local à travers la passerelle, donc il faut plutot utiliser l'adresse IP du controleur: 192.168.0.112
 +
 +------------------------------------------
 +2021/01/14 Enfin affichage 3D avec SRS2019 sous virtual box:
 +
 +Il faut démarrer windows en mode sans Echec (F8) puis insérer disque des Additions Invitées; lancer l'installation et COCHER SUPPORT DIRECT 3D EXPERIMENTAL, puis redémarrer!
 +
 +------------------------------------------
 +export et découpage de modèle 3D du rx60:
 +
 +
 +https://bvdp.inetdoc.net/files/staubli/stl/rx60-ascii.zip
 +
 +</ifauth>
 +
 +
 +=====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 2D composé d'une caméra et d'un ordinateur sur carte raspberry Pi permettant la localisation du bouchon dans l'espace de travail du robot.
 + 
 +Pour le développement de cette tâche, vous procéderez d'abord à la configuration d'un projet et de la cellule robotique. Ensuite vous développerez votre programme en réalisant des simulations, et utiliserez à cette occasion des logiciels fournis pour simuler les capteurs, puis finalement vous pourrez tester sur le robot réel en fin de projets afin de procéder aux réglages fins permettant d'adapter les mouvements du robots à la configuration spatiale des éléments dans la cellule.
 +
 +Dans un premier temps, vous programmerez le robot sans utiliser les capteurs. Le capteur de couple sera intégré dans le cadre de ce projet dans un second temps et le capteur de vision sera intégré plus tard dans le cadre d'une séance dédiée.
 + 
 +Dans le cadre de ce projet, les communications entre le robot et l'infrastructure se feront via 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.
 +
 +
 +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. 
 +
 +
 +Vidéo de la simulation: https://youtu.be/o6v0avbkwQ4
 +<html>
 +<iframe width="560" height="315" src="https://www.youtube.com/embed/o6v0avbkwQ4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 +</html>
 +
 +
 +
 +====Planning prévisionnel====
 +<ifauth @prof>
 +planning 2020:
 +
 +^  durée ^ Tâches^
 +|  30min   |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.|  
 +|  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 sujet 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'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.|
 +
 +</ifauth>
 +
 +planning 2021:
 +
 +^  durée ^ Tâches^
 +|  3h   |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 continue 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|
 +|     |Petits projets personnalisés.|
 +
 +
 +====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: https://bvdp.inetdoc.net/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", saisir dans Chemin: "L:\Staubli\SRS"
 +  - S'assurer que l'armoire de commande est sous tension et démarrée depuis 2 minutes
 +  - Cliquer sur "Ajouter ... à 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.
 +<color red>TODO: automatiser le ménage (sauvegarde et effacement)</color>
 +</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:  https://bvdp.inetdoc.net/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" suivi d'un numéro qui vous sera attribué en début de séance et que vous conserverez durant toutes les séances. <color red>  Il est important que vous ayez chacun un nom de projet différent pour pouvoir identifier votre programme une fois chargé sur le contrôleur du robot!</color>
 +  - Cliquer sur 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 à:
 + 
 +
 +{{https://bvdp.inetdoc.net/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 être nécessaire de désactiver l'affichage du plancher car il fait buguer l'application. Pour cela, cliquer droit sur la vue 3D, "réglages affichage" et décocher "afficher plancher".
 +
 +Le programme propose par défaut un certain nombres de vues (de face, de coté, etc...). Il peut être intéressant d'ajouter des caméras fixes dans l'environnement pour observer les mouvements du robot depuis des points de vues particuliers. Pour cela, configurer la vue à l'aide de la souris puis dans l'arbre à gauche de la vue 3D, cliquer droit sur la vue 3D et sélectionner Caméras->ajouter une camera pour la vue courante. Il suffira de double cliquer sur la caméra créée dans l'arbre pour revenir sur cette vue.
 +
 +
 +Dans certains cas l'affichage de trièdres est trop petit pour être visible. Pour changer leur taille, aller dans l'onglet Simulation->réglage affichage->taille des trièdres (en pixel).
 +
 +Lorsqu'il est nécessaire de définir un repère à l'aide de clics de souris, l'ordre de clics des points définit l'orientation du 3° axe par la règle de la main droite (aussi appelée du tire-bouchon).
 + 
 +===Modification de la configuration du robot===
 +Pour modifier la configuration du robot, double cliquer sur Scène->Robot->Controller dans l'arbre, ce qui fait apparaître des disques permettant de contrôler chaque articulation. Cliquer gauche maintenu sur un des disque pour faire tourner l'articulation. Il est également possible de modifier la configuration du robot en cartésien en jouant sur le trièdre placé au niveau de la bride du robot. Cliquer droit sur le robot pour faire apparaître le menu et clic gauche sur "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:
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/SRS_articulaire.PNG}}
 +
 +
 +Le pilotage manuel en cartésien se fait à l'aide de la fenêtre:
 +
 +{{https://bvdp.inetdoc.net/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://bvdp.inetdoc.net/files/staubli/stl/
 +
 +
 +===Import du modèle de pince===
 +Récupérer le modèle STL de la pince Schunk (clic droit puis enregistrer la cible du lien sous L:): https://bvdp.inetdoc.net/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. <color red> 
 +Il est important de respecter scrupuleusement les étapes suivantes sinon l'outils ne sera pas correctement ajouté au robot! 
 +</color>
 +
 +
 +
 +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://bvdp.inetdoc.net/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 TCP (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://bvdp.inetdoc.net/files/staubli/images_wiki/SRS_handle.PNG}} {{https://bvdp.inetdoc.net/files/staubli/images_wiki/SRS_handler.PNG}} 
 +
 +
 +
 +Optionnel: importer le modèle de gripper adapté au bouchon depuis  https://bvdp.inetdoc.net/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://bvdp.inetdoc.net/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://bvdp.inetdoc.net/files/staubli/stl/support_bouteille_cristaline_lr.stl
 +  - la bouteille: https://bvdp.inetdoc.net/files/staubli/stl/bouteille_cristaline.stl
 +  - le bouchon: https://bvdp.inetdoc.net/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://bvdp.inetdoc.net/files/staubli/images_wiki/SRS_espace_travail.PNG}} 
 +===Configuration de l'outils===
 +
 +Dans le données, sélectionner la variable tTool de type tool, et double cliquer pour l'éditer.
 +Vérifiez que vous avez bien comme changement de repère {0,0,-117.25,0,0,0}, et que le gripper est bien régler à valve. Saisir 1 pour les 2 champs suivants qui permettent de régler les durées de délais en seconde(s) pour que la pince s'ouvre et se ferme après que la commande lui soit envoyée.
 +
 +
 +===Activation de la détection de collision===
 +
 +Pour activer la détection de 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 (booléen) commençant par b
 +  * variable frame (repère) commençant par f
 +  * variable jointRx (configuration en articulaire) commençant par j
 +  * variable pointRx (configuration en cartésien) commençant par p
 +  * variable mdesc (descripteur de mouvement) commençant par m
 +  * variable num (valeur numérique) commençant par n
 +  * variable string (chaine de caractères) commençant par s
 +  * variable tool (outils) commençant par t
 +  * variable trsf (transformation) commençant par tr
 +  * variable sio (ressource de communication) commençant par si
 +
 +Ceci permettra notamment d'ajouter automatiquement une variable à partir du code en faisant clic droit sur la variable puis "ajouter donnée". Le type de la variable est alors inféré d'après la convention de nommage.
 +
 +Pour info, même si nous n'utiliserons pas forcement 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>
 +<color red>TODO: expliquer delay, waitEndMove, open, close, la file d'ordre et le lissage de trajectoire</color>
 +
 +
 +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, abbrégé de Débugguer Stop) .
 +  - Onglet Val3, cliquer sur "Démarrer et Debugguer l'application"  (CTRL+R, abbrégé de Run Débugguer )
 +  - Fenêtre "Emulator Controller", cliquer sur "Move"
 +
 +<ifauth @prof>
 +<color red>TODO : expliquer espions sur variables locales et globales</color>
 +</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. Dans le cas contraire, c'est le programme qui pilote le robot.
 +
 +
 +
 +===Utilisation du mode automatique déporté===
 +
 +Il est également possible d'utiliser le mode automatique déporté (remote) pour simuler l'application. Dans ce mode, le bouton de mise en marche de la puissance du robot du pendant n'est pas utilisable. Pour débugger, dans le pendant virtuel, changer le mode en automatique déporté à l'aide du bouton blanc. Une tentative d'exécution de votre programme provoquera l'affichage d'une erreur "Demande de mise sous puissance du bras refusée: la baie est en mode déporté ou invalide". Pour débloquer cette situation, il suffit d'appeler la fonction VAL3 **enablePower()** au début de votre programme. Grâce à cela vous n'aurez plus à agir sur le bouton "Move/Hold" et mise sous puissance du pendant virtuel.
 +
 +
 +
 +====Configuration du robot pour permettre le vissage sur une plus grande plage angulaire du poignet====
 +Le poignet du robot est configuré par défaut avec des butées logicielles pour pouvoir tourner le poignet de -270° à +270°, afin de ne pas détériorer les flexibles pneumatiques permettant de piloter la pince. Dans notre manip, nous pourrons être amené à débrancher ces flexibles et utiliserons alors 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:
 +
 +{{https://bvdp.inetdoc.net/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 (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 fournit 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.
 +
 +
 +<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://bvdp.inetdoc.net/files/staubli/PyQt4-4.11.4-cp37-cp37m-win_amd64.whl sur le L:\, Puis saisir dans un terminal en faisant Touche Windows+R puis taper “cmd” et entrée, puis copier coller la ligne suivante:
 +  pip install L:\PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
 +  
 +   
 +Pour la salle Groix, la version de python installée est python3.4 dans c:\Python34\Scripts> . Pour installer le paquet QT nécessaire, faire: 
 +  c:\Python34\Scripts\pip install L:\PyQt4-4.11.4-cp37-cp37m-win_amd64.whl
 +  
 +<ifauth @prof>
 +
 +  c:\Python34\Scripts>echo %UserProfile%
 +  C:\Users\bvande 
 +   
 +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 2021
 +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 numeroPremiereDonneeCapteur
 +#TODO: donner une valeur à cette variable en fonction de votre numéro d'étudiant
 +numeroPremiereDonneeCapteur=156
 + 
 +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 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 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('stop stream sensor')
 +quitButton = QPushButton('&Quit')
 +led0Button = QPushButton('Activer la sortie TOR')
 + 
 +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)
 +
 +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(-amplitude/2)
 +slider1.setMaximum(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(-amplitude/2)
 +slider2.setMaximum(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='@BVDP2021: 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 à la racine du disque L:\
 +
 +
 +Editer ce fichier avec Notepad++ pour l'adapter selon les consignes données en séance en modifiant la variable **numeroPremiereDonneeCapteur** au début du programme.
 +
 +
 +Lancer ce programme en faisant Touche Windows+R puis taper "cmd" et entrée, puis copier coller la ligne suivante:
 +  C:\RoboDK\Python37\python.exe L:\simu_sensor_2_joystick.py
 +
 +Pour la salle Groix, la version de python installée est python3.4 dans c:\Python34\Scripts> . Pour lancer le programme, faire:
 +  c:\Python34\python.exe L:\simu_sensor_2_joystick.py
 +
 +
 +
 +====Le robot en tant que capteur====
 +Présentation au tableau de la gestion de l'émission de l'état du robot via socket UDP.
 + 
 +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:
 +
 +La variable socket est normalement déjà configurée, mais il est possible la configurer au début du programme à l'aide de: 
 +
 +
 +<file cpp configsocketUDP.pgx>
 +//configuration de la socket UDP
 +  clearBuffer(siSocketUDP)    
 +  if(sioCtrl(siSocketUDP, "target", "192.168.3.4")!=0)
 +    putln("probleme sioCtrl(siSocketUDP, target, 192.168.3.4)")
 +  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)
 +    putln("probleme sioCtrl(siSocketUDP, endOfString, 13)")
 +  endIf
 +  //port 10000 utilisé par socket UDP
 +  if(sioCtrl(siSocketUDP, "port", 10000)!=0)
 +    putln("probleme sioCtrl(siSocketUDP, port, 10000)")
 +  endIf
 +  //0 pour configurer les lectures sur socket bloquante,
 +  //une autre valeur en seconde sinon
 +  if(sioCtrl(siSocketUDP, "timeout",1)!=0 )
 +    putln("probleme sioCtrl(siSocketUDP, timeout,1)")
 +  endIf
 +</file>
 +
 +La programmation de la tache périodique doit être faite dans le programme start avec:
 +<file cpp ajouttacheperiodique.pgx>
 +//programmation de la tache périodique
 +  //emissionEtat est un programme créé, et éxecuté à une périodicité de 0.1s
 +  taskCreateSync "emissionEtat",.1,bOverRun,emissionEtat()
 +  putln("Tache periodique emission Etat lancee")
 +</file>
 +
 +Ajouter un programme dans le projet:  Cellule->Projet->clic droit->Ajouter->Nouveau programme. Saisir le nom "emissionEtat"
 +
 +puis saisir:
 +
 +<file cpp emissionEtat.pgx>
 +begin
 +  //il faut une boucle car taskCreateSync ne réappelle pas le programme, juste il lui donne la main périodiquement
 +  while true
 +    pHereEtat=here(tTool,world)
 +    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 
 +    sEtat="DC:4F:22:00:00:00 100"
 +    sEtat=sEtat+" "+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) 
 +    //shoulder n'est pas un numero, si je veux l'envoyer il faut faire une correpondante avec numéros
 +    siSocketUDP=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 
 +    sEtat="DC:4F:22:00:00:00 106"
 +    sEtat=sEtat+" "+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)
 +    siSocketUDP=sEtat
 + 
 +    //Il faut un delay de la periodicité de la tâche sinon les données s'accumulent dans la variable sEtat et le controleur plante
 +    delay(0.1)  
 +  endWhile
 +end
 +</file>
 +
 +Ajouter les variables nécessaires dans votre projet pour que ce nouveau programme puisse fonctionner.
 +
 +=====Mise en oeuvre sur le robot=====
 +
 +Le chargement du programme sur le robot se fait depuis soit le poste situé à coté du robot soit depuis votre poste.
 +
 +====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>
 +<color red>TODO: mettre les 2 photos de la façade</color>
 +
 +</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>
 +<color red>TODO:  expliquer les 3 positions de clef</color>
 +</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 pour les 2 ressources socket UDP et TCP mais est indiquée ici pour référence:
 +Sur le pendant:
 +  - Tableau de bord
 +  - ES ->
 +  - Socket ->
 +  - Socket UDP, bouton "Nouveau"
 +  - donner un nom: "siSocketUDP" puis cliquer sur "Ok"
 +  - Editer, bouton "entrée" pour choisir les paramètres à modifier
 +  - filtre IP: 192.168.3.4
 +  - port: 10000 
 +  -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)
 +
 +Les ressources de communication sockets ajoutées sur le contrôleur sont importées dans le projet SRS créé à partir du contrôleur. Il faudra néanmoins créer la variable de type sio correspondante et l'associer via la fenêtre "IO physiques".
 +
 +====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:
 + {{https://bvdp.inetdoc.net/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 affecter dans les variables correspondantes du programme (c'est l'approche préférer par l'enseignant car les informations apparaissent dans le code) avec des instructions telles que:
 +
 +<file cpp conf>
 +   //configuration des points en articulaire par programme
 +  //position bras levé
 +  jBrasHaut={0, 0, 0, 0, 0, 0}
 +  //position bras vers le bas
 +  jBrasBas=
 +  
 +  //exemple d'affichage
 +  put("jBrasBas: ")
 +  put(jBrasBas.j1)
 +  put(", ")
 +  put(jBrasBas.j2)
 +  put(", ")
 +  put(jBrasBas.j3)
 +  put(", ")
 +  put(jBrasBas.j4)
 +  put(", ")
 +  put(jBrasBas.j5)
 +  put(", ")
 +  put(jBrasBas.j6)
 +  putln("       ")
 +  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=
 +  
 +</file>
 +
 +<ifauth @prof>
 +Solution 
 +
 +<file cpp confsolution>
 +   //configuration des points en articulaire par programme
 +  //position bras levé
 +  jBrasHaut={0, 0, 0, 0, 0, 0}
 +  //position bras vers le bas
 +  //jBrasBas={0, -50, -90, 0, -40, 0}
 +  //position bras vers le bas vers la fenêtre
 +  jBrasBas={-50,-50,-60,0,-70,0}
 + 
 +  //exemple d'affichage
 +  put("jBrasBas: ")
 +  put(jBrasBas.j1)
 +  put(", ")
 +  put(jBrasBas.j2)
 +  put(", ")
 +  put(jBrasBas.j3)
 +  put(", ")
 +  put(jBrasBas.j4)
 +  put(", ")
 +  put(jBrasBas.j5)
 +  put(", ")
 +  put(jBrasBas.j6)
 +  putln("       ")
 +  delay(3)  
 + 
 + //définition des position des points en cartésien
 +  pSaisieBouchon.trsf.x=-137.74
 +  pSaisieBouchon.trsf.y=510.87
 +  pSaisieBouchon.trsf.z=-303.78
 +  pSaisieBouchon.trsf.rx=-0.02
 +  pSaisieBouchon.trsf.ry=179.95
 +  pSaisieBouchon.trsf.rz=66.93
 +  pSaisieBouchon.config.shoulder=
 +  pSaisieBouchon.config.wrist=
 +  pSaisieBouchon.config.elbow=
 +  
 +  pVissageBouchon.trsf.x=72.04
 +  pVissageBouchon.trsf.y=477.2
 +  pVissageBouchon.trsf.z=-110.92
 +  pVissageBouchon.trsf.rx=-0.02
 +  pVissageBouchon.trsf.ry=179.94
 +  pVissageBouchon.trsf.rz=66.93
 +  pVissageBouchon.config.shoulder=
 +  pVissageBouchon.config.wrist=
 +  pVissageBouchon.config.elbow=
 +  
 +</file>
 +</ifauth>
 +
 +=====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 chaîne par les champs que vous aurez réglé dans votre programme Python.
 +
 +<file cpp test.val3>
 +begin
 +  cls()
 +  userPage()
 +  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
 +    sMsg = siSocketTCP  
 +    //affiche sur l'ecran la chaine recue
 +    putln(sMsg)
 +    //il reste a recuperer les donnees depuis la chaine
 +  endWhile
 +end
 +</file>
 +
 +Créer les variables **siSocketTCP** (attention à bien choisir le type sio, car le type automatiquement choisi risque d'être string) et **sMsg ** (de type string).
 +
 +Il faut ensuite associer la variable **siSocketTCP** à 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**.
 +
 +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 au début du programme à l'aide de: 
 +<file cpp config_socket.val3>
 +    clearBuffer(siSocketTCP)    
 +    if(sioCtrl(siSocketTCP, "target", "192.168.3.4")!=0)
 +      putln("probleme sioCtrl(siSocketTCP, 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(siSocketTCP, "endOfString", 13)!=0)
 +      putln("probleme sioCtrl(siSocketTCP, endOfString, 13)")
 +    endIf
 +    //port 30000 utilisé par socket TCP
 +    if(sioCtrl(siSocketTCP, "port", 30000)!=0)
 +      putln("probleme sioCtrl(siSocketTCP, port, 30000)")
 +    endIf
 +    //0 pour configurer les lectures sur socket bloquante,
 +    //une autre valeur en seconde sinon
 +    if(sioCtrl(siSocketTCP, "timeout",1)!=0 )
 +      putln("probleme sioCtrl(siSocketTCP, 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
 +
 +
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/configuration_passerelle.jpg}}
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/configuration_socket_pendant.jpg}}
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/configuration_socket_srs.jpg}}
 +
 +
 +=====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()          
 +
 +
 +
 +=====Étapes de développement=====
 +
 +Dans les étapes suivantes, vous veillerez à afficher avec **putln()** ce que fait le robot avant chaque commande **move?()** pour pouvoir visualiser sur le pendant ce que va faire le robot. Nous pourrions utiliser le mode debug pas à pas sur le pendant mais ce n'est pas pratique. De plus ces commandes d'affichage permettent de documenter le code.
 +
 +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.
 + 
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  Configurer le projet SRS et insérer les éléments 3D dans l'environnement du robot.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}   Programmer le mouvement pour faire  sortir le bras de la configuration singulière (2 positions du robot en articulaire: jBrasLeve et jBrasBaisse).
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} 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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 +<ifauth @prof>
 +nPasVissage=9 (mm/tour)
 +nDebAngulaire=120 (degrés)
 +</ifauth>
 +
 +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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} 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.
 +
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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)
 +
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}   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é.
 +
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 + 
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}}  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.
 +
 +{{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Utilisez ce que vous avez appris dans la formation PHL pour faire en sorte que la simulation permette d'animer le bouchon.
 +
 +
 +Désactiver les commandes de la pince (idéalement avec une variable booléenne bDesactivePince) car le nouveau préhenseur ne permet pas l'ouverture et la fermeture.
 +
 +
 +------------------------------------
 +
 +Bravo, vous êtes arrivé au bout de votre quête, Chevalier.... Maintenant il faut attendre la période suivante pour intégrer le capteur de vision au système afin de localiser automatiquement le bouchon.
 +------------------------------------
 +
 +
 +=====Annexes=====
 +
 +====Informations réseau====
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/reseauAIPManip.png}}
 +===IP et numéros de port===
 +  - IP pc rapid hébergeant le serveur de données capteurs en filaire: 192.168.3.4
 +  - 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 si connecté sur le réseau AIP: 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
 +  - IP du capteur de couple réel: 192.168.3.252 
 +  - IP du capteur joystick: 192.168.3.253 
 +
 +
 +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
 +  
 +Filtre Wireshark pour analyser le trafic UDP sur le réseau des capteurs:
 +  ip.addr==192.168.3.0/24 && udp
 +  
 +Indices de données capteurs utilisés:
 +  - capteur de couple: indice 0  
 +  - capteur joystick: indice 0 aussi et .... TODO compléter et expliquer
 +  
 +Petite subtilité pour le trafic:
 +  - Les capteurs esp8266 communiquent vers l'ip du wifi du pc serveur de capteurs.
 +  - Les capteurs simulés en python par les étudiant communiquent via l'ip ethernet du pc serveur de capteurs.
 +
 +   
 +  
 +====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)
 +    
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/SRS-ES.PNG}}
 +
 +
 +{{https://bvdp.inetdoc.net/files/staubli/images_wiki/SRS-ES2.PNG}}
 +
 +
 +{{https://bvdp.inetdoc.net/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 rand.gpx>
 +<?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="rand">
 +    <Parameters xmlns="http://www.staubli.com/robotics/VAL3/Param/1">
 +      <Parameter name="x_nNum" type="num" xsi:type="element" />
 +    </Parameters>
 +    <Code><![CDATA[begin
 +  //générateur de nombres aléatoires B.Vandeportaele 2019
 +  
 +  //on peut avoir des paramètres en sortie pour un programme, 
 +  //il faut  les déclarer en 'par référence'
 +  
 +  //est ce que le paramètre d'entrée vaut -1, auquel cas 
 +  //on initialise la graine avec l'heure courante
 +  //la graine doit être stockée dans une variable GLOBALE, 
 +  //car les variables locales ne conservent pas leurs valeurs 
 +  //d'un appel à l'autre (non statique)
 +  
 +  if x_nNum==-1    
 +    //transforme l'heure en nombre
 +    toNum(getDate("%H"), nH,bRapport)
 +    toNum(getDate("%M"), nM,bRapport)
 +    toNum(getDate("%S"), nS,bRapport)
 +    seed=nH*10000+nM*100+nS
 +    //put("initial seed from rand(): ")
 +    //put(seed)
 +    //putln("         ")
 +  else
 +    //put("previous seed from rand(): ")
 +    //put(seed)
 +    //putln("         ")
 +    
 +    //génère un nombre aléatoire suivant
 +    seed=round(12345.6789* seed+ 4657613.18732)% 148632
 +    //put("current seed from rand(): ")
 +    //put(seed)
 +    //putln("         ")
 +  endIf
 +  
 +    
 +end]]></Code>
 +  </Program>
 +</Programs>
 +</file>
 +
 +------------------------------------------
 +<file cpp start.gpx>
 +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", 10000)!=0)
 +    putln("probleme A")
 +  endIf
 +  
 +  if(sioCtrl(cUdpsock, "target", "192.168.3.4")!=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.gpx>
 +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.gpx>
 +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.1562746660.txt.gz · Dernière modification: 2019/07/10 10:17 de bvandepo