Skip to content

Commit 1c9265d

Browse files
committed
Add support for new tacho drivers
- New motor instantiation code for linear motors - Add new motor parameter and motion unit tests - Eliminate speed_regulation_enabled attribute - Rename speed_regulation_[pid] to speed_[pid] - Remove API test for speed_regulation_enabled - Add count_per_m attribute - Add full_travel_count attribute - Add improved test cases for motor parameters Fixed bad merges into develop - Fixed input ports, now they work as an `address=INPUT_X` parameter when instancing new Devices. Fixes #128.
1 parent 0e3cedc commit 1c9265d

File tree

12 files changed

+1564
-62
lines changed

12 files changed

+1564
-62
lines changed

ev3dev-lang

ev3dev/brickpi.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@
3434
OUTPUT_C = 'ttyAMA0:outC'
3535
OUTPUT_D = 'ttyAMA0:outD'
3636

37-
INPUT_1 = 'ttyAMA0:in1'
38-
INPUT_2 = 'ttyAMA0:in2'
39-
INPUT_3 = 'ttyAMA0:in3'
40-
INPUT_4 = 'ttyAMA0:in4'
37+
INPUT_1 = 'in1'
38+
INPUT_2 = 'in2'
39+
INPUT_3 = 'in3'
40+
INPUT_4 = 'in4'
4141

4242

4343
class Leds(object):

ev3dev/core.py

Lines changed: 117 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
# -----------------------------------------------------------------------------
2525

2626
# ~autogen autogen-header
27-
# Sections of the following code were auto-generated based on spec v1.0.0
27+
# Sections of the following code were auto-generated based on spec v1.1.0
2828

2929
# ~autogen
3030

@@ -279,10 +279,15 @@ class Motor(Device):
279279
positional and directional feedback such as the EV3 and NXT motors.
280280
This feedback allows for precise control of the motors. This is the
281281
most common type of motor, so we just call it `motor`.
282+
283+
The way to configure a motor is to set the '_sp' attributes when
284+
calling a command or before. Only in 'run_direct' mode attribute
285+
changes are processed immediately, in the other modes they only
286+
take place when a new command is issued.
282287
"""
283288

284289
SYSTEM_CLASS_NAME = 'tacho-motor'
285-
SYSTEM_DEVICE_NAME_CONVENTION = 'motor*'
290+
SYSTEM_DEVICE_NAME_CONVENTION = '*'
286291

287292
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
288293
if address is not None:
@@ -343,11 +348,19 @@ def count_per_rot(self):
343348
"""
344349
Returns the number of tacho counts in one rotation of the motor. Tacho counts
345350
are used by the position and speed attributes, so you can use this value
346-
to convert rotations or degrees to tacho counts. In the case of linear
347-
actuators, the units here will be counts per centimeter.
351+
to convert rotations or degrees to tacho counts. (rotation motors only)
348352
"""
349353
return self.get_attr_int('count_per_rot')
350354

355+
@property
356+
def count_per_m(self):
357+
"""
358+
Returns the number of tacho counts in one meter of travel of the motor. Tacho
359+
counts are used by the position and speed attributes, so you can use this
360+
value to convert from distance to tacho counts. (linear motors only)
361+
"""
362+
return self.get_attr_int('count_per_m')
363+
351364
@property
352365
def driver_name(self):
353366
"""
@@ -368,8 +381,7 @@ def duty_cycle_sp(self):
368381
"""
369382
Writing sets the duty cycle setpoint. Reading returns the current value.
370383
Units are in percent. Valid values are -100 to 100. A negative value causes
371-
the motor to rotate in reverse. This value is only used when `speed_regulation`
372-
is off.
384+
the motor to rotate in reverse.
373385
"""
374386
return self.get_attr_int('duty_cycle_sp')
375387

@@ -392,6 +404,15 @@ def encoder_polarity(self):
392404
def encoder_polarity(self, value):
393405
self.set_attr_string('encoder_polarity', value)
394406

