Outils pour utilisateurs

Outils du site


Action disabled: diff
kuka

Ceci est une ancienne révision du document !


Présentation du matériel

Système robotique

Le robot KR 6 R700 sixx est un bras manipulateur industriel. Il dispose de 6 degrés de libertés, et, dans sa configuration à l’AIP, est équipé d’une pince pneumatique en guise d’organe terminal. Le système robotique complet se compose de quatre éléments:

  • Le bras manipulateur KR6 R700
  • L’armoire de commande
  • Le Kuka control panel ou Smartpad
  • La cage de protection

Logiciels

Les différents logiciels utilisés pour simuler et programmer le robot sont:

  • KUKA.SimPro (Simulation du robot, programmation simplifiée)
  • KUKA.OfficeLite (Programmation complete du robot en simulation)
  • KUKA.VisualWork (Edition des programmes et configurations du robot, transfert avec le robot)

La plus part des information requises pour programmer un robot KUKA sont disponible dans le manuel suivant: Manuel de service intégrateur Il servira de référence pour l'ensemble des travaux pratiques à réaliser.

Le language de programmation des robots KUKA est le KRL (KUKA ROBOT LANGUAGE). Plusieurs niveaux de programmation sont possible pour programmer les robots KUKA suivant le groupe utilisateur:

Programmation pour le groupe d'utilisateur "Utilisateur" (formulaires en ligne)

Pour les instructions souvent utilisées, tel que des déplacements simples, on dispose de formulaires en ligne dans le KSS. Ceci facilite la programmation.

Programmation pour le groupe d'utilisateur "Expert" (syntaxe KRL)

Le mode utilisateur Expert donne accès à l’entièreté de la syntaxe KRL.

Présentation de l'application à réaliser

On se propose au cours de ce TP de résoudre un Rubik's cube à l'aide du bras KUKA. Le robot est équipé d'une pince pneumatique permettant de saisir le cube. De plus un support fixe sera placé dans l'espace de travail pour que le robot puisse faire tourner les deux premières rangés de cubies (facette d'un Rubik's cube).

Par un ensemble de manipulation à définir, le robot sera capable de faire tourner le cube et le replacer dans dans le socle dans toutes les orientations.

Ainsi, par déplacement successifs le robot disposera des mouvements de base pour entamer la résolution du Rubik's cube.

Un système de vision permet d'observer la face supérieure du cube et met à disposition les couleurs des 9 cases sur un serveur de capteur (Serveur TCP).

Un programme python se charge de donner les ordres de déplacement au robot KUKA sur demande.

Dans un premier temps, ce programme récupère les configurations de chaque faces du cube en donnant les ordre de déplacement permettant de presenter les différentes faces. Une fois les 6 faces connues, l'application puis fait appel à un algorithme de résolution https://github.com/Wiston999/python-rubik. Finalement, les consignes de résolutions sont envoyés au robots au fur et à mesure de leurs executions.

Notations

Pour résoudre un Rubik's cube, un ensemble de notation standards ont été définies. C'est sous cette forme que les algorithmes de résolution donnent les séquence de mouvement à réaliser. Elles expriment les mouvement en considérant l'orientation du robot dans le monde (faces UP, DOWN, LEFT, RIGHT, FRONT et BACK).

Avec notre système robotique, nous sommes obligés de tourner le cube pour présenter la face à faire tourner vers le bas. Aussi dans l'ensemble des programmes, on appellera les faces non pas par leurs orientations géométriques, mais par leurs couleurs centrale. (Red, Yellow, Orange, Blue, While, Green). Les ordres de résolutions sont alors, une couleur de face, et un sens de rotation horaire (CW - ClockWise) ou anti horaire (CCW - ConterClockWise). L'application de résolutions traduit la rotation d'une face (Rouge par exemple) par des rotations de l'ensemble du cube, pour placer la face rouge dans le socle, puis une rotation des deux rangés supérieures.

Mouvements de base: La résolution du Rubik's cube est traduite en mouvements de base qui sont:

  • code 0 - FCW : Tourner l'ensemble du cube dans le sens horaire en regardant la face FRONT (avant)
  • code 1 - FCCW : Tourner l'ensemble du cube dans le sens anti-horaire en regardant la face FRONT (avant)
  • code 2 - UCW : Tourner l'ensemble du cube dans le sens horaire en regardant la face UP (du haut)
  • code 3 - UCCW : Tourner l'ensemble du cube dans le sens anti-horaire en regardant la face UP (du haut)
  • code 4 - MCW : En bloquant la face DOWN (du bas), tourner les deux rangés du haut dans le sens horaire
  • code 5 - MCCW : En bloquant la face DOWN (du bas), tourner les deux rangés du haut dans le sens anti-horaire

