3131import select
3232import time
3333from os .path import abspath
34- from ev3dev import get_current_platform , Device
34+ from ev3dev import get_current_platform , Device , list_device_names
3535
3636# The number of milliseconds we wait for the state of a motor to
3737# update to 'running' in the "on_for_XYZ" methods of the Motor class
5656elif platform == 'brickpi3' :
5757 from ev3dev ._platform .brickpi3 import OUTPUT_A , OUTPUT_B , OUTPUT_C , OUTPUT_D
5858
59+ elif platform == 'fake' :
60+ from ev3dev ._platform .fake import OUTPUT_A , OUTPUT_B , OUTPUT_C , OUTPUT_D
61+
5962else :
6063 raise Exception ("Unsupported platform '%s'" % platform )
6164
@@ -77,6 +80,110 @@ class Motor(Device):
7780 SYSTEM_CLASS_NAME = 'tacho-motor'
7881 SYSTEM_DEVICE_NAME_CONVENTION = '*'
7982
83+ __slots__ = [
84+ '_address' ,
85+ '_command' ,
86+ '_commands' ,
87+ '_count_per_rot' ,
88+ '_count_per_m' ,
89+ '_driver_name' ,
90+ '_duty_cycle' ,
91+ '_duty_cycle_sp' ,
92+ '_full_travel_count' ,
93+ '_polarity' ,
94+ '_position' ,
95+ '_position_p' ,
96+ '_position_i' ,
97+ '_position_d' ,
98+ '_position_sp' ,
99+ '_max_speed' ,
100+ '_speed' ,
101+ '_speed_sp' ,
102+ '_ramp_up_sp' ,
103+ '_ramp_down_sp' ,
104+ '_speed_p' ,
105+ '_speed_i' ,
106+ '_speed_d' ,
107+ '_state' ,
108+ '_stop_action' ,
109+ '_stop_actions' ,
110+ '_time_sp' ,
111+ '_poll' ,
112+ ]
113+
114+ #: Run the motor until another command is sent.
115+ COMMAND_RUN_FOREVER = 'run-forever'
116+
117+ #: Run to an absolute position specified by `position_sp` and then
118+ #: stop using the action specified in `stop_action`.
119+ COMMAND_RUN_TO_ABS_POS = 'run-to-abs-pos'
120+
121+ #: Run to a position relative to the current `position` value.
122+ #: The new position will be current `position` + `position_sp`.
123+ #: When the new position is reached, the motor will stop using
124+ #: the action specified by `stop_action`.
125+ COMMAND_RUN_TO_REL_POS = 'run-to-rel-pos'
126+
127+ #: Run the motor for the amount of time specified in `time_sp`
128+ #: and then stop the motor using the action specified by `stop_action`.
129+ COMMAND_RUN_TIMED = 'run-timed'
130+
131+ #: Run the motor at the duty cycle specified by `duty_cycle_sp`.
132+ #: Unlike other run commands, changing `duty_cycle_sp` while running *will*
133+ #: take effect immediately.
134+ COMMAND_RUN_DIRECT = 'run-direct'
135+
136+ #: Stop any of the run commands before they are complete using the
137+ #: action specified by `stop_action`.
138+ COMMAND_STOP = 'stop'
139+
140+ #: Reset all of the motor parameter attributes to their default value.
141+ #: This will also have the effect of stopping the motor.
142+ COMMAND_RESET = 'reset'
143+
144+ #: Sets the normal polarity of the rotary encoder.
145+ ENCODER_POLARITY_NORMAL = 'normal'
146+
147+ #: Sets the inversed polarity of the rotary encoder.
148+ ENCODER_POLARITY_INVERSED = 'inversed'
149+
150+ #: With `normal` polarity, a positive duty cycle will
151+ #: cause the motor to rotate clockwise.
152+ POLARITY_NORMAL = 'normal'
153+
154+ #: With `inversed` polarity, a positive duty cycle will
155+ #: cause the motor to rotate counter-clockwise.
156+ POLARITY_INVERSED = 'inversed'
157+
158+ #: Power is being sent to the motor.
159+ STATE_RUNNING = 'running'
160+
161+ #: The motor is ramping up or down and has not yet reached a constant output level.
162+ STATE_RAMPING = 'ramping'
163+
164+ #: The motor is not turning, but rather attempting to hold a fixed position.
165+ STATE_HOLDING = 'holding'
166+
167+ #: The motor is turning, but cannot reach its `speed_sp`.
168+ STATE_OVERLOADED = 'overloaded'
169+
170+ #: The motor is not turning when it should be.
171+ STATE_STALLED = 'stalled'
172+
173+ #: Power will be removed from the motor and it will freely coast to a stop.
174+ STOP_ACTION_COAST = 'coast'
175+
176+ #: Power will be removed from the motor and a passive electrical load will
177+ #: be placed on the motor. This is usually done by shorting the motor terminals
178+ #: together. This load will absorb the energy from the rotation of the motors and
179+ #: cause the motor to stop more quickly than coasting.
180+ STOP_ACTION_BRAKE = 'brake'
181+
182+ #: Does not remove power from the motor. Instead it actively try to hold the motor
183+ #: at the current position. If an external force tries to turn the motor, the motor
184+ #: will `push back` to maintain its position.
185+ STOP_ACTION_HOLD = 'hold'
186+
80187 def __init__ (self , address = None , name_pattern = SYSTEM_DEVICE_NAME_CONVENTION , name_exact = False , ** kwargs ):
81188
82189 if address is not None :
@@ -112,37 +219,6 @@ def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, nam
112219 self ._time_sp = None
113220 self ._poll = None
114221
115- __slots__ = [
116- '_address' ,
117- '_command' ,
118- '_commands' ,
119- '_count_per_rot' ,
120- '_count_per_m' ,
121- '_driver_name' ,
122- '_duty_cycle' ,
123- '_duty_cycle_sp' ,
124- '_full_travel_count' ,
125- '_polarity' ,
126- '_position' ,
127- '_position_p' ,
128- '_position_i' ,
129- '_position_d' ,
130- '_position_sp' ,
131- '_max_speed' ,
132- '_speed' ,
133- '_speed_sp' ,
134- '_ramp_up_sp' ,
135- '_ramp_down_sp' ,
136- '_speed_p' ,
137- '_speed_i' ,
138- '_speed_d' ,
139- '_state' ,
140- '_stop_action' ,
141- '_stop_actions' ,
142- '_time_sp' ,
143- '_poll' ,
144- ]
145-
146222 @property
147223 def address (self ):
148224 """
@@ -491,79 +567,6 @@ def time_sp(self):
491567 def time_sp (self , value ):
492568 self ._time_sp = self .set_attr_int (self ._time_sp , 'time_sp' , value )
493569
494- #: Run the motor until another command is sent.
495- COMMAND_RUN_FOREVER = 'run-forever'
496-
497- #: Run to an absolute position specified by `position_sp` and then
498- #: stop using the action specified in `stop_action`.
499- COMMAND_RUN_TO_ABS_POS = 'run-to-abs-pos'
500-
501- #: Run to a position relative to the current `position` value.
502- #: The new position will be current `position` + `position_sp`.
503- #: When the new position is reached, the motor will stop using
504- #: the action specified by `stop_action`.
505- COMMAND_RUN_TO_REL_POS = 'run-to-rel-pos'
506-
507- #: Run the motor for the amount of time specified in `time_sp`
508- #: and then stop the motor using the action specified by `stop_action`.
509- COMMAND_RUN_TIMED = 'run-timed'
510-
511- #: Run the motor at the duty cycle specified by `duty_cycle_sp`.
512- #: Unlike other run commands, changing `duty_cycle_sp` while running *will*
513- #: take effect immediately.
514- COMMAND_RUN_DIRECT = 'run-direct'
515-
516- #: Stop any of the run commands before they are complete using the
517- #: action specified by `stop_action`.
518- COMMAND_STOP = 'stop'
519-
520- #: Reset all of the motor parameter attributes to their default value.
521- #: This will also have the effect of stopping the motor.
522- COMMAND_RESET = 'reset'
523-
524- #: Sets the normal polarity of the rotary encoder.
525- ENCODER_POLARITY_NORMAL = 'normal'
526-
527- #: Sets the inversed polarity of the rotary encoder.
528- ENCODER_POLARITY_INVERSED = 'inversed'
529-
530- #: With `normal` polarity, a positive duty cycle will
531- #: cause the motor to rotate clockwise.
532- POLARITY_NORMAL = 'normal'
533-
534- #: With `inversed` polarity, a positive duty cycle will
535- #: cause the motor to rotate counter-clockwise.
536- POLARITY_INVERSED = 'inversed'
537-
538- #: Power is being sent to the motor.
539- STATE_RUNNING = 'running'
540-
541- #: The motor is ramping up or down and has not yet reached a constant output level.
542- STATE_RAMPING = 'ramping'
543-
544- #: The motor is not turning, but rather attempting to hold a fixed position.
545- STATE_HOLDING = 'holding'
546-
547- #: The motor is turning, but cannot reach its `speed_sp`.
548- STATE_OVERLOADED = 'overloaded'
549-
550- #: The motor is not turning when it should be.
551- STATE_STALLED = 'stalled'
552-
553- #: Power will be removed from the motor and it will freely coast to a stop.
554- STOP_ACTION_COAST = 'coast'
555-
556- #: Power will be removed from the motor and a passive electrical load will
557- #: be placed on the motor. This is usually done by shorting the motor terminals
558- #: together. This load will absorb the energy from the rotation of the motors and
559- #: cause the motor to stop more quickly than coasting.
560- STOP_ACTION_BRAKE = 'brake'
561-
562- #: Does not remove power from the motor. Instead it actively try to hold the motor
563- #: at the current position. If an external force tries to turn the motor, the motor
564- #: will `push back` to maintain its position.
565- STOP_ACTION_HOLD = 'hold'
566-
567570 def run_forever (self , ** kwargs ):
568571 """Run the motor until another command is sent.
569572 """
@@ -726,12 +729,20 @@ def wait_while(self, s, timeout=None):
726729 return self .wait (lambda state : s not in state , timeout )
727730
728731 def _set_position_rotations (self , speed_pct , rotations ):
732+
733+ # +/- speed is used to control direction, rotations must be positive
734+ assert rotations >= 0 , "rotations is %s, must be >= 0" % rotations
735+
729736 if speed_pct > 0 :
730737 self .position_sp = self .position + int (rotations * self .count_per_rot )
731738 else :
732739 self .position_sp = self .position - int (rotations * self .count_per_rot )
733740
734741 def _set_position_degrees (self , speed_pct , degrees ):
742+
743+ # +/- speed is used to control direction, degrees must be positive
744+ assert degrees >= 0 , "degrees is %s, must be >= 0" % degrees
745+
735746 if speed_pct > 0 :
736747 self .position_sp = self .position + int ((degrees * self .count_per_rot )/ 360 )
737748 else :
0 commit comments