24
24
import config
25
25
import logging
26
26
import sonar
27
-
28
27
import mpu
29
28
30
29
PIN_MOTOR_ENABLE = 22
47
46
PWM_FREQUENCY = 100 #Hz
48
47
PWM_RANGE = 100 #0-100
49
48
50
- def coderbot_callback (gpio , level , tick ):
51
- return CoderBot .get_instance ().callback (gpio , level , tick )
52
-
53
49
class CoderBot (object ):
54
50
_pin_out = [PIN_MOTOR_ENABLE , PIN_LEFT_FORWARD , PIN_RIGHT_FORWARD , PIN_LEFT_BACKWARD , PIN_RIGHT_BACKWARD , PIN_SERVO_3 , PIN_SERVO_4 ]
55
51
56
52
def __init__ (self , servo = False , motor_trim_factor = 1.0 ):
57
53
self .pi = pigpio .pi ('localhost' )
58
54
self .pi .set_mode (PIN_PUSHBUTTON , pigpio .INPUT )
59
- self .pi .set_mode (PIN_ENCODER_LEFT , pigpio .INPUT )
60
- self .pi .set_mode (PIN_ENCODER_RIGHT , pigpio .INPUT )
55
+ # self.pi.set_mode(PIN_ENCODER_LEFT, pigpio.INPUT)
56
+ # self.pi.set_mode(PIN_ENCODER_RIGHT, pigpio.INPUT)
61
57
self ._cb = dict ()
62
58
self ._cb_last_tick = dict ()
63
59
self ._cb_elapse = dict ()
@@ -66,38 +62,40 @@ def __init__(self, servo=False, motor_trim_factor=1.0):
66
62
if self ._servo :
67
63
self .motor_control = self ._servo_motor
68
64
else :
69
- self .motor_control = self ._dc_motor
70
- self ._cb1 = self .pi .callback (PIN_PUSHBUTTON , pigpio .EITHER_EDGE , coderbot_callback )
71
- self ._cb2 = self .pi .callback (PIN_ENCODER_LEFT , pigpio .RISING_EDGE , coderbot_callback )
72
- self ._cb3 = self .pi .callback (PIN_ENCODER_RIGHT , pigpio .RISING_EDGE , coderbot_callback )
65
+ self .motor_control = self ._dc_enc_motor
66
+ self ._cb1 = self .pi .callback (PIN_PUSHBUTTON , pigpio .EITHER_EDGE , self . _cb_button )
67
+ # self._cb2 = self.pi.callback(PIN_ENCODER_LEFT, pigpio.RISING_EDGE, self._cb_enc_left )
68
+ # self._cb3 = self.pi.callback(PIN_ENCODER_RIGHT, pigpio.RISING_EDGE, self._cb_enc_right )
73
69
for pin in self ._pin_out :
74
70
self .pi .set_PWM_frequency (pin , PWM_FREQUENCY )
75
71
self .pi .set_PWM_range (pin , PWM_RANGE )
76
72
77
- self .stop ()
78
- self ._is_moving = False
79
73
self .sonar = [sonar .Sonar (self .pi , PIN_SONAR_1_TRIGGER , PIN_SONAR_1_ECHO ),
80
74
sonar .Sonar (self .pi , PIN_SONAR_2_TRIGGER , PIN_SONAR_2_ECHO ),
81
75
sonar .Sonar (self .pi , PIN_SONAR_3_TRIGGER , PIN_SONAR_3_ECHO )]
82
- self ._encoder_cur_left = 0
83
- self ._encoder_cur_right = 0
84
- self ._encoder_target_left = - 1
85
- self ._encoder_target_right = - 1
86
- self ._encoder_k_s_1 = 20
87
- self ._encoder_k_v_1 = 80
88
- self ._encoder_sem = threading .Condition ()
89
-
76
+
77
+ self ._twin_motors_enc = self .TwinMotorsEncoder (
78
+ self .pi ,
79
+ pin_enable = PIN_MOTOR_ENABLE ,
80
+ pin_forward_left = PIN_LEFT_FORWARD ,
81
+ pin_backward_left = PIN_LEFT_BACKWARD ,
82
+ pin_encoder_left = PIN_ENCODER_LEFT ,
83
+ pin_forward_right = PIN_RIGHT_FORWARD ,
84
+ pin_backward_right = PIN_RIGHT_BACKWARD ,
85
+ pin_encoder_right = PIN_ENCODER_RIGHT )
90
86
try :
91
87
self ._ag = mpu .AccelGyro ()
92
88
except IOError :
93
89
logging .info ("MPU not available" )
90
+
91
+ self .stop ()
92
+ self ._is_moving = False
94
93
95
94
the_bot = None
96
95
97
96
def exit (self ):
98
97
self ._cb1 .cancel ()
99
- self ._cb2 .cancel ()
100
- self ._cb3 .cancel ()
98
+ self ._twin_motors_enc .exit ()
101
99
for s in self .sonar :
102
100
s .cancel ()
103
101
@@ -148,7 +146,10 @@ def servo4(self, angle):
148
146
def get_sonar_distance (self , sonar_id = 0 ):
149
147
return self .sonar [sonar_id ].get_distance ()
150
148
151
- def _dc_motor (self , speed_left = 100 , speed_right = 100 , elapse = - 1 , steps_left = - 1 , steps_right = - 1 ):
149
+ def _dc_enc_motor (self , speed_left = 100 , speed_right = 100 , elapse = - 1 , steps_left = - 1 , steps_right = - 1 ):
150
+ self ._twin_motors_enc .control (power_left = speed_left , power_right = speed_right , elapse = elapse , speed_left = speed_left , speed_right = speed_right , steps_left = steps_left , steps_right = steps_right )
151
+
152
+ def _dc_motor (self , speed_left = 100 , speed_right = 100 , elapse = - 1 , steps_left = - 1 , steps_right = - 1 ):
152
153
self ._encoder_cur_left = 0
153
154
self ._encoder_cur_right = 0
154
155
self ._encoder_target_left = steps_left
@@ -161,6 +162,8 @@ def _dc_motor(self, speed_left=100, speed_right=100, elapse=-1, steps_left=-1, s
161
162
self ._encoder_motor_stopping_right = False
162
163
self ._encoder_motor_stopped_left = False
163
164
self ._encoder_motor_stopped_right = False
165
+ self ._motor_current_power_left = speed_left
166
+ self ._motor_current_power_right = speed_right
164
167
if steps_left >= 0 or steps_right >= 0 :
165
168
self ._encoder_sem .acquire ()
166
169
@@ -221,8 +224,9 @@ def _servo_control(self, pin, angle):
221
224
self .pi .set_PWM_dutycycle (pin , duty )
222
225
223
226
def stop (self ):
224
- for pin in self ._pin_out :
225
- self .pi .write (pin , 0 )
227
+ self ._twin_motors_enc .stop ()
228
+ #for pin in self._pin_out:
229
+ # self.pi.write(pin, 0)
226
230
self ._is_moving = False
227
231
228
232
def is_moving (self ):
@@ -233,73 +237,163 @@ def set_callback(self, gpio, callback, elapse):
233
237
self ._cb [gpio ] = callback
234
238
self ._cb_last_tick [gpio ] = 0
235
239
236
- def callback (self , gpio , level , tick ):
237
- if gpio == PIN_ENCODER_LEFT and self ._encoder_target_left >= 0 :
238
- self ._encoder_cur_left += 1
239
- delta_ticks_left = tick - self ._encoder_last_tick_time_left if tick > self ._encoder_last_tick_time_left else tick - self ._encoder_last_tick_time_left + 4294967295
240
- self ._encoder_last_tick_time_left = tick
241
- self ._encoder_speed_left = 1000000.0 / delta_ticks_left #convert speed in steps per second
242
- delta_s = self ._encoder_speed_left / self ._encoder_k_s_1 #delta_s is the delta (in steps)before the target to reverse the motor in order to arrive at target
243
- if (self ._encoder_cur_left >= self ._encoder_target_left - delta_s and
244
- not self ._encoder_motor_stopping_left ):
245
- self ._encoder_motor_stopping_left = True
246
- if self ._encoder_dir_left > 0 :
247
- self .pi .write (PIN_LEFT_FORWARD , 0 )
248
- self .pi .set_PWM_dutycycle (PIN_LEFT_BACKWARD , 100 )
249
- else :
250
- self .pi .set_PWM_dutycycle (PIN_LEFT_FORWARD , 100 )
251
- self .pi .write (PIN_LEFT_BACKWARD , 0 )
252
- elif (self ._encoder_motor_stopped_left == False and
253
- ((self ._encoder_motor_stopping_left and
254
- self ._encoder_speed_left < self ._encoder_k_v_1 ) or
255
- (self ._encoder_motor_stopping_left and
256
- self ._encoder_cur_left >= self ._encoder_target_left ))):
257
- self .pi .write (PIN_LEFT_FORWARD , 0 )
258
- self .pi .write (PIN_LEFT_BACKWARD , 0 )
259
- self ._encoder_motor_stopped_left = True
260
- self ._encoder_check_stopped_and_notify ()
261
- logging .info ( "LEFT: " + str (self ._encoder_cur_left ) + " speed: " + str (self ._encoder_speed_left ))
262
- elif gpio == PIN_ENCODER_RIGHT and self ._encoder_target_right >= 0 :
263
- self ._encoder_cur_right += 1
264
- delta_ticks_right = tick - self ._encoder_last_tick_time_right if tick > self ._encoder_last_tick_time_right else tick - self ._encoder_last_tick_time_right + 4294967295
265
- self ._encoder_last_tick_time_right = tick
266
- self ._encoder_speed_right = 1000000.0 / delta_ticks_right #convert speed in steps per second
267
- delta_s = self ._encoder_speed_right / self ._encoder_k_s_1 #delta_s is the delta (in steps)before the target to reverse the motor in order to arrive at target
268
- if (self ._encoder_cur_right >= self ._encoder_target_right - delta_s and
269
- not self ._encoder_motor_stopping_right ):
270
- self ._encoder_motor_stopping_right = True
271
- if self ._encoder_dir_right > 0 :
272
- self .pi .write (PIN_RIGHT_FORWARD , 0 )
273
- self .pi .set_PWM_dutycycle (PIN_RIGHT_BACKWARD , 100 )
240
+ def _cb_button (self , gpio , level , tick ):
241
+ cb = self ._cb .get (gpio )
242
+ if cb :
243
+ elapse = self ._cb_elapse .get (gpio )
244
+ if level == 0 :
245
+ self ._cb_last_tick [gpio ] = tick
246
+ elif tick - self ._cb_last_tick [gpio ] > elapse :
247
+ self ._cb_last_tick [gpio ] = tick
248
+ logging .info ( "pushed: " , level , tick )
249
+ cb ()
250
+
251
+ class MotorEncoder (object ):
252
+ def __init__ (self , parent , _pigpio , pin_enable , pin_forward , pin_backward , pin_encoder ):
253
+ self ._parent = parent
254
+ self ._pigpio = _pigpio
255
+ self ._pin_enable = pin_enable
256
+ self ._pin_forward = pin_forward
257
+ self ._pin_backward = pin_backward
258
+ self ._pin_encoder = pin_encoder
259
+ self ._direction = False
260
+ self ._pin_duty = 0
261
+ self ._pin_reverse = 0
262
+ self ._power = 0.0
263
+ self ._encoder_dist = 0
264
+ self ._encoder_speed = 0.0
265
+ self ._encoder_last_tick = 0
266
+ self ._encoder_dist_target = 0
267
+ self ._encoder_speed_target = 0.0
268
+ self ._encoder_k_s_1 = 20
269
+ self ._encoder_k_v_1 = 80
270
+ self ._motor_stopping = False
271
+ self ._motor_running = False
272
+ self ._pigpio .set_mode (self ._pin_encoder , pigpio .INPUT )
273
+ self ._cb = self ._pigpio .callback (self ._pin_encoder , pigpio .RISING_EDGE , self ._cb_encoder )
274
+
275
+ def exit (self ):
276
+ self ._cb .cancel ()
277
+
278
+ def _cb_encoder (self , gpio , level , tick ):
279
+ self ._encoder_dist += 1
280
+ delta_ticks = tick - self ._encoder_last_tick if tick > self ._encoder_last_tick else tick - self ._encoder_last_tick + 4294967295
281
+ self ._encoder_last_tick = tick
282
+ self ._encoder_speed = 1000000.0 / delta_ticks #convert speed in steps per second
283
+ #print "speed: " + str(self._encoder_speed)
284
+ if self ._encoder_dist_target >= 0 :
285
+ delta_s = max (min (self ._encoder_speed / self ._encoder_k_s_1 , 70 ),0 ) #delta_s is the delta (in steps)before the target to reverse the motor in order to arrive at target
286
+ #print "pin: " + str(self._pin_forward) + " dist: " + str(self._encoder_dist) + " target: " + str(self._encoder_dist_target) + " delta_s: " + str(delta_s)
287
+ if (self ._encoder_dist >= self ._encoder_dist_target - delta_s and
288
+ not self ._motor_stopping and self ._motor_running ):
289
+ self ._motor_stopping = True
290
+ self ._pigpio .write (self ._pin_duty , 0 )
291
+ self ._pigpio .set_PWM_dutycycle (self ._pin_reverse , self ._power )
292
+ #print "stopping"
293
+ elif (self ._motor_running and
294
+ ((self ._motor_stopping and
295
+ self ._encoder_speed < self ._encoder_k_v_1 ) or
296
+ (self ._motor_stopping and
297
+ self ._encoder_dist >= self ._encoder_dist_target ))):
298
+ self .stop ()
299
+ self ._parent ._check_complete ()
300
+ #print "stopped - pin: " + str(self._pin_forward) + " dist: " + str(self._encoder_dist) + " target: " + str(self._encoder_dist_target)
301
+ logging .info ( "dist: " + str (self ._encoder_dist ) + " speed: " + str (self ._encoder_speed ))
274
302
else :
275
- self .pi .set_PWM_dutycycle (PIN_RIGHT_FORWARD , 100 )
276
- self .pi .write (PIN_RIGHT_BACKWARD , 0 )
277
- elif (self ._encoder_motor_stopped_right == False and
278
- ((self ._encoder_motor_stopping_right and
279
- self ._encoder_speed_right < self ._encoder_k_v_1 ) or
280
- (self ._encoder_motor_stopping_right and
281
- self ._encoder_cur_right >= self ._encoder_target_right ))):
282
- self .pi .write (PIN_RIGHT_FORWARD , 0 )
283
- self .pi .write (PIN_RIGHT_BACKWARD , 0 )
284
- self ._encoder_motor_stopped_right = True
285
- self ._encoder_check_stopped_and_notify ()
286
- logging .info ("RIGHT: " + str (self ._encoder_cur_right ) + " speed: " + str (self ._encoder_speed_right ))
287
- else :
288
- cb = self ._cb .get (gpio )
289
- if cb :
290
- elapse = self ._cb_elapse .get (gpio )
291
- if level == 0 :
292
- self ._cb_last_tick [gpio ] = tick
293
- elif tick - self ._cb_last_tick [gpio ] > elapse :
294
- self ._cb_last_tick [gpio ] = tick
295
- logging .info ( "pushed: " , level , tick )
296
- cb ()
297
-
298
- def _encoder_check_stopped_and_notify (self ):
299
- if self ._encoder_motor_stopped_left and self ._encoder_motor_stopped_right :
300
- self ._encoder_sem .acquire ()
301
- self ._encoder_sem .notify ()
302
- self ._encoder_sem .release ()
303
+ self ._parent ._cb_encoder (self , gpio , level , tick )
304
+
305
+ def control (self , power = 100.0 , elapse = - 1 , speed = 100.0 , steps = - 1 ):
306
+ self ._direction = speed > 0
307
+ self ._encoder_dist_target = steps
308
+ self ._motor_stopping = False
309
+ self ._motor_running = True
310
+ self ._encoder_dist = 0
311
+ self ._encoder_speed_target = abs (speed )
312
+ self ._power = abs (power ) #TODO: initial power must be a function of desired speed
313
+ self ._pin_duty = self ._pin_forward if self ._direction else self ._pin_backward
314
+ self ._pin_reverse = self ._pin_backward if self ._direction else self ._pin_forward
315
+ self ._pigpio .write (self ._pin_reverse , 0 )
316
+ self ._pigpio .set_PWM_dutycycle (self ._pin_duty , self ._power )
317
+ self ._pigpio .write (self ._pin_enable , True )
318
+ if elapse > 0 :
319
+ time .sleep (elapse )
320
+ self .stop ()
321
+
322
+ def stop (self ):
323
+ self ._motor_stopping = False
324
+ self ._motor_running = False
325
+ self ._pigpio .write (self ._pin_forward , 0 )
326
+ self ._pigpio .write (self ._pin_backward , 0 )
327
+
328
+ def distance (self ):
329
+ return self ._encoder_dist
330
+
331
+ def speed (self ):
332
+ return self ._encoder_speed
333
+
334
+ def stopping (self ):
335
+ return self ._motor_stopping
336
+
337
+ def running (self ):
338
+ return self ._motor_running
339
+
340
+ def adjust_power (self , power_delta ):
341
+ power = min (max (self ._power + power_delta , 0 ), 100 )
342
+ self ._pigpio .set_PWM_dutycycle (self ._pin_duty , power )
343
+
344
+ class TwinMotorsEncoder (object ):
345
+ def __init__ (self , pigpio , pin_enable , pin_forward_left , pin_backward_left , pin_encoder_left , pin_forward_right , pin_backward_right , pin_encoder_right ):
346
+ self ._motor_left = CoderBot .MotorEncoder (self , pigpio , pin_enable , pin_forward_left , pin_backward_left , pin_encoder_left )
347
+ self ._motor_right = CoderBot .MotorEncoder (self , pigpio , pin_enable , pin_forward_right , pin_backward_right , pin_encoder_right )
348
+ self ._straight = False
349
+ self ._running = False
350
+ self ._encoder_sem = threading .Condition ()
351
+
352
+ def exit (self ):
353
+ self ._motor_left .exit ()
354
+ self ._motor_right .exit ()
355
+
356
+ def control (self , power_left = 100.0 , power_right = 100.0 , elapse = - 1 , speed_left = - 1 , speed_right = - 1 , steps_left = - 1 , steps_right = - 1 ):
357
+ self ._straight = power_left == power_right and speed_left == speed_right and steps_left == steps_right
358
+
359
+ if steps_left >= 0 or steps_right >= 0 :
360
+ self ._encoder_sem .acquire ()
361
+
362
+ self ._motor_left .control (power = power_left , elapse = - 1 , speed = speed_left , steps = steps_left )
363
+ self ._motor_right .control (power = power_right , elapse = - 1 , speed = speed_right , steps = steps_right )
364
+ self ._running = True
365
+
366
+ if elapse > 0 :
367
+ time .sleep (elapse )
368
+ self .stop ()
369
+
370
+ if steps_left >= 0 or steps_right >= 0 :
371
+ self ._encoder_sem .wait ()
372
+ self ._encoder_sem .release ()
373
+ self .stop ()
374
+
375
+ def stop (self ):
376
+ self ._motor_left .stop ()
377
+ self ._motor_right .stop ()
378
+ self ._running = False
379
+
380
+ def _cb_encoder (self , motor , gpio , level , tick ):
381
+ if (self ._straight and self ._running and not self ._motor_left .stopping () and not self ._motor_right .stopping () and
382
+ abs (self ._motor_left .distance () - self ._motor_right .distance ()) > 2 ):
383
+ distance_delta = self ._motor_left .distance () - self ._motor_right .distance ()
384
+ speed_delta = self ._motor_left .speed () - self ._motor_right .speed ()
385
+ power_delta = (distance_delta / 2.0 ) + (speed_delta / 10.0 )
386
+ #print "power_delta: " + str(power_delta) + " distance_delta: " + str(distance_delta) + " speed_delta: " + str(speed_delta)
387
+ if self ._motor_left == motor :
388
+ self ._motor_left .adjust_power (- power_delta )
389
+ if self ._motor_right == motor :
390
+ self ._motor_right .adjust_power (power_delta )
391
+
392
+ def _check_complete (self ):
393
+ if self ._motor_left .running () == False and self ._motor_right .running () == False :
394
+ self ._encoder_sem .acquire ()
395
+ self ._encoder_sem .notify ()
396
+ self ._encoder_sem .release ()
303
397
304
398
def halt (self ):
305
399
os .system ('sudo halt' )
0 commit comments