├── LICENSE.md
├── ReadMe.md
├── Screenshot (53).png
├── Screenshot (54).png
├── Screenshot (55).png
├── SerialCom.py
├── armControl.py
├── design.ui
├── down.png
├── invKin.py
├── kukadesign.gif
├── roboticArm.png
└── up.png
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Md. Zahidul Islam
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 |
2 |
3 | # InverseKinematics 6 DOF
4 | In robotics, inverse kinematics makes use of the kinematics equations to determine the joint parameters that provide a desired position for each of the robot's end-effectors. In this program, we will apply inverse kinematics on a 6 DOF robotic arm. (KUKA based design)
5 | We have the robotic arm's measurements i.e. link lengths, link configuration, rotation information. Given coordinates X, Y, Z and roll, pitch, yaw of the end effector, We have to determine every joint angle from q1, q2, q3 ,q4, q5, q6.
6 |
7 | ### The mathematical calculations of IK are taken from https://github.com/mithi/arm-ik/
8 |
9 | # Procedure
10 | In the terminal enter "python armControl.py". This will open up a GUI window where you give inputs and output angles are calculated.
11 | Inverse Kinematics is calculated in the file invKin.py. It is called by armControl.py. Arm control has a GUI that we use to control X Y Z roll pitch yaw. To see whether the output of the Inverse Kinematics is correct we use a live Matplotlib 3d graph. invKin.py has functions forwardKinematics() and getAngles() and some other helper functions. Given, the joint angles q1..q6 forwardKinematics() calculates the joint coordinates along with the end effector's coordinates. This helps us to draw the arm in matplotlib. Matplotlib window automatically pop up when you run armControl.py.
12 | # References
13 | some scholarly aritcles where the algorithms is explaind in detail.\
14 | http://scholar.google.com/scholar_url?url=https://forum.linuxcnc.org/media/kunena/attachments/1549/6-axis-serial-robot-2.pdf&hl=en&sa=X&scisig=AAGBfm0JxooSQg2Bp5iJwO5Te8mIan0TtA&nossl=1&oi=scholarr \
15 | \
16 | http://atmia.put.poznan.pl/Woluminy/Fil/ATMiA_34_3_5.pdf
17 | # Some instructions
18 | ```
19 | python armControl.py
20 | ```
21 | A GUI having control of X,Y,Z,roll,pitch,yaw will be initiated. A matplotlib window will be initiated. Play with GUI buttons to see inverse kinematics in action.
22 | .png)
23 | .png)
24 | .png)
25 |
26 | # Author
27 | Md. Zahidul Islam,
28 | Lecturer, CSE, IUT,
29 | Islamic University of Technology.
30 | https://github.com/Zedd1558
31 |
--------------------------------------------------------------------------------
/Screenshot (53).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/Screenshot (53).png
--------------------------------------------------------------------------------
/Screenshot (54).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/Screenshot (54).png
--------------------------------------------------------------------------------
/Screenshot (55).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/Screenshot (55).png
--------------------------------------------------------------------------------
/SerialCom.py:
--------------------------------------------------------------------------------
1 | import serial
2 |
3 |
4 | class SerialCom:
5 | #arduinoOut = serial.Serial('COM7',115200,timeout =.2)
6 |
7 | def getConn(self,comm,baudRate):
8 | self.arduinoOut = serial.Serial(comm,baudRate)
9 | return self.arduinoOut
10 |
11 | def sendString(self,data):
12 | data += "\n"
13 | self.arduinoOut.write(data.encode())
14 |
15 | def sendAngles(self,data):
16 | data = "{},{},{},{}\n".format(data[0],data[1],data[2],data[3])
17 | self.sendString(data)
18 |
19 | def receiveString(self):
20 | data = self.arduinoOut.readline()
21 | #print(data)
22 | return data
23 |
24 | def receiveAngles(self):
25 | data = self.receiveString()
26 | data = data.strip(" ")
27 | angles = []
28 | for angle in data:
29 | angles.append(int(angle))
30 | return angles
31 |
32 | def closeConn(self):
33 | self.arduinoOut.close()
34 |
35 |
36 | def main():
37 | SerialObj = SerialCom()
38 | arduinoOut = SerialObj.getConn('COM9',9600)
39 | while True:
40 | string_ = input('>')
41 | SerialObj.sendString(string_)
42 |
43 |
44 |
45 |
46 |
47 | if __name__=="__main__":
48 | main()
--------------------------------------------------------------------------------
/armControl.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'design.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.11.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 | import sys
11 | import SerialCom
12 | from invKin import *
13 |
14 | class Ui_ArmControl(object):
15 | def setupUi(self, ArmControl):
16 | ArmControl.setObjectName("ArmControl")
17 | ArmControl.setWindowModality(QtCore.Qt.NonModal)
18 | ArmControl.resize(482, 537)
19 | ArmControl.setMaximumSize(QtCore.QSize(16777215, 16777215))
20 | icon = QtGui.QIcon()
21 | icon.addPixmap(QtGui.QPixmap("../roboticArm.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
22 | ArmControl.setWindowIcon(icon)
23 | ArmControl.setWindowOpacity(1.0)
24 | ArmControl.setAutoFillBackground(False)
25 | self.xUp = QtWidgets.QPushButton(ArmControl)
26 | self.xUp.setGeometry(QtCore.QRect(360, 130, 41, 41))
27 | font = QtGui.QFont()
28 | font.setFamily("Roboto Slab")
29 | font.setPointSize(16)
30 | self.xUp.setFont(font)
31 | self.xUp.setStyleSheet("color : rgb(255, 255, 255);\n"
32 | "")
33 | self.xUp.setText("")
34 | icon1 = QtGui.QIcon()
35 | icon1.addPixmap(QtGui.QPixmap("up.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
36 | self.xUp.setIcon(icon1)
37 | self.xUp.setIconSize(QtCore.QSize(32, 32))
38 | self.xUp.setFlat(True)
39 | self.xUp.setObjectName("xUp")
40 | self.xVal = QtWidgets.QLabel(ArmControl)
41 | self.xVal.setGeometry(QtCore.QRect(260, 130, 81, 41))
42 | font = QtGui.QFont()
43 | font.setFamily("Roboto Slab")
44 | font.setPointSize(14)
45 | self.xVal.setFont(font)
46 | self.xVal.setFrameShape(QtWidgets.QFrame.Box)
47 | self.xVal.setFrameShadow(QtWidgets.QFrame.Raised)
48 | self.xVal.setLineWidth(1)
49 | self.xVal.setMidLineWidth(0)
50 | self.xVal.setAlignment(QtCore.Qt.AlignCenter)
51 | self.xVal.setWordWrap(False)
52 | self.xVal.setObjectName("xVal")
53 | self.yVal = QtWidgets.QLabel(ArmControl)
54 | self.yVal.setGeometry(QtCore.QRect(260, 190, 81, 41))
55 | font = QtGui.QFont()
56 | font.setFamily("Roboto Slab")
57 | font.setPointSize(14)
58 | self.yVal.setFont(font)
59 | self.yVal.setFrameShape(QtWidgets.QFrame.Box)
60 | self.yVal.setFrameShadow(QtWidgets.QFrame.Raised)
61 | self.yVal.setLineWidth(1)
62 | self.yVal.setMidLineWidth(0)
63 | self.yVal.setAlignment(QtCore.Qt.AlignCenter)
64 | self.yVal.setWordWrap(False)
65 | self.yVal.setObjectName("yVal")
66 | self.rollVal = QtWidgets.QLabel(ArmControl)
67 | self.rollVal.setGeometry(QtCore.QRect(260, 310, 81, 41))
68 | font = QtGui.QFont()
69 | font.setFamily("Roboto Slab")
70 | font.setPointSize(14)
71 | self.rollVal.setFont(font)
72 | self.rollVal.setFrameShape(QtWidgets.QFrame.Box)
73 | self.rollVal.setFrameShadow(QtWidgets.QFrame.Raised)
74 | self.rollVal.setLineWidth(1)
75 | self.rollVal.setMidLineWidth(0)
76 | self.rollVal.setAlignment(QtCore.Qt.AlignCenter)
77 | self.rollVal.setWordWrap(False)
78 | self.rollVal.setObjectName("rollVal")
79 | self.zVal = QtWidgets.QLabel(ArmControl)
80 | self.zVal.setGeometry(QtCore.QRect(260, 250, 81, 41))
81 | font = QtGui.QFont()
82 | font.setFamily("Roboto Slab")
83 | font.setPointSize(14)
84 | self.zVal.setFont(font)
85 | self.zVal.setFrameShape(QtWidgets.QFrame.Box)
86 | self.zVal.setFrameShadow(QtWidgets.QFrame.Raised)
87 | self.zVal.setLineWidth(1)
88 | self.zVal.setMidLineWidth(0)
89 | self.zVal.setAlignment(QtCore.Qt.AlignCenter)
90 | self.zVal.setWordWrap(False)
91 | self.zVal.setObjectName("zVal")
92 | self.xLabel = QtWidgets.QLabel(ArmControl)
93 | self.xLabel.setGeometry(QtCore.QRect(80, 130, 81, 41))
94 | font = QtGui.QFont()
95 | font.setFamily("Roboto Slab")
96 | font.setPointSize(12)
97 | self.xLabel.setFont(font)
98 | self.xLabel.setAutoFillBackground(False)
99 | self.xLabel.setStyleSheet("background-color: rgb(237, 255, 248)")
100 | self.xLabel.setFrameShape(QtWidgets.QFrame.Panel)
101 | self.xLabel.setFrameShadow(QtWidgets.QFrame.Raised)
102 | self.xLabel.setLineWidth(1)
103 | self.xLabel.setMidLineWidth(0)
104 | self.xLabel.setAlignment(QtCore.Qt.AlignCenter)
105 | self.xLabel.setWordWrap(False)
106 | self.xLabel.setObjectName("xLabel")
107 | self.yUp = QtWidgets.QPushButton(ArmControl)
108 | self.yUp.setGeometry(QtCore.QRect(360, 190, 41, 41))
109 | font = QtGui.QFont()
110 | font.setFamily("Roboto Slab")
111 | font.setPointSize(16)
112 | self.yUp.setFont(font)
113 | self.yUp.setStyleSheet("color : rgb(255, 255, 255);\n"
114 | "")
115 | self.yUp.setText("")
116 | self.yUp.setIcon(icon1)
117 | self.yUp.setIconSize(QtCore.QSize(32, 32))
118 | self.yUp.setFlat(True)
119 | self.yUp.setObjectName("yUp")
120 | self.rollup = QtWidgets.QPushButton(ArmControl)
121 | self.rollup.setGeometry(QtCore.QRect(360, 310, 41, 41))
122 | font = QtGui.QFont()
123 | font.setFamily("Roboto Slab")
124 | font.setPointSize(16)
125 | self.rollup.setFont(font)
126 | self.rollup.setStyleSheet("color : rgb(255, 255, 255);\n"
127 | "")
128 | self.rollup.setText("")
129 | self.rollup.setIcon(icon1)
130 | self.rollup.setIconSize(QtCore.QSize(32, 32))
131 | self.rollup.setFlat(True)
132 | self.rollup.setObjectName("rollup")
133 | self.zUp = QtWidgets.QPushButton(ArmControl)
134 | self.zUp.setGeometry(QtCore.QRect(360, 250, 41, 41))
135 | font = QtGui.QFont()
136 | font.setFamily("Roboto Slab")
137 | font.setPointSize(16)
138 | self.zUp.setFont(font)
139 | self.zUp.setStyleSheet("color : rgb(255, 255, 255);\n"
140 | "")
141 | self.zUp.setText("")
142 | self.zUp.setIcon(icon1)
143 | self.zUp.setIconSize(QtCore.QSize(32, 32))
144 | self.zUp.setFlat(True)
145 | self.zUp.setObjectName("zUp")
146 | self.xDown = QtWidgets.QPushButton(ArmControl)
147 | self.xDown.setGeometry(QtCore.QRect(200, 130, 41, 41))
148 | font = QtGui.QFont()
149 | font.setFamily("Roboto Slab")
150 | font.setPointSize(16)
151 | self.xDown.setFont(font)
152 | self.xDown.setStyleSheet("color : rgb(255, 255, 255);\n"
153 | "")
154 | self.xDown.setText("")
155 | icon2 = QtGui.QIcon()
156 | icon2.addPixmap(QtGui.QPixmap("down.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
157 | self.xDown.setIcon(icon2)
158 | self.xDown.setIconSize(QtCore.QSize(32, 32))
159 | self.xDown.setFlat(True)
160 | self.xDown.setObjectName("xDown")
161 | self.yDown = QtWidgets.QPushButton(ArmControl)
162 | self.yDown.setGeometry(QtCore.QRect(200, 190, 41, 41))
163 | font = QtGui.QFont()
164 | font.setFamily("Roboto Slab")
165 | font.setPointSize(16)
166 | self.yDown.setFont(font)
167 | self.yDown.setStyleSheet("color : rgb(255, 255, 255);\n"
168 | "")
169 | self.yDown.setText("")
170 | self.yDown.setIcon(icon2)
171 | self.yDown.setIconSize(QtCore.QSize(32, 32))
172 | self.yDown.setFlat(True)
173 | self.yDown.setObjectName("yDown")
174 | self.zDown = QtWidgets.QPushButton(ArmControl)
175 | self.zDown.setGeometry(QtCore.QRect(200, 250, 41, 41))
176 | font = QtGui.QFont()
177 | font.setFamily("Roboto Slab")
178 | font.setPointSize(16)
179 | self.zDown.setFont(font)
180 | self.zDown.setStyleSheet("color : rgb(255, 255, 255);\n"
181 | "")
182 | self.zDown.setText("")
183 | self.zDown.setIcon(icon2)
184 | self.zDown.setIconSize(QtCore.QSize(32, 32))
185 | self.zDown.setFlat(True)
186 | self.zDown.setObjectName("zDown")
187 | self.rollDown = QtWidgets.QPushButton(ArmControl)
188 | self.rollDown.setGeometry(QtCore.QRect(200, 310, 41, 41))
189 | font = QtGui.QFont()
190 | font.setFamily("Roboto Slab")
191 | font.setPointSize(16)
192 | self.rollDown.setFont(font)
193 | self.rollDown.setStyleSheet("color : rgb(255, 255, 255);\n"
194 | "")
195 | self.rollDown.setText("")
196 | self.rollDown.setIcon(icon2)
197 | self.rollDown.setIconSize(QtCore.QSize(32, 32))
198 | self.rollDown.setFlat(True)
199 | self.rollDown.setObjectName("rollDown")
200 | self.yLabel = QtWidgets.QLabel(ArmControl)
201 | self.yLabel.setGeometry(QtCore.QRect(80, 190, 81, 41))
202 | font = QtGui.QFont()
203 | font.setFamily("Roboto Slab")
204 | font.setPointSize(12)
205 | self.yLabel.setFont(font)
206 | self.yLabel.setAutoFillBackground(False)
207 | self.yLabel.setStyleSheet("background-color: rgb(237, 255, 248)")
208 | self.yLabel.setFrameShape(QtWidgets.QFrame.Panel)
209 | self.yLabel.setFrameShadow(QtWidgets.QFrame.Raised)
210 | self.yLabel.setLineWidth(1)
211 | self.yLabel.setMidLineWidth(0)
212 | self.yLabel.setAlignment(QtCore.Qt.AlignCenter)
213 | self.yLabel.setWordWrap(False)
214 | self.yLabel.setObjectName("yLabel")
215 | self.zLabel = QtWidgets.QLabel(ArmControl)
216 | self.zLabel.setGeometry(QtCore.QRect(80, 250, 81, 41))
217 | font = QtGui.QFont()
218 | font.setFamily("Roboto Slab")
219 | font.setPointSize(12)
220 | self.zLabel.setFont(font)
221 | self.zLabel.setAutoFillBackground(False)
222 | self.zLabel.setStyleSheet("background-color: rgb(237, 255, 248)")
223 | self.zLabel.setFrameShape(QtWidgets.QFrame.Panel)
224 | self.zLabel.setFrameShadow(QtWidgets.QFrame.Raised)
225 | self.zLabel.setLineWidth(1)
226 | self.zLabel.setMidLineWidth(0)
227 | self.zLabel.setAlignment(QtCore.Qt.AlignCenter)
228 | self.zLabel.setWordWrap(False)
229 | self.zLabel.setObjectName("zLabel")
230 | self.rollLabel = QtWidgets.QLabel(ArmControl)
231 | self.rollLabel.setGeometry(QtCore.QRect(80, 310, 81, 41))
232 | font = QtGui.QFont()
233 | font.setFamily("Roboto Slab")
234 | font.setPointSize(12)
235 | self.rollLabel.setFont(font)
236 | self.rollLabel.setAutoFillBackground(False)
237 | self.rollLabel.setStyleSheet("background-color: rgb(237, 255, 248)")
238 | self.rollLabel.setFrameShape(QtWidgets.QFrame.Panel)
239 | self.rollLabel.setFrameShadow(QtWidgets.QFrame.Raised)
240 | self.rollLabel.setLineWidth(1)
241 | self.rollLabel.setMidLineWidth(0)
242 | self.rollLabel.setAlignment(QtCore.Qt.AlignCenter)
243 | self.rollLabel.setWordWrap(False)
244 | self.rollLabel.setObjectName("rollLabel")
245 | self.titleLabel = QtWidgets.QLabel(ArmControl)
246 | self.titleLabel.setGeometry(QtCore.QRect(30, 40, 161, 41))
247 | font = QtGui.QFont()
248 | font.setFamily("Roboto Slab")
249 | font.setPointSize(20)
250 | font.setBold(False)
251 | font.setWeight(50)
252 | self.titleLabel.setFont(font)
253 | self.titleLabel.setObjectName("titleLabel")
254 | self.sendButton = QtWidgets.QPushButton(ArmControl)
255 | self.sendButton.setGeometry(QtCore.QRect(350, 30, 41, 51))
256 | self.sendButton.setText("")
257 | self.sendButton.setIcon(icon)
258 | self.sendButton.setIconSize(QtCore.QSize(32, 32))
259 | self.sendButton.setFlat(True)
260 | self.sendButton.setObjectName("sendButton")
261 | self.closeButton = QtWidgets.QPushButton(ArmControl)
262 | self.closeButton.setGeometry(QtCore.QRect(400, 30, 51, 51))
263 | self.closeButton.setText("")
264 | icon3 = QtGui.QIcon()
265 | icon3.addPixmap(QtGui.QPixmap("../closeIcon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
266 | self.closeButton.setIcon(icon3)
267 | self.closeButton.setIconSize(QtCore.QSize(48, 48))
268 | self.closeButton.setFlat(True)
269 | self.closeButton.setObjectName("closeButton")
270 | self.pitchVal = QtWidgets.QLabel(ArmControl)
271 | self.pitchVal.setGeometry(QtCore.QRect(260, 370, 81, 41))
272 | font = QtGui.QFont()
273 | font.setFamily("Roboto Slab")
274 | font.setPointSize(14)
275 | self.pitchVal.setFont(font)
276 | self.pitchVal.setFrameShape(QtWidgets.QFrame.Box)
277 | self.pitchVal.setFrameShadow(QtWidgets.QFrame.Raised)
278 | self.pitchVal.setLineWidth(1)
279 | self.pitchVal.setMidLineWidth(0)
280 | self.pitchVal.setAlignment(QtCore.Qt.AlignCenter)
281 | self.pitchVal.setWordWrap(False)
282 | self.pitchVal.setObjectName("pitchVal")
283 | self.pitchDown = QtWidgets.QPushButton(ArmControl)
284 | self.pitchDown.setGeometry(QtCore.QRect(200, 370, 41, 41))
285 | font = QtGui.QFont()
286 | font.setFamily("Roboto Slab")
287 | font.setPointSize(16)
288 | self.pitchDown.setFont(font)
289 | self.pitchDown.setStyleSheet("color : rgb(255, 255, 255);\n"
290 | "")
291 | self.pitchDown.setText("")
292 | self.pitchDown.setIcon(icon2)
293 | self.pitchDown.setIconSize(QtCore.QSize(32, 32))
294 | self.pitchDown.setFlat(True)
295 | self.pitchDown.setObjectName("pitchDown")
296 | self.pitchLabel = QtWidgets.QLabel(ArmControl)
297 | self.pitchLabel.setGeometry(QtCore.QRect(80, 370, 81, 41))
298 | font = QtGui.QFont()
299 | font.setFamily("Roboto Slab")
300 | font.setPointSize(12)
301 | self.pitchLabel.setFont(font)
302 | self.pitchLabel.setAutoFillBackground(False)
303 | self.pitchLabel.setStyleSheet("background-color: rgb(237, 255, 248)")
304 | self.pitchLabel.setFrameShape(QtWidgets.QFrame.Panel)
305 | self.pitchLabel.setFrameShadow(QtWidgets.QFrame.Raised)
306 | self.pitchLabel.setLineWidth(1)
307 | self.pitchLabel.setMidLineWidth(0)
308 | self.pitchLabel.setAlignment(QtCore.Qt.AlignCenter)
309 | self.pitchLabel.setWordWrap(False)
310 | self.pitchLabel.setObjectName("pitchLabel")
311 | self.pitchUp = QtWidgets.QPushButton(ArmControl)
312 | self.pitchUp.setGeometry(QtCore.QRect(360, 370, 41, 41))
313 | font = QtGui.QFont()
314 | font.setFamily("Roboto Slab")
315 | font.setPointSize(16)
316 | self.pitchUp.setFont(font)
317 | self.pitchUp.setStyleSheet("color : rgb(255, 255, 255);\n"
318 | "")
319 | self.pitchUp.setText("")
320 | self.pitchUp.setIcon(icon1)
321 | self.pitchUp.setIconSize(QtCore.QSize(32, 32))
322 | self.pitchUp.setFlat(True)
323 | self.pitchUp.setObjectName("pitchUp")
324 | self.yawVal = QtWidgets.QLabel(ArmControl)
325 | self.yawVal.setGeometry(QtCore.QRect(260, 430, 81, 41))
326 | font = QtGui.QFont()
327 | font.setFamily("Roboto Slab")
328 | font.setPointSize(14)
329 | self.yawVal.setFont(font)
330 | self.yawVal.setFrameShape(QtWidgets.QFrame.Box)
331 | self.yawVal.setFrameShadow(QtWidgets.QFrame.Raised)
332 | self.yawVal.setLineWidth(1)
333 | self.yawVal.setMidLineWidth(0)
334 | self.yawVal.setAlignment(QtCore.Qt.AlignCenter)
335 | self.yawVal.setWordWrap(False)
336 | self.yawVal.setObjectName("yawVal")
337 | self.yawDown = QtWidgets.QPushButton(ArmControl)
338 | self.yawDown.setGeometry(QtCore.QRect(200, 430, 41, 41))
339 | font = QtGui.QFont()
340 | font.setFamily("Roboto Slab")
341 | font.setPointSize(16)
342 | self.yawDown.setFont(font)
343 | self.yawDown.setStyleSheet("color : rgb(255, 255, 255);\n"
344 | "")
345 | self.yawDown.setText("")
346 | self.yawDown.setIcon(icon2)
347 | self.yawDown.setIconSize(QtCore.QSize(32, 32))
348 | self.yawDown.setFlat(True)
349 | self.yawDown.setObjectName("yawDown")
350 | self.yawLabel = QtWidgets.QLabel(ArmControl)
351 | self.yawLabel.setGeometry(QtCore.QRect(80, 430, 81, 41))
352 | font = QtGui.QFont()
353 | font.setFamily("Roboto Slab")
354 | font.setPointSize(12)
355 | self.yawLabel.setFont(font)
356 | self.yawLabel.setAutoFillBackground(False)
357 | self.yawLabel.setStyleSheet("background-color: rgb(237, 255, 248)")
358 | self.yawLabel.setFrameShape(QtWidgets.QFrame.Panel)
359 | self.yawLabel.setFrameShadow(QtWidgets.QFrame.Raised)
360 | self.yawLabel.setLineWidth(1)
361 | self.yawLabel.setMidLineWidth(0)
362 | self.yawLabel.setAlignment(QtCore.Qt.AlignCenter)
363 | self.yawLabel.setWordWrap(False)
364 | self.yawLabel.setObjectName("yawLabel")
365 | self.yawUp = QtWidgets.QPushButton(ArmControl)
366 | self.yawUp.setGeometry(QtCore.QRect(360, 430, 41, 41))
367 | font = QtGui.QFont()
368 | font.setFamily("Roboto Slab")
369 | font.setPointSize(16)
370 | self.yawUp.setFont(font)
371 | self.yawUp.setStyleSheet("color : rgb(255, 255, 255);\n"
372 | "")
373 | self.yawUp.setText("")
374 | self.yawUp.setIcon(icon1)
375 | self.yawUp.setIconSize(QtCore.QSize(32, 32))
376 | self.yawUp.setFlat(True)
377 | self.yawUp.setObjectName("yawUp")
378 | self.subtitleLabel = QtWidgets.QLabel(ArmControl)
379 | self.subtitleLabel.setGeometry(QtCore.QRect(190, 10, 131, 21))
380 | font = QtGui.QFont()
381 | font.setFamily("Roboto Slab")
382 | font.setPointSize(10)
383 | font.setBold(False)
384 | font.setWeight(50)
385 | self.subtitleLabel.setFont(font)
386 | self.subtitleLabel.setObjectName("subtitleLabel")
387 |
388 | self.retranslateUi(ArmControl)
389 | QtCore.QMetaObject.connectSlotsByName(ArmControl)
390 |
391 | def retranslateUi(self, ArmControl):
392 | _translate = QtCore.QCoreApplication.translate
393 | ArmControl.setWindowTitle(_translate("ArmControl", "Arm Control"))
394 | self.xVal.setText(_translate("ArmControl", "0.4"))
395 | self.yVal.setText(_translate("ArmControl", "1.3"))
396 | self.rollVal.setText(_translate("ArmControl", "1"))
397 | self.zVal.setText(_translate("ArmControl", "3"))
398 | self.xLabel.setText(_translate("ArmControl", "x"))
399 | self.yLabel.setText(_translate("ArmControl", "y"))
400 | self.zLabel.setText(_translate("ArmControl", "z"))
401 | self.rollLabel.setText(_translate("ArmControl", "roll"))
402 | self.titleLabel.setText(_translate("ArmControl", "Arm Control"))
403 | self.pitchVal.setText(_translate("ArmControl", "-1"))
404 | self.pitchLabel.setText(_translate("ArmControl", "pitch"))
405 | self.yawVal.setText(_translate("ArmControl", "-1"))
406 | self.yawLabel.setText(_translate("ArmControl", "yaw"))
407 | self.subtitleLabel.setText(_translate("ArmControl", "Team Avijatrik"))
408 | self.closeButton.clicked.connect(ArmControl.close)
409 | self.sendButton.clicked.connect(self.send)
410 | self.xDown.clicked.connect(self.xDownMethod)
411 | self.xUp.clicked.connect(self.xUpMethod)
412 | self.yDown.clicked.connect(self.yDownMethod)
413 | self.yUp.clicked.connect(self.yUpMethod)
414 | self.zDown.clicked.connect(self.zDownMethod)
415 | self.zUp.clicked.connect(self.zUpMethod)
416 | self.rollDown.clicked.connect(self.rollDownMethod)
417 | self.rollup.clicked.connect(self.rollupMethod)
418 | self.pitchDown.clicked.connect(self.pitchDownMethod)
419 | self.pitchUp.clicked.connect(self.pitchUpMethod)
420 | self.yawDown.clicked.connect(self.yawDownMethod)
421 | self.yawUp.clicked.connect(self.yawUpMethod)
422 | self.window = ArmControl
423 |
424 | def send(self):
425 | data = []
426 | val = int(self.xVal.text())
427 | data.append(str(val))
428 | val = int(self.yVal.text())
429 | data.append(str(val))
430 | val = int(self.zVal.text())
431 | data.append(str(val))
432 | val = int(self.rollVal.text())
433 | data.append(str(val))
434 | val = int(self.pitchVal.text())
435 | data.append(str(val))
436 | val = int(self.yawVal.text())
437 | data.append(str(val))
438 | dataString = ','.join(data)
439 | #self.window.SerialObj.sendString(dataString)
440 | print(dataString)
441 |
442 |
443 | def plot_data(self):
444 |
445 | px = float(self.xVal.text())
446 | py = float(self.yVal.text())
447 | pz = float(self.zVal.text())
448 | roll = float(self.rollVal.text())
449 | pitch = float(self.pitchVal.text())
450 | yaw = float(self.yawVal.text())
451 | q1,q2,q3,q4,q5,q6 = get_angles(px,py,pz,roll,pitch,yaw)
452 | X,Y,Z = forward_kin(q1,q2,q3,q4,q5,q6)
453 | update_plot(X,Y,Z,self.window.fig,self.window.ax)
454 |
455 |
456 | def xUpMethod(self):
457 | val = float(self.xVal.text())
458 | if(val<2):
459 | val+=.1
460 | self.xVal.setText(str(round(val,2)))
461 | self.plot_data()
462 | def xDownMethod(self):
463 | val = float(self.xVal.text())
464 | if(val>0):
465 | val -= .1
466 | self.xVal.setText(str(round(val,2)))
467 | self.plot_data()
468 |
469 |
470 | def yUpMethod(self):
471 | val = float(self.yVal.text())
472 | if(val<3):
473 | val+=.1
474 | self.yVal.setText(str(round(val,2)))
475 | self.plot_data()
476 | def yDownMethod(self):
477 | val = float(self.yVal.text())
478 | if(val>0):
479 | val -= .1
480 | self.yVal.setText(str(round(val,2)))
481 | self.plot_data()
482 |
483 |
484 | def zUpMethod(self):
485 | val = float(self.zVal.text())
486 | if(val<5):
487 | val+=.1
488 | self.zVal.setText(str(round(val,2)))
489 | self.plot_data()
490 | def zDownMethod(self):
491 | val = float(self.zVal.text())
492 | if(val>0):
493 | val -= .1
494 | self.zVal.setText(str(round(val,2)))
495 | self.plot_data()
496 |
497 | def rollupMethod(self):
498 | val = float(self.rollVal.text())
499 | if(val<3.14):
500 | val+=.1
501 | self.rollVal.setText(str(round(val,2)))
502 | self.plot_data()
503 | def rollDownMethod(self):
504 | val = float(self.rollVal.text())
505 | if(val>-3.14):
506 | val -= .1
507 | self.rollVal.setText(str(round(val,2)))
508 | self.plot_data()
509 |
510 | def pitchUpMethod(self):
511 | val = float(self.pitchVal.text())
512 | if(val<3.14):
513 | val+=.1
514 | self.pitchVal.setText(str(round(val,2)))
515 | self.plot_data()
516 | def pitchDownMethod(self):
517 | val = float(self.pitchVal.text())
518 | if(val>-3.14):
519 | val -= .1
520 | self.pitchVal.setText(str(round(val,2)))
521 | self.plot_data()
522 | def yawUpMethod(self):
523 | val = float(self.yawVal.text())
524 | if(val<3.14):
525 | val+=.1
526 | self.yawVal.setText(str(round(val,2)))
527 | self.plot_data()
528 | def yawDownMethod(self):
529 | val = float(self.yawVal.text())
530 | if(val>-3.14):
531 | val -= .1
532 | self.yawVal.setText(str(round(val,2)))
533 | self.plot_data()
534 |
535 |
536 |
537 |
538 | class Main_window(QtWidgets.QMainWindow):
539 | def __init__(self):
540 | super().__init__()
541 | self.InitSerial()
542 | self.InitPlot()
543 |
544 | def InitPlot(self):
545 | self.fig,self.ax = create_plot()
546 |
547 |
548 |
549 | def InitSerial(self):
550 | #self.SerialObj = SerialCom.SerialCom()
551 | #self.arduinoOut = self.SerialObj.getConn('COM9',9600)
552 | pass
553 | def close(self):
554 | sys.exit()
555 |
556 |
557 |
558 |
559 | def main():
560 | app = QtWidgets.QApplication(sys.argv)
561 | MainWindow = Main_window()
562 | ui = Ui_ArmControl()
563 | ui.setupUi(MainWindow)
564 | MainWindow.show()
565 | plt.show()
566 | sys.exit(app.exec_())
567 |
568 |
569 |
570 | if __name__ == "__main__":
571 | main()
572 |
573 |
574 |
--------------------------------------------------------------------------------
/design.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ArmControl
4 |
5 |
6 | Qt::NonModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 482
13 | 537
14 |
15 |
16 |
17 |
18 | 16777215
19 | 16777215
20 |
21 |
22 |
23 | Arm Control
24 |
25 |
26 |
27 | ../roboticArm.png../roboticArm.png
28 |
29 |
30 | 1.000000000000000
31 |
32 |
33 | false
34 |
35 |
36 |
37 |
38 | 360
39 | 130
40 | 41
41 | 41
42 |
43 |
44 |
45 |
46 | Roboto Slab
47 | 16
48 |
49 |
50 |
51 | color : rgb(255, 255, 255);
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | up.pngup.png
60 |
61 |
62 |
63 | 32
64 | 32
65 |
66 |
67 |
68 | true
69 |
70 |
71 |
72 |
73 |
74 | 260
75 | 130
76 | 81
77 | 41
78 |
79 |
80 |
81 |
82 | Roboto Slab
83 | 14
84 |
85 |
86 |
87 | QFrame::Box
88 |
89 |
90 | QFrame::Raised
91 |
92 |
93 | 1
94 |
95 |
96 | 0
97 |
98 |
99 | 123
100 |
101 |
102 | Qt::AlignCenter
103 |
104 |
105 | false
106 |
107 |
108 | 4
109 |
110 |
111 |
112 |
113 |
114 | 260
115 | 190
116 | 81
117 | 41
118 |
119 |
120 |
121 |
122 | Roboto Slab
123 | 14
124 |
125 |
126 |
127 | QFrame::Box
128 |
129 |
130 | QFrame::Raised
131 |
132 |
133 | 1
134 |
135 |
136 | 0
137 |
138 |
139 | 123
140 |
141 |
142 | Qt::AlignCenter
143 |
144 |
145 | false
146 |
147 |
148 | 4
149 |
150 |
151 |
152 |
153 |
154 | 260
155 | 310
156 | 81
157 | 41
158 |
159 |
160 |
161 |
162 | Roboto Slab
163 | 14
164 |
165 |
166 |
167 | QFrame::Box
168 |
169 |
170 | QFrame::Raised
171 |
172 |
173 | 1
174 |
175 |
176 | 0
177 |
178 |
179 | 123
180 |
181 |
182 | Qt::AlignCenter
183 |
184 |
185 | false
186 |
187 |
188 | 4
189 |
190 |
191 |
192 |
193 |
194 | 260
195 | 250
196 | 81
197 | 41
198 |
199 |
200 |
201 |
202 | Roboto Slab
203 | 14
204 |
205 |
206 |
207 | QFrame::Box
208 |
209 |
210 | QFrame::Raised
211 |
212 |
213 | 1
214 |
215 |
216 | 0
217 |
218 |
219 | 123
220 |
221 |
222 | Qt::AlignCenter
223 |
224 |
225 | false
226 |
227 |
228 | 4
229 |
230 |
231 |
232 |
233 |
234 | 80
235 | 130
236 | 81
237 | 41
238 |
239 |
240 |
241 |
242 | Roboto Slab
243 | 12
244 |
245 |
246 |
247 | false
248 |
249 |
250 | background-color: rgb(237, 255, 248)
251 |
252 |
253 | QFrame::Panel
254 |
255 |
256 | QFrame::Raised
257 |
258 |
259 | 1
260 |
261 |
262 | 0
263 |
264 |
265 | x
266 |
267 |
268 | Qt::AlignCenter
269 |
270 |
271 | false
272 |
273 |
274 | 4
275 |
276 |
277 |
278 |
279 |
280 | 360
281 | 190
282 | 41
283 | 41
284 |
285 |
286 |
287 |
288 | Roboto Slab
289 | 16
290 |
291 |
292 |
293 | color : rgb(255, 255, 255);
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 | up.pngup.png
302 |
303 |
304 |
305 | 32
306 | 32
307 |
308 |
309 |
310 | true
311 |
312 |
313 |
314 |
315 |
316 | 360
317 | 310
318 | 41
319 | 41
320 |
321 |
322 |
323 |
324 | Roboto Slab
325 | 16
326 |
327 |
328 |
329 | color : rgb(255, 255, 255);
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 | up.pngup.png
338 |
339 |
340 |
341 | 32
342 | 32
343 |
344 |
345 |
346 | true
347 |
348 |
349 |
350 |
351 |
352 | 360
353 | 250
354 | 41
355 | 41
356 |
357 |
358 |
359 |
360 | Roboto Slab
361 | 16
362 |
363 |
364 |
365 | color : rgb(255, 255, 255);
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 | up.pngup.png
374 |
375 |
376 |
377 | 32
378 | 32
379 |
380 |
381 |
382 | true
383 |
384 |
385 |
386 |
387 |
388 | 200
389 | 130
390 | 41
391 | 41
392 |
393 |
394 |
395 |
396 | Roboto Slab
397 | 16
398 |
399 |
400 |
401 | color : rgb(255, 255, 255);
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 | down.pngdown.png
410 |
411 |
412 |
413 | 32
414 | 32
415 |
416 |
417 |
418 | true
419 |
420 |
421 |
422 |
423 |
424 | 200
425 | 190
426 | 41
427 | 41
428 |
429 |
430 |
431 |
432 | Roboto Slab
433 | 16
434 |
435 |
436 |
437 | color : rgb(255, 255, 255);
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 | down.pngdown.png
446 |
447 |
448 |
449 | 32
450 | 32
451 |
452 |
453 |
454 | true
455 |
456 |
457 |
458 |
459 |
460 | 200
461 | 250
462 | 41
463 | 41
464 |
465 |
466 |
467 |
468 | Roboto Slab
469 | 16
470 |
471 |
472 |
473 | color : rgb(255, 255, 255);
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 | down.pngdown.png
482 |
483 |
484 |
485 | 32
486 | 32
487 |
488 |
489 |
490 | true
491 |
492 |
493 |
494 |
495 |
496 | 200
497 | 310
498 | 41
499 | 41
500 |
501 |
502 |
503 |
504 | Roboto Slab
505 | 16
506 |
507 |
508 |
509 | color : rgb(255, 255, 255);
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 | down.pngdown.png
518 |
519 |
520 |
521 | 32
522 | 32
523 |
524 |
525 |
526 | true
527 |
528 |
529 |
530 |
531 |
532 | 80
533 | 190
534 | 81
535 | 41
536 |
537 |
538 |
539 |
540 | Roboto Slab
541 | 12
542 |
543 |
544 |
545 | false
546 |
547 |
548 | background-color: rgb(237, 255, 248)
549 |
550 |
551 | QFrame::Panel
552 |
553 |
554 | QFrame::Raised
555 |
556 |
557 | 1
558 |
559 |
560 | 0
561 |
562 |
563 | y
564 |
565 |
566 | Qt::AlignCenter
567 |
568 |
569 | false
570 |
571 |
572 | 4
573 |
574 |
575 |
576 |
577 |
578 | 80
579 | 250
580 | 81
581 | 41
582 |
583 |
584 |
585 |
586 | Roboto Slab
587 | 12
588 |
589 |
590 |
591 | false
592 |
593 |
594 | background-color: rgb(237, 255, 248)
595 |
596 |
597 | QFrame::Panel
598 |
599 |
600 | QFrame::Raised
601 |
602 |
603 | 1
604 |
605 |
606 | 0
607 |
608 |
609 | z
610 |
611 |
612 | Qt::AlignCenter
613 |
614 |
615 | false
616 |
617 |
618 | 4
619 |
620 |
621 |
622 |
623 |
624 | 80
625 | 310
626 | 81
627 | 41
628 |
629 |
630 |
631 |
632 | Roboto Slab
633 | 12
634 |
635 |
636 |
637 | false
638 |
639 |
640 | background-color: rgb(237, 255, 248)
641 |
642 |
643 | QFrame::Panel
644 |
645 |
646 | QFrame::Raised
647 |
648 |
649 | 1
650 |
651 |
652 | 0
653 |
654 |
655 | roll
656 |
657 |
658 | Qt::AlignCenter
659 |
660 |
661 | false
662 |
663 |
664 | 4
665 |
666 |
667 |
668 |
669 |
670 | 30
671 | 40
672 | 161
673 | 41
674 |
675 |
676 |
677 |
678 | Roboto Slab
679 | 20
680 | 50
681 | false
682 |
683 |
684 |
685 | Arm Control
686 |
687 |
688 |
689 |
690 |
691 | 350
692 | 30
693 | 41
694 | 51
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 | ../roboticArm.png../roboticArm.png
703 |
704 |
705 |
706 | 32
707 | 32
708 |
709 |
710 |
711 | true
712 |
713 |
714 |
715 |
716 |
717 | 400
718 | 30
719 | 51
720 | 51
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 | ../closeIcon.png../closeIcon.png
729 |
730 |
731 |
732 | 48
733 | 48
734 |
735 |
736 |
737 | true
738 |
739 |
740 |
741 |
742 |
743 | 260
744 | 370
745 | 81
746 | 41
747 |
748 |
749 |
750 |
751 | Roboto Slab
752 | 14
753 |
754 |
755 |
756 | QFrame::Box
757 |
758 |
759 | QFrame::Raised
760 |
761 |
762 | 1
763 |
764 |
765 | 0
766 |
767 |
768 | 123
769 |
770 |
771 | Qt::AlignCenter
772 |
773 |
774 | false
775 |
776 |
777 | 4
778 |
779 |
780 |
781 |
782 |
783 | 200
784 | 370
785 | 41
786 | 41
787 |
788 |
789 |
790 |
791 | Roboto Slab
792 | 16
793 |
794 |
795 |
796 | color : rgb(255, 255, 255);
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 | down.pngdown.png
805 |
806 |
807 |
808 | 32
809 | 32
810 |
811 |
812 |
813 | true
814 |
815 |
816 |
817 |
818 |
819 | 80
820 | 370
821 | 81
822 | 41
823 |
824 |
825 |
826 |
827 | Roboto Slab
828 | 12
829 |
830 |
831 |
832 | false
833 |
834 |
835 | background-color: rgb(237, 255, 248)
836 |
837 |
838 | QFrame::Panel
839 |
840 |
841 | QFrame::Raised
842 |
843 |
844 | 1
845 |
846 |
847 | 0
848 |
849 |
850 | pitch
851 |
852 |
853 | Qt::AlignCenter
854 |
855 |
856 | false
857 |
858 |
859 | 4
860 |
861 |
862 |
863 |
864 |
865 | 360
866 | 370
867 | 41
868 | 41
869 |
870 |
871 |
872 |
873 | Roboto Slab
874 | 16
875 |
876 |
877 |
878 | color : rgb(255, 255, 255);
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 | up.pngup.png
887 |
888 |
889 |
890 | 32
891 | 32
892 |
893 |
894 |
895 | true
896 |
897 |
898 |
899 |
900 |
901 | 260
902 | 430
903 | 81
904 | 41
905 |
906 |
907 |
908 |
909 | Roboto Slab
910 | 14
911 |
912 |
913 |
914 | QFrame::Box
915 |
916 |
917 | QFrame::Raised
918 |
919 |
920 | 1
921 |
922 |
923 | 0
924 |
925 |
926 | 123
927 |
928 |
929 | Qt::AlignCenter
930 |
931 |
932 | false
933 |
934 |
935 | 4
936 |
937 |
938 |
939 |
940 |
941 | 200
942 | 430
943 | 41
944 | 41
945 |
946 |
947 |
948 |
949 | Roboto Slab
950 | 16
951 |
952 |
953 |
954 | color : rgb(255, 255, 255);
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 | down.pngdown.png
963 |
964 |
965 |
966 | 32
967 | 32
968 |
969 |
970 |
971 | true
972 |
973 |
974 |
975 |
976 |
977 | 80
978 | 430
979 | 81
980 | 41
981 |
982 |
983 |
984 |
985 | Roboto Slab
986 | 12
987 |
988 |
989 |
990 | false
991 |
992 |
993 | background-color: rgb(237, 255, 248)
994 |
995 |
996 | QFrame::Panel
997 |
998 |
999 | QFrame::Raised
1000 |
1001 |
1002 | 1
1003 |
1004 |
1005 | 0
1006 |
1007 |
1008 | yaw
1009 |
1010 |
1011 | Qt::AlignCenter
1012 |
1013 |
1014 | false
1015 |
1016 |
1017 | 4
1018 |
1019 |
1020 |
1021 |
1022 |
1023 | 360
1024 | 430
1025 | 41
1026 | 41
1027 |
1028 |
1029 |
1030 |
1031 | Roboto Slab
1032 | 16
1033 |
1034 |
1035 |
1036 | color : rgb(255, 255, 255);
1037 |
1038 |
1039 |
1040 |
1041 |
1042 |
1043 |
1044 | up.pngup.png
1045 |
1046 |
1047 |
1048 | 32
1049 | 32
1050 |
1051 |
1052 |
1053 | true
1054 |
1055 |
1056 |
1057 |
1058 |
1059 | 190
1060 | 10
1061 | 131
1062 | 21
1063 |
1064 |
1065 |
1066 |
1067 | Roboto Slab
1068 | 10
1069 | 50
1070 | false
1071 |
1072 |
1073 |
1074 | Team Avijatrik
1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 |
--------------------------------------------------------------------------------
/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/down.png
--------------------------------------------------------------------------------
/invKin.py:
--------------------------------------------------------------------------------
1 | from sympy import symbols, cos, sin, pi, simplify, pprint, tan, expand_trig, sqrt, trigsimp, atan2
2 | from sympy.matrices import Matrix
3 |
4 | from mpl_toolkits.mplot3d import Axes3D
5 | import matplotlib.pyplot as plt
6 | import time
7 | import numpy as np
8 |
9 | def pose(theta, alpha, a, d):
10 | # returns the pose T of one joint frame i with respect to the previous joint frame (i - 1)
11 | # given the parameters:
12 | # theta: theta[i]
13 | # alpha: alpha[i-1]
14 | # a: a[i-1]
15 | # d: d[i]
16 |
17 | r11, r12 = cos(theta), -sin(theta)
18 | r23, r33 = -sin(alpha), cos(alpha)
19 | r21 = sin(theta) * cos(alpha)
20 | r22 = cos(theta) * cos(alpha)
21 | r31 = sin(theta) * sin(alpha)
22 | r32 = cos(theta) * sin(alpha)
23 | y = -d * sin(alpha)
24 | z = d * cos(alpha)
25 |
26 | T = Matrix([
27 | [r11, r12, 0.0, a],
28 | [r21, r22, r23, y],
29 | [r31, r32, r33, z],
30 | [0.0, 0.0, 0.0, 1]
31 | ])
32 |
33 | T = simplify(T)
34 |
35 | return T
36 |
37 | # under construction
38 | def forward_kin(q1,q2,q3,q4,q5,q6):
39 | X = []
40 | Y = []
41 | Z = []
42 | d90 = pi/2
43 | T01 = pose(q1, 0, 0, 0.75)
44 | T0g = T01
45 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
46 | X.append(px)
47 | Y.append(py)
48 | Z.append(pz)
49 | T12 = pose(q2 - d90, -d90, 0.35, 0)
50 | T0g = T0g* T12
51 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
52 | X.append(px)
53 | Y.append(py)
54 | Z.append(pz)
55 | T23 = pose(q3, 0, 1.25, 0)
56 | T0g = T0g* T23
57 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
58 | X.append(px)
59 | Y.append(py)
60 | Z.append(pz)
61 | T34 = pose(q4, -d90, -0.054, 1.5)
62 | T0g = T0g* T34
63 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
64 | X.append(px)
65 | Y.append(py)
66 | Z.append(pz)
67 | T45 = pose(q5, d90, 0, 0)
68 | T0g = T0g* T45
69 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
70 | X.append(px)
71 | Y.append(py)
72 | Z.append(pz)
73 | T56 = pose(q6, -d90, 0, 0)
74 | T0g = T0g* T56
75 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
76 | X.append(px)
77 | Y.append(py)
78 | Z.append(pz)
79 | T6g = pose(0, 0, 0, 0.303)
80 | #final position and rotation
81 | T0g = T0g* T6g
82 | px,py,pz = T0g[0,3], T0g[1,3], T0g[2,3]
83 | X.append(px)
84 | Y.append(py)
85 | Z.append(pz)
86 | #fig = plt.figure()
87 | #ax = fig.add_subplot(111,projection = '3d')
88 | #ax.set_xlabel('x axis')
89 | #ax.set_ylabel('y axis')
90 | #ax.set_zlabel('z axis')
91 |
92 | X = np.reshape(X,(1,7))
93 | Y = np.reshape(Y,(1,7))
94 | Z = np.reshape(Z,(1,7))
95 |
96 | return X,Y,Z
97 | #ax.cla()
98 | #ax.plot_wireframe(X,Y,Z)
99 | #plt.draw()
100 | #plt.pause(3)
101 | #ax.cla()
102 | #ax.plot_wireframe(Z,Y,X,color='r')
103 |
104 | #plt.show()
105 |
106 |
107 |
108 | def create_plot():
109 |
110 | fig = plt.figure()
111 | ax = fig.add_subplot(111,projection = '3d')
112 | ax.set_xlabel('x axis')
113 | ax.set_ylabel('y axis')
114 | ax.set_zlabel('z axis')
115 | ax.set_xlim3d([0, 2])
116 | ax.set_ylim3d([0, 3])
117 | ax.set_zlim3d([0, 3])
118 | ax.set_autoscale_on(False)
119 | return fig,ax
120 |
121 | def update_plot(X,Y,Z,fig,ax):
122 | X = np.reshape(X,(1,7))
123 | Y = np.reshape(Y,(1,7))
124 | Z = np.reshape(Z,(1,7))
125 | ax.cla()
126 | ax.plot_wireframe(X,Y,Z)
127 | #plt.draw()
128 | ax.set_xlabel('x axis')
129 | ax.set_ylabel('y axis')
130 | ax.set_zlabel('z axis')
131 | ax.set_xlim3d([0, 2])
132 | ax.set_ylim3d([0, 3])
133 | ax.set_zlim3d([0, 3])
134 | ax.set_autoscale_on(False)
135 | fig.canvas.draw()
136 | fig.canvas.flush_events()
137 | #plt.pause(3)
138 | #ax.cla()
139 | #ax.plot_wireframe(Z,Y,X,color='r')
140 |
141 |
142 | #------------ Rotation Matrix and Euler Angles -----------
143 | # Calculates Rotation Matrix given euler angles.
144 | def eulerAnglesToRotationMatrix(theta) :
145 |
146 | R_x = np.array([[1, 0, 0 ],
147 | [0, math.cos(theta[0]), -math.sin(theta[0]) ],
148 | [0, math.sin(theta[0]), math.cos(theta[0]) ]
149 | ])
150 |
151 |
152 |
153 | R_y = np.array([[math.cos(theta[1]), 0, math.sin(theta[1]) ],
154 | [0, 1, 0 ],
155 | [-math.sin(theta[1]), 0, math.cos(theta[1]) ]
156 | ])
157 |
158 | R_z = np.array([[math.cos(theta[2]), -math.sin(theta[2]), 0],
159 | [math.sin(theta[2]), math.cos(theta[2]), 0],
160 | [0, 0, 1]
161 | ])
162 |
163 |
164 | R = np.dot(R_z, np.dot( R_y, R_x ))
165 |
166 | return R
167 |
168 |
169 | # Checks if a matrix is a valid rotation matrix.
170 | def isRotationMatrix(R) :
171 | Rt = np.transpose(R)
172 | shouldBeIdentity = np.dot(Rt, R)
173 | I = np.identity(3, dtype = R.dtype)
174 | n = np.linalg.norm(I - shouldBeIdentity)
175 | return n < 1e-6
176 |
177 | # Calculates rotation matrix to euler angles
178 | # The result is the same as MATLAB except the order
179 | # of the euler angles ( x and z are swapped ).
180 | def rotationMatrixToEulerAngles(R) :
181 |
182 | assert(isRotationMatrix(R))
183 |
184 | sy = math.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0])
185 |
186 | singular = sy < 1e-6
187 |
188 | if not singular :
189 | x = math.atan2(R[2,1] , R[2,2])
190 | y = math.atan2(-R[2,0], sy)
191 | z = math.atan2(R[1,0], R[0,0])
192 | else :
193 | x = math.atan2(-R[1,2], R[1,1])
194 | y = math.atan2(-R[2,0], sy)
195 | z = 0
196 |
197 | return np.array([x, y, z])
198 | #---------------------------------------
199 |
200 |
201 | def get_hypotenuse(a, b):
202 | # calculate the longest side given the two shorter sides
203 | # of a right triangle using pythagorean theorem
204 | return sqrt(a*a + b*b)
205 |
206 |
207 | def get_cosine_law_angle(a, b, c):
208 | # given all sides of a triangle a, b, c
209 | # calculate angle gamma between sides a and b using cosine law
210 | cos_gamma = (a*a + b*b - c*c) / (2*a*b)
211 | sin_gamma = sqrt(1 - cos_gamma * cos_gamma)
212 | gamma = atan2(sin_gamma, cos_gamma)
213 |
214 | return gamma
215 |
216 |
217 | def get_wrist_center(gripper_point, R0g, dg = 0.303):
218 | # get the coordinates of the wrist center wrt to the base frame (xw, yw, zw)
219 | # given the following info:
220 | # the coordinates of the gripper (end effector) (x, y, z)
221 | # the rotation of the gripper in gripper frame wrt to the base frame (R0u)
222 | # the distance between gripper and wrist center dg which is along common z axis
223 | # check WRITEUP.pdf for more info
224 | xu, yu, zu = gripper_point
225 |
226 | nx, ny, nz = R0g[0, 2], R0g[1, 2], R0g[2, 2]
227 | xw = xu - dg * nx
228 | yw = yu - dg * ny
229 | zw = zu - dg * nz
230 |
231 | return xw, yw, zw
232 |
233 |
234 | def get_first_three_angles(wrist_center):
235 | # given the wrist center which a tuple of 3 numbers x, y, z
236 | # (x, y, z) is the wrist center point wrt base frame
237 | # return the angles q1, q2, q3 for each respective joint
238 | # given geometry of the kuka kr210
239 | # check WRITEUP.pdf for more info
240 | x, y, z = wrist_center
241 |
242 | a1, a2, a3 = 0.35, 1.25, -0.054
243 | d1, d4 = 0.75, 1.5
244 | l = 1.50097168527591 # get_hypotenuse(d4, abs(a3))
245 | phi = 1.53481186671284 # atan2(d4, abs(a3))
246 |
247 | x_prime = get_hypotenuse(x, y)
248 | mx = x_prime - a1
249 | my = z - d1
250 | m = get_hypotenuse(mx, my)
251 | alpha = atan2(my, mx)
252 |
253 | gamma = get_cosine_law_angle(l, a2, m)
254 | beta = get_cosine_law_angle(m, a2, l)
255 |
256 | q1 = atan2(y, x)
257 | q2 = pi/2 - beta - alpha
258 | q3 = -(gamma - phi)
259 |
260 | return q1, q2, q3
261 |
262 |
263 | def get_last_three_angles(R):
264 | #Recall that from our simplification, R36 (R) equals the following:
265 | #Matrix([
266 | #[-sin(q4)*sin(q6) + cos(q4)*cos(q5)*cos(q6), -sin(q4)*cos(q6) - sin(q6)*cos(q4)*cos(q5), -sin(q5)*cos(q4)],
267 | #[ sin(q5)*cos(q6), -sin(q5)*sin(q6), cos(q5)],
268 | #[-sin(q4)*cos(q5)*cos(q6) - sin(q6)*cos(q4), sin(q4)*sin(q6)*cos(q5) - cos(q4)*cos(q6), sin(q4)*sin(q5)]])
269 | #From trigonometry we can get q4, q5, q6 if we know numerical values of all cells of matrix R36 (R)
270 | #check WRITEUP.pdf for more info
271 | sin_q4 = R[2, 2]
272 | cos_q4 = -R[0, 2]
273 |
274 | sin_q5 = sqrt(R[0, 2]**2 + R[2, 2]**2)
275 | cos_q5 = R[1, 2]
276 |
277 | sin_q6 = -R[1, 1]
278 | cos_q6 = R[1, 0]
279 |
280 | q4 = atan2(sin_q4, cos_q4)
281 | q5 = atan2(sin_q5, cos_q5)
282 | q6 = atan2(sin_q6, cos_q6)
283 |
284 | return q4, q5, q6
285 |
286 |
287 | def get_angles(x, y, z, roll, pitch, yaw):
288 | # input: given position and orientation of the gripper_URDF wrt base frame
289 | # output: angles q1, q2, q3, q4, q5, q6
290 |
291 | gripper_point = x, y, z
292 |
293 | ################################################################################
294 | # All important symbolic transformations matrices are declared below
295 | ################################################################################
296 |
297 | q1, q2, q3, q4, q5, q6 = symbols('q1:7')
298 | alpha, beta, gamma = symbols('alpha beta gamma', real = True)
299 | px, py, pz = symbols('px py pz', real = True)
300 |
301 | # Rotation of joint 3 wrt to the base frame interms the first three angles q1, q2, q3
302 | R03 = Matrix([
303 | [sin(q2 + q3)*cos(q1), cos(q1)*cos(q2 + q3), -sin(q1)],
304 | [sin(q1)*sin(q2 + q3), sin(q1)*cos(q2 + q3), cos(q1)],
305 | [ cos(q2 + q3), -sin(q2 + q3), 0]])
306 |
307 | # Transpose of R03
308 | R03T = Matrix([
309 | [sin(q2 + q3)*cos(q1), sin(q1)*sin(q2 + q3), cos(q2 + q3)],
310 | [cos(q1)*cos(q2 + q3), sin(q1)*cos(q2 + q3), -sin(q2 + q3)],
311 | [ -sin(q1), cos(q1), 0]])
312 |
313 | # Rotation of joint 6 wrt to frame of joint 3 interms of the last three angles q4, q5, q6
314 | R36 = Matrix([
315 | [-sin(q4)*sin(q6) + cos(q4)*cos(q5)*cos(q6), -sin(q4)*cos(q6) - sin(q6)*cos(q4)*cos(q5), -sin(q5)*cos(q4)],
316 | [ sin(q5)*cos(q6), -sin(q5)*sin(q6), cos(q5)],
317 | [-sin(q4)*cos(q5)*cos(q6) - sin(q6)*cos(q4), sin(q4)*sin(q6)*cos(q5) - cos(q4)*cos(q6), sin(q4)*sin(q5)]])
318 |
319 | # Rotation of urdf_gripper with respect to the base frame interms of alpha = yaw, beta = pitch, gamma = roll
320 | R0u = Matrix([
321 | [1.0*cos(alpha)*cos(beta), -1.0*sin(alpha)*cos(gamma) + sin(beta)*sin(gamma)*cos(alpha), 1.0*sin(alpha)*sin(gamma) + sin(beta)*cos(alpha)*cos(gamma)],
322 | [1.0*sin(alpha)*cos(beta), sin(alpha)*sin(beta)*sin(gamma) + 1.0*cos(alpha)*cos(gamma), sin(alpha)*sin(beta)*cos(gamma) - 1.0*sin(gamma)*cos(alpha)],
323 | [ -1.0*sin(beta), 1.0*sin(gamma)*cos(beta), 1.0*cos(beta)*cos(gamma)]])
324 |
325 | # Total transform of gripper wrt to base frame given orientation yaw (alpha), pitch (beta), roll (beta) and position px, py, pz
326 | T0g_b = Matrix([
327 | [1.0*sin(alpha)*sin(gamma) + sin(beta)*cos(alpha)*cos(gamma), 1.0*sin(alpha)*cos(gamma) - 1.0*sin(beta)*sin(gamma)*cos(alpha), 1.0*cos(alpha)*cos(beta), px],
328 | [sin(alpha)*sin(beta)*cos(gamma) - 1.0*sin(gamma)*cos(alpha), -1.0*sin(alpha)*sin(beta)*sin(gamma) - 1.0*cos(alpha)*cos(gamma), 1.0*sin(alpha)*cos(beta), py],
329 | [ 1.0*cos(beta)*cos(gamma), -1.0*sin(gamma)*cos(beta), -1.0*sin(beta), pz],
330 | [ 0, 0, 0, 1]])
331 |
332 | # Total transform of gripper wrt to base frame given angles q1, q2, q3, q4, q5, q6
333 | T0g_a = Matrix([
334 | [((sin(q1)*sin(q4) + sin(q2 + q3)*cos(q1)*cos(q4))*cos(q5) + sin(q5)*cos(q1)*cos(q2 + q3))*cos(q6) - (-sin(q1)*cos(q4) + sin(q4)*sin(q2 + q3)*cos(q1))*sin(q6), -((sin(q1)*sin(q4) + sin(q2 + q3)*cos(q1)*cos(q4))*cos(q5) + sin(q5)*cos(q1)*cos(q2 + q3))*sin(q6) + (sin(q1)*cos(q4) - sin(q4)*sin(q2 + q3)*cos(q1))*cos(q6), -(sin(q1)*sin(q4) + sin(q2 + q3)*cos(q1)*cos(q4))*sin(q5) + cos(q1)*cos(q5)*cos(q2 + q3), -0.303*sin(q1)*sin(q4)*sin(q5) + 1.25*sin(q2)*cos(q1) - 0.303*sin(q5)*sin(q2 + q3)*cos(q1)*cos(q4) - 0.054*sin(q2 + q3)*cos(q1) + 0.303*cos(q1)*cos(q5)*cos(q2 + q3) + 1.5*cos(q1)*cos(q2 + q3) + 0.35*cos(q1)],
335 | [ ((sin(q1)*sin(q2 + q3)*cos(q4) - sin(q4)*cos(q1))*cos(q5) + sin(q1)*sin(q5)*cos(q2 + q3))*cos(q6) - (sin(q1)*sin(q4)*sin(q2 + q3) + cos(q1)*cos(q4))*sin(q6), -((sin(q1)*sin(q2 + q3)*cos(q4) - sin(q4)*cos(q1))*cos(q5) + sin(q1)*sin(q5)*cos(q2 + q3))*sin(q6) - (sin(q1)*sin(q4)*sin(q2 + q3) + cos(q1)*cos(q4))*cos(q6), -(sin(q1)*sin(q2 + q3)*cos(q4) - sin(q4)*cos(q1))*sin(q5) + sin(q1)*cos(q5)*cos(q2 + q3), 1.25*sin(q1)*sin(q2) - 0.303*sin(q1)*sin(q5)*sin(q2 + q3)*cos(q4) - 0.054*sin(q1)*sin(q2 + q3) + 0.303*sin(q1)*cos(q5)*cos(q2 + q3) + 1.5*sin(q1)*cos(q2 + q3) + 0.35*sin(q1) + 0.303*sin(q4)*sin(q5)*cos(q1)],
336 | [ -(sin(q5)*sin(q2 + q3) - cos(q4)*cos(q5)*cos(q2 + q3))*cos(q6) - sin(q4)*sin(q6)*cos(q2 + q3), (sin(q5)*sin(q2 + q3) - cos(q4)*cos(q5)*cos(q2 + q3))*sin(q6) - sin(q4)*cos(q6)*cos(q2 + q3), -sin(q5)*cos(q4)*cos(q2 + q3) - sin(q2 + q3)*cos(q5), -0.303*sin(q5)*cos(q4)*cos(q2 + q3) - 0.303*sin(q2 + q3)*cos(q5) - 1.5*sin(q2 + q3) + 1.25*cos(q2) - 0.054*cos(q2 + q3) + 0.75],
337 | [ 0, 0, 0, 1]])
338 |
339 | # Rotation of urdf_gripper wrt (DH) gripper frame from rotz(pi) * roty(-pi/2) and it's transpose
340 | Rgu_eval = Matrix([[0, 0, 1], [0, -1.00000000000000, 0], [1.00000000000000, 0, 0]])
341 | RguT_eval = Matrix([[0, 0, 1], [0, -1.00000000000000, 0], [1.00000000000000, 0, 0]])
342 |
343 | # Inverse kinematics transformations starts below
344 |
345 | R0u_eval = R0u.evalf(subs = {alpha: yaw, beta: pitch, gamma: roll})
346 | R0g_eval = R0u_eval * RguT_eval
347 |
348 | wrist_center = get_wrist_center(gripper_point, R0g_eval, dg = 0.303)
349 |
350 | j1, j2, j3 = get_first_three_angles(wrist_center)
351 |
352 | R03T_eval = R03T.evalf(subs = {q1: j1.evalf(), q2: j2.evalf(), q3: j3.evalf()})
353 | R36_eval = R03T_eval * R0g_eval
354 |
355 | j4, j5, j6 = get_last_three_angles(R36_eval)
356 |
357 | j1 = j1.evalf()
358 | j2 = j2.evalf()
359 | j3 = j3.evalf()
360 | j4 = j4.evalf()
361 | j5 = j5.evalf()
362 | j6 = j6.evalf()
363 |
364 | return j1, j2, j3, j4, j5, j6
365 |
366 |
367 | def main():
368 | px, py, pz = 0.49792, 1.3673,3
369 | #px, py, pz = 0.49792, 1.3673, 2.4988
370 | roll, pitch, yaw = 1, -1, -1
371 | #roll, pitch, yaw = 0.366, -0.078, 2.561
372 | q1,q2,q3,q4,q5,q6 = get_angles(px,py,pz,roll,pitch,yaw)
373 | print("q1 : ",q1)
374 | print("q2 : ",q2)
375 | print("q3 : ",q3)
376 | print("q4 : ",q4)
377 | print("q5 : ",q5)
378 | print("q6 : ",q6)
379 |
380 | #now plot the arm with updated angles
381 | forward_kin(q1,q2,q3,q4,q5,q6)
382 |
383 | if __name__=="__main__":
384 | main()
385 |
--------------------------------------------------------------------------------
/kukadesign.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/kukadesign.gif
--------------------------------------------------------------------------------
/roboticArm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/roboticArm.png
--------------------------------------------------------------------------------
/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zahid58/Inverse-Kinematics-6-DOF-Python-With-Visualizer/495c4de76a4cf5836e2cd7e8c7f409c8930d24d4/up.png
--------------------------------------------------------------------------------