Using Motors

This page does not describe all the available motor functions, only those of most interest to beginner EV3 Python programmers. For full descriptions see the official documentation.

There are big improvements to the motor functions in the new (version 2) EV3 Python library. Improvements include:

Common parameters used by the 'on' functions

speed

Most methods which run motors will accept a speed argument. speed is an integer which represents the percentage of the rated maximum speed of the motor. For example, if you set speed to 50 then the motor will run at 50% of its rated maximum speed (for functions that control two motors speed refers to the faster motor).

As stated earlier, speed represents the percentage of the rated maximum speed of the motor. Therefore if a large motor and a medium motor are both set to speed=50 then they will run at different speeds (in degrees per second). The large motor will run at 50% x 1050 = 525 degrees per second and the medium motor will run at 50% x 1560 = 780 degrees per second. It is also possible to specify speeds in degrees per second or rotations per second or degrees per minute or rotations per minute - for all these cases the large and medium motors will rotate at the same speed if you give them the same value e.g. 100 degrees per second. The way this works is that you supply the desired value e.g. in degrees per second and a function converts that into the corresponding speed value. For example SpeedDPS() converts a value in degrees per second into the corresponding speed value. The following script demonstrates the use of these conversion functions. Notice that these conversion functions have to be imported before they can be used in the script, as shown below. 

#!/usr/bin/env python3

from ev3dev2.motor import LargeMotor

from ev3dev2.motor import SpeedDPS, SpeedRPM, SpeedRPS, SpeedDPM

from time import sleep

lm = LargeMotor()

'''

This will run the large motor at 50% of its

rated maximum speed of 1050 deg/s.

50% x 1050 = 525 deg/s

'''

lm.on_for_seconds(speed = 50, seconds=3)

sleep(1)

'''

speed and seconds are both POSITIONAL

arguments which means

you don't have to include the parameter names as

long as you put the arguments in this order 

(speed then seconds) so this is the same as

the previous command:

'''

lm.on_for_seconds(50, 3)

sleep(1)

'''

This will run at 500 degrees per second (DPS).

You should be able to hear that the motor runs a

little slower than before.

'''

lm.on_for_seconds(speed=SpeedDPS(500), seconds=3)

sleep(1)

# 36000 degrees per minute (DPM) (rarely useful!)

lm.on_for_seconds(speed=SpeedDPM(36000), seconds=3)

sleep(1)

# 2 rotations per second (RPS)

lm.on_for_seconds(speed=SpeedRPS(2), seconds=3)

sleep(1)

# 100 rotations per minute(RPM)

lm.on_for_seconds(speed=SpeedRPM(100), seconds=3)

brake

brake is a Boolean parameter, which means it can be either True or False. If it is True then once the motor completes its motion the motor will actively try to keep the motor in a fixed position. If brake is False then once the motor completes its motion the motor will coast gradually to a stop, slowed only by friction. brake is always True by default. brake is a keyword argument (a 'kwarg') so you do not need to include it in your motor command but if you do include you must include the name as well as the value, for example brake=False.

block

'Blocking' a program means making program execution pause until the current command has completed. Many v2 motor commands have a 'block' argument, and in almost every case block=True by default. The exception is the on() function, for which block=False by default. block is a keyword argument and therefore you do not necessarily have to include it in your code to run the command. If you don't include block=False then the default value block=True will be used (except for the on() function, for which block=False by default).

'on' functions to control a single motor

You may want to make one or more motors turn at a given speed

Turn a single motor through a given angle

Use either on_for_rotations() or on_for_degrees():

on_for_rotations(speed, rotations, brake=True, block=True)

Rotate the motor at speed for rotations

Example: turn on the single motor for 5 rotations at 50% of its rated maximum speed:

on_for_rotations(speed=50, rotations=5)

The names of positional arguments do not have to be given provided the arguments are given in the correct order and that you never put an un-named argument after a named argument, so this is the same as the above:

on_for_rotations(50, 5)

To make your scripts as clear as possible it is probably a good idea to include the names, as I normally do on this site.

As previously explained, speed is an integer percentage of the rated maximum speed of the motor. Conversion functions are available to convert units such as degrees per second into the corresponding speed value, as explained above. Example: to rotate the single motor for 5 rotations at 500 degrees per second:

on_for_rotations(speed=SpeedDPS(500), rotations=5)

Don't forget to import the conversion function before you use it, as shown in the first script on this page.

As previously mentioned, you don't need to include the keyword arguments brake and block if you want to use their default values True and True, as will normally be the case.

on_for_degrees(speed, degrees, brake=True, block=True)

Rotate the motor at speed for degrees

Example: rotate the single motor for 90 degrees at 80% of the rated maximum speed:

on_for_degrees(speed=80, degrees=90)

Run a single motor for a given time

on_for_seconds(speed, seconds, brake=True, block=True)

Rotate the motor at speed for seconds

Example: run the motor at 40% of the rated maximum speed for 3 seconds:

on_for_seconds(speed=40, seconds=3)

Run a single motor 'forever'

on(speed, brake=True, block=False)

Rotate the motor at speed 'forever'

