1
0

FullArmControlG1.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import os
  2. import PySimpleGUI as sg
  3. import serial
  4. import numpy as np
  5. import time
  6. # sg.preview_all_look_and_feel_themes() #to display all themes
  7. # open serial communication
  8. ser = serial.Serial("COM7", 9600)
  9. # Waiting for arduino to start sketch
  10. time.sleep(2)
  11. slider_width = 50
  12. slider_height = 40
  13. button_width = 10
  14. button_height = 2
  15. stepper_range = ((0, 360), (-115, 115), (-115, 115), (-115, 115))
  16. stepper_default_values_rel = [0, 0, 0, 0]
  17. stepper_og_values_rel = [0, 0, 0, 0]
  18. stepper_moveTo_angels_rel = [0, 0, 0, 0]
  19. stepper_actual_angels_rel = [0, 0, 0, 0]
  20. segments_length = [15, 50, 40, 30]
  21. end_effector_pos = [0, 0, 0] # x,y,z coordination of m4 and rotation angel theta
  22. ik_m3_actual_pos = [0, 0, 0] # y,z coordination of m3 and rotation angel theta
  23. ik_m3_move_to_pos = [0, 0, 0] # y,z coordination of m3 and rotation angel theta
  24. ik_step_size = 5 # default step size 5 cm
  25. arm_isCalibrated = 0
  26. arm_calibrate = 0
  27. FK_slider_values = [0, 0, 0, 0]
  28. # Definition of function to calculate angels of a triangle with known side lengths using the law of cosine
  29. def calculate_triangle_angles(a, b, c):
  30. angle_a = np.rad2deg(np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)))
  31. angle_b = np.rad2deg(np.arccos((c ** 2 + a ** 2 - b ** 2) / (2 * c * a)))
  32. angle_c = 180 - angle_a - angle_b # The sum of angles in a triangle is 180 degrees
  33. return angle_a, angle_b, angle_c
  34. # Definition of function to calculate joints angels relative to horizon
  35. def calculate_angels_to_horizon(relative_angels_stepper):
  36. absolute_angels = [0, 0, 0, 0]
  37. absolute_angels[0] = relative_angels_stepper[0]
  38. absolute_angels[1] = absolute_angels[0] + relative_angels_stepper[1]
  39. absolute_angels[2] = absolute_angels[1] + relative_angels_stepper[2]
  40. absolute_angels[3] = absolute_angels[2] + relative_angels_stepper[3]
  41. for j in range(4):
  42. if absolute_angels[j] > 360:
  43. absolute_angels[j] = absolute_angels[j] - 360
  44. return absolute_angels
  45. # Definition of function to calculate joints angels relative to another, based on their angels relative to horizon
  46. def calculate_angels_relative(absolute_angels_stepper):
  47. relative_angels = [0, 0, 0, 0]
  48. relative_angels[0] = absolute_angels_stepper[0]
  49. relative_angels[1] = absolute_angels_stepper[1] - relative_angels[0]
  50. relative_angels[2] = absolute_angels_stepper[2] - relative_angels[1]
  51. relative_angels[3] = absolute_angels_stepper[3] - relative_angels[2]
  52. for j in range(4):
  53. if relative_angels[j] > 360:
  54. relative_angels[j] = relative_angels[j] - 360
  55. return relative_angels
  56. # Definition of function to calculate coordination of end effector and Motor3
  57. def fk_calculate_position(stepper_angels):
  58. alpha = np.array(stepper_angels) * (np.pi / 180)
  59. start_x = 0
  60. start_y = 0
  61. y0 = 0
  62. z0 = segments_length[0]
  63. y1 = y0 + np.cos(alpha[1]) * segments_length[1]
  64. z1 = z0 + np.sin(alpha[1]) * segments_length[1]
  65. y2 = y1 + np.cos(alpha[2]) * segments_length[2]
  66. z2 = z1 + np.sin(alpha[2]) * segments_length[2]
  67. y3 = y2 + np.cos(alpha[3]) * segments_length[3]
  68. z3 = z2 + np.sin(alpha[3]) * segments_length[3]
  69. m4_pos_2d = [y3, z3, stepper_angels[0]]
  70. m3_pos_2d = [y2, z2, stepper_angels[0]]
  71. return m3_pos_2d, m4_pos_2d
  72. # Definition of function to calculate stepper angels to move Motor3 to desired coordination
  73. def ik_calculate_angels(m3_position, m4_angel):
  74. z0 = segments_length[0]
  75. # y0 = 0
  76. alpha = [90, 0, 0, m4_angel] # relative stepper angels to reach desired coordination
  77. beta = [0, 0, 90] # angels of right triangle
  78. # gamma = [0, 0, 0] # angels of triangle l_l1_l2
  79. y = m3_position[0] # - y0
  80. z = m3_position[1] - z0
  81. l1 = segments_length[1]
  82. l2 = segments_length[2]
  83. l_h = np.sqrt(np.square(y) + np.square(z)) # calculating hypothesis
  84. gamma = calculate_triangle_angles(l2, l1, l_h)
  85. beta[0] = np.rad2deg(np.arctan2(z, y))
  86. beta[1] = np.rad2deg(np.arctan2(y, z))
  87. alpha[1] = -(90 - gamma[0] - beta[0])
  88. alpha[2] = -(180 - gamma[2])
  89. return alpha
  90. # Define function to update slider values to match actual stepper values
  91. def update_slider_values(slider_updated_values):
  92. window['-Slider_Stepper0_FK-'].update(slider_updated_values[0])
  93. window['-Slider_Stepper1-'].update(slider_updated_values[1])
  94. window['-Slider_Stepper2-'].update(slider_updated_values[2])
  95. window['-Slider_Stepper3_FK-'].update(slider_updated_values[3])
  96. # Define function to get chosen step size
  97. def get_step_size():
  98. if values['-Radio_Option1-']:
  99. step_size = 1
  100. elif values['-Radio_Option2-']:
  101. step_size = 5
  102. elif values['-Radio_Option3-']:
  103. step_size = 10
  104. return step_size
  105. # Calculate Default angels and position
  106. stepper_actual_angels_abs = calculate_angels_to_horizon(stepper_actual_angels_rel)
  107. ik_m3_actual_pos, end_effector_pos = fk_calculate_position(stepper_actual_angels_abs)
  108. # Definition of GUI Layout
  109. FK_column = [
  110. [sg.Text("Forward Kinematics:")],
  111. [sg.Text("")],
  112. [sg.Text("Stepper motor 0")],
  113. [sg.Text(""),
  114. sg.Slider(range=(0, 360), size=(slider_width, slider_height), default_value=stepper_default_values_rel[0],
  115. orientation="h", key="-Slider_Stepper0_FK-"), sg.Text("")],
  116. [sg.Text("Stepper motor 1")],
  117. [sg.Text(""),
  118. sg.Slider(range=(-115, 115), size=(slider_width, slider_height), default_value=stepper_default_values_rel[1],
  119. orientation="h", key="-Slider_Stepper1-"), sg.Text("")],
  120. [sg.Text("Stepper motor 2")],
  121. [sg.Text(""),
  122. sg.Slider(range=(-115, 115), size=(slider_width, slider_height), default_value=stepper_default_values_rel[2],
  123. orientation="h", key="-Slider_Stepper2-"), sg.Text("")],
  124. [sg.Text("Stepper motor 3")],
  125. [sg.Text(""),
  126. sg.Slider(range=(-115, 115), size=(slider_width, slider_height), default_value=stepper_default_values_rel[3],
  127. orientation="h", key="-Slider_Stepper3_FK-"), sg.Text("")],
  128. [sg.Button("Submit", key="-FK_Set_Button-", size=(button_width, button_height)),
  129. sg.Button("Reset", key="-FK_Reset_Button-", size=(button_width, button_height)),
  130. sg.Button("Calibrate", key="-FK_Calibrate_Button-", size=(button_width, button_height))]
  131. ]
  132. IK_column = [
  133. [sg.Text("Inverse Kinematics:")],
  134. [sg.Text("")],
  135. [sg.Text("Choose Step size:"),
  136. sg.Radio('1 cm', "RADIO1", key="-Radio_Option1-"),
  137. sg.Radio('5 cm', "RADIO1", key="-Radio_Option2-", default=True, ),
  138. sg.Radio('10 cm', "RADIO1", key="-Radio_Option3-")],
  139. [sg.Text(""), sg.Text(""), sg.Text(""),
  140. sg.Button("Up", key="-IK_Up_Button-", size=(button_width, button_height))],
  141. [sg.Button("Backward", key="-IK_Backward_Button-", size=(button_width, button_height)),
  142. sg.Button("Forward", key="-IK_Forward_Button-", size=(button_width, button_height))],
  143. [sg.Text(""), sg.Text(""), sg.Text(""),
  144. sg.Button("Down", key="-IK_Down_Button-", size=(button_width, button_height))],
  145. [sg.Text("")],
  146. [sg.Text("")],
  147. # [sg.Text(ik_m3_actual_pos, key="-m3_pos-")],
  148. [sg.Text("")]
  149. ]
  150. layout = [
  151. [
  152. sg.Column(FK_column),
  153. sg.VSeparator(),
  154. sg.Column(IK_column), # vertical_alignment="Top"
  155. sg.VSeparator(),
  156. ]
  157. ]
  158. window = sg.Window("Robot Control", layout)
  159. # Loop for GUI feedback and Serial Communication
  160. while True:
  161. event, values = window.read()
  162. if event == "EXIT" or event == sg.WIN_CLOSED:
  163. break
  164. elif event == "-FK_Set_Button-" and arm_isCalibrated == 1:
  165. FK_slider_values[0] = values["-Slider_Stepper0_FK-"]
  166. FK_slider_values[1] = values["-Slider_Stepper1-"]
  167. FK_slider_values[2] = values["-Slider_Stepper2-"]
  168. FK_slider_values[3] = values["-Slider_Stepper3_FK-"]
  169. stepper_moveTo_angels_rel = np.array(stepper_actual_angels_rel) - np.array(FK_slider_values)
  170. stepper_actual_angels_rel = np.array(FK_slider_values)
  171. elif event == "-FK_Calibrate_Button-":
  172. update_slider_values(stepper_og_values_rel)
  173. arm_calibrate = 1
  174. arm_isCalibrated = 1
  175. stepper_actual_angels_rel = stepper_og_values_rel
  176. elif event == "-FK_Reset_Button-":
  177. update_slider_values(stepper_default_values_rel)
  178. # Do not forget maximal reachable coordination!
  179. elif event == "-IK_Up_Button-" and arm_isCalibrated == 1:
  180. ik_step_size = get_step_size()
  181. ik_m3_move_to_pos = np.array(ik_m3_actual_pos) + np.array([0, ik_step_size, 0])
  182. ik_m3_move_to_pos[2] = values["-Slider_Stepper0_FK-"]
  183. stepper_moveTo_angels_rel = np.array(stepper_actual_angels_rel) - np.array(
  184. ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"])) # may need to with - and +
  185. stepper_actual_angels_rel = np.array(ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  186. update_slider_values(stepper_actual_angels_rel)
  187. ik_m3_actual_pos = ik_m3_move_to_pos
  188. elif event == "-IK_Down_Button-" and arm_isCalibrated == 1:
  189. ik_step_size = get_step_size()
  190. ik_m3_move_to_pos = np.array(ik_m3_actual_pos) - np.array([0, ik_step_size, 0])
  191. ik_m3_move_to_pos[2] = values["-Slider_Stepper0_FK-"]
  192. stepper_moveTo_angels_rel = np.array(stepper_actual_angels_rel) - np.array(
  193. ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  194. stepper_actual_angels_rel = np.array(ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  195. update_slider_values(stepper_actual_angels_rel)
  196. ik_m3_actual_pos = ik_m3_move_to_pos
  197. elif event == "-IK_Forward_Button-" and arm_isCalibrated == 1:
  198. ik_step_size = get_step_size()
  199. ik_m3_move_to_pos = np.array(ik_m3_actual_pos) + np.array([ik_step_size, 0, 0])
  200. ik_m3_move_to_pos[2] = values["-Slider_Stepper0_FK-"]
  201. stepper_moveTo_angels_rel = np.array(stepper_actual_angels_rel) - np.array(
  202. ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  203. stepper_actual_angels_rel = np.array(ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  204. update_slider_values(stepper_actual_angels_rel)
  205. ik_m3_actual_pos = ik_m3_move_to_pos
  206. elif event == "-IK_Backward_Button-" and arm_isCalibrated == 1:
  207. ik_step_size = get_step_size()
  208. ik_m3_move_to_pos = np.array(ik_m3_actual_pos) - np.array([ik_step_size, 0, 0])
  209. ik_m3_move_to_pos[2] = values["-Slider_Stepper0_FK-"]
  210. stepper_moveTo_angels_rel = np.array(stepper_actual_angels_rel) - np.array(
  211. ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  212. stepper_actual_angels_rel = np.array(ik_calculate_angels(ik_m3_move_to_pos, values["-Slider_Stepper3_FK-"]))
  213. update_slider_values(stepper_actual_angels_rel)
  214. ik_m3_actual_pos = ik_m3_move_to_pos
  215. stepper_actual_angels_abs = calculate_angels_to_horizon(stepper_actual_angels_rel)
  216. ik_m3_actual_pos, end_effector_pos = fk_calculate_position(stepper_actual_angels_abs)
  217. # Formate data before sending
  218. # str(arm_calibrate)
  219. data = "<" + str(0) + "," + str(stepper_moveTo_angels_rel[0]) + "," + str(stepper_moveTo_angels_rel[1]) \
  220. + "," + str(stepper_moveTo_angels_rel[2]) + "," + str(stepper_moveTo_angels_rel[3]) + ">"
  221. print(data)
  222. ser.write(data.encode())
  223. received_string = ser.readline().decode()
  224. print(received_string)
  225. stepper_moveTo_angels_rel = [0, 0, 0, 0]
  226. arm_calibrate = 1
  227. ser.close()
  228. window.close()