Il est absolument nécessaire d’observer les quelques règles de sécurité suivantes afin d'éviter tout incidents pendant les phases de manipulation.
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:
Les différents logiciels utilisés pour simuler et programmer le robot sont:
La plupart des informations requises pour programmer un robot KUKA sont disponibles dans le manuel suivant: Manuel de service intégrateur Il servira de référence pour l'ensemble des travaux pratiques à réaliser.
Le langage de programmation des robots KUKA est le KRL (KUKA ROBOT LANGUAGE). Plusieurs niveaux de programmation sont possibles pour programmer les robots KUKA en fonction du groupe utilisateur:
Pour les instructions souvent utilisées, telles que des déplacements simples, on dispose de formulaires en ligne dans le KSS. Ceci facilite la programmation.
Le mode utilisateur Expert donne accès à l’entièreté de la syntaxe KRL.
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éplacements 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 capteurs (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 face du cube en donnant les ordre de déplacements au robot permettant de présenter les différentes faces à la caméra. Une fois les 6 faces connues, l'application fait appel à un algorithme de résolution https://github.com/Wiston999/python-rubik. Finalement, les consignes de résolutions sont envoyées au robots au fur et à mesure de leurs exécutions.
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:
Où le code est une valeur entière transmise au robot Un dernier code transmit comme un mouvement permet d'informer le robot que la manipulation est finie
A l'initialisation, le cube doit être placé avec le centre de chaque face dans la configuration suivante:
Modalisation de la pince: Doc_modelisation Kuka_Gripper.vcmx
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
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é&: https://bvdp.inetdoc.net/files/iut/kuka/
#!/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() '''
&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
modèle WRL:
https://bvdp.inetdoc.net/files/iut/staubli/stl/rubikscube3d/
j'ai une erreur avec srs lors du chargement du wrl, même si je vire la texture…
du coup je modélise un cube avec les lettres en 3D: https://bvdp.inetdoc.net/files/iut/staubli/stl/rubikscube3d/rubiks1.scad et https://bvdp.inetdoc.net/files/iut/staubli/stl/rubikscube3d/rubiks1.stl