Example: to turn on the motor at 45% of the rated maximum speed:

on(speed=45)

Stop a single motor

You'll often need this to turn off the motor that you have turned on 'forever' with on().

off()

Run a single motor until it stops moving

A good example would be when the arms of a gripper close around some object. You can't know exactly what angle or what time that motion corresponds to.

wait_until_not_moving()

This command would normally be issued after an on() command, as in this example. Just grab the moving wheel to stop it and the script will terminate.

#!/usr/bin/env python3

from ev3dev2.motor import LargeMotor, OUTPUT_B

large_motor = LargeMotor(OUTPUT_B)

large_motor.on(speed=50)

large_motor.wait_until_not_moving()

Turn a single motor to a given position

As of December 2018 there may be a bug in this command that can cause the program to freeze. Specifically, if the motor is instructed to move to a position that is within about 10 degrees of its current position then this can fail, causing the program to freeze. Therefore I advise you to avoid using this function for the time being.

on_to_position(speed, position, brake=True, block=True)

This function ignores the sign of the speed, which makes sense since there will always be only one possible direction for the motor to turn in order to reach the requested position. It's important to realize that the position (angle) is on an infinite scale and that the motor will therefore turn in a predictable sense. For example, if the motor is at the 1° position and is instructed to go to the 359° degree position then it will turn in the positive direction through 358°. Don't argue that the initial and final positions are just 2° apart - they are 358° apart. If the motor is in position 180° and you instruct it to go to -540° then it will rotate 720° (two rotations) in the negative direction - it will end up in the same physical position as before it moved but it is now 'officially' at the new position of -540°.

Run a single motor until some other state is reached

For other functions for single motors please see the official documentation.

Use a motor as a sensor

Since you can read the position of a motor, you can use a motor as a sensor. For example, you could manually turn a motor and then have code that could control the speed of a second motor, or play tones that depend on the motor's position, for example. For the Lego EV3 motors, position returns the current position of the motor in degrees. When the motor rotates clockwise (as seen when holding the motor such that the red motor axle is bottom right), the position will increase. Likewise, rotating counter-clockwise causes the position to decrease. Writing will set the position to that value.

'on' functions to control a motor pair

This group of functions includes the very important MoveSteering and MoveTank functions.

Just like for the Lego EV3 icon-based system, the MoveTank functions control two motors based on a left_speed value and a right_speed value.

Just like for the Lego EV3 icon-based system, the MoveSteering functions control two motors based on a steering value and a speed value (EV3-G calls speed 'power'). It's a bit more difficult to explain the meaning of these parameters, compared to the parameters of MoveTank. The steering value controls the path of the robot and can be any value between -100 and +100.

The speed value refers to the speed of the faster wheel (sometimes the wheels may be equally fast, such as when steering = 0). The speed of the slower wheel is automatically calculated based on the steering and speed values.

This chart may help you understand the relationship between MoveTank and MoveSteering. It is intended to show what values of left_speed and right_speed (the MoveTank parameters) correspond to all possible values of steering and a speed value of 40 (the MoveSteering parameters).

Before you can use these MoveTank and MoveSteering functions you must import them and you must define the motor pair. By default these functions will work with the Lego EV3 large motors and you don't need to import LargeMotor to use these functions with a pair of large motors. The following uses sensible names for the pairing of large motors:

steer_pair = MoveSteering(OUTPUT_B, OUTPUT_C)

tank_pair = MoveTank(OUTPUT_B, OUTPUT_C)

I recommend that you do not use names like drive_pair otherwise when you come across code like drive_pair.on_for_seconds(50,50,3) you won't know from that whether this is a steering command or a tank command - the movements would be very different.

You can also use the functions with a pair of medium motors but in that case you need to import MediumMotor. You also need to specify in the pairing that you are using medium motors like this:

tank_pair= MoveTank(OUTPUT_B, OUTPUT_C, motor_class=MediumMotor)

Here is a full script using a pair of medium motors:

#!/usr/bin/env python3

from ev3dev2.motor import MediumMotor, MoveSteering, OUTPUT_A, OUTPUT_D

from time import sleep

steer_pair = MoveSteering(OUTPUT_A, OUTPUT_D, motor_class=MediumMotor)

steer_pair.on_for_seconds(steering=0, speed=50, seconds=2)

You must use a matching pair of motors, so you can't pair a large motor with a medium motor.

Move Tank for a given angle

Use either on_for_rotations() or on_for_degrees().

on_for_rotations(left_speed, right_speed, rotations, brake=True, block=True)

Rotate the motors at left_speed and right_speed for rotations. Like for the speed parameter that is used with single motors, left_speed and right_speed are integer percentages of the rated maximum speed of the motor. Like for speed, you can use conversion functions like SpeedDPS() which converts degrees per second into the corresponding left_speed or right_speed.

If left_speed is not equal to right_speed (i.e. the robot will turn), the motor on the outside of the turn (the one with the faster speed) will rotate for the full rotations while the motor on the inside will have its number of rotations calculated according to the expected turn.

Example:

tank_pair = MoveTank(OUTPUT_B, OUTPUT_C)

