blob: 2836c50038043ba1523ab01dd2d6df61aea19429 [file] [log] [blame]
Michael Schuh10dd1e02018-01-20 13:19:44 -08001#!/usr/bin/python3
2
3# This code was used to select the gear ratio for the distal arm.
4# Run it from the command line and it displays the time required
5# to move the distal arm 60 degrees.
6#
7# Michael Schuh
8# January 20, 2018
9
10import math
11import numpy
12import scipy.integrate
13
14# apt-get install python-scipy python3-scipy python-numpy python3-numpy
15
16pi = math.pi
17pi2 = 2.0*pi
18rad_to_deg = 180.0/pi
19inches_to_meters = 0.0254
20lbs_to_kg = 1.0/2.2
21newton_to_lbf = 0.224809
22newton_meters_to_ft_lbs = 0.73756
23run_count = 0
24theta_travel = 0.0
25
26def to_deg(angle):
27 return (angle*rad_to_deg)
28
29def to_rad(angle):
30 return (angle/rad_to_deg)
31
32def to_rotations(angle):
33 return (angle/pi2)
34
35def time_derivative(x, t, voltage, c1, c2, c3):
36 global run_count
37 theta, omega = x
38 dxdt = [omega, -c1*omega + c3*math.sin(theta) + c2*voltage]
39 run_count = run_count + 1
40
41 #print ('dxdt = ',dxdt,' repr(dxdt) = ', repr(dxdt))
42 return dxdt
43
44
45def get_180_degree_time(c1,c2,c3,voltage,gear_ratio,motor_free_speed):
46 #print ("# step time theta angular_speed angular_acceleration theta angular_speed motor_speed motor_speed_fraction")
47 #print ("# (sec) (rad) (rad/sec) (rad/sec^2) (rotations) (rotations/sec) (rpm) (fraction)")
48 global run_count
49 global theta_travel
50
51 if ( False ):
52 # Gravity is assisting the motion.
53 theta_start = 0.0
54 theta_target = pi
55 elif ( False ):
56 # Gravity is assisting the motion.
57 theta_start = 0.0
58 theta_target = -pi
59 elif ( False ):
60 # Gravity is slowing the motion.
61 theta_start = pi
62 theta_target = 0.0
63 elif ( True ):
64 # Gravity is slowing the motion.
65 theta_start = -pi
66 theta_target = 0.0
67
68 theta_half = 0.5*(theta_start + theta_target)
69 if (theta_start > theta_target):
70 voltage = -voltage
71 theta = theta_start
72 theta_travel = theta_start - theta_target
73 if ( run_count == 0 ):
74 print ("# Theta Start = %.2f radians End = %.2f Theta travel %.2f Theta half = %.2f Voltage = %.2f" % (theta_start,theta_target,theta_travel,theta_half, voltage))
75 print ("# Theta Start = %.2f degrees End = %.2f Theta travel %.2f Theta half = %.2f Voltage = %.2f" % (to_deg(theta_start),to_deg(theta_target),to_deg(theta_travel),to_deg(theta_half), voltage))
76 omega = 0.0
77 time = 0.0
78 delta_time = 0.01 # time step in seconds
79 for step in range(1, 5000):
80 t = numpy.array([time, time + delta_time])
81 time = time + delta_time
82 x = [theta, omega]
83 angular_acceleration = -c1*omega + c2*voltage
84 x_n_plus_1 = scipy.integrate.odeint(time_derivative,x,t,args=(voltage,c1,c2,c3))
85 #print ('x_n_plus_1 = ',x_n_plus_1)
86 #print ('repr(x_n_plus_1) = ',repr(x_n_plus_1))
87 theta, omega = x_n_plus_1[1]
88 #theta= x_n_plus_1[0]
89 #omega = x_n_plus_1[1]
90 if ( False ):
91 print ("%4d %8.4f %8.2f %8.4f %8.4f %8.3f %8.3f %8.3f %8.3f" % \
92 (step, time, theta, omega, angular_acceleration, to_rotations(theta), \
93 to_rotations(omega), omega*gear_ratio*60.0/pi2, omega*gear_ratio/motor_free_speed ))
94 if (theta_start < theta_target):
95 # Angle is increasing through the motion.
96 if (theta > theta_half):
97 break
98 else:
99 # Angle is decreasing through the motion.
100 if (theta < theta_half):
101 break
102
103 #print ("# step time theta angular_speed angular_acceleration theta angular_speed motor_speed motor_speed_fraction")
104 #print ("# (sec) (rad) (rad/sec) (rad/sec^2) (rotations) (rotations/sec) (rpm) (fraction)")
105 #print ("# Total time for 1/2 rotation of arm is %0.2f" % (time*2))
106 return (2.0*time)
107
108def main():
109 gravity = 9.8 # m/sec^2 Gravity Constant
110 voltage_nominal = 12 # Volts
111
112 # Vex 775 Pro motor specs from http://banebots.com/p/M2-RS550-120
113 motor_name = "Vex 775 Pro motor specs from http://banebots.com/p/M2-RS550-120"
114 current_stall = 134 # amps stall current
115 current_no_load = 0.7 # amps no load current
116 torque_stall = 710/1000.0 # N-m Stall Torque
117 speed_no_load_rpm = 18730 # RPM no load speed
118
119 if ( False ):
120 # Bag motor from https://www.vexrobotics.com/217-3351.html
121 motor_name = "Bag motor from https://www.vexrobotics.com/217-3351.html"
122 current_stall = 53.0 # amps stall current
123 current_no_load = 1.8 # amps no load current
124 torque_stall = 0.4 # N-m Stall Torque
125 speed_no_load_rpm = 13180.0 # RPM no load speed
126
127 if ( True ):
128 # Mini CIM motor from https://www.vexrobotics.com/217-3371.html
129 motor_name = "Mini CIM motor from https://www.vexrobotics.com/217-3371.html"
130 current_stall = 89.0 # amps stall current
131 current_no_load = 3.0 # amps no load current
132 torque_stall = 1.4 # N-m Stall Torque
133 speed_no_load_rpm = 5840.0 # RPM no load speed
134
135 # How many motors are we using?
136 num_motors = 2
137
138 # Motor values
139 print ("# Motor: %s" % (motor_name))
140 print ("# Number of motors: %d" % (num_motors))
141 print ("# Stall torque: %.1f n-m" % (torque_stall))
142 print ("# Stall current: %.1f amps" % (current_stall))
143 print ("# No load current: %.1f amps" % (current_no_load))a
144 print ("# No load speed: %.0f rpm" % (speed_no_load_rpm))
145
146 # Constants from motor values
147 resistance_motor = voltage_nominal/current_stall
148 speed_no_load_rps = speed_no_load_rpm/60.0 # Revolutions per second no load speed
149 speed_no_load = speed_no_load_rps*2.0*pi
150 Kt = num_motors*torque_stall/current_stall # N-m/A torque constant
151 Kv_rpm = speed_no_load_rpm /(voltage_nominal - resistance_motor*current_no_load) # rpm/V
152 Kv = Kv_rpm*2.0*pi/60.0 # rpm/V
153
154 # Robot Geometry and physics
155 length_proximal_arm = inches_to_meters*47.34 # m Length of arm connected to the robot base
156 length_distal_arm = inches_to_meters*44.0 # m Length of arm that holds the cube
157 mass_cube = 6.0*lbs_to_kg # Weight of the cube in Kgrams
158 mass_proximal_arm = 5.5*lbs_to_kg # Weight of proximal arm
159 mass_distal_arm = 3.5*lbs_to_kg # Weight of distal arm
160 mass_distal = mass_cube + mass_distal_arm
161 radius_to_proximal_arm_cg = 22.0*inches_to_meters # m Length from arm pivot point to arm CG
162 radius_to_distal_arm_cg = 10.0*inches_to_meters # m Length from arm pivot point to arm CG
163
164 radius_to_distal_cg = ( length_distal_arm*mass_cube + radius_to_distal_arm_cg*mass_distal_arm)/mass_distal
165 J_cube = length_distal_arm*length_distal_arm*mass_cube
166 J_proximal_arm = radius_to_proximal_arm_cg*radius_to_proximal_arm_cg*mass_distal_arm # Kg m^2 Moment of inertia of the proximal arm
167 J_distal_arm = radius_to_distal_arm_cg*radius_to_distal_arm_cg*mass_distal_arm # Kg m^2 Moment of inertia of the distal arm
168 J = J_cube + J_distal_arm # Moment of inertia of the arm with the cube on the end
169
170 error_margine = 1.0
171 voltage = 10.0 # voltage for the motor. Assuming a loaded robot so not using 12 V.
172 # It might make sense to use a lower motor frees peed when the voltage is not a full 12 Volts.
173 # motor_free_speed = Kv*voltage
174 motor_free_speed = speed_no_load
175
176
177 print ("# Kt = %f N-m/A\n# Kv_rpm = %f rpm/V\n# Kv = %f radians/V" % (Kt, Kv_rpm, Kv))
178 print ("# %.2f Ohms Resistance of the motor " % (resistance_motor))
179 print ("# %.2f kg Cube weight" % (mass_cube))
180 print ("# %.2f kg Proximal Arm mass" % (mass_proximal_arm))
181 print ("# %.2f kg Distal Arm mass" % (mass_distal_arm))
182 print ("# %.2f kg Distal Arm and Cube weight" % (mass_distal))
183 print ("# %.2f m Length from distal arm pivot point to arm CG" % (radius_to_distal_arm_cg))
184 print ("# %.2f m Length from distal arm pivot point to arm and cube cg" % (radius_to_distal_cg))
185 print ("# %.2f kg-m^2 Moment of inertia of the cube about the arm pivot point" % (J_cube))
186 print ("# %.2f kg-m^2 Moment of inertia of the arm with the cube on the end" % (J))
187 print ("# %.2f m Proximal arm length" % (length_proximal_arm))
188 print ("# %.2f m Distal arm length" % (length_distal_arm))
189
190 print ("# %.2f kg-m^2 Moment of inertia of the proximal arm about the arm pivot point" % (J_proximal_arm))
191 print ("# %.2f kg-m^2 Moment of inertia of the distal arm about the arm pivot point" % (J_distal_arm))
192 print ("# %.2f kg-m^2 Moment of inertia of the distal arm and cube about the arm pivot point" % (J))
193 print ("# %d Number of motors" % (num_motors))
194
195 print ("# %.2f V Motor voltage" % (voltage))
196 for gear_ratio in range(30, 181, 10):
197 c1 = Kt*gear_ratio*gear_ratio/(Kv*resistance_motor*J)
198 c2 = gear_ratio*Kt/(J*resistance_motor)
199 c3 = radius_to_distal_cg*mass_distal*gravity/J
200
201 if ( False ):
202 print ("# %.8f 1/sec C1 constant" % (c1))
203 print ("# %.2f 1/sec C2 constant" % (c2))
204 print ("# %.2f 1/(V sec^2) C3 constant" % (c3))
205 print ("# %.2f RPM Free speed at motor voltage" % (voltage*Kv_rpm))
206
207 torque_90_degrees = radius_to_distal_cg*mass_distal*gravity
208 voltage_90_degrees = resistance_motor*torque_90_degrees/(gear_ratio*Kt)
209 torque_peak = gear_ratio*num_motors*torque_stall
210 torque_peak_ft_lbs = torque_peak * newton_meters_to_ft_lbs
211 normal_force = torque_peak/length_distal_arm
212 normal_force_lbf = newton_to_lbf*normal_force
213 time_required = get_180_degree_time(c1,c2,c3,voltage,gear_ratio,motor_free_speed)
214 print ("Time for %.1f degrees for gear ratio %3.0f is %.2f seconds. 90 degree torque %.1f N-m and voltage %.1f Volts. Peak torque %3.0f nm %3.0f ft-lb Normal force at distal end %3.0f N %2.0f lbf" % \
215 (to_deg(theta_travel),gear_ratio,time_required,torque_90_degrees,voltage_90_degrees,
216 torque_peak,torque_peak_ft_lbs,normal_force,normal_force_lbf))
217
218if __name__ == '__main__':
219 main()