Ultrasound: we see the cargo
The robot measures the distance with sound and stops in front of the load, not confusing “no echo” with “load nearby”.
Lesson result
The robot travels along the line and stops at a specified distance from the load. If the echo does not return, the program does not accept this as a “cargo nearby”.
You will learn
- Explain how an ultrasonic sensor measures distance.
- Display the distance in the Serial Monitor and check it with a ruler.
- Distinguish between the absence of an echo and a short distance.
- Stop the robot in front of the load by dimension, not by time.
Need to know
- 3.2 P-controller: smooth and fast
Will need
Why this lesson
The weight is at the end of the branch. The robot must drive up to it and stop just enough so that the gripper can take it. If you drive “on time”, the robot will either not get there or crash. Today he will learn to see cargo with ultrasound - the same way a bat sees obstacles.
- How does the robot stop at an intersection in the program from Lesson 4.1?
- What does
breakin a loop? (If you don’t remember, we’ll sort it out today.) - What two commands are needed for the robot to move along the line with the P-controller?
How ultrasound works
8 minWhat should a robot do. The courier needs to detect an object ahead, estimate the distance to it and stop in front of the cargo. Line sensors look down and do not solve this problem. Let's add an ultrasonic sensor: it will help measure the distance, but will not distinguish the load from the wall.
What we use and how it works. The sensor's transmitter emits a short series of ultrasonic vibrations that humans cannot hear. The sound is reflected from the object, and the receiver picks up the echo. The Arduino triggers the measurement with a pulse on TRIG and measures the duration of the ECHO signal. This is an electrical signal about the time of measurement, and not the sound itself. The path of sound is double: to the object and back. Therefore, the distance is equal to the speed of sound multiplied by time and divided by two.
How to link a dimension to an action. In the curriculum, time in microseconds is divided by 58 to get approximate centimeters: about 29 microseconds per centimeter in one direction and the same in the other direction. For example, 580 µs corresponds to approximately 10 cm. An integer result discards the fractional part; Temperature and reflective surface also affect the measurement. We compare it with a ruler from the front surface of the sensor.
If the measurement fails. An inclined surface can reflect sound to the side, a soft surface can absorb it, and an object that is too close or far away cannot produce a suitable echo. Therefore "no echo" means "distance unknown", not zero and not a clear path. The code has a separate value for this -1. The program decides to stop only after checking the measurement. The basic example at −1 continues to move - this is a limitation of the training algorithm, which we will analyze in the task of loss of echo.
The sensor sends out a short ultrasonic click and listens for the echo. The further away the object, the longer the sound travels back and forth. We calculate the distance by flight time.
Sound travels 1 cm in approximately 29 microseconds. An object is 10 cm away. How long will it take for the echo to return? (Remember: the sound travels there and back.)
Can you explain: echo time → distance. To an object 10 cm away and back - about 580 μs.
The sensor sends out a short ultrasonic click and listens for the echo. The further away the object, the longer the sound travels back and forth.
Sound travels 1 cm in approximately 29 microseconds. How long will it take for the echo to return if the object is 10 cm away? What if it is 30 cm away?
- Write the calculation in the journal.
- Explain why time needs to be multiplied by two.
The calculation for 10 and 30 cm is recorded with an explanation about “there and back”.
The sensor sends out a short ultrasonic click and listens for the echo. The distance is calculated by flight time.
- Sound travels 1 cm in approximately 29 µs. Derive a formula for the distance in centimeters from the echo duration in microseconds.
- The speed of sound depends on temperature. At 0 °C, sound travels 1 cm in approximately 30 µs. The load is 50 cm away. What distance will the sensor report in a cold corridor in winter if the program assumes 29 µs per centimeter? Does this error matter when stopping 5 cm away?
The formula and calculation of the error are recorded. Can you explain when an error can be ignored.
Distance in Serial Monitor
20 min- Look at the TRIG and ECHO contact numbers on the robot's card. There is no card - trace the wires from the TRIG and ECHO pins of the sensor to the board and read the numbers at the sockets. Write it down in a journal.
- Create a sketch
L51_Distanceand enter the contact numbers instead of-1.
// Контакты ультразвукового датчика: впиши номера из таблицы проводки своего робота.const int TRIG_PIN = -1;const int ECHO_PIN = -1; // Расстояние в сантиметрах или -1, если эхо не вернулось.int readDistanceCm() { digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); unsigned long echoUs = pulseIn(ECHO_PIN, HIGH, 25000); if (echoUs == 0) { return -1; } return echoUs / 58;} void setupSonar() { // Без контактов датчика программа дальше не пойдёт. if (TRIG_PIN < 0 || ECHO_PIN < 0) { while (true) { } } pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT);} void setup() { Serial.begin(9600); setupSonar();} void loop() { int distance = readDistanceCm(); if (distance < 0) { Serial.println("нет эха"); } else { Serial.print(distance); Serial.println(" см"); } delay(200);}
- Upload, open the Serial Monitor. Place the weight at 5, 10, 20 and 30 cm along the ruler. Record the readings.
| By line | Sensor reading |
|---|---|
| 5 cm | |
| 10 cm | |
| 20 cm | |
| 30 cm |
The sensor readings are close to the ruler, the difference is 1–2 cm.
How it works: How readDistanceCm works
- We apply a short pulse of 10 μs to TRIG - the sensor clicks.
pulseIn(ECHO_PIN, HIGH, 25000)waits no longer than 25,000 µs for an echo and returns the time in microseconds. If the echo does not return, it returns 0.- Divide the time by 58: that’s 29 microseconds per centimeter there and 29 back.
- If there is no echo, the function returns −1: "no measurement."
| What do you see | What to do |
|---|---|
| The program does not print anything | Are the TRIG and ECHO numbers entered instead of −1? |
| Always "no echo" | TRIG and ECHO are mixed up or the sensor is not receiving power |
| Numbers are jumping | The load must be directly opposite the sensor |
- Look at the TRIG and ECHO contact numbers on the robot's card. There is no card - trace the wires from the TRIG and ECHO pins of the sensor to the board and read the numbers at the sockets. Write it down in a journal.
- Create a sketch
L51_Distanceaccording to the template and enter the contact numbers instead-1. - Write the function
readDistanceCm()myself. Printing in the Serial Monitor is now ready. Until the function is written, the monitor prints "no echo".
| Command | What does |
|---|---|
digitalWrite(TRIG_PIN, HIGH); … LOW | Click: TRIG at HIGH for 10 µs, before short LOW |
delayMicroseconds(мкс); | Waits the specified number of microseconds |
pulseIn(ECHO_PIN, HIGH, 25000) | Echo time in microseconds; 0 - no echo for 25,000 µs |
// Шаблон среднего уровня. Напиши код в разделе «Твоя часть» по целям в комментариях. // Контакты ультразвукового датчика: впиши номера из таблицы проводки своего робота.const int TRIG_PIN = -1;const int ECHO_PIN = -1; // ===== Твоя часть: напиши сам ===== int readDistanceCm() { // Щёлкнуть датчиком и вернуть расстояние до груза в сантиметрах. // Если эхо не вернулось за 25 000 мкс, вернуть -1. return -1;} // ===== Готовое: настройка датчика и печать — не меняй ===== void setupSonar() { // Без контактов датчика программа дальше не пойдёт. if (TRIG_PIN < 0 || ECHO_PIN < 0) { while (true) { } } pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT);} void setup() { Serial.begin(9600); setupSonar();} void loop() { int distance = readDistanceCm(); if (distance < 0) { Serial.println("нет эха"); } else { Serial.print(distance); Serial.println(" см"); } delay(200);}
The echo returned after 1160 microseconds. How many centimeters to the load?
- Upload, open the Serial Monitor. Place the weight at 5, 10, 20 and 30 cm along the ruler. Record the readings.
| By line | Sensor reading |
|---|---|
| 5 cm | |
| 10 cm | |
| 20 cm | |
| 30 cm |
Hint: What to divide by
Sound travels back and forth: 29 microseconds per centimeter in one direction and 29 in the other. How many microseconds are there per centimeter of distance to the load?
Hint: Echo time is a large number
Time may be longer than fits in int. They take it for him unsigned long.
The readings are close to the line, the difference is 1–2 cm. The forecast for 1160 μs is correct.
| What do you see | What to do |
|---|---|
| The program does not print anything | Are the TRIG and ECHO numbers entered instead of −1? |
| Always "no echo" | Is there a click before waiting for an echo? Are TRIG and ECHO confused? |
| Numbers are jumping | The load must be directly in front of the sensor |
- Look at the TRIG and ECHO contact numbers on the robot's card. There is no card - trace the wires from the TRIG and ECHO pins of the sensor to the board and read the numbers at the sockets. Write it down in a journal.
Requirement 1. Function readDistanceCm() returns the distance in centimeters, or −1 if there is no echo. How the sensor works:
- a HIGH pulse with a length of 10 µs is sent to TRIG (preceded by a short LOW);
- the sensor keeps ECHO at HIGH for as many microseconds as the sound travels back and forth;
- sound travels 1 cm in approximately 29 μs;
- no need to wait for echo longer than 25,000 µs: command
pulseIn(pin, HIGH, timeoutUs)will return 0.
Without pin numbers, the program should not work with the sensor: let it stop. Write a sketch L51_Distance, which prints the distance or "no echo".
Acceptance. Ruled table and answers in the journal.
| By line | Indication | Error, see |
|---|---|---|
| 5 cm | ||
| 10 cm | ||
| 20 cm | ||
| 30 cm |
- What is the largest distance the function can measure when waiting 25,000 µs?
- Does the error increase with distance? How do you explain this?
Hint: Idea (1 of 3)
Click, measure echo pulse length, convert microseconds to centimeters.
Hint: Plan (2 of 3)
- TRIG: LOW 2 µs, HIGH 10 µs, LOW.
pulseInon ECHO with a wait of 25,000 µs.- Zero - no echo. Otherwise, divide the time by 58.
Hint: Code snippet (3 of 3)
unsigned long echoUs = pulseIn(ECHO_PIN, HIGH, 25000); - why unsigned long, not int?
The function fulfills requirement 1, the table with errors is filled in, the answers are recorded.
“No echo” - not “nearby”
15 min- Point the sensor into a void or onto soft tissue at an angle. What does the monitor print?
- Place your palm close to the sensor, closer than 2 cm. What does it print?
Neighbors wrote the stop like this: if (readDistanceCm() <= 5) { stopMotors(); }. The robot sometimes stops in the middle of an empty road. Why? What will the function return if there is no echo?
Can you explain why the stopping condition should check that the distance is greater than zero.
- Check the sensor in three positions and write down what the monitor prints:
| Position | What does it print? |
|---|---|
| Into the void | |
| On a soft cloth at an angle | |
| Palm closer than 2 cm |
Neighbors wrote the stop like this: if (readDistanceCm() <= 5) { stopMotors(); }. The robot sometimes stops in the middle of an empty road. Why? What will the function return if there is no echo?
- Write down the correct stopping condition.
The table is completed, the neighbors' error is explained, the correct condition is written down.
Find the limits beyond which the sensor cannot be trusted.
- Place the weight 20 cm and turn it sideways towards the sensor. From what angle does the echo disappear?
- Move the weight towards the sensor. At what distance do the readings stop matching the ruler?
- Point the sensor at soft tissue. What does the monitor print?
Neighbors wrote the stop like this: if (readDistanceCm() <= 5) { stopMotors(); }. The robot sometimes stops in the middle of an empty road. Why?
- Write down which of the boundaries found are dangerous for delivery and how the program should behave in each case.
In the log - echo loss angle, near boundary, behavior on fabric and rules for the program.
We go to the cargo and stop
17 min- Create a sketch
L51_Stop_At_Can. Transfer measurementskp,baseSpeedand sensor contacts.
const int LEFT_SENSOR_PIN = A4;const int RIGHT_SENSOR_PIN = A5;const int LEFT_DIR_PIN = 7;const int LEFT_SPEED_PIN = 6;const int RIGHT_DIR_PIN = 4;const int RIGHT_SPEED_PIN = 5;const int FORWARD = HIGH;const int BACKWARD = (FORWARD == HIGH) ? LOW : HIGH; // Измерения и настройки из журнала (уроки 3.1 и 3.2).const int LEFT_WHITE = 0;const int LEFT_BLACK = 0;const int RIGHT_WHITE = 0;const int RIGHT_BLACK = 0;float kp = 0.5;int baseSpeed = 100; int leftLevel = 100;int rightLevel = 100; int level(int value, int white, int black) { long result = (long)(value - black) * 100 / (white - black); return constrain(result, 0, 100);} void readSensors() { leftLevel = level(analogRead(LEFT_SENSOR_PIN), LEFT_WHITE, LEFT_BLACK); rightLevel = level(analogRead(RIGHT_SENSOR_PIN), RIGHT_WHITE, RIGHT_BLACK);} void drive(int leftDir, int leftSpeed, int rightDir, int rightSpeed) { digitalWrite(LEFT_DIR_PIN, leftDir); digitalWrite(RIGHT_DIR_PIN, rightDir); analogWrite(LEFT_SPEED_PIN, leftSpeed); analogWrite(RIGHT_SPEED_PIN, rightSpeed);} void stopMotors() { analogWrite(LEFT_SPEED_PIN, 0); analogWrite(RIGHT_SPEED_PIN, 0);} void followLineStep() { int error = leftLevel - rightLevel; int correction = kp * error; drive(FORWARD, constrain(baseSpeed + correction, 0, 255), FORWARD, constrain(baseSpeed - correction, 0, 255));} void setupRobot() { pinMode(LEFT_DIR_PIN, OUTPUT); pinMode(LEFT_SPEED_PIN, OUTPUT); pinMode(RIGHT_DIR_PIN, OUTPUT); pinMode(RIGHT_SPEED_PIN, OUTPUT); stopMotors(); // Без измерений робот не поедет. if (LEFT_WHITE == LEFT_BLACK || RIGHT_WHITE == RIGHT_BLACK) { while (true) { } } delay(2000);} // Контакты ультразвукового датчика: впиши номера из таблицы проводки своего робота.const int TRIG_PIN = -1;const int ECHO_PIN = -1; // Расстояние в сантиметрах или -1, если эхо не вернулось.int readDistanceCm() { digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); unsigned long echoUs = pulseIn(ECHO_PIN, HIGH, 25000); if (echoUs == 0) { return -1; } return echoUs / 58;} void setupSonar() { // Без контактов датчика программа дальше не пойдёт. if (TRIG_PIN < 0 || ECHO_PIN < 0) { while (true) { } } pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT);} const int STOP_CM = 5; // на каком расстоянии от груза остановиться void setup() { setupSonar(); setupRobot(); while (true) { int distance = readDistanceCm(); if (distance > 0 && distance <= STOP_CM) { break; } readSensors(); followLineStep(); } stopMotors();} void loop() {}
- Place the weight at the end of the line. Launch the robot from the other end.
The robot travels along the line and stops in front of the load without touching it.
How it works: What break does
break exits the loop immediately while. After the loop the program executes stopMotors(). So the “stop by distance” ends up in one place in the program.
- Create a sketch
L51_Stop_At_Canaccording to the template. Transfer measurementskp,baseSpeed, sensor contacts and replacereadDistanceCmby its function. - Write the movement in
setup()himself: the robot drives along the line and stops in front of the load. Remember the step “No echo - not nearby.”
// Шаблон среднего уровня. Напиши код в разделе «Твоя часть» по целям в комментариях.// Функцию readDistanceCm ниже замени своей из L51_Distance. const int LEFT_SENSOR_PIN = A4;const int RIGHT_SENSOR_PIN = A5;const int LEFT_DIR_PIN = 7;const int LEFT_SPEED_PIN = 6;const int RIGHT_DIR_PIN = 4;const int RIGHT_SPEED_PIN = 5;const int FORWARD = HIGH;const int BACKWARD = (FORWARD == HIGH) ? LOW : HIGH; // Измерения и настройки из журнала (уроки 3.1 и 3.2).const int LEFT_WHITE = 0;const int LEFT_BLACK = 0;const int RIGHT_WHITE = 0;const int RIGHT_BLACK = 0;float kp = 0.5;int baseSpeed = 100;int leftLevel = 100;int rightLevel = 100; // Контакты ультразвукового датчика: впиши номера из таблицы проводки своего робота.const int TRIG_PIN = -1;const int ECHO_PIN = -1;const int STOP_CM = 5; // на каком расстоянии от груза остановиться // ===== Твоя часть: напиши сам ===== void setup() { setupSonar(); setupRobot(); // Ехать по линии и остановиться, когда груз не дальше STOP_CM. // «Нет эха» — не «груз рядом»: тогда робот едет дальше.} // ===== Готовое из уроков 3.2 и 5.1 — не меняй ===== int level(int value, int white, int black) { long result = (long)(value - black) * 100 / (white - black); return constrain(result, 0, 100);} void readSensors() { leftLevel = level(analogRead(LEFT_SENSOR_PIN), LEFT_WHITE, LEFT_BLACK); rightLevel = level(analogRead(RIGHT_SENSOR_PIN), RIGHT_WHITE, RIGHT_BLACK);} void drive(int leftDir, int leftSpeed, int rightDir, int rightSpeed) { digitalWrite(LEFT_DIR_PIN, leftDir); digitalWrite(RIGHT_DIR_PIN, rightDir); analogWrite(LEFT_SPEED_PIN, leftSpeed); analogWrite(RIGHT_SPEED_PIN, rightSpeed);} void stopMotors() { analogWrite(LEFT_SPEED_PIN, 0); analogWrite(RIGHT_SPEED_PIN, 0);} void followLineStep() { int error = leftLevel - rightLevel; int correction = kp * error; drive(FORWARD, constrain(baseSpeed + correction, 0, 255), FORWARD, constrain(baseSpeed - correction, 0, 255));} void setupRobot() { pinMode(LEFT_DIR_PIN, OUTPUT); pinMode(LEFT_SPEED_PIN, OUTPUT); pinMode(RIGHT_DIR_PIN, OUTPUT); pinMode(RIGHT_SPEED_PIN, OUTPUT); stopMotors(); // Без измерений робот не поедет. if (LEFT_WHITE == LEFT_BLACK || RIGHT_WHITE == RIGHT_BLACK) { while (true) { } } delay(2000);} // Расстояние в сантиметрах или -1, если эхо не вернулось.int readDistanceCm() { digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); unsigned long echoUs = pulseIn(ECHO_PIN, HIGH, 25000); if (echoUs == 0) { return -1; } return echoUs / 58;} void setupSonar() { // Без контактов датчика программа дальше не пойдёт. if (TRIG_PIN < 0 || ECHO_PIN < 0) { while (true) { } } pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT);} void loop() {}
- Place the weight at the end of the line. Launch the robot from the other end.
Hint: Drive while...
As in followLineToCrossing() lesson 4.1: in a loop, measure the distance, decide whether it is time to stop, otherwise take a step along the line.
Hint: Two checks
You can stop only if there is a measurement and the load is close. What number will your function return if there is no echo?
How it works: How to exit the loop
break exits the loop immediately while. The program continues after the loop.
The robot drives along the line and stops in front of the load without touching it, and does not stop in the middle of an empty road.
Requirement 2. Continue with your program L42_Turn_At_Crossing and save as L51_Stop_At_Can. Function followLineToCan(stopCm) guides the robot along the line and stops it when the load is no further stopCm:
- "no echo" is never considered "cargo nearby";
- after stopping, the motors are turned off;
- the line and intersection functions from previous lessons do not change.
Acceptance. Load at the end of the line - the robot stops without touching the load. There is no load - the robot reaches the end of the line without stopping in the middle of the road (be prepared to turn off the power).
Hint: Idea (1 of 2)
This followLineToCrossing() from lesson 4.1, the only way out is by distance.
Hint: Code snippet (2 of 2)
if (distance > 0 && distance <= stopCm) { return; } - why here return, not break?
The program fulfills requirement 2, both acceptance checks are recorded.
Precise stop
15 min- Use a ruler to measure at what distance the robot stopped from the load.
- Pick up
STOP_CMandbaseSpeed, so that the robot stops where it is convenient for the gripper. - Repeat three times. Write it down in a journal
STOP_CMand actual distance.
Hint: The robot stops further or closer than STOP_CM
The robot does not stop instantly: it rolls a little more. The higher the speed, the further. You can drive slower in front of the load or put STOP_CM a little more.
The robot stops three times in a row at the required distance from the load.
Pick up STOP_CM and baseSpeed so that the robot stops where it is convenient to grab. Change one number at a time.
- Decide how far away from the load the robot should stand. If the gripper is already in place, measure it; if not, choose the distance at which the robot does not touch the load, and clarify it in lesson 5.2. Write it down.
- Start it, measure with a ruler where the robot stopped. Write it down in a table and decide what to change.
STOP_CM | baseSpeed | Where I stayed, see | What to change and why |
|---|---|---|---|
- When it works, repeat three times.
Hint: The robot stops closer than STOP_CM
The robot does not stop instantly: it rolls a little more. The higher the speed, the further.
The robot stops at the required distance three times in a row. The log contains a table of attempts with an explanation.
Get it to stop at the right distance ±1 cm three times out of three at its operating speed - the one at which the robot passes the line.
- Measure the run-out: at
baseSpeed80, 120 and set your workerSTOP_CM = 15and measure how many centimeters the robot rolled after the stop command. - Choose a method for precise stopping and justify it with a table: correct
STOP_CMcoast or drive slower in the last centimeters before the load. - Triple check.
baseSpeed | STOP_CM | Where I stayed, see | Run-out, cm |
|---|---|---|---|
| 80 | 15 | ||
| 120 | 15 | ||
| 15 |
Hint: Slow at the end
Two thresholds: beyond the first - working speed, between the first and second - slow, at the second - stop.
Rundown table, selected method with justification and three stops ±1 cm are recorded.
Quests by level
13 minStop 5 cm from the load at the end of the line.
If there is no echo, measure again. If there is no echo five times in a row, stop the robot: something is wrong with the sensor. This way the robot will not leave the field having lost its load.
Take three measurements and take the average value - the median. One random wrong number will then not ruin the stop. Compare the raw measurements and the median in the Serial Monitor.
Test yourself
Select answers to prepare. They are not stored or evaluated on the site. Take the knowledge test in the course syllabus or discuss the answers with your instructor.
● Basic
★ Intermediate level
★★ Advanced level
Answer questions at your level. Correct answers needed: Beginner - 4 out of 5; Average - 4 out of 5; Advanced - 4 out of 5. Answers will be checked by the teacher or course program.
Summary
The robot sees the load and stops in front of it along the dimension. All that remains is to learn how to take it - in the next lesson.
How to confirm the result
The result of the experiment relates the conditions, program version, observation and conclusion. Comparing attempts with one change helps verify the cause, including failed attempts. The mark refers to practice already completed; repetition for the sake of marking is not necessary. The discrepancy with the forecast sets the next hypothesis to be tested. A model, measurements of a real robot, and an explanation are different types of evidence.
Lesson vocabulary
| ultrasound | The sound is so high that a person cannot hear it. The sensor sends a click and waits for an echo. |
| echo | Sound reflected from an object and returned to the sensor. |
| pulseIn | A command that measures how many microseconds the input signal lasted. |
| μs | A microsecond is a millionth of a second. |
| median | The average of several numbers: of 4, 25 and 5, this is 5. |