Turns at the intersection and route
The robot turns from the intersection onto the desired line and follows a route consisting of several solutions.
Lesson result
The robot turns left or right from the intersection to a new line, turns around on the line and follows a route of several solutions written in order in the program.
You will learn
- Explain why turning by sensors is more reliable than turning by time.
- Choose an exit to the center of the intersection so that after the turn the robot is on the line.
- Write down the route as a sequence of decisions “left / right / straight”.
- Check the route on the field and find at which solution it breaks.
Need to know
- 4.1 Finding and counting intersections
- 2.2 Turns and U-turns
Will need
Why this lesson
The robot finds an intersection. Now he must collapse - to the cargo, to the delivery point or further down the road. In Lesson 2.2 the turns were timed and battery dependent. Today the robot will turn according to sensors: it will spin until it finds a new line.
- Why does the rotation time turn out different when the battery is low?
- What does
passCrossing()? - How does a robot understand that there is an intersection below it?
How to turn accurately
8 minWhat should a robot do. The robot needs to go through several intersections and choose the right direction at each one. We use line sensors to detect events and a pre-recorded route plan to select an action.
What we use and how it works. Sensors answer the question “what is under the robot now,” and the route answers “what to do next.” The program reaches the intersection, makes a turn or drive straight, exits the transverse lane and moves on to the next point. An array or call sequence stores order, but does not measure the robot's position.
How to link a dimension to an action. We check the route by sections: we note which intersection was found and what action was performed. If the robot did not detect the lane or turned in the wrong direction, the next commands will be executed in a different place. Therefore, first we will check each function, then we will assemble the whole route.
The robot stands at the intersection and turns left. How can he himself understand that he has turned enough and is already looking along the new line?
- Discuss with a partner. Place the robot at an intersection and slowly turn it with your hands.
- Watch the left sensor: when will it be above the new line?
Can you explain the idea: spin until the sensor on the turning side sees a new line.
The robot stands at the intersection and turns left. How can he himself understand that he has turned enough and is already looking along the new line?
- Place the robot in the center of the intersection and slowly turn your hands to the left, then to the right.
- For each turn, write down which sensor was first above the new line and which sensor was above the old line at the beginning of the turn.
| Rotate | Sees the new line first | Passes over the old one first |
|---|---|---|
| Left | ||
| Right |
The table is full. Can you explain the idea: spin until the sensor on the side of the turn sees a new line.
Test the "spin to new line" idea with a measurement before programming it.
- Place a sheet of paper with a protractor or lines at 10° intervals under the robot. Place the robot in the center of the intersection.
- Slowly turn your hands to the left. Write down the angle at which the left sensor for the first time sees the new line, and the angle at which the robot looks exactly along it.
- Repeat to the right.
- Are the angles the same? What then will a robot do if it stops the moment the sensor sees the line? How to fix this?
The log contains two angles for each turn and a conclusion about where the robot will stop.
Drive to the center of the intersection
12 minSensors are standing ahead wheels. When the sensors noticed the intersection, the wheels had not yet reached it. If you turn right away, the robot will end up on the side of the new line. Therefore, you first need to drive forward so that the wheels are above the center of the intersection.
- Place the robot so that the sensors are on the transverse line.
- Measure with a ruler how much longer the wheels will travel to the center of the intersection. Write it down in a journal.
- The time of this passage is
centerMs- we will select it in the next step.
You know why you need to go to the center before turning.
Sensors are standing ahead wheels. When the sensors noticed the intersection, the wheels had not yet reached it.
The robot turned in place as soon as the sensors saw the intersection. Where will the robot end up in relation to the new line? Show on the path with your hands.
- Place the robot with the sensors on the transverse line and turn it 90° with your hands in place. Where were the sensors - above the new line or on the side?
- Measure with a ruler how much longer the wheels will travel to the center of the intersection. Write it down in a journal.
- The time of this passage is
centerMs- you will pick it up in the next step. How will you understand that time is too short, and how will you know that it is too long? Write it down.
The forecast was checked by hand, the distance was recorded, the signs “few” and “many” for centerMs are recorded.
Sensors are standing ahead wheels, so before turning, the robot drives to the center of the intersection. Calculate the time of this departure, and do not select it at random.
- Measure the distance from the sensors to the wheel axle in millimeters.
- Take from the log of lesson 2.1 your speed in millimeters per second at close
baseSpeed. There is no table - measure: travel 1 second, travel with a ruler, three times. - Do the math
centerMsand write down the calculation. In the next step, compare it with the one picked up on the track. - Write down why time travel is a weak point and what its accuracy depends on.
In the journal - distance, speed, calculation centerMs and two reasons why the departure time may be wrong.
Turning at an intersection
22 min- Create a sketch
L42_Turn_At_Crossing. Transfer measurementskpandbaseSpeed.
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);} // Перекрёсток: оба датчика видят чёрное.bool onCrossing() { return leftLevel < 30 && rightLevel < 30;} // Ехать по линии, пока не найдём перекрёсток.void followLineToCrossing() { while (true) { readSensors(); if (onCrossing()) { return; } followLineStep(); }} // Проехать перекрёсток прямо, пока датчики не съедут с чёрного.void passCrossing() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); do { readSensors(); } while (onCrossing()); delay(100);} int turnSpeed = 100;int centerMs = 250; // подбираем: проехать от датчиков до центра перекрёсткаint leaveMs = 200; // время, чтобы датчик ушёл со старой линии // Выехать на центр перекрёстка: датчики стоят впереди колёс.void toCenter() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); delay(centerMs); stopMotors();} // Крутиться на месте, пока датчик со стороны поворота не найдёт новую линию.void turnUntilLine(bool left) { if (left) { drive(BACKWARD, turnSpeed, FORWARD, turnSpeed); } else { drive(FORWARD, turnSpeed, BACKWARD, turnSpeed); } delay(leaveMs); do { readSensors(); } while ((left ? leftLevel : rightLevel) > 30); stopMotors();} void turnLeftAtCrossing() { toCenter(); turnUntilLine(true);} void turnRightAtCrossing() { toCenter(); turnUntilLine(false);} // Развернуться на линии: крутиться, пока линия снова не окажется под датчиком.void turnAroundOnLine() { turnUntilLine(true);} // Ехать по линии заданное время.void followLineFor(unsigned long ms) { unsigned long start = millis(); while (millis() - start < ms) { readSensors(); followLineStep(); } stopMotors();} void setup() { setupRobot(); followLineToCrossing(); turnLeftAtCrossing(); followLineFor(1500); turnAroundOnLine(); followLineToCrossing(); stopMotors();} void loop() {}
- Parse the function
turnUntilLine. Why in itdelay(leaveMs)before searching for a line? - Start on the path with an intersection. Pick up
centerMs: after turning, the robot should confidently follow the new line.
The robot reaches the intersection, turns left and follows the new line.
How it works: Why leaveMs
At the beginning of the turn, the sensor is still above the old line and would immediately “find” it. Therefore the first leaveMs milliseconds the robot simply spins without looking at the sensors - so that the sensor leaves the old line. Then we look for a new one.
| What do you see | What to do |
|---|---|
| After turning, the robot is on the side of the line | Pick up centerMs |
| The robot spins endlessly | Sensor does not see the line: check threshold 30 and measurements |
| The robot stops immediately | Enlarge leaveMs |
- Create a sketch
L42_Turn_At_Crossingaccording to the template. Transfer measurementskpandbaseSpeed. The line and intersection functions are already ready. - Write a trip to the center yourself
toCenter(), turn to lineturnUntilLine()and turning left and right from the intersection.setup()below checks them out on the track.
// Шаблон среднего уровня. Напиши код в разделе «Твоя часть» по целям в комментариях.// setup() ниже — проверка твоих функций на дорожке. 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 turnSpeed = 100;int centerMs = 250; // подбираем: проехать от датчиков до центра перекрёсткаint leaveMs = 200; // время, чтобы датчик ушёл со старой линии // ===== Твоя часть: напиши сам ===== void toCenter() { // Колёса встают над центром перекрёстка: проехать вперёд centerMs и остановиться.} void turnUntilLine(bool left) { // Крутиться на месте (left = true — налево) до новой линии; в конце колёса стоят. // Пока датчик ещё над старой линией, она не должна считаться новой — для этого есть leaveMs.} void turnLeftAtCrossing() { // Повернуть с перекрёстка налево на новую линию.} void turnRightAtCrossing() { // Повернуть с перекрёстка направо на новую линию.} // ===== Готовое из уроков 3.2–4.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);} // Перекрёсток: оба датчика видят чёрное.bool onCrossing() { return leftLevel < 30 && rightLevel < 30;} // Ехать по линии, пока не найдём перекрёсток.void followLineToCrossing() { while (true) { readSensors(); if (onCrossing()) { return; } followLineStep(); }} // Проехать перекрёсток прямо, пока датчики не съедут с чёрного.void passCrossing() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); do { readSensors(); } while (onCrossing()); delay(100);} // Развернуться на линии: крутиться, пока линия снова не окажется под датчиком.void turnAroundOnLine() { turnUntilLine(true);} // Ехать по линии заданное время.void followLineFor(unsigned long ms) { unsigned long start = millis(); while (millis() - start < ms) { readSensors(); followLineStep(); } stopMotors();} void setup() { setupRobot(); followLineToCrossing(); turnLeftAtCrossing(); followLineFor(1500); turnAroundOnLine(); followLineToCrossing(); stopMotors();} void loop() {}
What happens if you start looking for a new line right away without waiting leaveMs?
- Start on the path with an intersection. Pick up
centerMsbased on the characteristics that you wrote down in the previous step.
Hint: Spin to the line
It's like passCrossing() from Lesson 4.1: Repeat reading sensors as long as the condition is true. What condition means “there is no line under the sensor yet”?
Hint: Which sensor to look for
Turn left - the left sensor will see the new line first.
The robot reaches the intersection, turns left and follows the new line. The forecast is recorded.
| What do you see | What to do |
|---|---|
| After turning, the robot is on the side of the line | Pick up centerMs |
| The robot spins endlessly | The sensor does not see the line: check the search and measurement conditions |
| The robot stops immediately | Enlarge leaveMs |
Requirement 1. Continue with your program L41_Count and save as L42_Turn_At_Crossing. Function turnUntilLine(left) turns the robot in place to a new line:
- first the robot spins without looking at the sensors until the sensor leaves the old line;
- then - until the sensor on the side of the turn sees the line;
- if the line is not found within 3 seconds, the robot stops: on the field without protection it will spin endlessly.
Requirement 2. turnLeftAtCrossing() and turnRightAtCrossing(): departure to the center according to your centerMs, then turn to the line.
Acceptance. Five turns left and right: after each, the robot leaves along a new line. Check the protection separately: lift the robot above the table while turning.
Hint: Idea (1 of 3)
Line search - cycle “read sensors while there is no line”. For protection, remember the start time of the search.
Hint: Plan (2 of 3)
- Turn on rotation, wait
leaveMs. - Remember
millis(). - Repeat reading until there is no line and less than 3 seconds have passed.
- Stop the motors.
Hint: Code snippet (3 of 3)
while ((left ? leftLevel : rightLevel) > 30 && millis() - start < 3000) - read the condition in words.
The program fulfills requirements 1-2, ten turns and the defense check are recorded. Handpicked centerMs is compared with the calculation.
Reversal on line
10 minAt the end of the branch, at the cargo or delivery point, the robot needs to turn around and return to the intersection. A turn is the same turn according to the sensors, only the line is now behind.
- Find the call in the sketch
turnAroundOnLine(). Check on the path: drive along the branch, turn around, return to the intersection.
The robot turns around, finds the same line and returns to the intersection.
At the end of the branch, the robot needs to turn around and return to the intersection. A turn is the same turn according to the sensors, only the line is now behind.
- Find the function in the sketch
turnAroundOnLine(). Why doesn’t it have an exit to the center, like a turn at an intersection? Write down the answer. - Check the path three times: drive along the branch, turn around, return to the intersection.
The robot turns around three times and returns to the intersection. The answer about going to the center is written down.
Requirement 3. turnAroundOnLine() turns the robot on the line and stops when the line is under the sensor again. The 3 second defense from requirement 1 works here too.
Acceptance. Five turns at the end of the branch: after each, the robot returns to the intersection. For each, measure how far the nose looks past the line immediately after the turn.
| Reversal | Back? | Nose off the line, mm |
|---|---|---|
| 1 |
If the nose points in the same direction every time, suggest and check one correction.
Five spreads in the table, bias correction verified.
Route in order
22 minThe route is solutions at intersections in order. The robot does not see what intersection it is: it simply makes the next decision.
- Create a sketch
L42_Route. Draw a training track and path for the robot in a journal.
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);} // Перекрёсток: оба датчика видят чёрное.bool onCrossing() { return leftLevel < 30 && rightLevel < 30;} // Ехать по линии, пока не найдём перекрёсток.void followLineToCrossing() { while (true) { readSensors(); if (onCrossing()) { return; } followLineStep(); }} // Проехать перекрёсток прямо, пока датчики не съедут с чёрного.void passCrossing() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); do { readSensors(); } while (onCrossing()); delay(100);} int turnSpeed = 100;int centerMs = 250; // подбираем: проехать от датчиков до центра перекрёсткаint leaveMs = 200; // время, чтобы датчик ушёл со старой линии // Выехать на центр перекрёстка: датчики стоят впереди колёс.void toCenter() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); delay(centerMs); stopMotors();} // Крутиться на месте, пока датчик со стороны поворота не найдёт новую линию.void turnUntilLine(bool left) { if (left) { drive(BACKWARD, turnSpeed, FORWARD, turnSpeed); } else { drive(FORWARD, turnSpeed, BACKWARD, turnSpeed); } delay(leaveMs); do { readSensors(); } while ((left ? leftLevel : rightLevel) > 30); stopMotors();} void turnLeftAtCrossing() { toCenter(); turnUntilLine(true);} void turnRightAtCrossing() { toCenter(); turnUntilLine(false);} // Развернуться на линии: крутиться, пока линия снова не окажется под датчиком.void turnAroundOnLine() { turnUntilLine(true);} // Ехать по линии заданное время.void followLineFor(unsigned long ms) { unsigned long start = millis(); while (millis() - start < ms) { readSensors(); followLineStep(); } stopMotors();} // Маршрут: решения на перекрёстках по порядку.void setup() { setupRobot(); followLineToCrossing(); turnLeftAtCrossing(); // решение 1: налево followLineToCrossing(); passCrossing(); // решение 2: прямо followLineToCrossing(); turnRightAtCrossing(); // решение 3: направо followLineToCrossing(); stopMotors(); // конец маршрута} void loop() {}
According to the program: left, straight, right. Draw where the robot will stop on the track.
- Run it. If the route breaks down, what is the solution? Why?
The robot goes through a route of three solutions and stops where you predicted.
At the neighbors after turnLeftAtCrossing() is worth it right away turnRightAtCrossing(), without followLineToCrossing() between them. What will the robot do?
The route is solutions at intersections in order. The robot does not see what intersection it is: it simply makes the next decision.
- Draw a training track and path in a journal: left, straight, right.
- Create a sketch
L42_Routeaccording to the template and write the route insetup()itself from the ready-made functions of the lesson.
// Шаблон среднего уровня. Напиши код в разделе «Твоя часть» по целям в комментариях. 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 turnSpeed = 100;int centerMs = 250; // подбираем: проехать от датчиков до центра перекрёсткаint leaveMs = 200; // время, чтобы датчик ушёл со старой линии // ===== Твоя часть: напиши сам ===== void setup() { setupRobot(); // Маршрут из журнала: на каждом перекрёстке — своё решение по порядку. // В конце остановиться на следующем перекрёстке.} // ===== Готовое из уроков 3.2–4.2 — не меняй ===== 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);} // Перекрёсток: оба датчика видят чёрное.bool onCrossing() { return leftLevel < 30 && rightLevel < 30;} // Ехать по линии, пока не найдём перекрёсток.void followLineToCrossing() { while (true) { readSensors(); if (onCrossing()) { return; } followLineStep(); }} // Проехать перекрёсток прямо, пока датчики не съедут с чёрного.void passCrossing() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); do { readSensors(); } while (onCrossing()); delay(100);} // Выехать на центр перекрёстка: датчики стоят впереди колёс.void toCenter() { drive(FORWARD, baseSpeed, FORWARD, baseSpeed); delay(centerMs); stopMotors();} // Крутиться на месте, пока датчик со стороны поворота не найдёт новую линию.void turnUntilLine(bool left) { if (left) { drive(BACKWARD, turnSpeed, FORWARD, turnSpeed); } else { drive(FORWARD, turnSpeed, BACKWARD, turnSpeed); } delay(leaveMs); do { readSensors(); } while ((left ? leftLevel : rightLevel) > 30); stopMotors();} void turnLeftAtCrossing() { toCenter(); turnUntilLine(true);} void turnRightAtCrossing() { toCenter(); turnUntilLine(false);} // Развернуться на линии: крутиться, пока линия снова не окажется под датчиком.void turnAroundOnLine() { turnUntilLine(true);} // Ехать по линии заданное время.void followLineFor(unsigned long ms) { unsigned long start = millis(); while (millis() - start < ms) { readSensors(); followLineStep(); } stopMotors();} void loop() {}
Draw where the robot will stop on the path.
- Run it. If the route breaks down, what is the solution? Why?
Hint: One solution
Before each decision, the robot must reach an intersection.
The robot goes through a route of three solutions and stops where you predicted.
At the neighbors after turnLeftAtCrossing() is worth it right away turnRightAtCrossing(), without followLineToCrossing() between them. What will the robot do?
Requirement 4. The route is planned to the program and checked in parts.
- Choose a path of four or more decisions on the training field that includes left, right, and straight. If the final task field is laid out in the classroom, take the path from the start to one delivery zone. Write it down in a table:
| № | Crossroads | Solution | Where does the robot look after |
|---|---|---|---|
| 1 |
- Write the route into the program
L42_Routefrom its functions. - If the route is broken, do not rewrite everything: run only the first solutions, then half, and find the first solution on which the robot makes a mistake. Write down how you searched.
At which solution is the route most likely to fail and why? Record before the first launch.
Hint: How to check in parts
Temporarily set stopMotors(); and return; after the required solution in setup().
Route table, program based on it, forecast and error search record. The robot goes through a route on a training track.
Quests by level
13 minTurn left and right from the intersection and go along the new line; turn around on the line and return.
Create a route on the training field with four solutions, which includes left, right and straight. Write it down in a journal, then into a program, and go through it without errors.
Write the solutions as an array: char route[] = {'L', 'S', 'R', 'L'};. Write a function decide(d), which makes one decision, and a loop that goes through the entire array. Create a route based on the field diagram so that only the row with the array changes for the new route.
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 turns according to sensors and follows a route of solutions. For the final task, all that remains is to learn to see the load and grab it.
How to confirm the result
For each experiment, save the conditions, program version, observation and conclusion. When comparing attempts, change one reason at a time; unsuccessful attempts also remain in the log. Marking a result refers to actions that have already been completed; there is no need to repeat them for the sake of marking. If the result is not obtained, write down the discrepancy and the next hypothesis to be tested. A model, measurements of a real robot, and an explanation are different types of evidence.
Lesson vocabulary
| route | Sequence of decisions at intersections: left, right or straight. |
| intersection center | The point where the lines intersect. To turn, the wheels must be in place above it. |
| array | A list of values under one name: route[0], route[1] and so on. |
| millis() | How many milliseconds have passed since the board was turned on. Allows you to ride for a specified time without stopping the program. |