Annexes

KUKA.Si Pro 3.04

Activation de l'option "connectivity"

File→Option, Add On, cliquer sur Enable à droite de Connectivity (le bouton devient disable)

d'après https://www.robot-forum.com/robotforum/thread/26079-kuka-tcp-udp-communication/ , il faut l'option Ethernet/KRL dont la doc est: http://www.wtech.com.tw/public/download/manual/kuka/krc4/KST-Ethernet-KRL-21-En.pdf

Export vers KRL

Kuka sim pro 3.0.4 (programmation via interface graphique), export vers KRL langage du pendant

Pour exporter en KRL, EXPORT→Generate Code

exemple de projet exporté&: http://homepages.laas.fr/bvandepo/files/kuka/

Programme pour extraire les faces d'un rubiks cube

tcv3.py
#!/usr/bin/python3
 
#B. Vandeportaele 31/12/2019
 
import cv2 as cv
import numpy as np
 
#https://docs.opencv.org/master/db/d5b/tutorial_py_mouse_handling.html
 
#pour afficher la liste des évenements possibles
#events = [i for i in dir(cv) if 'EVENT' in i]
#print( events )
 
 
#homography:
# https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html?highlight=findhomography
# cv2.findHomography(srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask]]]) → retval, mask
#You can use only inliers (i.e. points with corresponding mask value equals to 1) when doing your match.
 
'''
#https://stackoverflow.com/questions/50945385/python-opencv-findhomography-inputs
if len(good) > MIN_MATCH_COUNT:
    src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
'''
 
#enregistrement et lecture fichiers
#https://docs.scipy.org/doc/numpy/reference/generated/numpy.savetxt.html
#https://docs.scipy.org/doc/numpy/reference/generated/numpy.genfromtxt.html
 
if False:
    savePoints = np.float32((46, 82, 201, 30, 340, 85, 182, 144)).reshape(4,2)
    np.savetxt('test.out', savePoints, delimiter=',', fmt='%10.4f')
 
    filedata = np.genfromtxt('test.out', delimiter=',').astype('int32')
    print(filedata)
 
    exit()
 
 
 
if False:
    #test pour estimer une homographie unité:
    srcPoints=np.float32( (1,2,1,4,5,9,7,8)).reshape(-1, 1, 2)
    dstPoints=srcPoints
    (retval, mask)= cv.findHomography(srcPoints, dstPoints)
    print("srcPoints")
    print(srcPoints)
    print("retval")
    print(retval)
    print("mask")
    print(mask)
 
#rubikscube
# pour l'apprentissage, donner les 4 coins de la face supérieure + 6 points pour apprendre les 6 couleurs de faces
#éventuellement traiter les images en live pour pouvoir tourner le cube pendant l'apprentissage des couleurs
 
image = cv.imread("rubiks.jpg", cv.IMREAD_UNCHANGED)
if image is None:  # ne pas utiliser ==
    print("image non trouvee");
 
listeColors=["Blue","Red","White","Green","Orange","Yellow"]
#listePositions=[(88,80),(188,125),(137,101),(198,44),(298,82),(192,84)]
#apprentissage des couleurs sur la face top (pour le rouge)
listePositions=[[88,80],[188,125],[137,101],[198,44],[298,82],[192,84]]  #coordonée U puis V données par geeqie
#apprentissage des couleurs sur la face front (pour le rouge)
#listePositions=[[88,80],[210,243],[137,101],[198,44],[298,82],[192,84]]  #coordonée U puis V données par geeqie
 
 
listeRGB=[]
print(listeColors)
i=0
for color in listeColors:
    print(color)
    listeRGB.append(  image[ listePositions[i][1],listePositions[i][0] ]) #coordonée V puis U
    i=i+1
print(listeRGB)
#exit()
 
