Learn EV3 Python‎ > ‎

Robot Educator

The education version of the Lego EV3 software proposes various example programs in a sequence called ‘Robot Educator’. You can see those programs and my commentaries HERE. You can also see HERE how the same problems can be solved in EV3 Basic, if you're interested. Let’s see how to solve the same problems using EV3 Python. No, much better: YOU try to write a script to solve each challenge, only looking at my solution when you have have completed your own solution (or got stuck trying...).

As for all exercises on this site, it is assumed that you are using Laurens Valk's Explor3r model or the official Lego ‘Driving Base’ model, or something very similar, with motors attached to ports B and C. The official Lego  'Driving Base' model is also called the 'Educator Vehicle'. Building instructions for making the Driving Base model from the education version of the EV3 kit can be viewed or downloaded HERE. Building instructions for making the Driving Base model from the home (retail) version of the EV3 kit can be viewed HEREThe program solutions below can be copied into your EV3 Python editor or IDE so that you can test them, if you wish.

Further down this page you can find the 'Basics' exercises. Once you have completed them, follow these links for the 'Hardware' and 'Beyond Basics' exercises:

BASICS

Lesson 1 of the official Lego lesson sequence is about configuring blocks and is not relevant to EV3 Python and therefore not discussed here.

Lesson 2: Straight Move

Objective:

  1. Make the robot advance such that the wheels rotate 720° (50% speed, apply brake when movement terminated). Actually the Lego program makes the robot advance for two wheel rotations but this is equivalent to 720°. To keep EV3 Python as simple as possible, it does not include the option of programming the motors to rotate through a given number of rotations, therefore you will need to convert rotations to degrees (which you can do in the program, of course).
  2. Wait one second
  3. Make the robot move backwards such that the wheels rotate 720° (50% speed, apply brake when movement terminated)
  4. Wait one second
  5. Make the robot advance for one second (50% speed, apply brake when movement terminated)

EV3 Python solution:

#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Attach large motors to ports B and C
mB = LargeMotor('outB')
mC = LargeMotor('outC')

# Make the robot advance such that the wheels rotate 720 deg
# (50% speed, apply brake when movement terminated). 
# Assuming speed_sp=900 gives full speed then
# speed_sp=450 gives 50% speed
mB.run_to_rel_pos(position_sp=720, speed_sp=450, stop_action="brake")
mC.run_to_rel_pos(position_sp=720, speed_sp=450, stop_action="brake")

# wait for both motors to complete their movements
mB.wait_while('running')
mC.wait_while('running')
    
sleep(1) # Wait one second

# Make the robot move BACKWARDS such that the wheels rotate 720 deg
# (50% speed, apply brake when movement terminated)
mB.run_to_rel_pos(position_sp=-720, speed_sp=450)
mC.run_to_rel_pos(position_sp=-720, speed_sp=450)
# There was no need to include stop_action="brake" because
# that had already been set earlier

# wait for both motors to complete their movements
mB.wait_while('running')
mC.wait_while('running')
    
sleep(1) # Wait one second

# Make the robot advance for 1000 milliseconds
# (50% speed, apply brake when movement terminated)
mB.run_timed(time_sp=1000, speed_sp=450)
mC.run_timed(time_sp=1000, speed_sp=450)

# wait for both motors to complete their movements
mB.wait_while('running')
mC.wait_while('running')

For comparison, here is the solution as it appears within the standard Lego icon-based programming environment:

You can find the Lego solutions to the other challenges HERE.

Notes:

  1. The script above includes lines (highlighted) which detect when both motors have completed their movements. This code was explained on the motors page.

Lesson 3: Curved Move

