суббота, 11 июня 2016 г.

2.8. Логические выражения и ветвление программы

Урок: 2.8. Логические выражения и ветвление программы

Транскрибация урока: Теперь давайте извлечем из цифрового сигнала побольше пользы, чем трансляция его со входа на выход. Мы можем рассмотреть событие «кнопка нажата» и в каждый момент времени сказать, истинно это утверждение или ложно. Если кнопка нажата – то утверждение истинно, если кнопка не нажата – утверждение ложно. Точно так же мы можем, например, сказать про значение какой-нибудь переменной. Например, мы считывали аналоговый сигнал с потенциометра в переменную Sensor Value, и в каждый момент мы можем проверить такое условие: переменная Sensor Value меньше чем 512. Если у нас потенциометр выкручен в сторону, где он показывает 0, то это утверждение будет истинно, потому что Sensor Value действительно меньше 512-ти. Как только считываемое значение дойдет до 512-ти или станет больше, это утверждение станет ложным. И то и другое можно назвать логическим выражением. Как и обычное арифметическое выражение, оно может быть вычислено. Но если арифметическое выражение вычисляется, и мы получаем какое-то числовое значение, то после вычисления логического выражения мы получаем логическое значение, которое может быть либо 0, либо 1. Истина или ложь. А в случае с Arduino еще и High или Low. Это в каком-то смысле синоним. Помните, мы писали программу для светофора и улучшали мигание зеленого путем добавления цикла со счетчиком For? Там мы указывали условие, при выполнении которого цикл будет повторятся. Например, переменная i изначально равна нулю, и цикл работает до тех пор, пока переменная i < 3. Вот эта вот (i < 3) было логическим выражением, которое проверялось в начале каждой итерации цикла. И цикл выполнялся, если это значение истинно. Благодаря возможности вычислять логические выражения у нас появляется возможность сделать программу более сложной, разветвить ее. Если раньше мы выполняли строгую последовательность действий, которые шли одно за другим, то теперь мы можем посмотреть, выполняется ли то или иное условие, и в случае его выполнения сделать один набор действий, а в случае если условие не выполнено – другой набор действий. Сейчас я покажу, как это ветвление реализуется в программе. Я подготовил еще один экспериментальный скетч, где у меня есть выход это светодиод на 13-м пине, и вход на A0. Сейчас у меня на схеме подключен потенциометр. Посмотрите, что происходит в лупе. В лупе появляется управляющая конструкция – оператор if, то есть «если». Он предназначен для того, чтобы какие-то действия выполнялись только в случае выполнения условия. Вот здесь вот в скобках это условие и описано. В данном случае: analogRead (ANALOG_IN) > 512. То есть будет считан сигнал со входа ANALOG_IN, в нашем случае это A0, и сравнен со значением 512. И только если в случае, когда это выражение истинно, выполнятся действия, описанные внутри вот этих фигурных скобок. Единственное действие: digitalWrite(LED_PIN, HIGH), то есть включится встроенный светодиод. Давайте посмотрим, так ли это? Я буду вращать ручку потенциометра, и где-то на полпути светодиод зажегся. Что будет, если я начну вращать ручку в обратную сторону? Возможно, кто-то думает, что светодиод выключится? Но кто-то уже понял, что никакой магии в контроллере не происходит. Если вы явно какие-то действия не описали, ничего происходить не будет. У нас в программе не описан случай, что делать, если считываемое на аналоговом входе значение меньше 512-ти. И здесь мы совершим новое улучшение скетча. Теперь я произвел в скетче дополнение: добавил вот этот вот фрагмент, который начинается с ключевого слова else. Оно относится к оператору if и является его продолжением, в котором описывается, что же делать, если указанные условия не выполнены. В нашем случае это также единственная инструкция digitalWrite(LED_PIN, LOW). То есть если указанное условие про аналоговый вход не выполняется, и там значение меньше 512-ти или равное 512-ти, то будет выполняться вот эта вот часть – светодиод будет выключаться. Давайте посмотрим, действительно ли это происходит так? Я уже загрузил скетч. Вращаю ручку потенциометра. Вот мы перешли через границу 512 – светодиод зажегся, вот мы крутим ручку обратно – он гаснет. Все отлично работает. Теперь вы можете делать свои программы более сложными. Главное, запомните, каким образом оформляется вот этот вот условный оператор. Запомните его синтаксис. Во-первых, записывайте условие в круглых скобках. Затем, действие, которое нужно выполнить, если условие истинно, то есть выполняется, вы заключаете в пару фигурных скобок. И если вам нужно описать альтернативное действие, которое будет совершаться, если условие не выполнено, вы используете ключевое слово else и также пару фигурных скобок, внутри которых описываются альтернативные действия. Мы уже попрактиковались с вычислением логических значений, а теперь посмотрим, что можно с этим сделать еще. Их можно хранить в переменных. Для этого существует специальный тип данных, который называется boolean. В новом тестовом скетче я создаю переменную типа boolean, она называется trigger, и сразу же я помещаю в нее значение false, то есть ложь. Она нам будет нужна для того, чтобы хранить состояние светодиода. Теперь нашей задачей будет включать и выключать светодиод по нажатию кнопки. То есть одно нажатие относится к включению, другое – к выключению. Здесь у меня описано подключение устройств, как мы уже видели, а дальше я использую знакомый нам условный оператор if. Если кнопка нажата, то мы делаем вот такое вот действие. Что это за восклицательный знак перед trigger справа от оператора присваивания? Это логический оператор отрицания или инверсии. Что он делает? Он берет текущее значение логической переменной (оно было false изначально) и меняет его на противоположное, то есть на true (истина). Таким образом, переменная в этой строчке переворачивается. Ей присваивается значение, противоположное предыдущему, каким бы предыдущее значение ни было. А затем, после этого условного оператора мы просто trigger передаем в digitalWrite в качестве параметра. Как мы уже поняли, в контексте Arduino истинное значение логической переменной эквивалентно значению High, которое создаст высокое напряжение на указанном пине. Поэтому мы просто передаем логическую переменную как параметр в digitalWrite. Давайте теперь смотреть, как это будет работать? Видите, это работает некорректно. Давайте себе представим сигнал, который мы считываем, на графике. По оси X у нас будет отложено время, а здесь – сигнал. Допустим, у нас высокий будет на этом уровне, ну а низкий – на этом. Кнопка была не нажата, а затем ее нажали, то есть значение на входе изменилось. У нас получилась вот такая вещь. Почему же наш триггер сейчас не работает? Дело в том, что вот эта инструкция с оператором сравнения, – с условным оператором, который проверяет состояние пина, состояния кнопки, – за время пока кнопка нажата, успевает произойти много-много-много раз, поскольку даже если мы совершим самое короткое нажатие, которое сможем, контроллер все равно будет быстрее и считает вход несколько раз. Поэтому мы не можем заранее предсказать, сколько раз триггер перевернется и в каком состоянии окажется светодиод после того, как мы кнопку отпустили. Поэтому программу нужно видоизменить. Очевидным кажется решение следующее: мы можем запоминать предыдущее состояние кнопки после каждого сравнения. То есть мы должны отследить ситуацию, когда кнопка была не нажата и вдруг стала нажата. И только в случае, когда одновременно выполняется одно условие и другое условие, мы будем переворачивать триггер. Давайте посмотрим, как это выглядит в программе. Что появилось в улучшенном скетче? Я создал переменную для сохранения предыдущего значения, предыдущего состояния пина и, соответственно, кнопки, которая к нему подключена. Затем в loop создается еще одна переменная current, в которой сохраняется текущее значение кнопки, для того чтобы следующим шагом мы могли сделать вот такую вот интересную вещь: здесь я написал уже сложное условие и использовал логический оператор, который позволяет объединить два условия. Сейчас в конце фрагмента я расскажу об этом чуть подробнее, пока что сосредоточимся на общей логике программы. Итак, когда у нас одновременно выполняются два условия, только тогда у нас будет trigger переворачиваться, то есть ему будет присваиваться значение, обратное относительно предыдущего. И для следующей итерации то значение, которое только что было текущим, становится предыдущим, для того, чтобы мы вновь могли делать сравнение. Еще я здесь сделал небольшой комментарий, чтобы сразу удовлетворить ваше любопытство, а как же нам сравнивать другие ситуации, да? Мы проверяли равенство считанного функцией DigitalRead значения к значению High в прошлом эксперименте. Если мы хотим проверить неравенство двух значений, мы используем вот такое вот сочетание символов:! = > мы уже видели, < похоже на него, а кроме того бывает меньше или равно, а также больше или равно. Ну в общем-то это довольно очевидные вещи. Теперь давайте попробуем загрузить обновленный скетч и посмотреть, исправилась ли наша ошибка. Теперь скетч загрузился и посмотрим, что будет, когда я нажму кнопку? Светодиод зажегся, погас, зажегся, погас — все работает хорошо, наш триггер переворачивается вовремя, и светодиод, соответственно, вслед за ним включается и выключается. На самом деле, здесь может нам помешать еще одно явление — так называемый дребезг. Я просто обозначу то, что он существует. Вы, на самом деле, найдете кучу материалов о том, как его победить программным путем, аппаратным путем. Честно говоря, мне уже давно не попадались кнопки, которые обладают этим эффектом, тем не менее, такое явление встречается. Что есть «дребезг»? Когда мы нажимаем кнопку, за счет несовершенства физического мира, контакты ее могут сомкнуться не мгновенно. Они постепенно сближаются, и в какой-то промежуток времени между ними проскакивают искорки, и поэтому, если мы изобразим это на графике, то у нас вместо вот такого вот четкого перехода снизу наверх, будет несколько иная картина. У нас на протяжении нескольких милисекунд будет вот такая вот гребенка. И только потом мы зафиксируемся на верхнем уровне. То есть триггер может у нас перевернуться какое-то количество раз, прежде чем действительно кнопка будет нажата. Ну намекну, что вы можете, проверив состояние кнопки, подождать несколько милисекунд и убедиться, что кнопка действительно нажата, и только в случае совпадения этих условий считать, что кнопка была нажата. Но это уже за рамками наших экспериментов. Теперь я хочу чуть подробнее остановиться на операторе логической «и», который мы использовали в последнем примере. Нарисуем так называемую таблицу истинности. Это такая таблица, которая показывает все возможные состояния вычисления выражения. Например, p&&q – так обычно в математической логике обозначаются логические выражения. У нас есть исходное выражение p, исходное выражение q. В нашем последнем примере это переменные current и previous. И сочетания их значений могут быть следующими: оба из них истинны; истинно только p, а q — ложно; ложно p, а q — истинно; и оба они ложные. Какие результаты в каждом случае даст выражение p&&q. Оно будет истинным только в том случае, когда оба исходных операнда, то есть и p, и q, истинны. То есть это истинно только в этом случае. В остальных случаях p и q будет ложно. Здесь же я вам расскажу про логическое «или» — еще один оператор, который тоже может быть вам часто полезен. Он записывается как 2 символа, 2 вертикальных палочки, и таблица его истинности следующая: p и q будет истинно, когда истинен хотя бы один из операндов, то есть, когда и p, и q истинно; p и (или) q истинно. Когда истинно только p, p или q все равно истинно. Когда истинно q, p или q тоже истинно. И когда никто из них не истинен, p или q будет ложным. Ну и можно также зарисовать !p — помните, оператор инверсии, с которым мы столкнулись чуть раньше? Это просто противоположное значение: 0 0 1 1. Более того, вы можете комбинировать эти значения между собой. Ну наверняка вы с этим вскоре уже столкнетесь. Теперь вы знакомы со считыванием цифрового сигнала, знаете, что низкий или высокий уровень на входе можно рассматривать как логическое значение, вы знаете, что такое логические выражения, вы умеете сравнивать два значения, вы можете пользоваться логическим отрицанием, логическим объединением — вот эти вот операторы «не», «или» и «и». И благодаря всему этому управлять ходом программы, например, устраивать ветвление.