#coordonnées obtenues avec geeqie,Affichage,infos sur le pixel
#points dans le sens horaires
for numface in range(0, 3):  #trois faces pour débug
#for numface in range(0, 1):  #une seule face pour débug
    if numface==0:
        #https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html
        #srcPoints = np.float32((46,82,201,30,340,85,182,144)).reshape(-1, 1, 2)
        srcPoints = np.float32((46, 82, 201, 30, 340, 85, 182, 144)).reshape(4,2)
    elif numface==1:
        #srcPoints = np.float32((40,90,190,154,180,352,49,279)).reshape(-1, 1, 2)
        srcPoints = np.float32((40, 90, 190, 154, 180, 352, 49, 279)).reshape(4, 2)
    elif numface==2:
        #srcPoints = np.float32((186,152,347,92, 346,282,190,351)).reshape(-1, 1, 2)
        srcPoints = np.float32((186, 152, 347, 92, 346, 282, 190, 351)).reshape(4, 2)
 
    sizedest=30
    dstPoints = np.float32((0,0,sizedest-1,0,sizedest-1,sizedest-1,0,sizedest-1)).reshape(-1, 1, 2)
 
    (H, mask) = cv.findHomography(srcPoints, dstPoints)
    print("srcPoints")
    print(srcPoints)
    print("retval")
    print(H)
    print("mask")
    print(mask)
 
 
    #fonction warpPespective:
    #https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html?highlight=warpperspective#void%20warpPerspective(InputArray%20src,%20OutputArray%20dst,%20InputArray%20M,%20Size%20dsize,%20int%20flags,%20int%20borderMode,%20const%20Scalar&%20borderValue
 
    dst=cv.warpPerspective(image, H, (sizedest,sizedest))
 
    cv.imwrite('rubiksrect'+str(numface)+'.png', dst)
 
    #recherche pour chaque pixel la couleur la plus proche
 
    for u in range(0,sizedest):
        for v in range(0, sizedest):
            val=dst[v,u]
            listfdiff=[]
            for c in range(0,6): #pour chaque couleur à tester
                diff=0
                for comp in range(0,3): #pour chacune des composantes de la couleur
                    #print(listeRGB[c][comp])
                    #print(val[comp])
                    #print((listeRGB[c][comp]) - (val[comp]))
                    # RuntimeWarning: overflow                     encountered in ubyte_scalars
                    #print(abs( listeRGB[c][comp]-val[comp]) )
                    diff = diff+abs( int(listeRGB[c][comp])-int(val[comp]))  #cast en int
                    #print("diff:" +str(diff))
                listfdiff.append(diff)
                #print("listeRGB[c]" + str(listeRGB[c])+ str(val)+" diff= "+str(diff))
            l=listfdiff.index(min(listfdiff)) #indice du plus petit élément de la liste de différence
            #print(u,v,val,listfdiff,l)
            #if listfdiff[l]<150:
            dst[v,u]=listeRGB[l]
            #else:
            #    dst[v, u] = [0,0,0]
    cv.imwrite('rubiksrect'+str(numface)+'_label.png', dst)
 
 
    #https: // docs.opencv.org / trunk / df / d9d / tutorial_py_colorspaces.html
    if False:
        # Convert BGR to HSV
        hsv = cv.cvtColor(dst, cv.COLOR_BGR2HSV)
        cv.imwrite('rubiksrect_hsv'+str(numface)+'.png', hsv)
        #en HSV pour calculer distance entre couleur il faut tenir compte du fait qu'il y a modulo 2Pi sur la teinte (codé modulo 180)
 
'''
#######################################################
# mouse callback function
def draw_circle(event,x,y,flags,param):
    if event == cv.EVENT_LBUTTONDBLCLK:
        cv.circle(img,(x,y),100,(255,0,0),-1)
#######################################################
def nothing(x):
    pass
#######################################################
if False:
    # Create a black image, a window and bind the function to window
    img = np.zeros((512,512,3), np.uint8)
    cv.namedWindow('image')
    cv.setMouseCallback('image',draw_circle)
 
    while(1):
        cv.imshow('image',img)
        if cv.waitKey(20) & 0xFF == 32 : # barre espace pour sortir ?  27: #escape?
            break
    cv.destroyAllWindows()
 
else:
    drawing = False # true if mouse is pressed
    mode = True # if True, draw rectangle. Press 'm' to toggle to curve
    ix,iy = -1,-1
    # mouse callback function
    def draw_circle2(event,x,y,flags,param):
        global ix,iy,drawing,mode
        # get current positions of four trackbars
        r = cv.getTrackbarPos('R', 'image')
        g = cv.getTrackbarPos('G', 'image')
        b = cv.getTrackbarPos('B', 'image')
        #s = cv.getTrackbarPos(switch, 'image')
 
        if event == cv.EVENT_LBUTTONDOWN:
            drawing = True
            ix,iy = x,y
        elif event == cv.EVENT_MOUSEMOVE:
            if drawing == True:
                if mode == True:
                    #cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
                    cv.rectangle(img, (ix, iy), (x, y), (r,g,b), -1)
                else:
                    cv.circle(img,(x,y),5,(0,0,255),-1)
        elif event == cv.EVENT_LBUTTONUP:
            drawing = False
            if mode == True:
                #cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
                cv.rectangle(img, (ix, iy), (x, y), (r, g, b), -1)
            else:
                cv.circle(img,(x,y),5,(0,0,255),-1)
            cv.line(img, (ix,iy), (x, y), (255, 255, 0), 5)
 
 
    img = np.zeros((512,512,3), np.uint8)
    cv.namedWindow('image')
    # create trackbars for color change
    cv.createTrackbar('R', 'image', 0, 255, nothing)
    cv.createTrackbar('G', 'image', 0, 255, nothing)
    cv.createTrackbar('B', 'image', 0, 255, nothing)
 
    cv.setTrackbarPos('R', 'image',255)
 
    cv.setMouseCallback('image',draw_circle2)
    while(1):
        cv.imshow('image',img)
        k = cv.waitKey(1) & 0xFF
        if k == ord('m'):
            mode = not mode
        elif k == ord('s'):
            cv.imwrite('dessin.png', img)
        elif k == 27:   #escape?
            break
 
    cv.destroyAllWindows()
 
'''

