-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathServo.py
138 lines (106 loc) · 4.76 KB
/
Servo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python
"""
A servo is for switching some tools on/off. This one is for Replicape.
Author: Mathieu Monney
email: zittix(at)xwaves(dot)net
Website: http://www.xwaves.net
License: GNU GPL v3: http://www.gnu.org/copyleft/gpl.html
Redeem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Redeem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Redeem. If not, see <http://www.gnu.org/licenses/>.
"""
from threading import Thread
import time
import math
import Queue
from multiprocessing import JoinableQueue
import logging
from PWM_pin import PWM_pin
from ShiftRegister import ShiftRegister
class Servo:
def __init__(self, channel, pulse_width_start, pulse_width_stop, init_angle, turnoff_timeout=0):
"""Define a new software controllable servo with adjustable speed control
Keyword arguments:
pulse_width_start -- The minimum pulse width defining the lowest angle
pulse_width_stop -- The maximum pulse width defining the biggest angle
init_angle -- Initial angle that the servo should take when it is powered on. Range is 0 to 180deg
turnoff_timeout -- number of seconds after which the servo is turned off if no command is received. 0 = never turns off
"""
self.pulse_width_start = pulse_width_start
self.pulse_width_stop = pulse_width_stop
self.turnoff_timeout = turnoff_timeout
self.current_pulse_width = init_angle*(self.pulse_width_stop-self.pulse_width_start)/180.0+self.pulse_width_start
self.last_pulse_width = self.current_pulse_width
self.queue = JoinableQueue(1000)
self.lastCommandTime = 0
self.t = Thread(target=self._wait_for_event)
self.t.daemon = True
self.running = True
self.t.start()
self.pwm = PWM_pin(channel, 100, self.current_pulse_width)
# Set up the Shift register for enabling this servo
if channel == "P9_14":
shiftreg_nr = 3
elif channel == "P9_16":
shiftreg_nr = 2
else:
logging.warning("Tried to assign servo to an unknown channel/pin: "+str(channel))
return
ShiftRegister.make()
self.shift_reg = ShiftRegister.registers[shiftreg_nr]
self.set_enabled()
def set_enabled(self, is_enabled=True):
if is_enabled:
self.shift_reg.add_state(0x01)
else:
self.shift_reg.remove_state(0x01)
def set_angle(self, angle, speed=60, asynchronous=True):
''' Set the servo angle to the given value, in degree, with the given speed in deg / sec '''
pulse_width = angle*(self.pulse_width_stop-self.pulse_width_start)/180.0+self.pulse_width_start
last_angle = (self.last_pulse_width-self.pulse_width_start)/float(self.pulse_width_stop-self.pulse_width_start)*180.0
t = (math.fabs(angle-last_angle)/speed) / math.fabs(angle-last_angle)
for w in xrange(int(self.last_pulse_width*1000), int(pulse_width*1000), (1 if pulse_width>=self.last_pulse_width else -1)):
self.queue.put((w/1000.0,t))
self.last_pulse_width = pulse_width
if not asynchronous:
self.queue.join()
def turn_off(self):
self.pwm.set_enabled(False)
def stop(self):
self.running = False
self.t.join()
self.turn_off()
def _wait_for_event(self):
while self.running:
try:
ev = self.queue.get(block=True, timeout=1)
except Queue.Empty:
if self.turnoff_timeout>0 and self.lastCommandTime>0 and time.time()-self.lastCommandTime>self.turnoff_timeout:
self.lastCommandTime = 0
self.turn_off()
continue
except Exception:
# To avoid exception printed on output
pass
self.current_pulse_width = ev[0]
self.pwm.set_value(self.current_pulse_width)
self.lastCommandTime = time.time()
time.sleep(ev[1])
self.queue.task_done()
if __name__ == '__main__':
servo_0 = Servo("P9_14", 0.1, 0.2, 90)
servo_1 = Servo("P9_16", 0.1, 0.2, 90)
while True:
for i in range(1, 180):
servo_0.set_angle(i)
servo_1.set_angle(i)
for i in range(180, 1, -1):
servo_0.set_angle(i)
servo_1.set_angle(i)