@@ -40,65 +40,82 @@ class _BaseServo: # pylint: disable-msg=too-few-public-methods
40
40
:param ~pulseio.PWMOut pwm_out: PWM output object.
41
41
:param int min_pulse: The minimum pulse length of the servo in microseconds.
42
42
:param int max_pulse: The maximum pulse length of the servo in microseconds."""
43
- def __init__ (self , pwm_out , * , min_pulse = 550 , max_pulse = 2400 ):
43
+ def __init__ (self , pwm_out , * , min_pulse = 750 , max_pulse = 2250 ):
44
44
self ._min_duty = int ((min_pulse * pwm_out .frequency ) / 1000000 * 0xffff )
45
45
max_duty = (max_pulse * pwm_out .frequency ) / 1000000 * 0xffff
46
46
self ._duty_range = int (max_duty - self ._min_duty )
47
47
self ._pwm_out = pwm_out
48
48
49
49
@property
50
- def _fraction (self ):
50
+ def fraction (self ):
51
+ """Pulse width expressed as fraction between 0.0 (`min_pulse`) and 1.0 (`max_pulse`).
52
+ For conventional servos, corresponds to the servo position as a fraction
53
+ of the actuation range.
54
+ """
51
55
return (self ._pwm_out .duty_cycle - self ._min_duty ) / self ._duty_range
52
56
53
- @_fraction .setter
54
- def _fraction (self , value ):
55
- """The fraction of pulse high."""
57
+ @fraction .setter
58
+ def fraction (self , value ):
56
59
duty_cycle = self ._min_duty + int (value * self ._duty_range )
57
60
self ._pwm_out .duty_cycle = duty_cycle
58
61
59
62
class Servo (_BaseServo ):
60
63
"""Control the position of a servo.
61
64
62
65
:param ~pulseio.PWMOut pwm_out: PWM output object.
63
- :param int actuation_range: The physical range of the servo corresponding to the signal's
64
- duty in degrees.
65
- :param int min_pulse: The minimum pulse length of the servo in microseconds.
66
- :param int max_pulse: The maximum pulse length of the servo in microseconds."""
67
- def __init__ (self , pwm_out , * , actuation_range = 180 , min_pulse = 550 , max_pulse = 2400 ):
66
+ :param int actuation_range: The physical range of motion of the servo in degrees, \
67
+ for the given ``min_pulse`` and ``max_pulse`` values.
68
+ :param int min_pulse: The minimum pulse width of the servo in microseconds.
69
+ :param int max_pulse: The maximum pulse width of the servo in microseconds.
70
+
71
+ The specified pulse width range of a servo has historically been 1000-2000us,
72
+ for a 90 degree range of motion. But nearly all modern servos have a 170-180
73
+ degree range, and the pulse widths can go well out of the range to achieve this
74
+ extended motion. The default values here of ``750`` and ``2250`` typically give
75
+ 135 degrees of motion. You can set ``actuation_range`` to correspond to the
76
+ actual range of motion you observe with your given ``min_pulse`` and ``max_pulse``
77
+ values.
78
+
79
+ .. warning:: You can extend the pulse width above and below these limits to
80
+ get a wider range of movement. But if you go too low or too high,
81
+ the servo mechanism may hit the end stops, buzz, and draw extra current as it stalls.
82
+ Test carefully to find the safe minimum and maximum.
83
+ """
84
+ def __init__ (self , pwm_out , * , actuation_range = 180 , min_pulse = 750 , max_pulse = 2250 ):
68
85
super ().__init__ (pwm_out , min_pulse = min_pulse , max_pulse = max_pulse )
69
86
self ._actuation_range = actuation_range
70
87
self ._pwm = pwm_out
71
88
72
89
@property
73
90
def angle (self ):
74
- """The servo angle in degrees."""
75
- return self ._actuation_range * self ._fraction
91
+ """The servo angle in degrees. Must be in the range ``0`` to ``actuation_range``. """
92
+ return self ._actuation_range * self .fraction
76
93
77
94
@angle .setter
78
95
def angle (self , new_angle ):
79
96
if new_angle < 0 or new_angle > self ._actuation_range :
80
97
raise ValueError ("Angle out of range" )
81
- self ._fraction = new_angle / self ._actuation_range
98
+ self .fraction = new_angle / self ._actuation_range
82
99
83
100
class ContinuousServo (_BaseServo ):
84
101
"""Control a continuous rotation servo.
85
102
86
- :param int min_pulse: The minimum pulse length of the servo in microseconds.
87
- :param int max_pulse: The maximum pulse length of the servo in microseconds."""
103
+ :param int min_pulse: The minimum pulse width of the servo in microseconds.
104
+ :param int max_pulse: The maximum pulse width of the servo in microseconds."""
88
105
@property
89
106
def throttle (self ):
90
107
"""How much power is being delivered to the motor. Values range from ``-1.0`` (full
91
108
throttle reverse) to ``1.0`` (full throttle forwards.) ``0`` will stop the motor from
92
109
spinning."""
93
- return self ._fraction * 2 - 1
110
+ return self .fraction * 2 - 1
94
111
95
112
@throttle .setter
96
113
def throttle (self , value ):
97
114
if value > 1.0 or value < - 1.0 :
98
115
raise ValueError ("Throttle must be between -1.0 and 1.0" )
99
116
if value is None :
100
117
raise ValueError ("Continuous servos cannot spin freely" )
101
- self ._fraction = (value + 1 ) / 2
118
+ self .fraction = (value + 1 ) / 2
102
119
103
120
def __enter__ (self ):
104
121
return self
0 commit comments