├── 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 | ![](https://github.com/Zedd1558/Inverse-Kinematics-6-DOF-for-ERC-2019/blob/master/Screenshot%20(55).png) 23 | ![](https://github.com/Zedd1558/Inverse-Kinematics-6-DOF-for-ERC-2019/blob/master/Screenshot%20(54).png) 24 | ![](https://github.com/Zedd1558/Inverse-Kinematics-6-DOF-for-ERC-2019/blob/master/Screenshot%20(53).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 --------------------------------------------------------------------------------