bricknil.sensor.motor

All motor related peripherals including base motor classes

Classes

CPlusLargeMotor(name[, port, capabilities]) Access the Technic Control Plus Large motors
CPlusXLMotor(name[, port, capabilities]) Access the Technic Control Plus XL motors
DuploTrainMotor(name[, port, capabilities]) Train Motor on Duplo Trains
ExternalMotor(name[, port, capabilities]) Access the stand-alone Boost motors
InternalMotor(name[, port, capabilities]) Access the internal motor(s) in the Boost Move Hub.
Motor(name[, port, capabilities]) Utility class for common functions shared between Train Motors, Internal Motors, and External Motors
TachoMotor(name[, port, capabilities])
TrainMotor(name[, port, capabilities]) Connects to the train motors.
WedoMotor(name[, port, capabilities]) Connects to the Wedo motors.

Members

class bricknil.sensor.motor.Motor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Utility class for common functions shared between Train Motors, Internal Motors, and External Motors

ramp_speed(target_speed, ramp_time_ms)[source]

Ramp the speed by 10 units in the time given in milliseconds

set_speed(speed)[source]

Validate and set the train speed

If there is an in-progress ramp, and this command is not part of that ramp, then cancel that in-progress ramp first, before issuing this set_speed command.

Parameters:speed (int) – Range -100 to 100 where negative numbers are reverse. Use 0 to put the motor into neutral. 255 will do a hard brake
class bricknil.sensor.motor.TachoMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.Motor

class capability

Bases: enum.Enum

An enumeration.

sense_pos = 2
sense_speed = 1
datasets = {<capability.sense_speed: 1>: (1, 1), <capability.sense_pos: 2>: (1, 4)}

Dict of (num_datasets, bytes_per_dataset). sense_speed (1-byte), and sense_pos (uint32)

allowed_combo = [<capability.sense_speed: 1>, <capability.sense_pos: 2>]
ramp_speed2(target_speed, ramp_time_ms)[source]

Experimental function, not implemented yet DO NOT USE

rotate(degrees, speed, max_power=50)[source]

Rotate the given number of degrees from current position, with direction given by sign of speed

Examples:

await self.motor.rotate(90, speed=50)   # Rotate 90 degrees clockwise (looking from end of shaft towards motor)
await self.motor.set_pos(90, speed=-50)  # Rotate conter-clockwise 90 degrees
await self.motor.set_pos(720, speed=50)  # Rotate two full circles clockwise
Parameters:
  • degrees (uint) – Relative number of degrees to rotate
  • speed (int) – -100 to 100
  • max_power (int) – Max percentage power that will be applied (0-100%)

Notes

Use command StartSpeedForDegrees
  • 0x00 = hub id
  • 0x81 = Port Output command
  • port
  • 0x11 = Upper nibble (0=buffer, 1=immediate execution), Lower nibble (0=No ack, 1=command feedback)
  • 0x0b = Subcommand
  • degrees (int32) 0..1000000
  • speed -100 - 100%
  • max_power abs(0-100%)
  • endstate = 0 (float), 126 (hold), 127 (brake)
  • Use Accel profile = (bit 0 = acc profile, bit 1 = decc profile)
set_pos(pos, speed=50, max_power=50)[source]

Set the absolute position of the motor

Everytime the hub is powered up, the zero-angle reference will be reset to the motor’s current position. When you issue this command, the motor will rotate to the position given in degrees. The sign of the pos tells you which direction to rotate: (1) a positive number will rotate clockwise as looking from end of shaft towards the motor, (2) a negative number will rotate counter-clockwise

Examples:

await self.motor.set_pos(90)   # Rotate 90 degrees clockwise (looking from end of shaft towards motor)
await self.motor.set_pos(-90)  # Rotate conter-clockwise 90 degrees
await self.motor.set_pos(720)  # Rotate two full circles clockwise
Parameters:
  • pos (int) – Absolute position in degrees.
  • speed (int) – Absolute value from 0-100
  • max_power (int) – Max percentage power that will be applied (0-100%)

Notes

Use command GotoAbsolutePosition
  • 0x00 = hub id
  • 0x81 = Port Output command
  • port
  • 0x11 = Upper nibble (0=buffer, 1=immediate execution), Lower nibble (0=No ack, 1=command feedback)
  • 0x0d = Subcommand
  • abs_pos (int32)
  • speed -100 - 100
  • max_power abs(0-100%)
  • endstate = 0 (float), 126 (hold), 127 (brake)
  • Use Accel profile = (bit 0 = acc profile, bit 1 = decc profile)
class bricknil.sensor.motor.InternalMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.TachoMotor

Access the internal motor(s) in the Boost Move Hub.

Unlike the train motors, these motors (as well as the stand-alone Boost motors ExternalMotor) have a built-in sensor/tachometer for sending back the motor’s current speed and position. However, you don’t need to use the sensors, and can treat this motor strictly as an output device.

Examples:

# Basic connection to the motor on Port A
@attach(InternalMotor, name='left_motor', port=InternalMotor.Port.A)

# Basic connection to both motors at the same time (virtual I/O port).
# Any speed command will cause both motors to rotate at the same speed
@attach(InternalMotor, name='motors', port=InternalMotor.Port.AB)

