Alexey Savchenko, Evangelist, Unreal Engine/ Epic Games
Робототехника с Not eXactly C. Часть I
1. Not eXactly C
Программируем LEGO-роботов
Александр Колотов
alexandr.kolotov@gmail.com
http://nnxt.blogspot.com
Тюмень, 2013
2. Давайте знакомиться!
Колотов
Александр Васильевич
• Нижний Новгород
• 4 года с LEGO-роботами
• Тренер российской сборной World Robot Olympiad
• http://nnxt.blogspot.com – самый полезный ресурс на
русском языке по LEGO роботам
3. LEGO Mindstorms
Если вы можете придумать
робота, вы можете его построить!
4. Поколения LEGO Mindstorms
• Первые наборы Lego Mindstorms
начали выпускаться в 1998 году. Они
были созданы на базе RCX блока.
• Следующая версия - Lego Mindstorms
NXT - выпускается в 2006 году.
Основа – NXT блок.
• Начиная с середины 2009, продается
новая версия Lego Mindstorm NXT
2.0. Новшества: цветовой датчик и
математика с дробными числами
• 2013 год – начинается продажа LEGO
Mindstorms EV3: более мощное
«железо», новые датчики.
6. Программа на PC
Команды на моторы
Данные с сенсоров и
енкодеров
MS Robotics Developer Studio NI LabView
LEGO::NXT Robolab
NXT-Python Scratch
RWTH - Mindstorms NXT Toolbox for MATLAB
7. Программа на NXT
Скомпилированный
исполняемый файл
NXT-G NI LabView
leJOS NXJ Robolab
Enchanting RobotC
Not Exactly C (NXC) NXT Byte Code (NBC)
8. Программа на телефоне
Программа-посредник
RPC
Результаты вызова RPC
MINDroid – OpenSource проект от LEGO
Chatterbox – как инициировать общение со
стороны NXT блока
Конструкторы: MIT App Inventor, CATROID
9. Язык программирования
Not eXactly C
• Not eXactly C (NXC) – язык
программирования, специально придуманный для
программирования LEGO-роботов.
• В основе языка NXC (ЭнИксСи) лежит популярный язык
программирования С (Си), на котором создаются
профессиональные программы.
• Язык NXC значительно проще своего предка, что
позволяет изучить его очень быстро – можно написать
первые программы для робота уже на первый день
знакомства.
10. Язык программирования
Not eXactly C
• Программирование на NXC доступно в:
• Windows
• Среды: Bricx Comand Center, RobotC Virtual World
• Linux
• Среды: nxcEditor, любой текстовый редактор
• Mac OS X
• Официальный сайт: http://bricxcc.sourceforge.net/
• Компилятора языка NXC, как и среду BricxCC
можно использовать бесплатно.
12. Bricx Command Center
• Основа среды BricxCC (БрикИксСиСи) – текстовый
редактор с подсветкой синтаксиса (конструкций языка)
• Среда поддерживает программирование RCX и NXT
блоков. Идет разработка поддержки EV3 блоков.
13. Bricx Command Center
• Установка среды BricxCC
• Скачать и установить офиц. версию:
http://sourceforge.net/projects/bricxcc/files/bricxcc/
• Разработчики все время добавляют новые функции
в программу. Чтобы получить доступ к самым
последним функциям, можно скачать тестовую
стабильную сборку:
http://bricxcc.sourceforge.net/test_releases/
• Компьютер должен увидеть NXT блок, как
устройство, поэтому нужно установить Fantom
Driver от LEGO:
http://mindstorms.lego.com/en-us/support/files/Driver.aspx
14. Bricx Command Center
Если блок не
подключен шаг
• Запуск среды программирования можно пропустить
18. Bricx Command Center
• Инструменты для
работы с файлами на
NXT блоке позволяют
копировать файлы на
блок, читатать файлы с
блока, удалять их
19. Bricx Command Center
• Специальный
инструмент NeXT Screen
позволет отображать в
отдельном окне, то что
выводится на экран
блока.
20. Bricx Command Center
• В любой момент
времени по каждой
конструкции или
функции языка
можно получить
справку, нажав <F1>
21. Самая простая программа
/* основная часть
программы */
task main() {
//Вывести на экран NXT блока строку
TextOut(0, LCD_LINE1, "Start");
}
22. Самая простая программа
Многострочный комментарий
Открывающая часть - /*, закрывающая часть - */
/* основная часть
программы */
task main() {
//Вывести на экран NXT блока строку
TextOut(0, LCD_LINE1, "Start");
}
23. Самая простая программа
Каждая
программа
должна
содержать, как /* основная часть
минимум, одну программы */
задачу. task main() {
Основная //Вывести на экран NXT блока строку
задача в TextOut(0, LCD_LINE1, "Start");
программе }
всегда
называется
«main».
24. Самая простая программа
Внутри задач содержится блок команд. Каждый
блок команд в программе отделяется от
другого блока фигурными скобками.
/* основная часть
программы */
task main() {
//Вывести на экран NXT блока строку
TextOut(0, LCD_LINE1, "Start");
}
25. Самая простая программа
Можно использовать
однострочные комментарии.
Начинаются с //.
/* основная часть
программы */
task main() {
//Вывести на экран NXT блока строку
TextOut(0, LCD_LINE1, "Start");
}
Однострочные комментарии удобно
использовать, чтобы временно
«скрыть» часть программы: //TextOut(LCD_LINE1, "Start");
26. Самая простая программа
/* основная часть
программы */
task main() {
//Вывести на экран NXT блока строку
TextOut(0, LCD_LINE1, "Start");
}
Функции в программе чувствительный к регистру: “TextOut” не
тоже самое, что “textout”. Внутри скобок – параметры
настраивающие поведение функции. Каждая функция в программе
отделяется от остальных точкой с запятой.
27. Компиляция
• Все программы для NXT блока представляют собой
специальный набор инструкций - байткод, который
исполняется интерпретатором, являющимся частью NXT
firmware (набор программ стартующих при включении
блока).
• Компилятор языка NXC преобразует исходный код
программ в байткод понятный для NXT.
• После компиляции исполняемый файл должен быть
скопирован на NXT блок.
28. Компиляция
Просто скомпилировать Cкомпилировать
программу. Используется и загрузить Запустить
для проверки на наличие программу на программу на
ошибок синтаксиса. NXT блок. NXT блоке
<F5> <F6> <F7>
29. Компиляция
• При компиляции может
выдаться ошибка о
использовании не той
версии NXT firmware.
• Необходимо указать
компилятору, чтобы он
автоматически определял
firmware у подключенного
блока.
• Сделать это можно в
настройках компилятора.
30. Программирование моторов
• Наиболее часто используемой функцией робота
является «Движение».
• Двигаться может весь робот:
• движение тележки
• Двигаться могут части робота:
• движение манипулятора (рука, клешня)
• движение сенсора
31. Программирование моторов
• Программирование моторов может происходить
посредством одной из следующих функций:
RotateMotor(outputs, pwr, angle) – поворот мотора с заданной мощностью
на заданный угол
RotateMotorEx(outputs, pwr, angle, turnpct, sync, stop) – аналогично
RotateMotor, но позволяет контролировать распределение мощности
между моторами, синхронизацию и тип остановки после окончания
движения
OnFwd(outputs, pwr) – включить моторы для движения вперед с заданной
можностью и передать управление следующей команде
OnRev(outputs, pwr) – то же, но с движением назад
OnFwdSync(outputs, pwr, turnpct) – аналогично OnFwd, но позволяет
контролировать распределение мощности
OnRevSync(outputs, pwr, turnpct) – то же, но с движением назад
Off(outputs) – торможение моторами
Coast(outputs) – отключение энергии от моторов
32. Программирование моторов
• Управляем количеством движения:
RotateMotor(outputs, pwr, angle)
Тормозить
Какие моторы вращать: Угол в градусах. моторами
OUT_A, OUT_B, OUT_C Мощность: Отрицательные значения – или просто
OUT_BC, OUT_AC -100..100 поворот в противоположную отключить
OUT_AC сторону энергию
RotateMotorEx(outputs, pwr, angle, turnpct, sync, stop)
Распределение мощности между двумя моторами Вкл/выкл
при использовании «спаренных» сихнронизацию
двигателей, например, A и B или B и С (-100..100) между моторами
• Пример:
RotateMotor(OUT_A, 100, 275);
RotateMotorEx(OUT_BC, -75, 720, -100, true, true);
33. Программирование моторов
• Строя последовательность из функций управления
моторами с нужными параметрами можно добиться
сложной траектории движения робота:
task main() {
//Движение вперед
RotateMotor(OUT_BC, 100, 720);
//Поворот вокург своей оси
RotateMotorEx(OUT_BC, -75, 360, 100, true, true);
//Движение назад
RotateMotor(OUT_BC, -80, 1800);
//Поворот одним двигателем
RotateMotor(OUT_C, 75, -180);
}
34. Программирование моторов
• Задание 1. Движение одним мотором.
• Запрограммировать только один мотор у тележки через функцию
RotateMotor
• Пронаблюдать, как тележка двигается в зависимости от того какой мотор
мы контролируем.
• Пронаблюдать, как тележка двигается в зависимости от того какое
направление движения мотора (вперед или назад) мы выбираем:
• Изменять направления движения через указание отрицательной
мощности и через отрицательное значение угла поворота.
Мотор и направление
Левый мотор, движение вперед
Правый мотор, движение вперед
Левый мотор, движение назад (отрицательная мощность)
Правый мотор, движение назад (отицательный угол)
35. Программирование моторов
• Задание 2а. Движение двумя моторами.
• Составить программу для робота-тележки таким образом, чтобы робот
проехал вперед, а потом назад, вернувшись на то же место
• Изменяя мощность подаваемая на моторы, посмотрите как это влияет на
скорость движения робота
• За счет чего будет задаваться движение назад? За счет управления
мощностью или за счет управления направлением угла поворота?
Мощность
25%
50%
100%
Помните, что при разном уровне заряда на батарейках,
моторы будут вращаться с разной скоростью при одном и
том же значении задаваемой мощности в программе.
36. Программирование моторов
• Задание 2b. Движение двумя моторами.
• Запрограммируйте робота таким образом, чтобы он проехал 30 см. (лист
альбомной бумаги) – на сколько оборотов или градусов необходимо
повернуть колеса тележки.
37. Программирование моторов
• Задание 2c. Движение двумя моторами.
• Изучить, что произойдет, если запрограммировать робота ехать три
оборота колес (1080 градусов), и в то же время руками остановить
двигатели - искусственно создать ситуацию, когда робот натолкнулся на
препятствие и колеса провернуться не могут.
Цель эксперимента - показать, что выполнение программы
блокируется в ожидании поворота двигателей. Это важно
помнить, при движении робота по поверхности с
препятствиями или при выполнении поворотов.
38. Программирование моторов
• Задание 2d. Движение двумя моторами.
• Изучить, как распределение мощности между двумя моторами влияет
на движение тележки.
turnpct
0
-25
-50
RotateMotorEx(OUT_BC, -75, 720, , true, true);
-100
25
50
100
39. Программирование моторов
• Задание 2e. Движение двумя моторами.
• Подберите значение распределения мощности между двумя моторами
для того, чтобы робот начал двигаться по каждой из указанных
траекторий.
40. Программирование моторов
• Задание 3. Остановка.
• Составить программу таким образом, чтобы тележка проехала вперед на
максимальной скорости (максимальная мощность) в течение 4 оборотов
двигателя. После окончания движения использовать торможение
двигателем.
RotateMotorEx(OUT_BC, 100, 1420, 0, true, true );
• Изменить программу, чтобы использовать отключение питания от
мотора в качестве торможения.
RotateMotorEx(OUT_BC, 100, 1420, 0, true, false );
41. Программирование моторов
• Сложные траектории.
• Одной из сложностей при программировании
движения робота является определение нужного
количества оборотов мотора для передвижения на
заданное расстояние.
• Например,
• На сколько нужно повернуть моторы, чтобы робот повернул на 90
градусов налево?
• Как разворачиваться быстрее - повернуть на 90 градусов, включив
только один мотор, или используя максимальное/минимальное
значение распределения мощности между двумя моторами?
• Подобрать экспериментальным путем, на сколько нужно повернуть
моторы и какое нужно задать направление поворота, чтобы робот
проехал полкруга с радиусом 30 сантиметров?
42. Программирование моторов
• Задание 4. Движение по квадрату.
• Составьте программу для того, чтобы робот двигался по сторонам
квадрата.
• Как бы мы действовали, если бы мы двигались подобным образом?
43. Программирование моторов
• Задание 5. Движение по восьмерке.
• Составьте программу для того, чтобы робот двигался по сторонам
восьмерки.
• Одной из трудностей в этой программе является возврат в то же место,
откуда робот начал двигаться.
44. Программирование моторов
• Включаем моторы:
OnFwd(outputs, pwr)
OnRev(outputs, pwr)
Распределение мощности между
Какие моторы вращать: двумя моторами при использовании
OUT_A, OUT_B, OUT_C Мощность: «спаренных»
OUT_BC, OUT_AC -100..100 двигателей, например, A и B или B и
OUT_AC С (-100..100)
OnFwdSync(outputs, pwr, turnpct)
OnRevSync(outputs, pwr, turnpct)
• Пример:
OnFwd(OUT_BC, 60);
OnRev(OUT_A, 100);
OnFwdSync(OUT_BC, -75, -100);
45. Программирование моторов
• Задание 6. Включение моторов.
• Изучить, что произойдет, включить моторы и закончить программу.
task main() {
OnFwd(OUT_BC, 100);
}
Цель эксперимента - показать, что функции включения
моторов никак не определяют сколько будет включен
мотор, сколько колеса тележки проедут.
Также он показывает, что при заверешении программы
моторы явно не останавливаются – вместо этого с них
снимается энергия и моторы продолжают двигаться по
инерции.
46. Ожидание
• Иногда бывает необходимо вставить
задержку между двумя
выполняющимися действиями.
• Примеры:
• Подождать, пока человек отреагирует
на действие
• Подождать, пока датчики будут
готовы к работе
• Подождать, пока тележка проедет
какое-то расстояние
47. Ожидание
• В языке NXC задержку между двумя командами можно
добавить с помощью функции:
Wait(milliseconds) Сколько
миллисекунд
ждать
• Специальные константы для упрощения задания задержек:
SEC_1, SEC_2, ..., SEC_10, SEC_
MIN_1 - секунды
15, SEC_20, SEC_30 - секунды
• Пример:
Wait(1); //Ждать 1 миллисекунду
Wait(500); //Ждать полсекунды
Wait(10000); //Ждать 10 секунд
Wait(SEC_10); //Ждать 10 секунд
Wait(SEC_2*5); //Ждать 10 секунд
48. Программирование моторов
• Останавливаем моторы:
Off(outputs)
Coast(outputs)
Какие моторы останавливать:
OUT_A, OUT_B, OUT_C
OUT_BC, OUT_AC, OUT_AC
OUT_ABC
• Пример:
Off(OUT_A); //Затормозить мотор А
Coast(OUT_BC); //Отключить энергию с моторов B и C
Off(OUT_BC); //Затормозить моторы B и C
49. Программирование моторов
• Задание 7. Еще одно движение по квадрату.
• Составьте программу для того, чтобы робот двигался по сторонам
квадрата. Но используйте функции включения/выключения моторов и
временные задержки для того, чтобы определять сколько робот проедет
и на сколько повернет.
• Нужно ли останавливать двигатели перед поворотом?
• Что произойдет, если во всей программе теперь изменить мощность
на моторах в два раза?
50. Программирование моторов
• Задание 8. Блокировка колес.
• Изучить, что произойдет, если запрограммировать робота ехать 5
секунд, и в то же время руками остановить двигатели - искусственно
создать ситуацию, когда робот натолкнулся на препятствие и колеса
провернуться не могут.
Цель эксперимента - показать, что не смотря на то, что
колеса заблокированы и не могут двигаться, программа
продолжит выполняться после истечения 5 секунд.
51. Работа с экраном
• Среда программирования
предоставляет возможность
выводить текстовую и
графическую информацию на
графический экран NXT блока
52. Работа с экраном
• Экран имеет разрешение 100x64 точки – или можно
сказать, что он имеет 100 столбцов по 64 строчки
каждый. x = 99
y = 63
координата Y
строчки
x = 11
y=4
x=0
y=0
координата X
столбцы
53. Работа с экраном
• Помимо графической информации, на экран можно
вывести 8 строк текста по 16 символов
• Поддерживаются только латинские символы, цифры
строка 1
строка 2 Размер одного
строка 3 знакоместа
6 x 8 точек
строка 4
строка 5
строка 6
строка 7
строка 8
54. Работа с экраном
• Вывод текста и цифр на экран:
TextOut(x, y, str) – вывести строку, начиная с заданных координат
NumOut(x, y, value) – вывести число
• Для упрощения позиционирования вывода на экран в
нужных строках можно использовать спец. константы:
LCD_LINE1 – первая сверху строка, строка в самом верху экрана
LCD_LINE2 – вторая сверху строка
. . .
LCD_LINE8 – последняя строка, строка в самом низу экрана
• Весь экран можно очистить:
ClearScreen()
TextOut(56, 0, "Hello");
• Пример: NumOut(10, LCD_LINE2, 314159);
TextOut(6*8, LCD_LINE3, "Robot");
55. Работа с экраном
• Задание 9. Вывод текста во время работы программы.
• Изменить программу движения по восьмерке таким образом, чтобы
робот печатал соответствующие направление движения или
направление поворота на экране:
• “Forward” – прямо
• “Left” – налево
• “Right” – направо
• Каждая новая надпись должна выводиться в новой строчке.
56. Воспроизведение звуков
• NXT блок имеет встроенный
динамик, через который
можно выводить звук
определенной частоты или
звуковые файлы в
специальном формате.
57. Воспроизведение звуков
• Воспроизведение звука:
PlayTone(frequency, duration) – воспроизвести звук заданной
частоты (frequency, в герцах) и заданной продолжительности
(duration, в миллисекундах)
PlayToneEx(frequency, duration, volume, loop) – аналогично
PlayTone, но позволяет задать громкость (volume, 0..4) и
повторяемость действия.
• Если нужно вывести конкретную ноту можно
использовать спец. константы:
TONE_C4 – нота ДО четвертой октавы, TONE_D4 – нота РЕ четвертой октавы
TONE_E4 – нота МИ четвертой октавы, TONE_F4 – нота ФА четвертой октавы
TONE_G4 – нота СОЛЬ четвертой октавы, TONE_A4 – нота ЛЯ четвертой октавы
TONE_B4 – нота СИ четвертой октавы
PlayTone(440, 250);
• Пример: PlayTone(TONE_F4, 125);
PlayToneEx(TONE_A4, 500, 4, false);
58. Воспроизведение звуков
• Задание 10. Звуки во время работы программы.
• Изменить программу движения по восьмерке таким образом, чтобы
робот воспроизводил звуки после завершения соответствующего
движения прямо или поворота.
• На повороте в лево звук должен быть отличным от звука на повороте в
право.
59. Для чего нужны датчики?
• Основной функцией робота является движение или
перемещение его частей
(манипуляторы, захваты, ноги, сенсоры)
60. Для чего нужны датчики?
• Роботу необходимо изменять свое поведение
(движение) в зависимости от внешних событий.
61. Для чего нужны датчики?
• Внешние события приходят роботу через сенсоры и
датчики, от внутренних часов робота, от оператора, а
также от других роботов.
62. Что такое состояние?
• Смена состояния робота:
• При программировании роботов часто говорят о
состояниях. Например, робот находится в состоянии
движения или робот находится в состоянии
бездействия.
• Чтобы перейти к следующему состоянию, робот
должен получить указание на это через какое-то
событие.
63. Что такое состояние?
• Например, когда робот находился в состоянии
движения, к нему приходит сигнал от датчика касания,
что впереди перпятствие, и робот из состояния
движения переходит в состояние бездействия.
Сигнал от датчика
Движение Остановка
64. Ожидание событий
• Следовательно, робот будет продолжать находиться в
предыдущем состоянии до тех пор, пока не получит
сигнал на переход в следующее состояни.
• Робот должен ожидать возникновения сигнала – этот
процесс можно назвать «Ожидание события»
65. Ожидание событий
• В языке NXC есть специальная конструкция для
ожидания какого-то события:
until(УСЛОВИЕ) – программа не идет к выполнению следующих команд,
пока не наступит заданное условие.
• Конструкцию можно описать фразой: «выполнять
предыдущее действие до тех пор, пока не случиться ...»
• УСЛОВИЕ - чаще всего сравнение текущих показаний
датчиков с каким-то эталонным значением (точка
срабатывания, предельное значение и т.п.). Сравнение
происходит посредством конструкций:
ЗНАЧЕНИЕ1 == ЗНАЧЕНИЕ2 – равныпрограмма не идет к выполнению
следующих команд, пока не наступит заданное условие.
66. Ожидание событий
• УСЛОВИЕ - чаще всего, сравнение текущих показаний
датчиков с каким-то эталонным значением (точка
срабатывания, предельное значение и т.п.). Сравнение
происходит посредством конструкций:
ЗНАЧЕНИЕ1 == ЗНАЧЕНИЕ2 – условие справедливо, если значения равны
ЗНАЧЕНИЕ1 != ЗНАЧЕНИЕ2 – условие справедливо, если значения не равны
ЗНАЧЕНИЕ1 < ЗНАЧЕНИЕ2 – условие справедливо, если первое значение
меньше второго
ЗНАЧЕНИЕ1 > ЗНАЧЕНИЕ2 – условие справедливо, если первое значение
больше второго
ЗНАЧЕНИЕ1 <= ЗНАЧЕНИЕ2 – условие справедливо, если первое значение
меньше или равно второму (не больше второго)
ЗНАЧЕНИЕ1 >= ЗНАЧЕНИЕ2 – условие справедливо, если первое значение
больше или равно второму (не меньше второго)
67. Датчик касания
• Датчик касания позволяет роботу
воспринимать прикосновения и
реагировать на внешние
раздражители
• С помощью датчика касания робот
может подбирать предметы
• Манипулятор, оснащенный датчиком касания, позволит
роботу узнать, имеется ли объект, который можно взять
• Датчик касания по сути своей кнопка, у которой
возможно два состояния - Нажато и Отжато.
68. Датчик касания
• Перед работой с любым датчиком в языке NXC его
нужно инициализировать, то есть сказать программе к
какому порту, какой именно датчик присоединен.
• Инициализация датчика касания:
SetSensorTouch(port) – с этого времени работать с заданным
портом, как с датчиком касания
• Тогда получить текущее значение в программе можно
посредством опроса функции:
Sensor(port) – если датчик нажат, функция вернет 1, если отжат, то
возвращаемое значение будет 0.
• port – номер порта, к которому подключен
датчик, задается константами:
S1, S2, S3, S4 или IN_1, IN_2, IN_3, IN_4
69. Датчик касания
• Пример:
task main() {
SetSensorTouch(S1);
//Ничего не делать до тех пор, пока датчик не будет отпущен
until(Sensor(S1) == 0);
//Начать движение вперед
OnFwd(OUT_BC, 100);
//Двигаться до тех пор, пока датчик не будет нажат
until(Sensor(S1) == 1);
//Остановиться
Off(OUT_BC);
}
70. Датчик касания
• Задание 11. Робот обнаруживает препятствие.
• На роботе датчик касания «смотрит» вперед
• Робот начинает двигаться
• Как только обнаружится касание с препятствием, робот должен
остановиться.
• Остановился робот сразу после касания или сколько-то еще пытался
продолжать двигаться?
• За счет какого действия в программе нужно остановить робота, сразу
после обнаружения нажатия?
71. Датчик касания
• Задание 12. Запуск робота c кнопки.
• Изначально робот стоит и должен начать двигаться только после
того, как происходит нажатие на датчик касания.
• Робот останавливается после столкновения с препятствием.
• Почему робот не поехал, а
программа сразу завершилась?
72. Датчик касания
Программа исполняется на NXT блоке быстрее, чем человек
взаимодействует с роботом.
Человек нажал на
кнопку
task main() {
SetSensorTouch(S1); Моторы только начали
запускаться, и управление
until(Sensor(S1) == 1); передалось следующей
команде
OnFwd(OUT_BC, 100);
Очень-очень быстро! Человек еще не
Тысячные доли секунды успел отдернуть
until(Sensor(S1) == 1);
руку от датчика
Off(OUT_BC); Моторы
} остановились и
программа
завершилась
73. Датчик касания
• Вариант решения:
task main() { Человек нажал на
SetSensorTouch(S1); кнопку
until(Sensor(S1) == 1); За это время, кнопка
отжимается
Wait(500);
OnFwd(OUT_BC, 100);
Моторы
запускаются
until(Sensor(S1) == 1);
К этому времени датчик
Off(OUT_BC); «освобожден» и ожидает
} сигнала касания
Минусы подхода:
• Задержку надо подбирать индивидуально для человека
• Запуск мотора происходит с видимой задержкой после нажатия
74. Датчик расстояния
• Датчик расстояния (ультразвуковой
датчик) позволяет роботу измерять
расстояние до объекта и
реагировать на движение
• Сенсор измеряет расстояние
путем расчета времени, которое
потребовалось звуковой волне
для возвращения после
отражения от объекта
75. Датчик расстояния
• Инициализация датчика расстояния:
SetSensorLowspeed(port) – с этого времени работать с заданным
портом, как с датчиком расстояния. В названии функции фигурирует
«медленный датчик», потому что этот датчик цифровой и работает по
I2C шине, которая не позволяет опрашивать датчик слишком часто.
• Текущее значение датчика:
SensorUS(port) – расстояние в сантиметрах (6..255)
76. Датчик расстояния
• Пример:
task main() {
SetSensorLowspeed(S4);
//Начать вращение вокруг своей оси
OnFwdSync(OUT_BC, 50, -100);
//До тех пор, пока не возникнет препятствие ближе, чем 50 см.
until(SensorUS(S4) < 50);
//Остановить моторы
Off(OUT_BC);
//Начать движение и двигаться 3,5 секунды
OnFwd(OUT_BC, 100); Wait(3500); Off(OUT_BC);
}
77. Датчик касания
• Задание 13. Робот обнаруживает препятствие.
• Датчик расстояния на роботе «смотрит» вперед
• Робот двигается до тех пор, пока не появится препятствие ближе, чем 20
см.
20 см.
78. Датчик касания
• Задание 14. Робот-воин.
• Роботу понадобятся два датчика: расстояния и касания
• «Воин» крутится быстро на одном месте вокруг себя
• Как только в его поле зрения появляется предмет ближе чем 50
см., робот начинает двигаться к этому предмету и останавливается когда
стукнется об него
79. Датчик касания
• Задание 15. Парковка.
• Датчик расстояния смотрит в сторону
• Робот должен найти пространство для парковки между двумя
«автомобилями» и выполнить заезд в обнаруженное пространство
15 см. ?? см. 15 см.
80. Датчик освещенности
• Датчик освещенности (световой
датчик) позволяет роботу
различать яркость объектов,
освещенность помещения и даже
различать цвета.
• Что видит глаз человека
• Что видит робот через датчик освещенности
81. Датчик освещенности
• Инициализация датчика освещенности:
SetSensorLight(port, active) – с этого времени работать с
заданным портом, как с датчиком освещенности. Включать светодиод
или нет, определяется в параметре active
• Включить/отключить светодиод можно также позднее с
помощью функций:
SetSensorType(port, SENSOR_TYPE_LIGHT_ACTIVE) – включить
SetSensorType(port, SENSOR_TYPE_LIGHT_INACTIVE) – выключить
• Но тогда после функций выше надо вызвать
ResetSensor(port) – firmware применит новую конфигурацию датчика
• Текущее значение датчика:
Sensor(port) – освещенность в процентах: чем меньше, тем темнее.
Если светодиод не включен, то покажет окружающую освещенность.
Если включен, то будет происходить замер отраженного света.
82. Датчик освещенности
• Пример:
task main() {
SetSensorLight(S3, true);
//Начать движение
OnFwd(OUT_BC, 80);
//Ехать вперед до тех пор, пока не наедем на темный участок
until(Sensor(S3) < 40);
//Продолжать движение (эта команда не обязательна)
OnFwd(OUT_BC, 80);
//До тех пор, пока не наедем на светлый участок
until(Sensor(S3) > 50);
//Остановить моторы
Off(OUT_BC);
}
83. Датчик освещенности
• Задание 16а. Отобразить показания датчика.
• На экране NXT блока должно отображаться текущее значение
окружающей освещенности (светодиод выключен).
• Как избежать запуска программы каждый раз, когда мы пытаемся
измерить новую освещенность?
84. Повтор одинаковых событий
• Иногда в программе возникает необходимость
повторить несколько одинаковых операций друг за
другом несколько раз:
1
2
4
3
85. Повтор одинаковых событий
• Для повтора одинаковых действий в программах
используются циклы. Например,
while(УСЛОВИЕ) { тело цикла } – повторять команды, входящие в
тело цикла, пока УСЛОВИЕ (условие существования цикла)
справедливо
Те действия, которые необходимо
повторять несколько
while(Sensor(S1 == 0)) { раз, помещаются внутрь цикла. Они
RotateMotor(OUT_BC, 100, 1800); составляют тело цикла.
RotateMotor(OUT_B, 50, 720);
}
Как только действие последней команде в теле цикла
заканчивается, программа проверяет еще раз УСЛОВИЕ и переходит к
первой команде в теле цикла, если оно справедливо.
86. Повтор одинаковых событий
• Довольно часто нужно повторять часть программы
бесконечно, пока целиком вся программа не будет
прервана.
• Бесконечный цикл – в нем условие существование
цикла всегда справедливо.
while(true) {
TextOut(0, LCD_LINE1, "Light Sensor:");
NumOut(20, LCD_LINE2, Sensor(S3));
Wait(500);
ClearScreen();
}
87. Датчик освещенности
• Задание 16b. Отобразить показания датчика.
• На экране NXT блока должно отображаться текущее значение
отраженного света (светодиод включен).
88. Датчик освещенности
• Задание 17а. Черно-белое движение.
• Пусть робот доедет до темной области на поле и остановится.
• Что будем измерять: окружающую
22% освещенность или отраженный свет?
• Как определить, что робот заехал на
54% темную область?
Количество света, возвращенное в датчик на темной
области зависит от окружающей освещенности, от высоты
датчика, от цвета освещающего светодиода. Поэтому
никогда не берите пограничное измеренное значение в
условии генерации события. Обычно выбирают середину
между показаниями на темной и светлой области.
22% 38% 54%
89. Датчик освещенности
• Задание 17b. Черно-белое движение.
• Пусть робот доедет, до темной области, а затем съедет обратно на
светлую
• Как только получилось, добавьте цикл в программу - пусть робот
перемещается вперед-назад попеременно, то на темную, то на светлую
область.
90. Датчик освещенности
• Задание 17c. Движение вдоль линии.
• Пусть робот перемещается попеременно, то на темную, то на светлую
область, но теперь движение должно выполняться поочередно то
одним, то другим колесом.
• Попробуйте теперь поставить робота на узкую черную линию.
91. Датчик угла поворота оси
мотора
• B каждый мотор встроен датчик
угла поворота оси (енкодер),
который позволяет контролировать
движение с высокой точностью –
до 1 градуса.
• Енкодеры автоматически используются в большинстве
программ, когда задается проехать определенное
количество движения или для того, чтобы обеспечить
роботу движение прямо (оба колеса должны
поворачиваться на одно и то же количество градусов в
единицу времени).
92. Датчик угла поворота оси
мотора
• По-умолчанию, показания датчика поворота накапливаются с
момента старта робота. Т.е. можно в любой момент времени
узнать, на какое расстояние робот уехал от зоны старта. Причем
движение мотора вперед увеличивают это число, движение
мотора назад уменьшает его.
• Это поведение можно изменить, если в сбросить показания
датчика - накопление будет происходить с момента, когда
произошел сброс.
Старт программы Сброс Замер показаний
3 оборота
Поведение по-умолчанию, 5 оборотов Количество оборотов
Количество оборотов мотора мотора после сброса
2 оборота
после старта
93. Датчик угла поворота оси
мотора
• Инициализация датчика угла поворота оси мотора
(енкодера) не требуется.
• Получить текущее значение датчика:
MotorRotationCount(output) – на какое количество градусов
повернулся соответствующий мотор. Имеет смысл указывать только
один мотор. Мотор задается одной из констант:
OUT_A, OUT_B, OUT_C
• Сбросить датчик угла поворота:
ResetAllTachoCounts(output)
94. Датчик угла поворота оси
мотора
• Пример:
task main () {
RotateMotor(OUT_BC, 80, 720);
//Вывести значения енкодеров
NumOut(0, LCD_LINE1, MotorRotationCount(OUT_C));
NumOut(0, LCD_LINE2, MotorRotationCount(OUT_B));
//Сбросить значения енкодеров только на моторе С
ResetAllTachoCounts(OUT_C);
RotateMotor(OUT_BC, 80, 720);
//Вывести новые значени енкодеров. Один будет
//примерно в два раза больше другого.
NumOut(0, LCD_LINE4, MotorRotationCount(OUT_C));
NumOut(0, LCD_LINE5, MotorRotationCount(OUT_B));
}
95. Датчик угла поворота оси
мотора
• Задание 18. Непослушный робот.
• Робот стоит на неизвестном расстоянии от черной линии.
• После старта программы робот должен доехать до черной линии и
остановиться.
• Затем робот должен проехать назад ровно такое же расстояние
так, чтобы оказаться на том же месте, откуда начал движение.
?
96. Состязание!
• Задание 19. Кегельринг.
• Роботу понадобятся датчик расстояния и датчик освещенности
• Задача робота обнаружить внутри ринга 8 кеглей (предметы
обнаруживаемые датчиком расстояния) и вытолкнуть их за черную
линию, ограничивающую ринг
• Сам робот не должен выезжать за границу ринга больше, чем на 5
секунд.
97. Принятие решений
• В ходе выполнения задания перед роботом может
стоять выбор, в какое состояние ему перейти.
• Подобный выбор стоит перед богатырем на распутье.
• Выбор может зависеть от показаний
на сенсорах и датчиках, внутренних
часов робота или от информации
полученной от других роботов.
98. Принятие решений
• Например, робот, обнаружив красный мяч, должен
отнести его в корзину, а синий оставить на месте.
Включить
моторы
Узнать захвата
какого
цвета
мяч
Включить
моторы для
разворота
99. Принятие решений
• Также можно говорить о причинах и действиях, которые
эти причины вызывают.
Стало Поднять
тихо занавес
Подать
Стало
звуковой
громко
сигнал
причины действия
100. Принятие решений
• В языке NXC для анализа причины и выборе
соотвестствующего действия используется конструкция:
if (УСЛОВИЕ) { действия А и Б } else { действия В и Г } –
если УСЛОВИЕ справедливо, то выполнять действия А и
Б, иначе, если УСЛОВИЕ не верно, то выполнять действия В и Г.
• Можно использовать сокращенную запись, если не
нужно выполнять никаких действий при
несправедливости условия:
if (УСЛОВИЕ) { действия А и Б }
101. Принятие решений
• В месте принятия решения происходит разветвление
программы.
• В зависимости от решения, программа может пойти
либо по одной, либо по другой ветке
RotateMotor(OUT_BC, 60, 720); • После выполнения
if (Sensor(S1)<40) {
действий внутри
//Если на сенсоре маленькие значения той или иной
RotateMotor(OUT_A, 40, 90); ветки, программа
} else {
//Если на сенсоре большие значения вновь
TextOut(0, LCD_LINE1, "Error"); возвращается в
PlayTone(TONE_C4, MS_250);
} «основное русло».
RotateMotor(OUT_BC, 60, -720);
102. Принятие решений
• Можно вкладывать конструкции друг в друга, для
принятия сложных решений:
if (Sensor(S1) < 40) {
if (SensorUS(S4) > 25) {
RotateMotor(OUT_B, 90, 360);
} else {
RotateMotor(OUT_C, 90, 360);
}
TextOut(0, LCD_LINE1, "Too bright");
} else {
TextOut(0, LCD_LINE1, "Error");
PlayTone(TONE_C4, MS_250);
}
103. Принятие решений
• Задание 20. Нажми кнопку!
• После включения блок должен проверить нажат ли датчик касания.
• В зависимости от того нажат или нет, вывести на экран “Yes” или “No”
• После вывода на экран – остановить программу
YES
NO
104. Принятие решений
• Задание 21. Управляемая машинка
• Датчик касания закреплен на длинном проводе
• Если датчик нажат – робот-тележка стоит, если отжат – едет
• Измените, программу так, чтобы при нажатом датчике робот вращался
вокруг своей оси, а при отжатом – двигался вперед.
105. Принятие решений
• Задание 22. Азбука Морзе
• Пусть тележка крутиться вокруг своей оси
• Когда датчик находится на темной поверхности – издается звук, как
только поверхность светлее – звук смолкает
L E G O
106. Принятие решений
• Задание 22. Неудачный пешеходный переход
• Робот-тележка должен пересекать черные полоски – дорожки, при
пересечении издавать звук.
• Как только перед роботом возникнет препятствие – он должен
остановиться
• Как сделать так, чтобы робот перестал выполнять цикл после
обнаружения стены?
107. Выход из цикла по условию
• Типичная ситуация, когда цикл должен завершиться при
по какому-то событию, из-за какой то причины.
• В начале цикла можно задать условие, которое будет
определять, когда тело цикла все еще должно
выполняться:
while (УСЛОВИЕ) { тело цикла }.
• УСЛОВИЕ будет проверяться каждый раз, когда
происходить переход от последней команды в теле
цикла к первой. Если УСЛОВИЕ не справедливо, то цикл
завершиться.
• После выхода из цикла будут выполняться
команды, идущие сразу после закрывающей скобки.
108. Выход из цикла по условию
• Пример:
while(SensorUS(S3) > 15) {
if (Sensor(S3) > 40) {
OnFwd(OUT_B); Coast(OUT_C);
} else {
OnFwd(OUT_C); Coast(OUT_B);
}
}
//Переход к этой функции случиться, когда расстояние
//станет меньше 15 см.
Off(OUT_BC);
109. Принятие решений
• Задание 23а. Беспокойный любопытный робот
• Робот должен находиться все время на одном расстоянии от руки (или
другого предмета) – 25 см.
• Если рука удаляется от робота, то робот придвигается к ней
• Если рука приближается к роботу, то робот отъезжает назад.
110. Принятие решений
• Задание 23b. Опытный любопытный робот
• В предыдущем задании, робот никогда не был в состоянии покая – он, то
ехал вперед, то двигался назад
• Нужно изменить программу так, чтобы робот был неподвижен при
нахождении на определенном расстоянии
• Задание нужно выполнить с использование вложенных условий
if (SensorUS(S4) < 24) {
OnFwd(OUT_BC, 60);
} else {
24 см.
if (SensorUS(S4) < 26) {
26 см.
Off(OUT_BC);
} else {
OnFwd(OUT_BC, -60);
}
}