Beyond Basics Ex 7-11
Exercise 7: 'Sensor Blocks'
I have kept the original title for this exercise, 'Sensor Blocks', even though EV3 Python doesn't use programming blocks like the Lego software does.
Objective:
When the touch sensor is NOT pressed the robot will turn on the spot to the right at a speed that is proportional to the ambient light intensity. When the touch sensor IS pressed then the robot will stop moving for as long as the switch is pressed, and the status light will glow red. This program will not stop by itself so you must force the program to stop by pressing the Back button on the EV3 or the stop button in VS Code if you launched the script from there.
Solution:
#!/usr/bin/env python3
from ev3dev2.motor import MoveSteering, OUTPUT_B, OUTPUT_C
from ev3dev2.sensor.lego import TouchSensor, ColorSensor
from ev3dev2.led import Leds
from time import sleep
steer_pair = MoveSteering(OUTPUT_B, OUTPUT_C)
cl = ColorSensor()
ts = TouchSensor()
leds = Leds()
while True: # forever
if ts.is_pressed==0: # touch sensor NOT pressed
leds.all_off() # turn off LEDs
# turn motors at opposite speeds to turn on the spot
steer_pair.on(steering=100, speed=cl.ambient_light_intensity)
else: # touch sensor is pressed
steer_pair.off()
leds.set_color('LEFT', 'RED')
leds.set_color('RIGHT', 'RED')
Notes:
1. My solution is very different to the official EV3-G solution, shown below:
The official solution uses two threads which run simultaneously since they are both attached to a Start block. When the lower loop detects that the touch sensor has been pressed it issues a Stop Motor command but this seems to be in conflict with the Motor command in the top loop, which tells the motors to move. Presumably the Stop Motor command takes precedence, but how can it, since the stop motor command and the start motor command are in different loops and will be executed at different times? So this solution may work but is hard to understand and unnecessarily complex - why use two threads for this solution?
Exercise 8: Text
This exercise is like exercise 5, but simpler.
Objective:
The ultrasonic sensor will measure distance. The distance value will be displayed in centimeters on the LCD screen followed by the string ' cm'. The text will be displayed in the font courB24. The display will be continuously updated with the current distance reading of the sensor.
Solution:
#!/usr/bin/env python3
from ev3dev2.sensor.lego import UltrasonicSensor
from ev3dev2.display import Display
from time import sleep
lcd = Display()
us = UltrasonicSensor()
while True: # forever
distance = us.distance_centimeters # a float
lcd.text_pixels(str(distance) +' cm', x=40, y=50, font='courB24')
lcd.update()
sleep(0.1) # so the display doesn't change too frequently
Notes:
Stop the program by pressing the Back button on the EV3 or the stop button in VS Code if you launched the script from there.
This script sometimes displays readings such as 63.40000000000 cm rather than the expected 63.4 cm.
It's possible to rewrite the above script to work with the IR sensor, although the distance readings will be much less accurate. Just for once, I won't give you the solution - YOU can do some work for a change!
Exercise 9: Range
Objective:
Make the robot follow an object that is moving away from it - it should move forwards towards the object as long as the object is between 10 and 20 cm in front of the robot but will stop moving if it gets closer than 10 cm, thereby avoiding a collision. It will also stop moving (give up) if the leading object is more than 20 cm in front of the robot.
Solution:
#!/usr/bin/env python3
from ev3dev2.motor import MoveTank, OUTPUT_B, OUTPUT_C
from ev3dev2.sensor.lego import UltrasonicSensor
from time import sleep
tank_pair = MoveTank(OUTPUT_B, OUTPUT_C)
us = UltrasonicSensor()
while True: # forever
distance = us.distance_centimeters
if distance > 10 and distance < 20:
tank_pair.on(left_speed=50, right_speed=50)
else:
tank_pair.off()
sleep(0.1)
Notes:
As for the previous exercise, it should be very possible (and a good challenge) to convert this program to work with the IR sensor rather then the US sensor.
Exercise 10: Math - Basic
Objective:
This program will calculate how many wheel rotations are necessary to make the robot move forward 50 cm, then it will make the robot move, then it will calculate the speed of the robot during the motion.
Solution:
Each time a robot wheel turns through one rotation the entire circumference of the wheel rolls along the ground.
The diameter of the EV3 Education version rubber tires is about 5.6 cm so the circumference is 5.6 cm * π = 5.6 cm * 3.14 = 17.6 cm approx.
The diameter of the EV3 Home version rubber tires is 4.32 cm so the circumference is 4.32 cm * π = 4.32 cm * 3.14 = 13.6 cm approx.
To find the number of rotations necessary to move the robot forward 50 cm we must divide 50 cm by the distance moved in each rotation of the wheel (equal to the circumference of the wheel).
We will use the function time() which is part of the time library - don't confuse the function with the library of the same name. time() returns (as a float) the number of seconds that have elapsed since the 'epoch'. We don't need to know when the 'epoch' was (it may be the very beginning of 1970?) because all we are interested in is the increase in time between the start of the movement and the end of the movement. In this script I use from time import time so in the script I only need to use time() to invoke the function. If I had used import time then in the script I would have had to use time.time() to invoke the function.
#!/usr/bin/env python3
from ev3dev2.motor import MoveSteering, OUTPUT_B, OUTPUT_C
from ev3dev2.display import Display
from time import sleep, time
steer_pair = MoveSteering(OUTPUT_B, OUTPUT_C)
lcd = Display()
# num_rots is number of wheel rotations needed for robot to advance 50 cm
num_rots = 50/17.6 # wheel circumference = 17.6 cm for education version
# num_rots = 50/13.6 # wheel circumference = 13.6 cm for home version
start_time = time() # time() returns seconds since the 'epoch'
steer_pair.on_for_rotations(steering=0, speed=40, rotations=num_rots)
travel_time = time() - start_time # calculate how long the movement took
speed = 50/travel_time # speed = distance in cm / time in s
lcd.text_pixels(str(round(speed)) + ' cm/s', x=40, y=50, font='helvB24')
lcd.update()
sleep(5) # Give enough time for the screen to be read
Notes:
If you are using the Home version then comment out the line that mentions the education version and uncomment the line that mentions the home version.
Here is the official EV3-G solution to the same problem:
Exercise 11: Gyro - rate
Objective:
The program should continuously (every 0.5 seconds) display the rate of turn of the gyro sensor in degrees per second. In EV3 Python v2 the rate of turn is given by the rate property of the gyro sensor.
Solution:
Recall that whenever you use the gyro sensor it is vitally important to keep the sensor absolutely stationary when the EV3 brick is powered up or the gyro sensor is plugged in, otherwise the gyro reading will continually wander away from the correct value.
#!/usr/bin/env python3
from ev3dev2.sensor.lego import GyroSensor
from ev3dev2.display import Display
import ev3dev2.fonts as fonts
from time import sleep
gyro = GyroSensor()
lcd = Display()
while True:
lcd.text_pixels(str(gyro.rate)+' deg/s', x=40, y=50, font='helvB24')
lcd.update()
sleep(0.4) # so the display doesn't change too frequently
Notes:
Note how when the robot is turning clockwise the rate is positive and vice versa, irrespective of the direction in which the robot is actually pointing.
gyro.rate is a number so it has to be converted to a string with str() before it can be drawn to the LCD as text.
You are now ready to tackle Beyond Basics exercises 12-18.