# Report back when motor speed changes. You must have a motor_change method defined
@attach(InternalMotor, name='motor', port=InternalMotor.Port.A, capabilities=['sense_speed'])

# Only report back when speed change exceeds 5 units
@attach(InternalMotor, name='motors', port=InternalMotor.Port.A, capabilities=[('sense_speed', 5)])
And within the run body you can control the motor output::
await self.motor.set_speed(50) # Setting the speed await self.motor.ramp_speed(80, 2000) # Ramp speed to 80 over 2 seconds await self.motor.set_pos(90, speed=20) # Turn clockwise to 3 o’clock position await self.motor.rotate(60, speed=-50) # Turn 60 degrees counter-clockwise from current position

See also

Maps the port names A, B, AB to hard-coded port numbers

class Port

Bases: enum.Enum

Address either motor A or Motor B, or both AB at the same time

A = 0
AB = 2
B = 1
class bricknil.sensor.motor.ExternalMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.TachoMotor

Access the stand-alone Boost motors

These are similar to the InternalMotor with build-in tachometer and sensor for sending back the motor’s current speed and position. You don’t need to use the sensors, and can treat this as strictly an output.

Examples:

# Basic connection to the motor on Port A
@attach(ExternalMotor, name='motor')

# Report back when motor speed changes. You must have a motor_change method defined
@attach(ExternalMotor, name='motor', capabilities=['sense_speed'])

# Only report back when speed change exceeds 5 units, and position changes (degrees)
@attach(ExternalMotor, name='motor', capabilities=[('sense_speed', 5), 'sense_pos'])

And then within the run body:

await self.motor.set_speed(50)   # Setting the speed
await self.motor.ramp_speed(80, 2000)  # Ramp speed to 80 over 2 seconds
await self.motor.set_pos(90, speed=20) # Turn clockwise to 3 o'clock position
await self.motor.rotate(60, speed=-50) # Turn 60 degrees counter-clockwise from current position

See also

class bricknil.sensor.motor.CPlusLargeMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.TachoMotor

Access the Technic Control Plus Large motors

These are similar to the InternalMotor with build-in tachometer and sensor for sending back the motor’s current speed and position. You don’t need to use the sensors, and can treat this as strictly an output.

Examples:

# Basic connection to the motor on Port A
@attach(CPlusLargeMotor, name='motor')

# Report back when motor speed changes. You must have a motor_change method defined
@attach(CPlusLargeMotor, name='motor', capabilities=['sense_speed'])

# Only report back when speed change exceeds 5 units, and position changes (degrees)
@attach(CPlusLargeMotor, name='motor', capabilities=[('sense_speed', 5), 'sense_pos'])

And then within the run body:

await self.motor.set_speed(50)   # Setting the speed
await self.motor.ramp_speed(80, 2000)  # Ramp speed to 80 over 2 seconds
await self.motor.set_pos(90, speed=20) # Turn clockwise to 3 o'clock position
await self.motor.rotate(60, speed=-50) # Turn 60 degrees counter-clockwise from current position

See also

class bricknil.sensor.motor.CPlusXLMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.TachoMotor

Access the Technic Control Plus XL motors

These are similar to the InternalMotor with build-in tachometer and sensor for sending back the motor’s current speed and position. You don’t need to use the sensors, and can treat this as strictly an output.

Examples:

# Basic connection to the motor on Port A
@attach(CPlusXLMotor, name='motor')

# Report back when motor speed changes. You must have a motor_change method defined
@attach(CPlusXLMotor, name='motor', capabilities=['sense_speed'])

# Only report back when speed change exceeds 5 units, and position changes (degrees)
@attach(CPlusXLMotor, name='motor', capabilities=[('sense_speed', 5), 'sense_pos'])

And then within the run body:

await self.motor.set_speed(50)   # Setting the speed
await self.motor.ramp_speed(80, 2000)  # Ramp speed to 80 over 2 seconds
await self.motor.set_pos(90, speed=20) # Turn clockwise to 3 o'clock position
await self.motor.rotate(60, speed=-50) # Turn 60 degrees counter-clockwise from current position

See also

class bricknil.sensor.motor.TrainMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.Motor

Connects to the train motors.

TrainMotor has no sensing capabilities and only supports a single output mode that sets the speed.

Examples:

@attach(TrainMotor, name='train')

And then within the run body, use:

await self.train.set_speed(speed)
speed

Keep track of the current speed in order to ramp it

Type:int

See also

InternalMotor

class bricknil.sensor.motor.WedoMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.Motor

Connects to the Wedo motors.

WedoMotor has no sensing capabilities and only supports a single output mode that sets the speed.

Examples:

@attach(WedoMotor, name='motor')

And then within the run body, use:

await self.motor.set_speed(speed)
speed

Keep track of the current speed in order to ramp it

Type:int
class bricknil.sensor.motor.DuploTrainMotor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.motor.Motor

Train Motor on Duplo Trains

Make sure that the train is sitting on the ground (the front wheels need to keep rotating) in order to keep the train motor powered. If you pick up the train, the motor will stop operating withina few seconds.

Examples:

@attach(DuploTrainMotor, name='motor')

And then within the run body, use:

await self.train.set_speed(speed)
speed

Keep track of the current speed in order to ramp it

Type:int

See also

TrainMotor for connecting to a PoweredUp train motor