Objective:

  1. Make the robot do a hard turn right (on the spot) with 685° wheel rotation (speed 40%, brake on).  The left wheel will turn forwards through that angle and the right wheel will turn backwards through the same angle so that the robot itself turns on the spot. Note that a hard turn on the spot like this corresponds to a 'steering' setting of +/-100 in the Move Steering block of the standard Lego software.
  2. Wait one second
  3. Medium turn right (equivalent to a 'steering' setting of 50 in the Move Steering block of the standard Lego software, with only one wheel rotating) with a wheel rotation of 1380° (speed 40%, brake on).
  4. Wait one second
  5. Gentle turn right. A 'steering' setting of 25 in the Move Steering block of the standard Lego software means that the right wheel with turn half as fast as the left wheel. Speed 50% for the faster (left) wheel, so the right wheel will need a speed of 25%. Brake on. The faster-turning wheel should rotate through two rotations (720°) so the wheel rotating half as fast will rotate 360° in the same time.

Solution:

#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Attach large motors to ports B and C
mB = LargeMotor('outB')
mC = LargeMotor('outC')

# Make the robot do a hard turn right (on the spot) with
# 685 deg wheel rotation (speed 40%, brake on).
# Assuming speed_sp=900 gives full speed then
# speed_sp=360 gives 40% speed
mB.run_to_rel_pos(position_sp=685, speed_sp=360, stop_action="brake")
mC.run_to_rel_pos(position_sp=-685, speed_sp=360, stop_action="brake")

# wait for both motors to complete their movements
mB.wait_while('running')
mC.wait_while('running')
    
sleep(1) # Wait one second

# Medium turn right, equvalent to steering=50 in EV3-G.
# This means only the left motor (B) will turn
# Speed 40% corresponds to speed_sp=360
mB.run_to_rel_pos(position_sp=1380, speed_sp=360)

while any(mB.state):  
    sleep(0.1)

sleep(1) # Wait one second

# Gentle turn right with speed_sp=450 and position_sp=720 for B
# and speed_sp=225 and position_sp=360 for C
mB.run_to_rel_pos(position_sp=720, speed_sp=450)
mC.run_to_rel_pos(position_sp=360, speed_sp=225)
# There was no need to include stop_action="brake" because
# that had already been set earlier

mB.wait_while('running')
mC.wait_while('running')

Lesson 4: Tank Move

Objective:
The intended movement in the official Lego lesson 4 is exactly the same as in lesson 3 above, so the solution has already been given. In the Lego lessons, the difference is that lesson 3 is to be achieved using the 'Move Steering' block while lesson 4 is to be solved using the 'Move Tank' block.

Lesson 5: Move Object

Objective:
This program uses the medium motor to lower the robot's gripper bar, trapping an object, then it does a medium left turn backwards, pulling the object with it, then it raises the gripper bar. It is assumed that the gripper bar is attached to the medium motor which is itself attached to port A. The photo shows the gripper bar attached to the standard Lego 'Driving Base' model, also called the 'Educator Vehicle' model.
  1. Make the medium motor (on port A) turn +100° at 30% speed and apply the brake. In the standard 'driving base' model the medium motor is attached to a gripper which is assumed to start in a vertical position - this movement will cause the gripper to be lowered to the ground, hopefully enclosing an object within its grip as it does so.
  2. Robot makes a medium left turn backwards. The left wheel should rotate backwards 360° with speed -50% and the right wheel should not rotate. The brake option is on.
  3. Make the medium motor turn -100° at 30% speed, and apply the brake. This will cause the gripper to be raised back into the vertical position.
Solution:
#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Attach large motors to ports B and C
# and medium motor to port A
mA = MediumMotor('outA')
mB = LargeMotor('outB')
mC = LargeMotor('outC')

# Make the medium motor (on port A) turn 100 deg at -30% speed
# and apply the brake.
# Assuming speed_sp=900 gives full speed then
# speed_sp=270 gives 30% speed
mA.run_to_rel_pos(position_sp=100, speed_sp=270, stop_action="brake")

# wait for motor A to complete its movement
mA.wait_while('running')
    
# Medium left turn backwards. The left wheel (B) should rotate backwards
# -360 deg with speed 50% and the right wheel should not rotate.
# This means only the left motor (B) will turn
# Speed 50% corresponds to speed_sp=450
mB.run_to_rel_pos(position_sp=-360, speed_sp=450)
mB.wait_while('running')

# Medium motor A turns 100 deg at +30% speed (speed_sp=270)
mA.run_to_rel_pos(position_sp=-100, speed_sp=270)
mA.wait_while('running')

Lesson 6: Stop at line

Objective:
This exercise assumes that a colour sensor is attached and is suspended just above (ideally 3 mm above) the ground, pointing at the ground. This program turns on the right motor (making the robot turn left), then waits until the detected brightness falls below a certain value (because the sensor has passed over a black line, for example) then turns off the motor.
  1. Start the right motor moving with speed 50%.
  2. Wait until the colour sensor detects that the brightness has fallen beneath a certain threshold value (see note below)
  3. Turn off the motor and apply the brake
Solution:

#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Connect an EV3 color sensor and check connected.

cl = ColorSensor() 
assert cl.connected, "Connect a color sensor to any sensor port"

# Put the color sensor into COL-REFLECT mode
# to measure reflected light intensity.
# In this mode the sensor will return a value between 0 and 100
cl.mode='COL-REFLECT'

# Attach large motors to ports B and C
mB = LargeMotor('outB')  # not used
mC = LargeMotor('outC')

# Make the right motor turn at 50% speed (speed_sp=450)
mC.run_forever(speed_sp=450)

# Wait until the colour sensor detects that the brightness
# has fallen beneath a threshold value of 40 (see note)

while cl.value() > 40: # loop while over white surface
    sleep(0.01)
    
# Turn off the motor and apply the brake
mC.stop(stop_action="brake")

Notes:
  1. With the sensor 3 mm from the reflecting surface I get a value of 80 for white paper and 5 for a typical back surface. Therefore I have chosen for this script a threshold value of 40 to distinguish between black and white reflecting surfaces.

Lesson 7: Stop at Angle