Часть: Видео

Модуль: Контроллер изучает мир

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

Курс: Строим роботов и другие устройства на Arduino. От светофора до 3D-принтера

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

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

Пройдя этот курс, вы сможете создавать устройства, которые считывают данные о внешнем мире с разнообразных датчиков, обрабатывают информацию, получают и отправляют данные на ПК, в Интернет, на мобильные устройства, управляют индикацией и движением. Создание устройств будет включать проектирование, изучение компонентов, сборку схем, написание программ, диагностику. Попутно с созданием самих устройств вы сделаете визуализацию на ПК, создадите веб-страницу, которую будет демонстрировать одно из ваших устройств, а также разберетесь с устройством и работой FDM 3D-принтера.

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

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

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

Программа:
  • Неделя 1 Один старый и много новых знакомых
  • Неделя 2 Контроллер изучает мир
  • Неделя 3 Цель обнаружена
  • Неделя 4 Как полить цветок из другого города
  • Неделя 5 Мобильный робот
  • Неделя 6 Как создать новый предмет за час
Преподаватель: Алексей Перепелкин (1), Дмитрий Савицкий (2)

Описание преподавателя: (1) Алексей Перепёлкин занимается развитием робототехники на базе ЛИОТ МФТИ. В 2012 году открыл для себя новое захватывающее чувство – когда устройство, которое сам построил и запрограммировал, работает. Свернул с финансовой дорожки и создал кружок робототехники для подростков. Готовил их к соревнованиям. Стал посещать конференции, а затем проводил мастер-классы для тех, кто тоже хочет организовать занятия. Совместно с коллегами в 2013 году разработал новые соревнования – Робопрофи – для конкурса Робот для жизни и провел их. В 2014 году впервые провел Arduino-номинацию на фестивале Робофест, а для российского финала Russian Robot Olympiad 2014 сделал творческую категорию. С тех пор эти соревнования стали регулярными. Летом 2014 провел двухнедельную мастерскую в детском лагере Никола-Ленивца, а затем преподавал в выездной школе, посвященной программированию и робототехнике, которую провели ABBYY и Яндекс. В 2015 году стал руководителем направления робототехники в GoTo Camp, выездных школах, где участники создали десятки проектов, от прототипов умных домов и операторских тележек до робота-бубниста и принтера для незрячих. В 2014 году с коллегами начал проект Роболабы: мероприятия для школьников и студентов, где участники параллельно решают усложненные задачи, а затем проводят рефлексию сделанной работы и оценивают чужие в ходе серии мероприятий.

