Skip to content

Commit 87579f9

Browse files
committed
wip #64
1 parent 6913141 commit 87579f9

File tree

1 file changed

+185
-91
lines changed

1 file changed

+185
-91
lines changed

coderbot.py

Lines changed: 185 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import config
2525
import logging
2626
import sonar
27-
2827
import mpu
2928

3029
PIN_MOTOR_ENABLE = 22
@@ -47,17 +46,14 @@
4746
PWM_FREQUENCY = 100 #Hz
4847
PWM_RANGE = 100 #0-100
4948

50-
def coderbot_callback(gpio, level, tick):
51-
return CoderBot.get_instance().callback(gpio, level, tick)
52-
5349
class CoderBot(object):
5450
_pin_out = [PIN_MOTOR_ENABLE, PIN_LEFT_FORWARD, PIN_RIGHT_FORWARD, PIN_LEFT_BACKWARD, PIN_RIGHT_BACKWARD, PIN_SERVO_3, PIN_SERVO_4]
5551

5652
def __init__(self, servo=False, motor_trim_factor=1.0):
5753
self.pi = pigpio.pi('localhost')
5854
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)
6157
self._cb = dict()
6258
self._cb_last_tick = dict()
6359
self._cb_elapse = dict()
@@ -66,38 +62,40 @@ def __init__(self, servo=False, motor_trim_factor=1.0):
6662
if self._servo:
6763
self.motor_control = self._servo_motor
6864
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)
7369
for pin in self._pin_out:
7470
self.pi.set_PWM_frequency(pin, PWM_FREQUENCY)
7571
self.pi.set_PWM_range(pin, PWM_RANGE)
7672

77-
self.stop()
78-
self._is_moving = False
7973
self.sonar = [sonar.Sonar(self.pi, PIN_SONAR_1_TRIGGER, PIN_SONAR_1_ECHO),
8074
sonar.Sonar(self.pi, PIN_SONAR_2_TRIGGER, PIN_SONAR_2_ECHO),
8175
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)
9086
try:
9187
self._ag = mpu.AccelGyro()
9288
except IOError:
9389
logging.info("MPU not available")
90+
91+
self.stop()
92+
self._is_moving = False
9493

9594
the_bot = None
9695

9796
def exit(self):
9897
self._cb1.cancel()
99-
self._cb2.cancel()
100-
self._cb3.cancel()
98+
self._twin_motors_enc.exit()
10199
for s in self.sonar:
102100
s.cancel()
103101

@@ -148,7 +146,10 @@ def servo4(self, angle):
148146
def get_sonar_distance(self, sonar_id=0):
149147
return self.sonar[sonar_id].get_distance()
150148

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):
152153
self._encoder_cur_left = 0
153154
self._encoder_cur_right = 0
154155
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
161162
self._encoder_motor_stopping_right = False
162163
self._encoder_motor_stopped_left = False
163164
self._encoder_motor_stopped_right = False
165+
self._motor_current_power_left = speed_left
166+
self._motor_current_power_right = speed_right
164167
if steps_left >= 0 or steps_right >= 0:
165168
self._encoder_sem.acquire()
166169

@@ -221,8 +224,9 @@ def _servo_control(self, pin, angle):
221224
self.pi.set_PWM_dutycycle(pin, duty)
222225

223226
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)
226230
self._is_moving = False
227231

228232
def is_moving(self):
@@ -233,73 +237,163 @@ def set_callback(self, gpio, callback, elapse):
233237
self._cb[gpio] = callback
234238
self._cb_last_tick[gpio] = 0
235239

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))
274302
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()
303397

304398
def halt(self):
305399
os.system('sudo halt')

0 commit comments

Comments
 (0)