Fichier image de rubiks cube

homepages.laas.fr_bvandepo_files_kuka_rubiks.jpg

Programme KRL

TestTpCube.src
&ACCESS RVP
&REL 14
&PARAM EDITMASK = *
&PARAM TEMPLATE = C:\KRC\Roboter\Template\vorgabe
DEF TestTpCube( )
;FOLD Declaration
DECL INT cmdN
DECL BOOL FLAG_END
;ENDFOLD (Declaration)
;FOLD INI;%{PE}
  ;FOLD BASISTECH INI
    GLOBAL INTERRUPT DECL 3 WHEN $STOPMESS==TRUE DO IR_STOPM ( )
    INTERRUPT ON 3 
    BAS (#INITMOV,0 )
  ;ENDFOLD (BASISTECH INI)
  ;FOLD USER INI
    ;Make your modifications here
 
  ;ENDFOLD (USER INI)
;ENDFOLD (INI)
 
;FOLD PTP HOME  Vel= 100 % DEFAULT;%{PE}%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:HOME, 3:, 5:100, 7:DEFAULT
$BWDSTART = FALSE
PDAT_ACT=PDEFAULT
FDAT_ACT=FHOME
BAS (#PTP_PARAMS,100 )
$H_POS=XHOME
PTP  XHOME
;ENDFOLD
 
 
;FOLD initialisation et ouverture du canal 
;Initialize and Open channel 
   RET=EKI_Init("configcomcube")
   RET=EKI_Open("configcomcube")
   WAIT FOR $FLAG[1]
   FLAG_END = FALSE
   WHILE(NOT FLAG_END)
      ;Envoi des données
         OFFSET=0
         FOR i=(1) TO (100)
            Cmd[i]=0
         ENDFOR
         SWRITE(Cmd[],STATE,OFFSET,"%s","getmove")
         RET=EKI_Send("configcomcube",Cmd[])
         wait sec 1.5
 
      ;récupération des données
       ;RET = EKI_CheckBuffer("configcomcube","Buffer")
       ;wait sec 1
       ;IF RET.Buff <> 0 THEN
          WAIT FOR $Out[60]
          RET=EKI_GetString("configcomcube","Buffer",Cmd[])
          $Out[60]=FALSE
          wait sec 1
       ;ENDIF
      ;************************************************************
       OFFSET=0
       SREAD(Cmd[],STATE,OFFSET,"%d",cmdN)
       if cmdN == 20 THEN
 
         ;msg = {modul[] "Info", nr 123, msg_txt[]  "Caractere 20 recu"}
         ;opt = {vl_stop true, clear_p_reset true, clear_p_SAW false,log_to_DB true}
         ;nHandle = Set_KrlMsg (#notify, msg,par[], opt)
         ;wait sec 1
       endif   
 
       if cmdN == 0 THEN
 
         ;msg = {modul[] "Info", nr 123, msg_txt[]  "Caractere 0 recu"}
         ;opt = {vl_stop true, clear_p_reset true, clear_p_SAW false,log_to_DB true}
         ;nHandle = Set_KrlMsg (#notify, msg,par[], opt)
         ;Fin de programme
         FLAG_END = TRUE
       ENDIF
   ENDWHILE
 
 
 
;FOLD PTP HOME  Vel= 100 % DEFAULT;%{PE}%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:HOME, 3:, 5:100, 7:DEFAULT
$BWDSTART = FALSE
PDAT_ACT=PDEFAULT
FDAT_ACT=FHOME
BAS (#PTP_PARAMS,100 )
$H_POS=XHOME
PTP  XHOME
;ENDFOLD
 
END
kuka.1579461958.txt.gz · Dernière modification : 2020/01/19 20:25 de tflayols