blob: 4d34f4bfdde10f9aa07ab19f247fb1db33d0fbd1 [file] [log] [blame]
Austin Schuhf173eb82018-01-20 23:32:30 -08001#!/usr/bin/python3
2
3# This code was used to select the gear ratio for the intake.
4# Run it from the command line and it displays the time required
5# to rotate the intake 180 degrees.
6#
7# Michael Schuh
8# January 20, 2018
9
10import math
11import numpy
12import scipy.integrate
13
14pi = math.pi
15pi2 = 2.0 * pi
16rad_to_deg = 180.0 / pi
17inches_to_meters = 0.0254
18lbs_to_kg = 1.0 / 2.2
19newton_to_lbf = 0.224809
20newton_meters_to_ft_lbs = 0.73756
21run_count = 0
22theta_travel = 0.0
23
Ravago Jones5127ccc2022-07-31 16:32:45 -070024
Austin Schuhf173eb82018-01-20 23:32:30 -080025def to_deg(angle):
Ravago Jones5127ccc2022-07-31 16:32:45 -070026 return angle * rad_to_deg
27
Austin Schuhf173eb82018-01-20 23:32:30 -080028
29def to_rad(angle):
Ravago Jones5127ccc2022-07-31 16:32:45 -070030 return angle / rad_to_deg
31
Austin Schuhf173eb82018-01-20 23:32:30 -080032
33def to_rotations(angle):
Ravago Jones5127ccc2022-07-31 16:32:45 -070034 return angle / pi2
35
Austin Schuhf173eb82018-01-20 23:32:30 -080036
37def time_derivative(x, t, voltage, c1, c2, c3):
Ravago Jones5127ccc2022-07-31 16:32:45 -070038 global run_count
39 theta, omega = x
40 dxdt = [omega, -c1 * omega + c3 * math.sin(theta) + c2 * voltage]
41 run_count = run_count + 1
Austin Schuhf173eb82018-01-20 23:32:30 -080042
Ravago Jones5127ccc2022-07-31 16:32:45 -070043 return dxdt
44
Austin Schuhf173eb82018-01-20 23:32:30 -080045
46def get_distal_angle(theta_proximal):
Ravago Jones5127ccc2022-07-31 16:32:45 -070047 # For the proximal angle = -50 degrees, the distal angle is -180 degrees
48 # For the proximal angle = 10 degrees, the distal angle is -90 degrees
49 distal_angle = to_rad(-180.0 - (-50.0 - to_deg(theta_proximal)) * \
50 (180.0 - 90.0) / (50.0 + 10.0))
51 return distal_angle
Austin Schuhf173eb82018-01-20 23:32:30 -080052
53
54def get_180_degree_time(c1, c2, c3, voltage, gear_ratio, motor_free_speed):
Ravago Jones5127ccc2022-07-31 16:32:45 -070055 global run_count
56 global theta_travel
Austin Schuhf173eb82018-01-20 23:32:30 -080057
Ravago Jones5127ccc2022-07-31 16:32:45 -070058 if (True):
59 # Gravity is assisting the motion.
60 theta_start = 0.0
61 theta_target = pi
62 elif (False):
63 # Gravity is assisting the motion.
64 theta_start = 0.0
65 theta_target = -pi
66 elif (False):
67 # Gravity is slowing the motion.
68 theta_start = pi
69 theta_target = 0.0
70 elif (False):
71 # Gravity is slowing the motion.
72 theta_start = -pi
73 theta_target = 0.0
74 elif (False):
75 # This is for the proximal arm motion.
76 theta_start = to_rad(-50.0)
77 theta_target = to_rad(10.0)
Austin Schuhf173eb82018-01-20 23:32:30 -080078
Ravago Jones5127ccc2022-07-31 16:32:45 -070079 theta_half = 0.5 * (theta_start + theta_target)
80 if theta_start > theta_target:
81 voltage = -voltage
82 theta = theta_start
83 theta_travel = theta_start - theta_target
84 if run_count == 0:
85 print("# Theta Start = %.2f radians End = %.2f Theta travel %.2f "
86 "Theta half = %.2f Voltage = %.2f" %
87 (theta_start, theta_target, theta_travel, theta_half, voltage))
88 print("# Theta Start = %.2f degrees End = %.2f Theta travel %.2f "
89 "Theta half = %.2f Voltage = %.2f" %
90 (to_deg(theta_start), to_deg(theta_target), to_deg(theta_travel),
91 to_deg(theta_half), voltage))
92 omega = 0.0
93 time = 0.0
94 delta_time = 0.01 # time step in seconds
95 for step in range(1, 5000):
96 t = numpy.array([time, time + delta_time])
97 time = time + delta_time
98 x = [theta, omega]
99 angular_acceleration = -c1 * omega + c2 * voltage
100 x_n_plus_1 = scipy.integrate.odeint(time_derivative,
101 x,
102 t,
103 args=(voltage, c1, c2, c3))
104 theta, omega = x_n_plus_1[1]
Austin Schuhf173eb82018-01-20 23:32:30 -0800105
Ravago Jones5127ccc2022-07-31 16:32:45 -0700106 if (False):
107 print(
108 "%4d %8.4f %8.2f %8.4f %8.4f %8.3f "
109 "%8.3f %8.3f %8.3f" %
110 (step, time, theta, omega, angular_acceleration,
111 to_rotations(theta), to_rotations(omega), omega * gear_ratio *
112 60.0 / pi2, omega * gear_ratio / motor_free_speed))
113 if theta_start < theta_target:
114 # Angle is increasing through the motion.
115 if theta > theta_half:
116 break
117 else:
118 # Angle is decreasing through the motion.
119 if (theta < theta_half):
120 break
Austin Schuhf173eb82018-01-20 23:32:30 -0800121
Ravago Jones5127ccc2022-07-31 16:32:45 -0700122 return 2.0 * time
123
Austin Schuhf173eb82018-01-20 23:32:30 -0800124
125def main():
Ravago Jones5127ccc2022-07-31 16:32:45 -0700126 # m/sec^2 Gravity Constant
127 gravity = 9.8
128 # m/sec^2 Gravity Constant - Use 0.0 for the intake. It is horizontal.
129 gravity = 0.0
130 # Volts
131 voltage_nominal = 12
Austin Schuhf173eb82018-01-20 23:32:30 -0800132
Ravago Jones5127ccc2022-07-31 16:32:45 -0700133 # Vex 775 Pro motor specs from http://banebots.com/p/M2-RS550-120
134 motor_name = "Vex 775 Pro motor specs from http://banebots.com/p/M2-RS550-120"
135 current_stall = 134 # amps stall current
136 current_no_load = 0.7 # amps no load current
137 torque_stall = 710 / 1000.0 # N-m Stall Torque
138 speed_no_load_rpm = 18730 # RPM no load speed
Austin Schuhf173eb82018-01-20 23:32:30 -0800139
Ravago Jones5127ccc2022-07-31 16:32:45 -0700140 if (True):
141 # Bag motor from https://www.vexrobotics.com/217-3351.html
142 motor_name = "Bag motor from https://www.vexrobotics.com/217-3351.html"
143 current_stall = 53.0 # amps stall current
144 current_no_load = 1.8 # amps no load current
145 torque_stall = 0.4 # N-m Stall Torque
146 speed_no_load_rpm = 13180.0 # RPM no load speed
Austin Schuhf173eb82018-01-20 23:32:30 -0800147
Ravago Jones5127ccc2022-07-31 16:32:45 -0700148 if (False):
149 # Mini CIM motor from https://www.vexrobotics.com/217-3371.html
150 motor_name = "Mini CIM motor from https://www.vexrobotics.com/217-3371.html"
151 current_stall = 89.0 # amps stall current
152 current_no_load = 3.0 # amps no load current
153 torque_stall = 1.4 # N-m Stall Torque
154 speed_no_load_rpm = 5840.0 # RPM no load speed
Austin Schuhf173eb82018-01-20 23:32:30 -0800155
Ravago Jones5127ccc2022-07-31 16:32:45 -0700156 # How many motors are we using?
157 num_motors = 1
Austin Schuhf173eb82018-01-20 23:32:30 -0800158
Ravago Jones5127ccc2022-07-31 16:32:45 -0700159 # Motor values
160 print("# Motor: %s" % (motor_name))
161 print("# Number of motors: %d" % (num_motors))
162 print("# Stall torque: %.1f n-m" % (torque_stall))
163 print("# Stall current: %.1f amps" % (current_stall))
164 print("# No load current: %.1f amps" % (current_no_load))
165 print("# No load speed: %.0f rpm" % (speed_no_load_rpm))
Austin Schuhf173eb82018-01-20 23:32:30 -0800166
Ravago Jones5127ccc2022-07-31 16:32:45 -0700167 # Constants from motor values
168 resistance_motor = voltage_nominal / current_stall
169 speed_no_load_rps = speed_no_load_rpm / 60.0 # Revolutions per second no load speed
170 speed_no_load = speed_no_load_rps * 2.0 * pi
171 Kt = num_motors * torque_stall / current_stall # N-m/A torque constant
172 Kv_rpm = speed_no_load_rpm / (
173 voltage_nominal - resistance_motor * current_no_load) # rpm/V
174 Kv = Kv_rpm * 2.0 * pi / 60.0 # rpm/V
Austin Schuhf173eb82018-01-20 23:32:30 -0800175
Ravago Jones5127ccc2022-07-31 16:32:45 -0700176 # Robot Geometry and physics
177 # m Length of arm connected to the robot base
178 length_proximal_arm = inches_to_meters * 47.34
179 # m Length of arm that holds the cube
180 length_distal_arm = inches_to_meters * 44.0
181 # m Length of intake arm from the pivot point to where the big roller contacts a cube.
182 length_intake_arm = inches_to_meters * 9.0
183 mass_cube = 6.0 * lbs_to_kg # Weight of the cube in Kgrams
184 mass_proximal_arm = 5.5 * lbs_to_kg # Weight of proximal arm
185 mass_distal_arm = 3.5 * lbs_to_kg # Weight of distal arm
186 mass_distal = mass_cube + mass_distal_arm
187 mass_proximal = mass_proximal_arm + mass_distal
188 # m Length from arm pivot point to arm CG
189 radius_to_proximal_arm_cg = 22.0 * inches_to_meters
190 # m Length from arm pivot point to arm CG
191 radius_to_distal_arm_cg = 10.0 * inches_to_meters
Austin Schuhf173eb82018-01-20 23:32:30 -0800192
Ravago Jones5127ccc2022-07-31 16:32:45 -0700193 radius_to_distal_cg = (length_distal_arm * mass_cube +
194 radius_to_distal_arm_cg * mass_distal_arm) / \
195 mass_distal
196 radius_to_proximal_cg = (length_proximal_arm * mass_distal +
197 radius_to_proximal_arm_cg * mass_proximal_arm) / \
198 mass_proximal
199 J_cube = length_distal_arm * length_distal_arm * mass_cube
200 # Kg m^2 Moment of inertia of the proximal arm
201 J_proximal_arm = radius_to_proximal_arm_cg * radius_to_proximal_arm_cg * \
202 mass_distal_arm
203 # Kg m^2 Moment of inertia distal arm and cube at end of proximal arm.
204 J_distal_arm_and_cube_at_end_of_proximal_arm = length_proximal_arm * \
205 length_proximal_arm * mass_distal
206 # Kg m^2 Moment of inertia of the distal arm
207 J_distal_arm = radius_to_distal_arm_cg * radius_to_distal_arm_cg * mass_distal_arm
208 # Moment of inertia of the arm with the cube on the end
209 J = J_distal_arm_and_cube_at_end_of_proximal_arm + J_proximal_arm
210 # Intake claw
211 J_intake = 0.295 # Kg m^2 Moment of inertia of intake
212 J = J_intake
Austin Schuhf173eb82018-01-20 23:32:30 -0800213
Ravago Jones5127ccc2022-07-31 16:32:45 -0700214 gear_ratio = 140.0 # Guess at the gear ratio
215 gear_ratio = 100.0 # Guess at the gear ratio
216 gear_ratio = 90.0 # Guess at the gear ratio
Austin Schuhf173eb82018-01-20 23:32:30 -0800217
Ravago Jones5127ccc2022-07-31 16:32:45 -0700218 error_margine = 1.0
219 voltage = 10.0 # voltage for the motor. Assuming a loaded robot so not using 12 V.
220 # It might make sense to use a lower motor frees peed when the voltage is not a full 12 Volts.
221 # motor_free_speed = Kv * voltage
222 motor_free_speed = speed_no_load
Austin Schuhf173eb82018-01-20 23:32:30 -0800223
Ravago Jones5127ccc2022-07-31 16:32:45 -0700224 print("# Kt = %f N-m/A\n# Kv_rpm = %f rpm/V\n# Kv = %f radians/V" %
225 (Kt, Kv_rpm, Kv))
226 print("# %.2f Ohms Resistance of the motor " % (resistance_motor))
227 print("# %.2f kg Cube weight" % (mass_cube))
228 print("# %.2f kg Proximal Arm mass" % (mass_proximal_arm))
229 print("# %.2f kg Distal Arm mass" % (mass_distal_arm))
230 print("# %.2f kg Distal Arm and Cube weight" % (mass_distal))
231 print("# %.2f m Length from distal arm pivot point to arm CG" %
232 (radius_to_distal_arm_cg))
233 print("# %.2f m Length from distal arm pivot point to arm and cube cg" %
234 (radius_to_distal_cg))
235 print(
236 "# %.2f kg-m^2 Moment of inertia of the cube about the arm pivot point"
237 % (J_cube))
238 print("# %.2f m Length from proximal arm pivot point to arm CG" %
239 (radius_to_proximal_arm_cg))
240 print("# %.2f m Length from proximal arm pivot point to arm and cube cg" %
241 (radius_to_proximal_cg))
242 print("# %.2f m Proximal arm length" % (length_proximal_arm))
243 print("# %.2f m Distal arm length" % (length_distal_arm))
Austin Schuhf173eb82018-01-20 23:32:30 -0800244
Ravago Jones5127ccc2022-07-31 16:32:45 -0700245 print(
246 "# %.2f kg-m^2 Moment of inertia of the intake about the intake pivot point"
247 % (J_intake))
248 print(
249 "# %.2f kg-m^2 Moment of inertia of the distal arm about the arm pivot point"
250 % (J_distal_arm))
251 print(
252 "# %.2f kg-m^2 Moment of inertia of the proximal arm about the arm pivot point"
253 % (J_proximal_arm))
254 print(
255 "# %.2f kg-m^2 Moment of inertia of the distal arm and cube mass about "
256 "the proximal arm pivot point" %
257 (J_distal_arm_and_cube_at_end_of_proximal_arm))
258 print(
259 "# %.2f kg-m^2 Moment of inertia of the intake the intake pivot point "
Austin Schuhf173eb82018-01-20 23:32:30 -0800260 "(J value used in simulation)" % (J))
Ravago Jones5127ccc2022-07-31 16:32:45 -0700261 print("# %d Number of motors" % (num_motors))
Austin Schuhf173eb82018-01-20 23:32:30 -0800262
Ravago Jones5127ccc2022-07-31 16:32:45 -0700263 print("# %.2f V Motor voltage" % (voltage))
264 for gear_ratio in range(60, 241, 10):
265 c1 = Kt * gear_ratio * gear_ratio / (Kv * resistance_motor * J)
266 c2 = gear_ratio * Kt / (J * resistance_motor)
267 c3 = radius_to_proximal_cg * mass_proximal * gravity / J
Austin Schuhf173eb82018-01-20 23:32:30 -0800268
Ravago Jones5127ccc2022-07-31 16:32:45 -0700269 if (False):
270 print("# %.8f 1/sec C1 constant" % (c1))
271 print("# %.2f 1/sec C2 constant" % (c2))
272 print("# %.2f 1/(V sec^2) C3 constant" % (c3))
273 print("# %.2f RPM Free speed at motor voltage" %
274 (voltage * Kv_rpm))
Austin Schuhf173eb82018-01-20 23:32:30 -0800275
Ravago Jones5127ccc2022-07-31 16:32:45 -0700276 torque_90_degrees = radius_to_distal_cg * mass_distal * gravity
277 voltage_90_degrees = resistance_motor * torque_90_degrees / (
278 gear_ratio * Kt)
279 torque_peak = gear_ratio * num_motors * torque_stall
280 torque_peak_ft_lbs = torque_peak * newton_meters_to_ft_lbs
281 normal_force = torque_peak / length_intake_arm
282 normal_force_lbf = newton_to_lbf * normal_force
283 time_required = get_180_degree_time(c1, c2, c3, voltage, gear_ratio,
284 motor_free_speed)
285 print("Time for %.1f degrees for gear ratio %3.0f is %.2f seconds. "
286 "Peak (stall) torque %3.0f nm %3.0f ft-lb Normal force at intake "
287 "end %3.0f N %2.0f lbf" % \
288 (to_deg(theta_travel), gear_ratio, time_required,
289 torque_peak, torque_peak_ft_lbs, normal_force, normal_force_lbf))
290
Austin Schuhf173eb82018-01-20 23:32:30 -0800291
292if __name__ == '__main__':
Ravago Jones5127ccc2022-07-31 16:32:45 -0700293 main()