This exercise uses the gyro sensor. Note that the gyro sensor is included in the education version of the EV3 but not in the home version, so if you have the home version you will not be able to test this program (it's always possible to buy additional sensors). In mode GYRO-ANG the gyro sensor measures the angle in which it is pointing, relative to the angle that is was at when the program was launched. It's very important to keep the Gyro Sensor and EV3 steady when connecting the cable and during start-up of the EV3, otherwise the gyro reading will continually wander away from the correct value. If you are not sure that this condition was met then simply unplug the sensor from its port and then reconnect it before running the program, while ensuring that the EV3 and the gyro sensor are perfectly still. 

Objective:
  1. Start the left motor with speed 40% to initiate a medium turn right.
  2. Wait until the gyro sensor detects that the robot has turned (at least) 45° in the positive direction (to the right). Note that the gyro measures the rotation of the robot itself and not the rotation of the motors or the wheels.
  3. Then the robot moves straight ahead with speed 50% until the wheels have turned through one rotation (360°).
Solution:

#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Connect gyro sensor and check connected.
gy = GyroSensor() 
assert gy.connected, "Connect a gyro sensor to any sensor port"

# Put the gyro sensor into GYRO-ANG mode
# to measure the turn angle in degrees
gy.mode='GYRO-ANG'

# Attach large motors to ports B and C
mB = LargeMotor('outB')
mC = LargeMotor('outC')

# Start the left motor with speed 40% to initiate a medium turn right.
mB.run_forever(speed_sp=360)

# Wait until the gyro sensor detects that the robot has turned
# (at least) 45 deg in the positive direction (to the right)
while gy.value() < 45: # loop until turn angle exceeds 45 degrees
    sleep(0.01)
    
# Robot moves straight ahead with speed 50% until the wheels
# have turned through one rotation (360 degrees)
mB.run_to_rel_pos(position_sp=360, speed_sp=450, stop_action="brake")
mC.run_to_rel_pos(position_sp=360, speed_sp=450, stop_action="brake")

# Wait for the motion to finish
mB.wait_while('running')
mC.wait_while('running')

Lesson 8: Stop at Object

This project will use the ultrasound sensor. If you don't have the ultrasound sensor (because you bought the home edition of the EV3) you could perhaps substitute the IR sensor but it won't be possible to get exact distances because the IR sensor does not return exact distances. Also, the code will be different if you use the IR sensor. This difference means other small changes need to be made to the code. See note 2 for a solution using the infrared sensor.

Objective:
The robot will move forward in a straight line (speed=50%) until it has moved (at least) 11 cm closer to the reflecting object in front of it, then it will stop and pause for one second, then it will back up continuously (speed=-50%) until it detects that it has moved (at least) 6 cm away from the object, then it will stop.

Solution (using the ultrasound sensor):
Remember that the US sensor in mode US-DIST-CM returns distance values in mm not cm (put another way, it returns distances in cm that include a first decimal place but no decimal point!). Therefore it is necessary to convert the cm values in the objective above into mm. We will also make use of the fact that if the robot moves 11 cm closer and then 6 cm further away it will then be 5 cm from its starting position.

#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Connect ultrasonic sensor and check connected.

us = UltrasonicSensor() 
assert us.connected, "Connect ultrasonic sensor to any sensor port"

# Put the US sensor into distance mode.
us.mode='US-DIST-CM'

# Attach large motors to ports B and C
mB = LargeMotor('outB')
mC = LargeMotor('outC')

# Record the initial separation of the sensor and the object
startdistance = us.value()

# Advance at 50% speed (speed_sp=450)
mB.run_forever(speed_sp=450)
mC.run_forever(speed_sp=450)

# Wait until robot has moved (at least) 11 cm (110 mm) closer
# to the reflecting object in front of it
while us.value() > startdistance-110:
    sleep(0.01)
    
# Turn off the motors and apply the brake
mB.stop(stop_action="brake")
mC.stop(stop_action="brake")

sleep(1)

# Reverse at 50% speed
mB.run_forever(speed_sp=-450)
mC.run_forever(speed_sp=-450)

# Wait until robot is less than 5 cm from its starting position
while us.value() < startdistance-50:
    sleep(0.01)
    
mB.stop()
mC.stop()

Notes:
  1. I find that the sensor can give unreliable readings (due to unwanted reflections) if the robot is on a hard, highly reflective surface or if the sensor is mounted too close to the floor.
  2. If you use the infrared sensor in place of the ultrasound sensor then you must modify the code since these sensors use different commands to obtain the sensor reading and since the infrared sensor returns a value that is neither in cm nor in mm. To convert an IR value into a very approximate distance in cm, multiply the IR value by 0.7. For example, if the IR value is 100 then the distance is roughly 70 cm. That means 11 cm corresponds to 16 'IR units' and 5 cm corresponds to 7 'IR units'. Here is the same program, modified for the IR sensor. Changed lines are highlighted.
#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import sleep

# Connect infrared sensor to any sensor port
# and check it is connected.
ir = InfraredSensor() 
assert ir.connected, "Connect an IR sensor to any sensor port"

# Put the infrared sensor into proximity mode.
ir.mode = 'IR-PROX'

# Attach large motors to ports B and C
mB = LargeMotor('outB')
mC = LargeMotor('outC')

# Record the initial separation of the sensor and the object
startdistance = ir.value()

# Advance at 50% speed (speed_sp=450)
mB.run_forever(speed_sp=450)
mC.run_forever(speed_sp=450)

# Wait until robot has moved (at least) 11 cm closer
# to the reflecting object in front of it
while ir.value() > startdistance-16:  # 16 IR units = 11cm approx
    sleep(0.01)
    
# Turn off the motors and apply the brake
mB.stop(stop_action="brake")
mC.stop(stop_action="brake")

sleep(1)

# Reverse at 50% speed
mB.run_forever(speed_sp=-450)
mC.run_forever(speed_sp=-450)

# Wait until robot is less than 5 cm from its starting position
while ir.value() < startdistance-7:  # 7 IR units = 5cm approx
    sleep(0.01)
    
mB.stop()
mC.stop()

Now that you have complete the 'Basics' exercises you are ready to tackle the 18 'Beyond Basics' exercises which begin with Beyond Basics exercises 1-6.