Захват: берём и ставим
Робот подъезжает к грузу, берёт его захватом, увозит и ставит в нужном месте.
Результат урока
Робот подъезжает к грузу по ультразвуку, берёт её, разворачивается, везёт по линии и ставит на другом конце. Действия оформлены функциями pickUp() и putDown().
Ты научишься
- Объяснить, как сервопривод поворачивается на заданный угол.
- Найти углы «открыто» и «закрыто» для своего захвата опытом.
- Соблюдать порядок: остановиться — закрыть; открыть — подождать — отъехать.
- Собрать перевозку груза из функций прошлых уроков.
Нужно знать
- 5.1 Ультразвук: видим груз
- 4.2 Повороты на перекрёстке и маршрут
Понадобится
Зачем этот урок
Робот умеет доезжать до груза. Остался последний навык курьера — взять груз, довезти и аккуратно поставить. Сегодня робот соберёт всё вместе: линия, ультразвук и захват.
- Какое условие остановки перед грузом правильное и почему?
- Как робот разворачивается на линии?
- Что делает
followLineFor(1500)?
Не держи пальцы в захвате, когда включено питание. Сервопривод может резко повернуться при загрузке программы.
Как работает сервопривод
8 минЧто должен делать робот. Курьер должен взять груз, удержать его при перевозке и отпустить в нужном месте. Для этого добавим механический захват с сервоприводом. Ультразвук помогает подъехать, но сам ничего не захватывает.
Что используем и как это работает. Внутри сервопривода есть мотор, редуктор, датчик положения и управляющая схема. По управляющим импульсам он получает заданное положение вала и старается его удержать. Библиотека Servo формирует эти импульсы; gripper.write задаёт положение, а не скорость вращения. Рычаг превращает поворот вала в движение губок захвата.
Как связать измерение с действием. Углы «открыто» и «закрыто» подбираем для своей механики небольшими изменениями; чужие числа могут упереть механизм в ограничитель. Сначала останавливаем колёса, затем закрываем захват и даём ему время. Команда закрытия не доказывает, что груз удерживается: это проверяем наблюдением. Подключение и питание сверяем с подтверждённой схемой комплекта.
Обычный мотор крутится, пока включён. Сервопривод поворачивается на заданный угол и держит его. Внутри у него мотор, шестерёнки и датчик положения. Командуем углом в градусах: gripper.write(90).
Что сделает сервопривод после gripper.write(90), а потом gripper.write(40)?
Ты можешь объяснить, чем сервопривод отличается от мотора колеса.
Обычный мотор крутится, пока включён. Сервопривод поворачивается на заданный угол и держит его. Командуем углом в градусах: gripper.write(90).
Что сделает сервопривод после gripper.write(90), а потом gripper.write(40)? А мотор колеса после analogWrite(…, 90)?
- Запиши в журнал: чем команда сервоприводу отличается от команды мотору колеса — что задаёт число и когда движение заканчивается.
Сравнение сервопривода и мотора колеса записано.
Сервопривод поворачивается на заданный угол и держит его: внутри мотор, шестерёнки и датчик положения.
- Посмотри контакт сервопривода на карточке у робота и впиши его в скетч пробы угла.
- Сделай опыт:
gripper.write(40), пауза,gripper.write(90), пауза. Пробуй паузы 100, 300 и 600 мс. При какой паузе захват успевает дойти до угла? - Запиши, сколько примерно времени нужно сервоприводу на 50° и почему программа должна ждать после команды.
В журнале — опыт с паузами и наименьшая пауза, при которой захват доходит до угла.
Найди углы «открыто» и «закрыто»
22 минУ каждого захвата свои углы. Найдём их опытом, как время поворота в уроке 2.2.
- Посмотри контакт сервопривода на карточке у робота и впиши его вместо
-1.
#include <Servo.h> // Контакт сервопривода захвата: впиши номер из таблицы проводки своего робота.const int SERVO_PIN = -1; int angle = 90; // меняй понемногу, чтобы найти «открыто» и «закрыто» Servo gripper; void setup() { if (SERVO_PIN < 0) { while (true) { } } gripper.attach(SERVO_PIN); gripper.write(angle);} void loop() {}
- Начни с
angle = 90. Загрузи. Меняй угол по 10°: найди положение, где захват открыт так, что груз свободно входит. - Найди угол, где захват держит груз крепко, но не давит изо всех сил.
- Запиши оба угла в журнал.
Подсказка: Сервопривод гудит или дрожит
Захват упёрся в груз или в собственный упор и не может дойти до угла. Отступи на 5–10° от этого положения: сервопривод не должен работать в упор.
В журнале записаны углы «открыто» и «закрыто», при которых груз свободно входит и надёжно держится.
У каждого захвата свои углы. Найди их опытом — способ выбери сам, но меняй только angle и записывай каждую попытку.
| Команда | Что делает |
|---|---|
gripper.attach(контакт); | Связывает сервопривод с контактом |
gripper.write(угол); | Поворачивает на угол 0…180 и держит его |
- Создай скетч
L52_Servo_Testпо шаблону. Посмотри контакт сервопривода на карточке у робота и впиши его вместо-1. - Допиши
setup()сам: захват должен повернуться наangle.
// Шаблон среднего уровня. Напиши код в разделе «Твоя часть» по целям в комментариях. #include <Servo.h> // Контакт сервопривода захвата: впиши номер из таблицы проводки своего робота.const int SERVO_PIN = -1;int angle = 90; // меняй понемногу, чтобы найти «открыто» и «закрыто» Servo gripper; // ===== Твоя часть: напиши сам ===== void setup() { if (SERVO_PIN < 0) { while (true) { } } // Захват поворачивается на угол angle и держит его.} void loop() {}
- Найди угол «открыто»: груз свободно входит в захват.
- Найди угол «закрыто»: груз держится крепко, а сервопривод не гудит.
- Проверь «закрыто»: подними робота с грузом и слегка наклони. Груз не выпадает?
| Попытка | angle | Что видно | Что поменять и почему |
|---|---|---|---|
| 1 | 90 | ||
| 2 | |||
| 3 | |||
| 4 |
Подсказка: Сервопривод гудит или дрожит
Захват упёрся и не может дойти до угла. Что нужно сделать с углом?
В журнале — попытки с объяснением, углы «открыто» и «закрыто» и проверка наклоном.
Посмотри контакт сервопривода на карточке у робота.
Требование 1. Скетч L52_Servo_Test для подбора углов: угол вводится числом в монитор порта, и захват поворачивается сразу, без новой загрузки программы.
- Принимаются только числа от 0 до 180; на другое число программа отвечает, что так нельзя, и захват не двигается.
- После каждого поворота программа печатает, какой угол сейчас.
- Без номера контакта программа не трогает сервопривод.
Как это устроено: Справка по командам
| Команда | Что делает |
|---|---|
#include <Servo.h>, Servo gripper; | Подключить библиотеку и создать сервопривод |
gripper.attach(pin) | Связать сервопривод с контактом |
gripper.write(angle) | Повернуть на угол 0…180 |
Serial.available() | Сколько символов пришло из монитора порта |
Serial.parseInt() | Прочитать из пришедших символов целое число |
Требование 2. Углы «открыто» и «закрыто» найдены с запасом и проверены:
- «открыто» — груз входит в захват, даже если робот остановился на 1 см левее или правее середины;
- «закрыто» — найди угол, где захват упирается в груз, и отступи от него так, чтобы сервопривод не гудел; запиши, на сколько градусов отступил;
- груз не выпадает, когда робота с грузом наклоняют на 30° вперёд и назад.
Требование 3. Функция moveGripper(target) поворачивает захват к углу плавно — шагами по 2° — а не одним рывком. Сравни, как ведёт себя груз при резком и плавном закрытии.
Подсказка: Идея (1 из 2)
Помни текущий угол в переменной. Пока он не равен цели, сдвигай его на шаг в сторону цели и делай короткую паузу.
Подсказка: Фрагмент кода (2 из 2)
currentAngle += (target > currentAngle) ? 2 : -2; — что будет, если цель отличается на нечётное число градусов?
Подсказка: В мониторе порта ничего не происходит
Проверь скорость 9600 и что монитор отправляет строку по Enter.
Скетч подбора углов выполняет требование 1. В журнале — углы, запас «закрыто» в градусах, проверка наклоном и сравнение резкого и плавного закрытия. moveGripper работает.
Порядок действий важен
15 минСопоставь функции pickUp() и putDown() в итоговом скетче с правилом порядка (следующее занятие):
- Взять: сначала остановиться, потом закрыть захват.
- Поставить: открыть захват, подождать, пока он раскроется, и только потом отъехать.
У соседей putDown() такая: gripper.write(OPEN_ANGLE); и сразу drive(BACKWARD, …). Груз то падает, то уезжает вместе с роботом. Почему? Как исправить?
Ты можешь объяснить, зачем пауза после открытия захвата.
- До того как смотреть код, запиши в журнал по шагам: как роботу правильно взять груз и как поставить. Что должно случиться раньше: остановка или захват? Открытие или отъезд?
- Сравни свой порядок с правилом:
- Взять: сначала остановиться, потом закрыть захват.
- Поставить: открыть захват, подождать, пока он раскроется, и только потом отъехать.
У соседей putDown() такая: gripper.write(OPEN_ANGLE); и сразу drive(BACKWARD, …). Груз то падает, то уезжает вместе с роботом. Почему? Как исправить?
Твой порядок записан и сверен с правилом, ошибка соседей объяснена.
У соседей putDown() такая: gripper.write(OPEN_ANGLE); и сразу drive(BACKWARD, …). Груз то падает, то уезжает вместе с роботом. Почему?
- Запиши правила порядка для «взять» и «поставить».
- Найди опытом наименьшую паузу после открытия, при которой груз остаётся на месте: 100, 200, 400, 600 мс, по три раза каждую.
- Какую паузу ты возьмёшь в программу и почему не самую короткую из удачных?
Правила записаны, таблица опыта и выбранная пауза с обоснованием.
Взять и поставить
20 мин- Создай скетч
L52_Pick_Place. Перенеси измерения,kp,baseSpeed, контакты датчика и сервопривода, свои углы.
#include <Servo.h> 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);} 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();} // Сервопривод захвата: впиши контакт и свои углы из журнала.const int SERVO_PIN = -1;const int OPEN_ANGLE = 90;const int CLOSED_ANGLE = 40;const int STOP_CM = 5;Servo gripper; void setupGripper() { // Без контакта сервопривода программа дальше не пойдёт. if (SERVO_PIN < 0) { while (true) { } } gripper.attach(SERVO_PIN); gripper.write(OPEN_ANGLE); delay(500);} // Ехать по линии и остановиться перед грузом по ультразвуку.void approachCan() { while (true) { int distance = readDistanceCm(); if (distance > 0 && distance <= STOP_CM) { break; } readSensors(); followLineStep(); } stopMotors();} // Сначала остановиться, потом закрыть захват.void pickUp() { stopMotors(); gripper.write(CLOSED_ANGLE); delay(600);} // Открыть захват, подождать и только потом отъехать назад.void putDown() { stopMotors(); gripper.write(OPEN_ANGLE); delay(600); drive(BACKWARD, baseSpeed, BACKWARD, baseSpeed); delay(300); stopMotors();} const unsigned long CARRY_MS = 1500; // сколько ехать по линии с грузом void setup() { setupSonar(); setupGripper(); setupRobot(); approachCan(); pickUp(); turnAroundOnLine(); followLineFor(CARRY_MS); putDown();} void loop() {}
- Поставь груз в конце линии, робота — на другом конце. Запусти.
Прочитай setup() и расскажи по шагам, что сделает робот.
Робот подъезжает, берёт груз, разворачивается, везёт его по линии и ставит.
- Создай скетч
L52_Pick_Placeпо шаблону. Перенеси измерения,kp,baseSpeed, контакты датчика и сервопривода, свои углы. Езда по линии, перекрёстки и подъезд к грузу уже готовы. - Напиши сам подготовку захвата
setupGripper(),pickUp(),putDown()и доставку вsetup()— по своим правилам порядка из прошлого шага.
// Шаблон среднего уровня. Напиши код в разделе «Твоя часть» по целям в комментариях. #include <Servo.h>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;int turnSpeed = 100;int centerMs = 250; // подбираем: проехать от датчиков до центра перекрёсткаint leaveMs = 200; // время, чтобы датчик ушёл со старой линии // Сервопривод захвата: впиши контакт и свои углы из журнала.const int SERVO_PIN = -1;const int OPEN_ANGLE = 90;const int CLOSED_ANGLE = 40;const int STOP_CM = 5; Servo gripper;const unsigned long CARRY_MS = 1500; // сколько ехать по линии с грузом // ===== Твоя часть: напиши сам ===== void setupGripper() { // Без контакта сервопривода программа дальше не идёт. // Захват подключён и открыт; дай ему время раскрыться.} void pickUp() { // Взять груз: груз оказывается в захвате и не выталкивается.} void putDown() { // Поставить груз: груз остаётся на месте, когда робот отъезжает назад на 300 мс; в конце колёса стоят.} void setup() { setupSonar(); setupGripper(); setupRobot(); // Доставка: подъехать к грузу, взять, развернуться на линии, проехать с грузом CARRY_MS, поставить.} // ===== Готовое из уроков 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 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 approachCan() { while (true) { int distance = readDistanceCm(); if (distance > 0 && distance <= STOP_CM) { break; } readSensors(); followLineStep(); } stopMotors();} void loop() {}
Прочитай свой setup() и расскажи напарнику по шагам, что сделает робот.
- Поставь груз в конце линии, робота — на другом конце. Запусти.
Подсказка: Сколько ждать
Захвату нужно время, чтобы дойти до угла. Попробуй паузу 300 и 600 мс: успевает ли он?
Подсказка: Без контакта
Защиту без контакта ты уже видел в скетче пробы угла.
Робот подъезжает, берёт груз, разворачивается, везёт его по линии и ставит.
Требование 4. Продолжи свою программу L51_Stop_At_Can и сохрани как L52_Pick_Place. Робот выполняет доставку по линии:
pickUp()иputDown()соблюдают порядок: остановиться — закрыть; открыть — подождать — отъехать;- захват двигается твоей функцией
moveGripper; - без контакта сервопривода программа не начинает движение;
- в
setup(): подъехать к грузу, взять, развернуться на линии, проехать с грузом, поставить.
Приёмка. Груз в конце линии, робот — на другом конце: доставка без помощи рук.
Подсказка: Идея (1 из 2)
Каждое действие доставки — уже готовая функция из прошлых уроков или этого урока. Осталось соединить их по порядку.
Подсказка: План (2 из 2)
followLineToCan(STOP_CM).pickUp().turnAroundOnLine().- Проехать по линии
CARRY_MS. putDown().
Программа выполняет требования 1–4, доставка проходит без помощи рук.
Надёжность
12 мин- Повтори перевозку три раза подряд. Где робот ошибается чаще всего?
- Подбери
STOP_CMтак, чтобы груз оказывался в середине захвата. - Подбери
CARRY_MS, чтобы груз ставился в нужном месте.
Три перевозки подряд без помощи рук. Значения записаны в журнал.
- Повтори перевозку пять раз подряд. Каждую неудачу запиши: на каком этапе и что случилось.
| Заезд | Подъезд | Захват | Перевозка | Постановка | Что случилось |
|---|---|---|---|---|---|
| 1 | |||||
| 2 | |||||
| 3 | |||||
| 4 | |||||
| 5 |
- Найди этап, где ошибок больше всего. Какое одно число поменять, чтобы это исправить? Поменяй и повтори три раза.
Подсказка: Какие числа есть
STOP_CM — где робот встаёт перед грузом, CARRY_MS — где ставит, углы захвата — как держит.
Таблица из пяти заездов, исправленный этап и три перевозки подряд без помощи рук.
Измерь надёжность доставки и улучши её по данным.
- Сделай 10 доставок подряд и отметь для каждой, на каком этапе она сорвалась: подъезд, захват, разворот, перевозка, постановка.
- Посчитай, сколько доставок из 10 прошли. Какой этап даёт больше всего срывов?
- Исправь только этот этап и снова сделай 10 доставок. Стало лучше? На сколько?
| Серия | Успешно из 10 | Подъезд | Захват | Разворот | Перевозка | Постановка |
|---|---|---|---|---|---|---|
| До | ||||||
| После |
Подсказка: Если срывов нет
Усложни условия: поставь груз на 1 см в сторону от линии или подними baseSpeed. Где сорвётся первым?
Две серии по 10 доставок, этап с больше всего срывов, что изменено и насколько выросла надёжность.
Задания по уровням
13 минВзять груз с конца линии и поставить его на другом конце той же линии.
Груз стоит на одной ветке, место доставки — на другой. Перевези груз через перекрёсток, используя функции урока 4.2.
Напиши функцию deliver(маршрут до груза, маршрут до места, время до места), которая выполняет всю доставку. Маршруты передавай строками решений, например "LS". Тогда в итоговой задаче доставка будет одной строкой программы.
Проверь себя
Выберите ответы для подготовки. Они не сохраняются и не оцениваются на сайте. Пройдите проверку знаний в программе курса или обсудите ответы с преподавателем.
● Основное
★ Средний уровень
★★ Продвинутый уровень
Отвечай на вопросы своего уровня. Нужно верных ответов: Начальный — 4 из 5; Средний — 4 из 5; Продвинутый — 4 из 5. Ответы проверит преподаватель или программа курса.
Итог
У робота есть все умения итоговой задачи: ехать, поворачивать, держаться линии, находить перекрёстки, видеть груз и перевозить его. Дальше — итоговый проект.
Как подтвердить результат
Результат опыта связывает условия, версию программы, наблюдение и вывод. Сравнение попыток с одним изменением помогает проверить причину, включая неудачные попытки. Отметка относится к уже выполненной практике; повтор ради отметки не нужен. Расхождение с прогнозом задаёт следующую проверяемую гипотезу. Модель, измерения настоящего робота и объяснение — разные виды доказательств.
Словарь урока
| сервопривод | Мотор, который поворачивается на заданный угол и держит его. |
| угол | Положение рычага сервопривода в градусах, обычно от 0 до 180. |
| библиотека | Готовый набор команд, который подключают строкой #include. Servo — библиотека для сервоприводов. |