forked from evildmp/BrachioGraph
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathturtle_draw.py
237 lines (156 loc) · 6.38 KB
/
turtle_draw.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# run with python3 turtle_draw.py
from turtle import *
import math
# describe the arm and its joints
inner_radius = 8 # the blue (inner) arm
outer_radius = 8 # the red (outer) arm
inner_extent = 120 # the arcs covered by each of the two joints
outer_extent = 120
joint_angle = 90 # the centre of the outer arm relative to the blue arm
steps = 5 # number of degrees to step between drawing arcs
draw_arms_every = 10 # the number of degrees between drawing the arms
class T(Turtle):
def draw_inner_arm(self, angle):
self.up()
self.home()
self.width(2)
# only draw the inner arm every draw_arms_every degrees
if (angle/draw_arms_every).is_integer() or angle==inner_extent:
self.down()
self.color("blue")
self.left(angle)
self.fd(inner_radius * self.multiplier)
self.dot(5, "black")
else:
self.left(angle)
self.fd(inner_radius * self.multiplier)
def draw_outer_arm(self):
self.rt(joint_angle)
self.color("red")
# go back to the start of the arm before drawing the arc
self.fd(outer_radius * self.multiplier)
self.fd(-outer_radius * self.multiplier)
def draw_arc(self):
# get the turtle into the correct position for drawing the arc
self.up()
self.rt(180)
self.fd(outer_radius * self.multiplier)
self.rt(-90)
# cover the undrawn part of the arc first
self.circle(outer_radius * self.multiplier, (360-outer_extent)/2)
# and then the part we want to draw
self.color("gray")
self.down()
self.width(3)
self.circle(outer_radius * self.multiplier, outer_extent)
def visualise():
# set up the environment
s = Screen()
s.setup(width=800, height=800)
mode("logo")
t = T()
t.multiplier = 400/(inner_radius + outer_radius)
t.speed(0)
t.hideturtle()
for angle in range (0, inner_extent+1, steps):
t.draw_inner_arm(angle)
t.draw_outer_arm()
t.draw_arc()
s.exitonclick()
class PGT(T):
def __init__(
self,
driver=4, # the lengths of the arms
follower=10, # the lengths of the arms
# The angles are relative to each motor, so we need to know where each motor actually is.
motor_1_pos = -1, # position of motor 1 on the x axis
motor_2_pos = 1, # position of motor 2 on the x axis
box_bounds=(-3, -3, 3, 3),
angle_multiplier=1, # set to -1 if necessary to reverse directions
correction_1=0,
correction_2=0,
centre_1=1350, multiplier_1=425/45,
centre_2=1350, multiplier_2=415/45
):
# set the pantograph geometry
self.DRIVER = driver
self.FOLLOWER = follower
self.MOTOR_1_POS, self.MOTOR_2_POS = motor_1_pos, motor_2_pos
# the box bounds describe a rectangle that we can safely draw in
self.box_bounds = box_bounds
self.angle_multiplier = angle_multiplier
self.correction_1 = correction_1
self.correction_2 = correction_2
self.centre_1, self.centre_2 = centre_1, centre_2
self.multiplier_1, self.multiplier_2 = multiplier_1, multiplier_2
super().__init__()
def angles_to_xy(self, angle1, angle2):
# Given the angle of each arm, returns the x/y co-ordinates
angle1 = math.radians(angle1 * self.angle_multiplier)
angle2 = math.radians(angle2 * self.angle_multiplier)
# calculate the x position of the elbows
elbow_1_x = math.sin(angle1) * self.DRIVER
elbow_2_x = math.sin(angle2) * self.DRIVER
print("elbows x:", elbow_1_x, elbow_2_x)
# calculate the y position of the elbows
elbow_1_y = math.cos(angle1) * self.DRIVER
elbow_2_y = math.cos(angle2) * self.DRIVER
print("elbows y:", elbow_1_y, elbow_2_y)
motor_distance = self.MOTOR_2_POS - self.MOTOR_1_POS
# calculate x and y distances between the elbows
elbow_dx = motor_distance + elbow_2_x - elbow_1_x
elbow_dy = elbow_2_y - elbow_1_y
print("elbow distances:", elbow_dx, elbow_dy)
# calculate the length of the base of the top triangle
base_of_top_triangle = math.sqrt(elbow_dx ** 2 + elbow_dy ** 2)
print("base_of_top_triangle:", base_of_top_triangle)
# calculate the angle at which the top triangle is tilted
angle_of_base_of_top_triangle = math.asin((elbow_dy) / base_of_top_triangle)
print("angle_of_base_of_top_triangle", math.degrees(angle_of_base_of_top_triangle))
# calculate the left inner angle of the top triangle
corner_of_top_triangle = math.acos((base_of_top_triangle / 2) / self.FOLLOWER)
print("corner_of_top_triangle", math.degrees(corner_of_top_triangle))
# calculate the x and y distances to the left elbow
x_to_elbow = math.cos(corner_of_top_triangle + angle_of_base_of_top_triangle) * self.FOLLOWER
y_to_elbow = math.sin(corner_of_top_triangle + angle_of_base_of_top_triangle) * self.FOLLOWER
print("x_to_elbow, y_to_elbow", x_to_elbow, y_to_elbow)
x = elbow_1_x + x_to_elbow + self.MOTOR_1_POS
y = elbow_1_y + y_to_elbow
# return x, y - self.adder
return x, y
def visualisepg():
# set up the environment
s = Screen()
s.setup(width=800, height=800)
mode("logo")
t = PGT()
t.speed(0)
t.up()
multiplier = 400/(t.DRIVER + t.FOLLOWER)
t.goto(t.MOTOR_1_POS*multiplier, 0)
t.dot(10, "red")
t.goto(t.MOTOR_2_POS*multiplier, 0)
t.dot(10, "blue")
for angle1 in range (-180, 20, steps):
for angle2 in range (0, 200, steps):
x, y = t.angles_to_xy(angle1, angle2)
t.goto(t.MOTOR_1_POS*multiplier, 0)
t.setheading(angle1)
t.down()
t.color("red")
t.forward(t.DRIVER*multiplier)
t.color("green")
t.goto(x*multiplier, y*multiplier)
t.up()
t.goto(t.MOTOR_2_POS*multiplier, 0)
t.setheading(angle2)
t.down()
t.color("blue")
t.forward(t.DRIVER*multiplier)
t.color("yellow")
t.goto(x*multiplier, y*multiplier)
t.dot(4 , "blue")
t.up()
s.exitonclick()
visualise()
mainloop()