├── LICENSE ├── README.md ├── example.py └── kukapython.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jonathan Malott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KUKA Python 2 | 3 | ![This is an image](https://jonathanmalott.com/wp-content/uploads/2021/12/david-675x450.png) 4 | 5 | ## Introduction 6 | 7 | Kuka Python is a library that allows for the creation of KUKA KR4 control files using simple, friendly python. 8 | 9 | ## Basic KUKApython program 10 | ```python 11 | from pyKUKA import pyKUKA 12 | 13 | myRobot = pyKUKA("ExampleProgramName") 14 | 15 | 16 | #Coordinates of the end of the tool relative to the end of the robot arm 17 | myRobot.setToolCoordinates(145,0,86,0,90,0) 18 | 19 | #Coordinates relative to robot in milimeters of the origin of the program. 20 | myRobot.setBaseCoordinates(-100,1600,828,-90,0,0) 21 | 22 | #Set the speed, expressed as a percentage of the max speed. 23 | myRobot.setVelocity(0.3) 24 | 25 | #Before we can do anything, we MUST give the robot an initial state for each axis. Skipping this will throw an error on the robot. 26 | myRobot.PTP(90,-75,100,169,-60,-150,0,180) 27 | 28 | 29 | #Finally, we give it a series of LIN commands to trace out a square in space. The parameters are X,Y,Z A,B,C E1,E2 30 | myRobot.LIN( 0, 0, 400, 0, 0, 180, 0, 180) 31 | myRobot.LIN( 0, 300, 400, 0, 0, 180, 0, 180) 32 | myRobot.LIN(300, 300, 400, 0, 0, 180, 0, 180) 33 | myRobot.LIN(300, 0, 400, 0, 0, 180, 0, 180) 34 | myRobot.LIN( 0, 0, 400, 90, 0, 180, 0, 180) 35 | 36 | 37 | #Show an graph of the robot joints over time to detect if there are singularities or 38 | myRobot.showAnalysis() 39 | 40 | myRobot.saveFile("example.src") 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | from pyKUKA import pyKUKA 2 | 3 | myRobot = pyKUKA("ExampleProgramName") 4 | 5 | #Coordinates of the end of the tool relative to the end of the robot arm 6 | myRobot.setToolCoordinates(145,0,86,0,90,0) 7 | 8 | #Coordinates relative to robot in milimeters of the origin of the program. 9 | myRobot.setBaseCoordinates(-100,1600,828,-90,0,0) 10 | 11 | 12 | myRobot.saveFile("example.src") 13 | -------------------------------------------------------------------------------- /kukapython.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Create KUKA src files easily in python that run on KUKA KR4 robots. 6 | AUTHOR: Jonathan Malott (JonathanMalott.com) 7 | University of Texas at Austin School of Architecture 8 | v0.3.2 Edited November 15 2021 9 | """ 10 | class kukapython: 11 | 12 | def __init__(self,name): 13 | 14 | self.TOOL_IS_DEFINED = False 15 | self.BASE_IS_DEFINED = False 16 | 17 | #An Array that will contain all of the commands 18 | self.code = [] 19 | 20 | #add some initial setup stuff 21 | self.code.append("DEF "+str(name)+"()") 22 | self.code.append("GLOBAL INTERRUPT DECL 3 WHEN $STOPMESS==TRUE DO IR_STOPM ( )") 23 | 24 | 25 | """ 26 | INTERRUPT 27 | 28 | Description Executes one of the following actions: 29 | - Activates an interrupt. 30 | - Deactivates an interrupt. 31 | - Disables an interrupt. 32 | - Enables an interrupt. 33 | Up to 16 interrupts may be active at any one time 34 | 35 | """ 36 | #self.code.append("INTERRUPT ON 3") 37 | 38 | 39 | self.code.append("$APO.CDIS = 0.5000") 40 | self.code.append("BAS (#INITMOV,0)") 41 | self.code.append("BAS (#VEL_PTP,20)") 42 | self.code.append("BAS (#ACC_PTP,20)") 43 | self.code.append("") 44 | 45 | 46 | """ 47 | Advance run 48 | The advance run is the maximum number of motion blocks that the robot controller calculates and plans in advance during program execution. The actual 49 | number is dependent on the capacity of the computer. 50 | The advance run refers to the current position of the block pointer. It is set via 51 | the system variable $ADVANCE: 52 | - Default value: 3 53 | - Maximum value: 5 54 | The advance run is required, for example, in order to be able to calculate approximate positioning motions. If $ADVANCE = 0 is set, approximate positioning is not possible. 55 | Certain statements trigger an advance run stop. These include statements 56 | that influence the periphery, e.g. OUT statements 57 | """ 58 | self.code.append("$advance=3") 59 | 60 | 61 | 62 | #--------------------------------------------------------------------------- 63 | # The following methods are used to set the TOOL 64 | #--------------------------------------------------------------------------- 65 | def setToolNumber(self, toolNumber): 66 | if(self.TOOL_IS_DEFINED == False): 67 | self.code.append("$TOOL=TOOL_DATA["+str(toolNumber)+"]") 68 | self.TOOL_IS_DEFINED = True 69 | return 70 | raise Exception('You have already defined a tool. Either use setToolNumber or setToolCoordinates but not both.') 71 | 72 | 73 | def setToolCoordinates(self,x,y,z,a,b,c): 74 | #if(self.TOOL_IS_DEFINED == False): 75 | if(True): 76 | self.code.append("$TOOL={X "+str(x)+", Y "+str(y)+", Z "+str(z)+", A "+str(a)+", B "+str(b)+", C "+str(c)+"}") 77 | self.TOOL_IS_DEFINED = True 78 | return 79 | raise Exception('You have already defined a tool. Either use setToolNumber or setToolCoordinates but not both.') 80 | 81 | #--------------------------------------------------------------------------- 82 | # The following methods are used to set the BASE 83 | #--------------------------------------------------------------------------- 84 | 85 | def setBaseNumber(self, number): 86 | if(self.BASE_IS_DEFINED == False): 87 | self.code.append("$BASE=BASE_DATA["+str(number)+"]") 88 | self.BASE_IS_DEFINED = True 89 | return 90 | raise Exception('You have already defined a base. Either use setToolNumber or setToolCoordinates but not both.') 91 | 92 | 93 | 94 | def setBaseCoordinates(self,x,y,z,a,b,c): 95 | if(self.BASE_IS_DEFINED == False): 96 | self.code.append("$BASE={X "+str(x)+", Y "+str(y)+", Z "+str(z)+", A "+str(a)+", B "+str(b)+", C "+str(c)+"}") 97 | self.BASE_IS_DEFINED = True 98 | return 99 | raise Exception('You have already defined a base. Either use setToolNumber or setToolCoordinates but not both.') 100 | 101 | def setVelocity(self,velocity): 102 | self.code.append("$VEL.CP="+str(velocity)) 103 | 104 | def openFold(self,comment): 105 | self.code.append(";FOLD "+str(comment)) 106 | 107 | def closeFold(self): 108 | self.code.append(";ENDFOLD") 109 | 110 | #--------------------------------------------------------------------------- 111 | # The following methods deal with inputs and outputs 112 | #--------------------------------------------------------------------------- 113 | 114 | def setOutput(self, outputNumber, state): 115 | self.code.append("$OUT["+str(outputNumber)+"] = "+str(state)) 116 | 117 | 118 | def WAIT(self,waitTime): 119 | self.code.append("WAIT sec "+str(waitTime)) 120 | 121 | 122 | def PTP(self,a1,a2,a3,a4,a5,a6,e1,e2): 123 | self.code.append("PTP {A1 "+str(a1)+", A2 "+str(a2)+", A3 "+str(a3)+", A4 "+str(a4)+", A5 "+str(a5)+", A6 "+str(a6)+", E1 "+str(e1)+", E2 "+str(e2)+", E3 0, E4 0, E5 0, E6 0}") 124 | 125 | def LIN(self,x,y,z,a,b,c,e1,e2): 126 | self.code.append("LIN {X "+str(x)+", Y "+str(y)+", Z "+str(z)+", A "+str(a)+", B "+str(b)+", C "+str(c)+", E1 "+str(e1)+", E2 "+str(e2)+"} C_DIS") 127 | 128 | def CIRC(self,x1,y1,z1,a1,b1,c1,e11,e21,x2,y2,z2,a2,b2,c2,e12,e22): 129 | self.code.append("CIRC {X "+str(x1)+", Y "+str(y1)+", Z "+str(z1)+", A "+str(a1)+", B "+str(b1)+", C "+str(c1)+", E1 "+str(e11)+", E2 "+str(e21)+"},{X "+str(x2)+", Y "+str(y2)+", Z "+str(z2)+", A "+str(a2)+", B "+str(b2)+", C "+str(c2)+", E1 "+str(e12)+", E2 "+str(e22)+"} C_DIS") 130 | 131 | 132 | 133 | def LIN_REL(self,x=False,y=False,z=False,a=False,b=False,c=False,e1=False,e2=False): 134 | st = [] 135 | if(x): 136 | st.append("X "+str(x)) 137 | if(y): 138 | st.append("Y "+str(y)) 139 | if(z): 140 | st.append("Z "+str(z)) 141 | if(a): 142 | st.append("A "+str(a)) 143 | if(b): 144 | st.append("B "+str(b)) 145 | if(c): 146 | st.append("C "+str(c)) 147 | if(e1): 148 | st.append("E1 "+str(e1)) 149 | if(e2): 150 | st.append("E2 "+str(e2)) 151 | 152 | assert len(st) > 0 153 | 154 | app = "" 155 | 156 | for s in range(len(st)-1): 157 | app += st[s] + ", " 158 | app += st[-1] 159 | 160 | self.code.append("LIN_REL {"+app+"} C_DIS") 161 | 162 | def PTP_REL(self,a1=False,a2=False,a3=False,a4=False,a5=False,a6=False,e1=False,e2=False): 163 | st = [] 164 | if(a1): 165 | st.append("A1 "+str(a1)) 166 | if(a2): 167 | st.append("A2 "+str(a2)) 168 | if(a3): 169 | st.append("A3 "+str(a3)) 170 | if(a4): 171 | st.append("A4 "+str(a4)) 172 | if(a5): 173 | st.append("A5 "+str(a5)) 174 | if(a6): 175 | st.append("A6 "+str(a6)) 176 | if(e1): 177 | st.append("E1 "+str(e1)) 178 | if(e2): 179 | st.append("E2 "+str(e2)) 180 | 181 | assert len(st) > 0 182 | 183 | app = "" 184 | 185 | for s in range(len(st)-1): 186 | app += st[s] + ", " 187 | app += st[-1] 188 | 189 | self.code.append("PTP_REL {"+app+"} C_DIS") 190 | 191 | 192 | def COMMENT(self,text): 193 | self.code.append(";"+str(text)) 194 | 195 | def BREAK(self): 196 | self.code.append("") 197 | 198 | #--------------------------------------------------------------------------- 199 | # Export the code as a file 200 | #--------------------------------------------------------------------------- 201 | 202 | def saveFile(self, filename): 203 | 204 | if(self.TOOL_IS_DEFINED == False): 205 | Exception('You must define a tool') 206 | return 207 | if(self.BASE_IS_DEFINED == False): 208 | Exception('You must define a base') 209 | return 210 | 211 | 212 | #Since we are done adding lines to the program, we will END it 213 | self.code.append("END") 214 | 215 | #Write each line of the KUKA src program to the specified file 216 | fileOut = open(filename,"w") 217 | for line in range(len(self.code)-1): 218 | fileOut.write(self.code[line] + "\n") 219 | 220 | fileOut.write(self.code[-1]) 221 | 222 | --------------------------------------------------------------------------------