Measuring terrain using ultrasonic

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.

image0

  • circularly, the robot spins on the spot and measures the distance from the terrain.

image1

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
Next Section - The motion of a robot inside a field with obstacles