Перейти к основному содержимому

Декомпозиция задачи

Декомпозиция задачи в робототехнике

Коротко

Декомпозиция - это разбиение большой задачи на маленькие понятные части. Каждую часть проще описать, реализовать, проверить и потом соединить с остальными.

Зачем это нужно

Сложная задача пугает, если пытаться решить ее одной большой программой. Например: "робот должен ехать по линии, объезжать препятствия, подавать сигнал, запоминать ошибки и останавливаться по кнопке". Если писать все сразу, легко запутаться: где чтение датчиков, где выбор режима, где управление моторами, где отладка.

Декомпозиция помогает разложить поведение на части. Вместо одной огромной задачи появляются небольшие подзадачи: прочитать датчики, определить ситуацию, выбрать действие, задать скорость моторов, вывести сигнал. Каждую подзадачу можно проверить отдельно.

Главная идея

Большой алгоритм можно представить как набор связанных блоков.

сложная задача -> подзадача 1 + подзадача 2 + подзадача 3

Большой алгоритм разбивается на блоки

Декомпозиция не означает "разрезать как попало". Хорошая часть имеет понятную роль: получает входные данные, выполняет одно осмысленное действие и выдает результат.

Что такое подзадача

Подзадача - это часть общей задачи, которую можно описать отдельно. Например, "считать датчики линии" или "рассчитать скорость моторов".

Как делить задачу

Удобный способ - задавать вопросы о потоке данных и действий.

ВопросПример ответа для робота
Какие данные нужны?датчики линии, кнопка, расстояние
Какие решения принимает программа?ехать, повернуть, остановиться
Какие действия выполняет робот?задать скорость моторов, включить сигнал
Что можно проверить отдельно?датчики, моторы, индикацию
Что повторяется?чтение датчиков и выбор действия

Для робота, который едет по линии, разбиение может быть таким:

прочитать датчики линии
определить положение линии
выбрать направление
задать скорость моторов
показать состояние светодиодом

Каждый блок можно сначала описать словами, потом превратить в код.

Функции как способ декомпозиции

В программировании подзадачи часто оформляют функциями. Функция - это именованный фрагмент программы, который можно вызвать из другого места.

Псевдокод:

прочитать_датчики()
выбрать_движение()
управлять_моторами()
показать_состояние()

В блок-схемах вызов функции или подпрограммы можно показывать прямоугольником с дополнительными вертикальными линиями по краям.

Блок-схема алгоритма из подпрограмм

Название функции должно объяснять действие. Если функция называется doStuff, по ней ничего не понятно. Если функция называется readLineSensors, уже видно, что она читает датчики линии.

Что такое функция

Функция - это отдельная часть программы с именем. Ее можно вызвать, чтобы выполнить заложенные в нее команды.

Функция не обязана быть большой. Часто лучше несколько коротких функций с ясными ролями, чем одна огромная функция, где перемешаны датчики, моторы и логика.

Пример: робот едет по линии

Разложим задачу "ехать по линии" на части.

ПодзадачаВходВыход
Считать датчикисигналы датчиковзначения левый, правый
Определить ситуациюзначения датчиковлиния слева, справа, по центру или потеряна
Выбрать действиеситуацияехать прямо, повернуть, искать
Управлять моторамидействиескорости левого и правого мотора
Показать состояниеситуация или ошибкацвет светодиода

Такой подход помогает тестировать. Можно отдельно проверить, правильно ли читаются датчики. Потом отдельно проверить моторы. Потом соединить их через блок выбора действия.

Проверка отдельных частей перед сборкой

В главном цикле эти части вызываются по очереди, а затем алгоритм возвращается к новому чтению датчиков.

Блок-схема декомпозиции движения по линии

Если робот едет не туда, декомпозиция сужает поиск. Ошибка может быть в датчиках, выборе действия или моторах. Когда все смешано в одном куске кода, найти место ошибки сложнее.

Уровни детализации

Одна и та же задача может быть описана крупно или подробно.

Крупно:

ехать по линии

Подробно:

прочитать левый датчик
прочитать правый датчик
сравнить значения с порогом
выбрать направление
задать скорость моторов

На блок-схеме можно оставить один крупный блок для общего плана или раскрыть его до конкретных действий.

Сравнение крупного и подробного уровней блок-схемы

Для планирования удобно начать крупно, а затем раскрывать блоки. Для программирования нужен такой уровень детализации, где каждую команду можно реализовать.

Как понять, что разбиение получилось

Хорошая декомпозиция помогает отвечать на вопросы без чтения всей программы. Если робот не видит линию, мы идем к блоку чтения датчиков. Если видит линию, но поворачивает не туда, проверяем блок выбора действия. Если решение верное, а колеса крутятся неправильно, смотрим блок управления моторами.

Для каждого блока полезно записать короткий контракт:

БлокЧто получаетЧто должен выдать
Чтение датчиковсигналы с пиновзначения датчиков
Выбор действиязначения датчиковкоманда движения
Управление моторамикоманда движенияскорости моторов

Контракт не обязан быть сложным. Он просто фиксирует ожидания. Если входы и выходы блока невозможно описать, блок слишком расплывчатый.

Что запомнить про декомпозицию

Декомпозиция делает сложную задачу управляемой.

Хороший блокПлохой блок
имеет понятное имяназывается слишком общо
выполняет одну рольделает все сразу
можно проверить отдельноработает только внутри огромной программы
имеет понятные входы и выходыберет данные непонятно откуда
помогает читать алгоритмпрячет смысл

Если блок сложно назвать одним коротким действием, он, вероятно, слишком большой. Его стоит разделить еще раз.

Практика

Задание 1

Разбейте задачу "робот объезжает препятствие" на 5 подзадач. Для каждой подзадачи запишите, какие данные она получает и какой результат выдает.

Задание 2

У вас есть большой блок "ехать по линии". Раскройте его на более мелкие шаги так, чтобы их можно было нарисовать в блок-схеме.

Задание 3

Придумайте названия функций для трех частей робота:

  • чтение датчика расстояния;
  • управление моторами;
  • вывод состояния светодиодом.

Проверьте себя

  • Что такое декомпозиция?
  • Почему одну большую программу сложнее проверять?
  • Чем подзадача отличается от случайного куска кода?
  • Зачем функции нужны понятные имена?
  • Как декомпозиция помогает искать ошибку в роботе?
Ориентиры для самопроверки

Сначала ответьте без подсказки. Ответ можно считать полным, если вы:

  • формулируете основную мысль своими словами;
  • называете важные условия, ограничения или меры безопасности;
  • для схемы, кода или расчёта показываете ход решения и ожидаемый результат.

Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.

Словарь статьи

  • Декомпозиция - разбиение сложной задачи на более простые части.
  • Подзадача - отдельная часть общей задачи.
  • Функция - именованный фрагмент программы, который можно вызвать.
  • Вход функции - данные, которые функция получает для работы.
  • Выход функции - результат, который функция возвращает или создает.
  • Модуль - относительно самостоятельная часть программы или устройства.
  • Тестирование - проверка, что часть работает как ожидается.

Связанные темы

Источники