407+
@property
408+
def full_travel_count(self):
409+
"""
410+
Returns the number of tacho counts in the full travel of the motor. When
411+
combined with the `count_per_m` atribute, you can use this value to
412+
calculate the maximum travel distance of the motor. (linear motors only)
413+
"""
414+
return self.get_attr_int('full_travel_count')
415+
395416
@property
396417
def polarity(self):
397418
"""
@@ -467,6 +488,15 @@ def position_sp(self):
467488
def position_sp(self, value):
468489
self.set_attr_int('position_sp', value)
469490

491+
@property
492+
def max_speed(self):
493+
"""
494+
Returns the maximum value that is accepted by the `speed_sp` attribute. This
495+
may be slightly different than the maximum speed that a particular motor can
496+
reach - it's the maximum theoretical speed.
497+
"""
498+
return self.get_attr_int('max_speed')
499+
470500
@property
471501
def speed(self):
472502
"""
@@ -479,9 +509,12 @@ def speed(self):
479509
@property
480510
def speed_sp(self):
481511
"""
482-
Writing sets the target speed in tacho counts per second used when `speed_regulation`
483-
is on. Reading returns the current value. Use the `count_per_rot` attribute
484-
to convert RPM or deg/sec to tacho counts per second.
512+
Writing sets the target speed in tacho counts per second used for all `run-*`
513+
commands except `run-direct`. Reading returns the current value. A negative
514+
value causes the motor to rotate in reverse with the exception of `run-to-*-pos`
515+
commands where the sign is ignored. Use the `count_per_rot` attribute to convert
516+
RPM or deg/sec to tacho counts per second. Use the `count_per_m` attribute to
517+
convert m/s to tacho counts per second.
485518
"""
486519
return self.get_attr_int('speed_sp')
487520

@@ -493,10 +526,10 @@ def speed_sp(self, value):
493526
def ramp_up_sp(self):
494527
"""
495528
Writing sets the ramp up setpoint. Reading returns the current value. Units
496-
are in milliseconds. When set to a value > 0, the motor will ramp the power
497-
sent to the motor from 0 to 100% duty cycle over the span of this setpoint
498-
when starting the motor. If the maximum duty cycle is limited by `duty_cycle_sp`
499-
or speed regulation, the actual ramp time duration will be less than the setpoint.
529+
are in milliseconds and must be positive. When set to a non-zero value, the
530+
motor speed will increase from 0 to 100% of `max_speed` over the span of this
531+
setpoint. The actual ramp time is the ratio of the difference between the
532+
`speed_sp` and the current `speed` and max_speed multiplied by `ramp_up_sp`.
500533
"""
501534
return self.get_attr_int('ramp_up_sp')
502535

@@ -508,10 +541,10 @@ def ramp_up_sp(self, value):
508541
def ramp_down_sp(self):
509542
"""
510543
Writing sets the ramp down setpoint. Reading returns the current value. Units
511-
are in milliseconds. When set to a value > 0, the motor will ramp the power
512-
sent to the motor from 100% duty cycle down to 0 over the span of this setpoint
513-
when stopping the motor. If the starting duty cycle is less than 100%, the
514-
ramp time duration will be less than the full span of the setpoint.
544+
are in milliseconds and must be positive. When set to a non-zero value, the
545+
motor speed will decrease from 0 to 100% of `max_speed` over the span of this
546+
setpoint. The actual ramp time is the ratio of the difference between the
547+
`speed_sp` and the current `speed` and max_speed multiplied by `ramp_down_sp`.
515548
"""
516549
return self.get_attr_int('ramp_down_sp')
517550

@@ -520,51 +553,36 @@ def ramp_down_sp(self, value):
520553
self.set_attr_int('ramp_down_sp', value)
521554

522555
@property
523-
def speed_regulation_enabled(self):
524-
"""
525-
Turns speed regulation on or off. If speed regulation is on, the motor
526-
controller will vary the power supplied to the motor to try to maintain the
527-
speed specified in `speed_sp`. If speed regulation is off, the controller
528-
will use the power specified in `duty_cycle_sp`. Valid values are `on` and
529-
`off`.
530-
"""
531-
return self.get_attr_string('speed_regulation')
532-
533-
@speed_regulation_enabled.setter
534-
def speed_regulation_enabled(self, value):
535-
self.set_attr_string('speed_regulation', value)
536-
537-
@property
538-
def speed_regulation_p(self):
556+
def speed_p(self):
539557
"""
540558
The proportional constant for the speed regulation PID.
541559
"""
542560
return self.get_attr_int('speed_pid/Kp')
543561

544-
@speed_regulation_p.setter
545-
def speed_regulation_p(self, value):
562+
@speed_p.setter
563+
def speed_p(self, value):
546564
self.set_attr_int('speed_pid/Kp', value)
547565

548566
@property
549-
def speed_regulation_i(self):
567+
def speed_i(self):
550568
"""
551569
The integral constant for the speed regulation PID.
552570
"""
553571
return self.get_attr_int('speed_pid/Ki')
554572

555-
@speed_regulation_i.setter
556-
def speed_regulation_i(self, value):
573+
@speed_i.setter
574+
def speed_i(self, value):
557575
self.set_attr_int('speed_pid/Ki', value)
558576

559577
@property
560-
def speed_regulation_d(self):
578+
def speed_d(self):
561579
"""
562580
The derivative constant for the speed regulation PID.
563581
"""
564582
return self.get_attr_int('speed_pid/Kd')
565583

566-
@speed_regulation_d.setter
567-
def speed_regulation_d(self, value):
584+
@speed_d.setter
585+
def speed_d(self, value):
568586
self.set_attr_int('speed_pid/Kd', value)
569587

570588
@property
@@ -666,13 +684,6 @@ def time_sp(self, value):
666684
# cause the motor to rotate counter-clockwise.
667685
POLARITY_INVERSED = 'inversed'
668686

669-
# The motor controller will vary the power supplied to the motor
670-
# to try to maintain the speed specified in `speed_sp`.
671-
SPEED_REGULATION_ON = 'on'
672-
673-
# The motor controller will use the power specified in `duty_cycle_sp`.
674-
SPEED_REGULATION_OFF = 'off'
675-
676687
# Power will be removed from the motor and it will freely coast to a stop.
677688
STOP_COMMAND_COAST = 'coast'
678689

@@ -781,7 +792,7 @@ class LargeMotor(Motor):
781792
"""
782793

783794
SYSTEM_CLASS_NAME = Motor.SYSTEM_CLASS_NAME
784-
SYSTEM_DEVICE_NAME_CONVENTION = Motor.SYSTEM_DEVICE_NAME_CONVENTION
795+
SYSTEM_DEVICE_NAME_CONVENTION = 'motor*'
785796

786797
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
787798
if address is not None:
@@ -799,14 +810,68 @@ class MediumMotor(Motor):
799810
"""
800811

801812
SYSTEM_CLASS_NAME = Motor.SYSTEM_CLASS_NAME
802-
SYSTEM_DEVICE_NAME_CONVENTION = Motor.SYSTEM_DEVICE_NAME_CONVENTION
813+
SYSTEM_DEVICE_NAME_CONVENTION = 'motor*'
803814

804815
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
805816
if address is not None:
806817
kwargs['address'] = address
807818
Device.__init__(self, self.SYSTEM_CLASS_NAME, name_pattern, name_exact, driver_name=['lego-ev3-m-motor'], **kwargs)
808819

809820

821+
# ~autogen
822+
# ~autogen generic-class classes.nxtMotor>currentClass
823+
824+
class NxtMotor(Motor):
825+
826+
"""
827+
NXT servo motor
828+
"""
829+
830+
SYSTEM_CLASS_NAME = Motor.SYSTEM_CLASS_NAME
831+
SYSTEM_DEVICE_NAME_CONVENTION = 'motor*'
832+
833+
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
834+
if address is not None:
835+
kwargs['address'] = address
836+
Device.__init__(self, self.SYSTEM_CLASS_NAME, name_pattern, name_exact, driver_name=['lego-nxt-motor'], **kwargs)
837+
838+
839+
# ~autogen
840+
# ~autogen generic-class classes.firgelli50Motor>currentClass
841+
842+
class FirgelliL1250Motor(Motor):
843+
844+
"""
845+
Firgelli L12 50 linear servo motor
846+
"""
847+
848+
SYSTEM_CLASS_NAME = Motor.SYSTEM_CLASS_NAME
849+
SYSTEM_DEVICE_NAME_CONVENTION = 'linear*'
850+
851+
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
852+
if address is not None:
853+
kwargs['address'] = address
854+
Device.__init__(self, self.SYSTEM_CLASS_NAME, name_pattern, name_exact, driver_name=['fi-l12-ev3-50'], **kwargs)
855+
856+
857+
# ~autogen
858+
# ~autogen generic-class classes.firgelli100Motor>currentClass
859+
860+
class FirgelliL12100Motor(Motor):
861+
862+
"""
863+
Firgelli L12 100 linear servo motor
864+
"""
865+
866+
SYSTEM_CLASS_NAME = Motor.SYSTEM_CLASS_NAME
867+
SYSTEM_DEVICE_NAME_CONVENTION = 'linear*'
868+
869+
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
870+
if address is not None:
871+
kwargs['address'] = address
872+
Device.__init__(self, self.SYSTEM_CLASS_NAME, name_pattern, name_exact, driver_name=['fi-l12-ev3-100'], **kwargs)
873+
874+
810875
# ~autogen
811876
# ~autogen generic-class classes.dcMotor>currentClass
812877

@@ -1420,7 +1485,7 @@ class I2cSensor(Sensor):
14201485
"""
14211486

14221487
SYSTEM_CLASS_NAME = Sensor.SYSTEM_CLASS_NAME
1423-
SYSTEM_DEVICE_NAME_CONVENTION = Sensor.SYSTEM_DEVICE_NAME_CONVENTION
1488+
SYSTEM_DEVICE_NAME_CONVENTION = 'sensor*'
14241489

14251490
def __init__(self, address=None, name_pattern=SYSTEM_DEVICE_NAME_CONVENTION, name_exact=False, **kwargs):
14261491
if address is not None:
@@ -2435,7 +2500,7 @@ def __init__(self):
24352500

24362501
self._img = Image.new(
24372502
self.var_info.bits_per_pixel == 1 and "1" or "RGB",
2438-
(self.fix_info.line_length * 8 / self.var_info.bits_per_pixel, self.yres),
2503+
(self.fix_info.line_length * 8 // self.var_info.bits_per_pixel, self.yres),
24392504
"white")
24402505

24412506
self._draw = ImageDraw.Draw(self._img)

spec_version.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# ~autogen spec_version
2-
spec_version = "spec: 1.0.0, kernel: v3.16.7-ckt21-9-ev3dev"
2+
spec_version = "1.1.0"
3+
kernel_versions = {
4+
"10-ev3dev"
5+
"10-rc1-ev3dev"
6+
}
37

48
# ~autogen

templates/generic-class.liquid

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ for line in currentClass.description %}{%
2828
endfor %}
2929
"""
3030
{% if currentClass.inheritance %}
31-
SYSTEM_CLASS_NAME = {{ base_class }}.SYSTEM_CLASS_NAME
32-
SYSTEM_DEVICE_NAME_CONVENTION = {{ base_class }}.SYSTEM_DEVICE_NAME_CONVENTION
31+
SYSTEM_CLASS_NAME = {{ base_class }}.SYSTEM_CLASS_NAME{%
32+
if currentClass.systemDeviceNameConvention %}
33+
SYSTEM_DEVICE_NAME_CONVENTION = '{{ device_name_convention }}'{%
34+
else %}
35+
SYSTEM_DEVICE_NAME_CONVENTION = {{ base_class }}.SYSTEM_DEVICE_NAME_CONVENTION{%
36+
endif %}
3337
{% else %}
3438
SYSTEM_CLASS_NAME = '{{ currentClass.systemClassName }}'
3539
SYSTEM_DEVICE_NAME_CONVENTION = '{{ device_name_convention }}'

templates/spec_version.liquid

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
spec_version = "spec: {{ meta.version }}{% if meta.specRevision %}-r{{ meta.specRevision }}{% endif %}, kernel: {{ meta.supportedKernel }}"
1+
spec_version = "{{ meta.version }}{% if meta.specRevision %}-r{{ meta.specRevision }}{% endif %}"
2+
kernel_versions = { {%
3+
for kernel in meta.supportedKernel.kernels %}
4+
"{{ kernel }}"{%
5+
endfor %}
6+
}

tests/api_tests.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ def dummy(self):
6868
self.assertEqual(m.ramp_down_sp, 0)
6969
self.assertEqual(m.ramp_up_sp, 0)
7070
self.assertEqual(m.speed, 0)
71-
self.assertEqual(m.speed_regulation_enabled, 'off')
7271
self.assertEqual(m.speed_sp, 0)
7372
self.assertEqual(m.state, ['running'])
7473
self.assertEqual(m.stop_command, 'coast')

0 commit comments

Comments
 (0)