Measuring terrain using ultrasonic¶
To check how the ultrasonic sensor works at different angles according to the terrain, to define the maximum slope to still gain sensible results.
To make several diverse terrains from cardboard or items we have close at hand and measure them using a robot. Terrains for linear measuring and those for circular measuring need to be made. The measurements will be displayed in a graph.
Prerequisite¶
What students should know before (Required prior knowledge)
Sound basics, how sound travels through the air.
What is ultrasound?
Wavelength equation c=λ*ν.
Converting polar to Cartesian coordinates.
Use of list and for loops.
Time constraints:
The time needed for the activity is 90-135 minutes.
Preparing For This Tutorial:¶
The LEGO Mindstorm EV3 Robot that coincides with this tutorial comes from building specific sections found in the LEGO Mindstorm Education Core Set building instructions. You will need to build the main body for the robot (I’ll refer to use the Driving Base), plus an ultrasonic sensor.
Effects¶
Students get acquainted with how to make measurements, which is an important part of each physical experiment.
Students face problems and try to solve them inventively and constructively.
They learn how to display data on a graph, they revise the knowledge of converting polar to Cartesian coordinates and the knowledge of programming.
Exercise¶
Check the functioning of the sensor at different terrain angles. We can predict that at bigger angles the measurements slowly become
useless as the sensor does not obtain the rebound. Place the flat plank at different angles towards the sensor. The robot should drive and measure approximately one meter in length. It makes the measurement, drives on a few centimetres and makes another measurement, etc., so that there are at least 30 measurements for each plank position. To ensure better accuracy each measurement should be the average of ten measurements from the same position. Every time increase the plank slope by a few degrees up to the point when the measurements are useless and not sensible anymore.
What is the maximal plank slope that still gives sensible results?
Several diverse terrains need to be made to be measured by our robot.
We can use items that we have close at hand, such as cardboard, polystyrene, smaller furniture parts. The sensor does not detect at a distance longer than 255 cm, which you should take into account when making the terrain. The length of the measured terrain should be at least 2 meters and the measurement should be made every few centimetres.
Scan the terrain linearly and circularly, save the data which will later be displayed.
Illustrate the measured distances in a graph and compare them with real values.
Example solution¶
An ultrasonic sensor is an electronic device that can emit and receive ultrasound. The sensor emits an ultrasound pulse and records how much time it takes for a pulse to deflect from the obstacle and come back to the sensor. The time can be converted into distance and we get a simple distance meter. Our mindstorm lego robot can do that automatically and it can also show the distance in centimetres or inches. In this activity the ultrasonic sensor will serve as a tool for perceiving the environment.
The terrain can be scanned:
linearly, the robot drives along the terrain and measures the distances perpendicular to the direction of motion.
circularly, the robot spins on the spot and measures the distance from the terrain.
Programming¶
Install appropriate libraries in Python:
#!/usr/bin/env python3
from ev3dev2.sensor.lego import UltrasonicSensor
from ev3dev2.motor import LargeMotor, OUTPUT_A, OUTPUT_B,OUTPUT_C, SpeedPercent, MoveTank
from time import sleep
The first three lines enter the libraries for the ultrasonic sensor and for the engine power. The fourth line defines the sleep() function, which freezes the programme for the entered time.
Objects for the robot move and ultrasonic sensor need to be set up:
#!/usr/bin/env python3
tank_drive = MoveTank(OUTPUT_B, OUTPUT_C)
us=UltrasonicSensor()
The following function needs to be written for the robot to move forward:
#!/usr/bin/env python3
def forward(length):
tank_drive.on_for_rotations(SpeedPercent(30),SpeedPercent(30),length/wheel)
A similar function can also be written for the robot rotation at a specific angle.
The first propery states the distance to the obstacle in centimetres, while the other one states the distance in inches. In both cases the distance is accurate to the tenth of the centimetre or inch.
#!/usr/bin/env python3
us.distance_centimeters
us.distance_inches
We show the measurement data:
print(us.distance_centimeters)
We introduce the following variables:
#!/usr/bin/env python3
nofmeas=40 #number of measurements
scanlength=200 # cm, length of measuring
step=scanlength/nofmeas #the move of one step
wheel=17.9 # wheel circumference
threesixty=2.106 #wheel rotation needed for 360deg
We create a list of distances[]. The measured distance is saved in this list by using the following command:
#!/usr/bin/env python3
distances=[]
distances.append(us.distance_centimetres)
An example of a code for linear measurement:
#!/usr/bin/env python3
from ev3dev2.sensor.lego import UltrasonicSensor
from ev3dev2.motor import LargeMotor, OUTPUT_A, OUTPUT_B,OUTPUT_C, SpeedPercent, MoveTank
from time import sleep
us=UltrasonicSensor()
tank_drive = MoveTank(OUTPUT_B, OUTPUT_C)
nofmeas=40
scanlength=200 #cm
step=scanlength/nofmeas
distances=[]
counter=0
def forward(length): #define the function for a move forward for a specific length
tank_drive.on_for_rotations(SpeedPercent(30), SpeedPercent(30), length/wheel)
def turn(angle): #define the function for rotation at a certain angle(deg)
tank_drive.on_for_rotations(SpeedPercent(-10), SpeedPercent(10),threesixty*angle/360)
while(counter<nofmeas): #loop until counter reaches the number of measurements(40)
sum=0 # save 10 successive measurements in this variable
for i in range(10): #for better accuracy take the average of 10 measurements
dist=us.distance_centimeters
sum+=dist
distances.append(sum/10) #save the average of 10 measurements to the list
print(distances[counter]) #we print the measurement
sleep(0.01)
forward(step) #robot moves forward one step
counter+=1 #increase counter by 1
For circular measuring, the function forward(step) in the while loop needs to be replaced by the function turn(360/nofmeas).
We would like to show the obtained results graphically. In python there is the plotting library Matplotlib, which can generate graphs, functions, etc. Each measurement can be displayed as a point on the graph, using the x and y coordinates. As there are many points, we use 2 lists. The first one is used to save x coordinates of our points (linear moves along the terrain, e.g. from 0 – 200 cm) and the second list is used to save y coordinates (the measured distances to the terrain / obstacles).
Example:
#!/usr/bin/env python3
import matplotlib.pyplot as plt #enter library
x =[1,2,3,4] #list in which x coordinates are saved
y =[1,4,9,16] #list in which y coordinates are saved
plt.plot(x,y,'ro') #draws red points on x, y coordinates
plt.axis([0,6,0,20]) #define graph boundaries
plt.show() #draws a graph
Circular measurement example:
#!/usr/bin/env python3
import matplotlib.pyplot as plt #enter libraries
import math
angle=2*math.pi/steps
distances=[14,12,10,8,6,5,6,7,8,8,9,10,11,12,13] #measured distances
pointsX=[]
pointsY=[]
The calculated x and y coordinates will be saved in the lists pointsX and pointsY.
The for loop is repeated as many times as there are the saved elements in the distances list. We calculate the coordinates x and y and save them in the appropriate lists.
#!/usr/bin/env python3
for i in range(len(distances)):
x=distances[i]*math.cos(i*angle)
y=distances[i]*math.sin(i*angle)
pointsX.append(x)
pointsY.append(y)
We define the graph boundaries and display it:
#!/usr/bin/env python3
plt.plot(pointsX,pointsY,'ro') #draws red points on x,y coordinates
plt.axis([-20,20,-20,20]) #define graph boundaries
plt.show() #draws a graph