Как мне написать модульные тесты для роботов (и других механических устройств)?

22

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

Тем не менее, я не совсем уверен, как я мог сделать это. Насколько мне известно, модульное тестирование выполняется путем взятия функции (или подсистемы кода) и подачи ей набора входных данных, чтобы убедиться, что он каждый раз выдает один и тот же результат. Код, который у меня есть в настоящее время, не выполняет каких-либо сложных операций с данными, а напрямую управляет аппаратными компонентами робота. Большая часть сложности заключается в том, чтобы убедиться, что электроника исправна, что код в данный момент соответствует фактическому оборудованию робота и т. Д. Часто я могу только видеть, есть ли проблема, загружая код в самого робота, и пытается запустить его.

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

Или я просто неправильно понимаю, как должны работать модульные тесты?

( Если это имеет значение, вот код , он написан на C ++, и я участвую в FRC )

Michael0x2a
источник

Ответы:

21

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

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

  • Дразнить вещи на относительно низкоуровневых языках труднее (и, следовательно, гораздо больше работы)
  • Дразнить аппаратные вещи сложнее (а значит, гораздо больше работы)

Кроме того, большая ценность автоматизированного модульного тестирования заключается в возможности запуска ваших тестов в любое время для выявления ошибок регрессии в течение длительных периодов времени после написания исходного кода. В таких соревнованиях ваш код вообще не будет использоваться после его завершения, поэтому вы не сможете получить большую часть пользы от тестов. А учитывая, насколько сложно было бы добавить тесты к вашему конкретному случаю, было бы лучше использовать ваше время, чтобы просто выполнить ручное тестирование и сосредоточиться на функциях для конкурса.

Oleksi
источник
1
Хороший ответ. Особенно о том, что код не будет использоваться после соревнования, и что большое преимущество автоматических модульных тестов хорошо проявляется после их написания. Возможно, вы захотите автоматизировать некоторые из ваших тестов в том случае, если вы снова и снова запускаете один и тот же тест; но пока это не произойдет, нет особого смысла.
Дауд говорит восстановить Монику
Не нужно издеваться над оборудованием вообще. Если у робота есть логирование, запустите тестовую программу и просмотрите логи. Финальный тест требует наблюдения «поворот налево» в журнале, который должен соответствовать повороту робота влево. Вам нужно будет написать тестовый жгут для проверки устройств ввода - подключить код устройства ввода как можно ближе к аппаратному уровню
mattnz
4
@DavidWallace В качестве небольшой пищи для размышлений, при использовании TDD / BDD преимущества модульного тестирования проявляются немедленно. Во-первых, путем немедленного уверенного рефакторинга кода, а во-вторых, путем поощрения реализации, которая должна быть ограничена минимальной реализацией, необходимой для выполнения тестов.
С.Робинс
4
@mattnz плохая идея, и я знаю по своему опыту. Что делать, если тестируемый код очень сильно терпит неудачу, и робототехническое средство падает на стену, разрушая часть оборудования xxxx $ ???
Стийн
2
@mattnz: Наши роботы размером около 2 на 3 на 4 фута и весят около 150 фунтов. Стоимость комплекта / регистрации составляет 5 тысяч долларов в год, и мы обычно собираем от 5 до 10 тысяч долларов для покупки дополнительных деталей. Худший сценарий, вероятно, будет стоить более $ 10;)
Michael0x2a
10

Я могу придумать пару вещей, которые вам нужно будет рассмотреть. Первый - сделать аппаратный слой доступа максимально тонким, даже если это означает создание базового слоя типа оболочки для него. Это дает вам пару преимуществ. Во-первых, это позволяет вам изолировать поведение вашего кода от аппаратного обеспечения от самого доступа к аппаратному обеспечению, что означает, что вы можете тестировать все до самого конца ваших аппаратных коммуникаций без необходимости доступа к самому оборудованию.

Например, если вам нужно разработать протокол сигнализации на основе I2C, вы можете проверить, что ваш код генерирует правильные сигналы I2C без необходимости подключать аппаратное обеспечение к вашим тестам.

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

Это в основном соответствует тому, что Олекси сказал в своем ответе , в том смысле , что обычно надо больше надсматривать вещи на аппаратном уровне, однако это не так сложно, если вы придерживаетесь минимально возможного уровня минимального кода / вызова, который вы можете сделать для аппаратное обеспечение.

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

Другая вещь, которая приходит на ум, кроме насмешек и наслоений, - это использование практики разработки в тестовом режиме. По сути, вы кодируете свои требования в качестве критериев тестирования и основываете свою реализацию на своих тестах. Это поможет вам свести код реализации к минимуму, а все ваши тестовые примеры будут направлять ваши усилия на разработку. Не тратя слишком много времени на другой потенциально некритический код, который вы можете испытать «просто потому, что», тестирование сначала поможет вам оставаться сосредоточенным и упростит изменение кода при отладке, как и использование. из ваших юнит-тестов и издевательств. Отладка программных ошибок с помощью аппаратного обеспечения общеизвестно сложна и отнимает много времени, которое вы бы лучше потратили на другие задачи.

S.Robins
источник
2

Я могу рассказать вам, как они делают это на Flight Simulator

Во-первых, вы получите половину ответа только в том случае, если зададите этот вопрос только программистам, поэтому вам, вероятно, стоит опубликовать этот вопрос на http://electronics.stackexchange.com, пока вы на нем.

Я не работал с роботами, но я потратил 5 лет, занимаясь аппаратными средствами на симуляторах полета, чтобы я мог рассказать вам, как работает их архитектура.

Аппаратный слой тупой

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

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

Уровень программного обеспечения является противоположным

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

На имитаторе полета это называется QTG (Руководство по квалификационным испытаниям). По своей сути он выводит данные на двумерную сетку, где одно измерение является временем, а другое - выходным.

Хотите верьте, хотите нет, но это суть того, как они разрабатывают модели. Настоящий самолет оснащен кучей датчиков и управляется по управляемым сценариям. Поскольку все элементы управления могут управляться без участия человека, тесты запускаются (то есть, сим летит сам) компьютером и сравниваются данные.

Хотя робототехника создается в очень разных масштабах, принципы одинаковы. Традиционный подход состоит в том, чтобы полностью разделить аппаратные и программные уровни, чтобы оба можно было протестировать по отдельности. Аппаратный ввод собирается через сервоприводы и устанавливается через независимый интерфейс. Входной сигнал программного обеспечения может быть установлен / считан путем независимого измерения и сравнения сигналов, которые в противном случае поступали бы на аппаратные средства, и построения их графика с известными «хорошими» данными.

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

Эван Плейс
источник
1

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

martiert
источник