(2) Физик, научный сотрудник, выпускник МФТИ. Запустил кружок робототехники в 2011 году. Рассказал Алексею Перепелкину о том, как здорово вести кружок робототехники. Рассказал об этом еще целому ряду людей. Побеждал со своими командами на соревнованиях. Проводил проектную работу с участниками исследовательской выездной школы МКШ с 2013 года, где руководил реализацией физических и робототехнических проектов, например, «Вслед за солнцем», в котором изучалась эффективность динамической ориентации солнечных батарей на солнце. Вместе с коллегами разрабатывал и был судьей Робопрофи. Участвовал в подготовке проекта Роболабы. Вновь пришел в МФТИ для проведения факультативного курса «Основы создания киберфизических устройств»

Организатор: Лаборатория инновационных образовательных технологий МФТИ (1), Лаборатория инновационных образовательных технологий МФТИ (2)

Описание организатора: (2) Московский физико-технический институт (неофициально известный как МФТИ или Физтех) является одним из самых престижных в мире учебных и научно-исследовательских институтов. Он готовит высококвалифицированных специалистов в области теоретической и прикладной физики, прикладной математики, информатики, биотехнологии и смежных дисциплин. Физтех был основан в 1951 году Нобелевской премии лауреатами Петром Капицей, Николаем Семеновым, Левом Ландау и Сергеем Христиановичем. Основой образования в МФТИ является уникальная «система Физтеха»: кропотливое воспитание и отбор самых талантливых абитуриентов, фундаментальное образование высшего класса и раннее вовлечение студентов в реальную научно-исследовательскую работу. Среди выпускников МФТИ есть Нобелевские лауреаты, основатели всемирно известных компаний, известные космонавты, изобретатели, инженеры.

Категория: Компьютерные науки

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

Тематика: Разработка ПО

Материал: