ME 405 Romi
Loading...
Searching...
No Matches
control_task.py
Go to the documentation of this file.
18
19# The arguments are a mix of controllers, data shares, and flag shares.
20# @param fwd_ref : fwd_ref is an integer share that holds the expected forward reference speed of ROMI in mm.s.
21# It is set by the UI task for testing purposes or by pathing plan task for course navigation.
22# @param arc_ref : arc_ref is an integer share that holds the expected turning arc of ROMI in mm of arc radius.
23# It is set by the UI task for testing purposes.
24# @param piv_ref : piv_ref is a float share that holds the expected pivoting reference angular speed of ROMI in rad/s.
25# It is set by the UI task for testing purposes or by pathing plan task for course navigation.
26# @param c_state : c_state is an integer share flag that holds the expected state of control_task.
27# It is set by UI or pathing plan to tell control_task the expected motion of ROMI.
28# @param my_controller_left : my_controller_left is a controller object made in main that has gains for controlling
29# the motion of the left wheel.
30# @param my_controller_right: my_controller_right is a controller object made in main that has gains for controlling
31# the motion of the right wheel.
32# @param position_l: position_l is a float share that the left motor and encoder class fills with the current left motor position.
33# @param velocity_l: velocity_l is a float share that the left motor and encoder class fills with the current left motor velocity.
34# @param position_r: position_r is a float share that the right motor and encoder class fills with the current right motor position.
35# @param velocity_r: velocity_r is a float share that the right motor and encoder class fills with the current right motor velocity.
37# @param PWM_l : PWM_l is a float share that control_task sets to a value -100 to 100 as the duty cycle of the left wheel's enable pin.
38# The motor_encoder_left_class will use it.
39# @param PWM_r : PWM_r is a float share that control_task sets to a value -100 to 100 as the duty cycle of the right wheel's enable pin.
40# The motor_encoder_right_class will use it.
41# @param encoder_Right: encoder_Right is an encoder object attached to the right encoder. It is used here to save an offset and zero the encoders
42# for accurate observer behavior. It is also used to get the dt between runs for the integral sums in the motor controllers.
43# @param encoder_Left :encoder_Left is an encoder object attached to the left encoder. It is used here to save an offset and zero the encoders
44# for accurate observer behavior. It is also used to get the dt between runs for the integral sums in the motor controllers.
45# @param m_state_l : m_state_l is an integer share flag used by control task to tell the left motor encoder class which state the left motor needs to be in.
46# @param m_state_r : m_state_r is an integer share flag used by control task to tell the right motor encoder class which state the right motor needs to be in.
48# @param centroid : centroid is a float share that the line sensor task fills with the current location of the line that ROMI is following. It is used for the
49# automatic line following mode in control task.
50# @param line_controller : line_controller is a controller object made in main that has gains for changing the set point of the wheel controllers slightly to move
51# the centroid of the line to a certain point.
52# @param automatic_mode : automatic_mode is an integer share flag that is set to tell control_task that it should start automatically following a line.
53# It is set by UI for testing or pathing plan for course navigation.
54# @param line_sensor : line_sensor is the line_sensor object made in main. It is not used in control task's current implementation but was used before for debugging the line following.
55# @param need_Calibrate : need_Calibrate is an integer share flag that tells control task whether the IR sensors are calibrated and control task is ok to start
56# line following. It is set by the line sensor task.
57# @param real_yaw : real_yaw is a float share that the IMU task fills with the current yaw of ROMI. control_task uses it for heading control.
58# @param centroid_goal: centroid_goal is a float share that the pathing plan task sets. It is then used as the line following centroid controller set point.
59# @param yaw_goal : yaw_goal is a float share that is the set point of the heading control. It is the angle ROMI should turn to on the course and is set by
60# pathing plan for course navigation.
61# @param controller_yaw : controller_yaw is a controller object made in main. It looks at the current yaw of ROMI to get new wheel speeds for pivoting towards the yaw_goal.
62# It is set by the pathing plan for course navigation.
63
64 def __init__(self, fwd_ref, arc_ref, piv_ref, c_state, my_controller_left, my_controller_right,
65 position_l, velocity_l, position_r, velocity_r, PWM_l, PWM_r, encoder_Right, encoder_Left,
66 m_state_l, m_state_r, centroid, line_controller, automatic_mode, line_sensor, need_Calibrate, real_yaw, centroid_goal, yaw_goal, controller_yaw):
67 self.fwd_ref = fwd_ref
68 self.arc_ref = arc_ref
69 self.piv_ref = piv_ref
70 self.c_state = c_state
71 self.controller_left = my_controller_left
72 self.controller_right = my_controller_right
73 self.position_l = position_l
74 self.velocity_l = velocity_l
75 self.position_r = position_r
76 self.velocity_r = velocity_r
77 self.PWM_l = PWM_l
78 self.PWM_r = PWM_r
79 self.state = 0
80 self.enc_R = encoder_Right
81 self.enc_L = encoder_Left
82 self.m_state_l = m_state_l
83 self.m_state_r = m_state_r
84 self.centroid = centroid
85 self.line_controller = line_controller
86 self.automatic_mode = automatic_mode
87 self.yaw_rate = 0
88 self.c_state.put(0)
89 self.line_sensor = line_sensor
90 self.need_Calibrate = need_Calibrate
91 self.real_yaw = real_yaw
92 self.centroid_goal = centroid_goal
93 self.yaw_goal = yaw_goal
94 self.controller_yaw = controller_yaw
95 self.idx = 0
96 self.startup = 0
97
120
121 def run(self):
122
123 while(True):
124
125 if self.state == 0:
126 # Hub State
127 if self.automatic_mode.get() == 1:
128 print("going dark")
129 self.state = 6
130 self.line_controller.change_Ref(0)
131 if self.startup == 0:
132 self.enc_R.zero()
133 self.enc_L.zero()
134 self.enc_R.set_offset(((.141/2))*self.real_yaw.get())
135 self.enc_L.set_offset(-((.141/2))*self.real_yaw.get())
136 self.startup = 1
137 elif self.c_state.get() != 0:
138 self.state = self.c_state.get()
139 yield 0
140 # Forward control state
141 elif self.state == 1:
142 if self.c_state.get() == 4:
143 self.state = 4
144 #print("going forward")
145 #print(self.fwd_ref.get())
146 self.controller_left.change_Ref(self.fwd_ref.get())
147 #self.controller_right.change_Ref(self.fwd_ref.get())
148 self.controller_right.change_Ref(self.fwd_ref.get())
149 self.state = 0
150 self.c_state.put(0)
151 yield 1
152 # Turn control state
153 elif self.state == 2:
154 if self.c_state.get() == 4:
155 self.state = 4
156 v_r = 15*((2*self.arc_ref.get()+141)/(2*self.arc_ref.get()-141))
157 self.controller_left.change_Ref(15)
158 self.controller_right.change_Ref(v_r)
159 self.state = 0
160 self.c_state.put(0)
161 yield 2
162 # Pivot control state
163 elif self.state == 3:
164 if self.c_state.get() == 4:
165 self.state = 4
166 self.controller_left.change_Ref(-(self.piv_ref.get()*141//2))
167 #self.controller_left.change_Ref(100)
168 #print(self.piv_ref.get()*141//2)
169 self.controller_right.change_Ref((self.piv_ref.get()*141//2))
170 #self.controller_right.change_Ref(100)
171 #self.state = 0
172 #self.c_state.put(0)
173 yield 3
174 # Disable State
175 elif self.state == 4:
176 print("I tried to turn them off")
177 self.controller_left.change_Ref(0)
178 self.controller_right.change_Ref(0)
179 self.fwd_ref.put(0)
180 self.arc_ref.put(0)
181 self.piv_ref.put(0)
182 self.state = 0
183 self.c_state.put(0)
184 yield 4
185 # Automatic control
186 elif self.state == 5:
187 #if not self.line_sensor.check_Line():
188 # self.controller_left.change_Ref(0)
189 # self.controller_right.change_Ref(0)
190 # print("No line")
191 #else:
192 #print(f"got in state 5")
193 if self.automatic_mode.get() == 0:
194 self.state = 4
195 if self.c_state.get() == 4:
196 self.state = 4
197
198 if self.centroid_goal.get() != self.line_controller.get_Ref():
199 print("Centroid Ref Changed")
200 self.line_controller.change_Ref(self.centroid_goal.get())
201 print(self.line_controller.get_Ref())
202
203 self.yaw_rate = self.line_controller.pi_Control(self.centroid.get(), 15)
204 #print("Yaw Rate")
205 #print(f"yaw rate {self.yaw_rate}")
206 #print(self.line_controller.get_Error())
207 #print(self.yaw_rate)
208 #print(f" centroid= {self.centroid.get()}")
209 self.controller_left.change_Ref(100-self.yaw_rate)
210 self.controller_right.change_Ref(100+self.yaw_rate)
211 yield 5
212
213 elif self.state == 6:
214 if self.need_Calibrate.get() == 0:
215 self.state = 5
216 print("CALIBRATED")
217 yield 6
218
219 elif self.state ==7:
220 # Yaw alignment state
221 yaw_actuation = self.controller_yaw.pi_Control(self.yaw_goal.get(), 15)
222 self.controller_left.change_Ref(-yaw_actuation)
223 self.controller_right.change_Ref(yaw_actuation)
224 #print(yaw_actuation)
225 if self.c_state.get() == 4:
226 self.state = 4
227 if yaw_actuation <= 1:
228 self.yaw_goal.put(0)
229 self.controller_left.change_Ref(0)
230 self.controller_right.change_Ref(0)
231 self.state = 0
232 yield 7
233 else:
234 raise ValueError("Not that many states")
235
236 # For Proportional Tests
237 #cntrl_l = self.controller_left.proportional_Control(self.velocity_l.get())
238 #cntrl_r = self.controller_right.proportional_Control(self.velocity_r.get())
239 #print(f"cntrl_l : {cntrl_l}")
240 #print(f"cntrl_r : {cntrl_r}")
241 #self.PWM_l.put(cntrl_l)
242 #self.m_state_l.put(2)
243 #self.PWM_r.put(cntrl_r)
244 #self.m_state_r.put(2)
245
246 # For PI Tests
247 new_left_pwm = self.controller_left.pi_Control(self.velocity_l.get(), self.enc_L.get_dt())
248 new_right_pwm = self.controller_right.pi_Control(self.velocity_r.get(), self.enc_R.get_dt())
249
250 #print(f"new_right {new_right_pwm}")
251 #print(f"new_left {new_left_pwm}")
252 #self.PWM_l.put(new_left_pwm)
253 #self.PWM_r.put(new_right_pwm)
254
255 #print(f"new_left after filter {self.PWM_l.get()}")
256
257 #IMPORTANT LOGIC CHECKS READ @detail
258 if new_left_pwm > 0 and new_right_pwm > 0:
259 # Both positive
260 self.PWM_l.put(new_left_pwm)
261 self.PWM_r.put(new_right_pwm)
262 elif new_left_pwm < 0 and new_right_pwm < 0:
263 # Both negative
264 self.PWM_l.put(new_left_pwm)
265 self.PWM_r.put(new_right_pwm)
266 elif new_left_pwm > 0 and new_right_pwm < 0:
267 # Left positive, right negative
268 #print("Flipping them 1")
269 self.PWM_l.put(-new_left_pwm)
270 self.PWM_r.put(-new_right_pwm)
271 elif new_left_pwm < 0 and new_right_pwm > 0:
272 # Left negative, right positive
273 #print("Flipping them 2")
274 self.PWM_l.put(-new_left_pwm)
275 self.PWM_r.put(-new_right_pwm)
276 elif new_left_pwm != 0 and new_right_pwm == 0:
277 # Left non zero, right zero
278 #print("Flipping them 3")
279 self.PWM_l.put(-new_left_pwm)
280 self.PWM_r.put(0)
281 elif new_left_pwm == 0 and new_right_pwm != 0:
282 # Left zero, right non zero
283 #print("Flipping them 4")
284 self.PWM_l.put(0)
285 self.PWM_r.put(new_right_pwm)
286 # print(f"new_right after filter {self.PWM_l.get()}")
287 # self.PWM_l.put(self.controller_left.pi_Control(self.velocity_l.get(), self.enc_L.get_dt()))
288 #self.PWM_l.put(0)
289 # print(f"Left PWM{self.PWM_l.get()}")
290 #print(self.PWM_l.get())
291 #print(f"Left V: {self.velocity_l.get()}")
292 #print(f"Right V: {self.velocity_r.get()}")
293 #print(f"Left Reference {self.enc_L.get_dt()}")
294 #print(f"Right Reference {self.enc_R.get_dt()}")
295 #print(f"Left Reference {self.controller_left.get_Ref()}")
296 #print(f"Right Reference {self.controller_right.get_Ref()}")
297 #print(self.velocity_l.get())
298 #print("Left Set Point")
299 #print(self.controller_left.get_Ref())
300 #self.PWM_r.put(self.controller_right.pi_Control(self.velocity_r.get(), self.enc_R.get_dt()))
301 #self.PWM_r.put(-50)
302 #print("Right PWM")
303 #print(self.PWM_r.get())
304
305 #Ask motors to update their PWM every task cycle
306 self.m_state_l.put(2)
307 self.m_state_r.put(2)
308
309 yield self.state
This file contains a class to create a control_task object which is compatible with the cotask schedu...
__init__(self, fwd_ref, arc_ref, piv_ref, c_state, my_controller_left, my_controller_right, position_l, velocity_l, position_r, velocity_r, PWM_l, PWM_r, encoder_Right, encoder_Left, m_state_l, m_state_r, centroid, line_controller, automatic_mode, line_sensor, need_Calibrate, real_yaw, centroid_goal, yaw_goal, controller_yaw)
run(self)
run is the generator that the cotask scheduler will run since our tasks are objects.