# drive in a turn for 10 rotations of the outer (faster) motor

tank_pair.on_for_rotations(left_speed=50, right_speed=75, rotations=10)

Since these are positional arguments the names are optional so the same command can be written

tank_pair.on_for_rotations(50, 75, 10)

but it's probably better to include the names for clarity.

on_for_degrees(left_speed, right_speed, degrees, brake=True, block=True)

Rotate the motors at left_speed and right_speed for degrees. The only difference between on_for_rotations() and on_for_degrees() is that one uses rotations and the other uses degrees.

Move Tank for a given time

on_for_seconds(left_speed, right_speed, seconds, brake=True, block=True)

Rotate the motors at left_speed and right_speed for seconds.

Move Tank 'forever'

on(left_speed, right_speed)

Start rotating the motors according to left_speed and right_speed forever.

Stop the motors

off(brake=True)

Stop both motors immediately.

Example script

Make the robot move forward in a straight line until a touch sensor attached to a bumper is pressed, then stop both motors. Note that 'is_pressed' is not a function, so it does not need parentheses.  Note that it is not appropriate to use ts.wait_for_bump() here because when the bumper collides with an object that is a 'press' on the touch sensor rather than a 'bump' (a press and release). Finally, notice also that after the motors are turned off the brake will act on them for 5 seconds, during which time they will be very hard to turn by hand, whereas after the program terminates they will be much easier to turn.

#!/usr/bin/env python3

from ev3dev2.motor import MoveTank, OUTPUT_B, OUTPUT_C

from ev3dev2.sensor.lego import TouchSensor

from time import sleep

ts = TouchSensor()

tank_pair = MoveTank(OUTPUT_B, OUTPUT_C)

tank_pair.on(left_speed=30, right_speed=30)

while not ts.is_pressed:  # while touch sensor is not pressed

    sleep(0.01)

tank_pair.off()

sleep(5)

Move Steering for a given angle

Use either on_for_rotations() or on_for_degrees().

on_for_rotations(steering, speed, rotations, brake=True, block=True)

Rotate the motors so that the robot moves along the path determined by steering and such that the faster motor has a speed equal to speed and will move through an angle given by rotations. The speed and rotation angle of the slower motor is calculated automatically based on the values of steering and speed.

speed is an integer percentage of the rated maximum speed of the motor. You can use conversion functions like SpeedDPS() which converts degrees per second into the corresponding speed value.

Example:

steer_pair = MoveSteering(OUTPUT_B, OUTPUT_C)

# drive in a turn for 10 rotations of the outer motor

steer_pair.on_for_rotations(steering=-20, speed=75, rotations=10)

Since these are positional arguments the names are optional so the same command can be written

steer_pair.on_for_rotations(-20, 75, 10)

but it's probably better to include the names for clarity.

on_for_degrees(steering, speed, degrees, brake=True, block=True)

Rotate the motors so that the robot moves along the path determined by steering and such that the faster motor has a speed equal to speed and will move through an angle given by degrees. The speed and rotation angle of the slower motor is calculated automatically based on the values of steering and speed. The only difference between on_for_rotations() and on_for_degrees() is that one uses rotations and the other uses degrees.

Move Steering for a given time

on_for_seconds(steering, speed, seconds, brake=True, block=True)

Rotate the motors such that the robot moves long the path determined by steering at the speed determined by speed. The faster motor will have a speed equal to speed and the speed of the slower motor will be calculated as a function of the speed value and the steering value. (Sometimes the motors are equally fast, such as when steering = 0.)

Move Steering 'forever'

on(steering, speed)

Start rotating the motors according to steering and speed forever.

Stop the motors

off(brake=True)

Stop both motors immediately.

Speed Regulation and Synchronization

EV3 Python usually uses a feature called 'speed regulation' when using motors. When speed regulation is on, the motor controller will vary the power supplied to the motor to try to maintain the requested speed. It's comparable to the way your car's cruise control will try to maintain a constant speed even if your car goes up or down hills.

Although EV3 Python uses speed regulation is does not currently offer motor synchronization for motor pairs such that if one motor is slowed below its requested speed the other motor slows to match. Motor synchronisation IS a feature of EV3-G, and may one day be available in EV3 Python.

Other Notes

Note that if you have only one large motor plugged in to the EV3 then you do not need to specify which motor port it is plugged into. The same is true for the medium motor, and also for each type of sensor.

If you have two motors of the same type plugged into the EV3 and you run a command to move a single motor of that type without specifying a port letter then the port that is alphabetically first will be the one that receives the command. The very first script on this page is an example of this. There is nothing in that script to say which motor should move, so the script will use the first large motor that it finds as it scans alphabetically through the motor ports. If you have large motors on ports B and C then motor B will move. If you wanted motor C to move then you could modify the beginning of the script like this:

#!/usr/bin/env python3

from ev3dev2.motor import LargeMotor, OUTPUT_C

from ev3dev2.motor import SpeedDPS, SpeedRPM, SpeedRPS, SpeedDPM

from time import sleep

lm = LargeMotor(OUTPUT_C)