JavaScript:Библиотеки/p5.bots

Материал из Онлайн справочника
Перейти к навигации Перейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Pixel Art Mini Meow Animated.gif Черновик


Содержание

p5.bots[1]

Эта библиотека предназначена для упрощения коммуникации между p5.js в браузере и микроконтроллером, работающем на Firmata.

Примечания:

  • Библиотека p5.bots была протестирована на Arduino Uno, но должна быть совместима с любыми устройствами, работающими на Firmata
  • API для последовательной коммуникации никак от Firmata не зависит

Библиотека p5.bots использует библиотеку socket.io и платформу node.js, чтобы отправлять сообщения между двумя устройствами на языке, который понимают оба этих устройства.

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

P5.bots how-it-works.png

Для работы с p5.bots необходимы два набора файлов: клиентский файл «p5bots.js», который вместе с «p5.js» нужно подключить в файле «index.html», и серверные файлы «p5bots-server», которые можно загрузить с npm.

Библиотека p5.bots распространяется по лицензии LGPL.

p5.Serial

В библиотеке p5.bots есть метод p5.serial(), который можно использовать вместе со скетчем Arduino, прослушивающим последовательный порт. Все это работает примерно так же, как библиотека Serial для Processing.

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

Если вы для коммуникации используете только последовательный порт, то Firmata на плату устанавливать не нужно.

p5.Board

Большая часть функционала p5.bots содержится в классе p5.board. Он многое заимствует у фреймворка Johnny-Five и имеет несколько методов для работы с цифровыми и аналоговыми устройствами, методы для чтения/записи ШИМ, а также методы, предназначенные специально для работы с различными электротехническими компонентами. Более подробно о них читайте ниже. Скетчи-примеры и схемы подключения смотрите по этой ссылке.

С чего начать

Вот материалы, которые помогут побыстрее разобраться, что к чему:

Проблемы

О проблемах сообщайте сюда.

Вклад

Хотите исправить найденную проблему? Хотите добавить новую функцию, которой еще нет? Загляните сюда.

Использование p5.bots вместе с p5.js

Базовые функции

Чтобы начать коммуникацию с устройством, вам нужно для начала инициализируем плату и как минимум один контакт. Для этого сначала вызовите функцию p5.board(). Она вернет объект платы, на котором в дальнейшем можно использовать функцию pin() для инициализации контакта. Созданный таким образом объект поддерживает не только pin(), но и другие функции.

Инициализация платы

// возвращает указатель на объект платы:
p5.board(port, type)

Здесь параметр «port» – значение типа String, обозначающее, соответственно, порт для подключения (о том, как определить порт, читайте в начале этой статьи). Параметр «type» – это тип платы (например, «arduino»).

Инициализация контакта

Теперь, когда у нас есть плата, мы можем создать контакт. Нам понадобится по крайней мере один контакт, чтобы программа знала, куда отправлять информацию. Эту функцию можно задавать со всеми возможными параметрами («num», «mode» и «direction») или только с одним («num»). Она возвращает указатель к объекту контакта, поддерживающему несколько разных методов (подробнее о них – ниже). Вот пример вызова pin() со всеми возможными параметрами:

// возвращает указатель к объекту контакта:
board.pin(num, mode, direction)

Здесь параметр «num» – это номер контакт, «mode» – режим работы контакта («digital» или «цифровой режим», «analog» или «аналоговый режим» и «pwm» или «ШИМ»), а «direction» – это направление передачи информации («input» или ввод данных и «output» или вывод данных).

Вот пример вызова pin() только с параметром «num»:

// сокращенный вариант инициализации контакта:
pin = board.pin(num)

Константы

Выше было показано, как параметры вроде типа платы или направления передачи информации задаются с помощью строк вроде «DIGITAL». Но это также можно сделать при помощи констант вроде «b.HIGH». Библиотека p5.bots поддерживает использование следующих констант:

 1 // значения:
 2 board.HIGH
 3 board.LOW
 4 
 5 // направление:
 6 board.INPUT 
 7 board.OUTPUT
 8 
 9 // базовые режимы работы контакта:
10 board.ANALOG
11 board.DIGITAL
12 board.PWM 
13 
14 // специальные режимы работы контакта:
15 board.SERVO
16 board.BUTTON
17 board.KNOCK 
18 board.LED 
19 board.MOTOR 
20 board.PIEZO 
21 board.RGBLED
22 board.TEMP
23 board.TONE
24 board.VRES

Базовые методы для работы с контактами

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

Метод write() всегда отправляет значение на контакт. Если контакту задан режим «input» (режим ввода данных), то отправленное значение может выставить этот контакт в положение «HIGH» или «LOW». Принцип работы метода read() в библиотеке p5.bots отличается от того, как он работает в языках Arduino и Processing. Он не возвращает значение напрямую, а принимает функцию обратного вызова, запускаемую при каждом изменении значения. Кроме того, с каждым изменением значения p5.bots меняет значение в свойстве «pin.val», но это асинхронная операция и потому будет выполняться, возможно, с маленькой задержкой.

1 // с каждым изменением значения будет обновляться свойство «pin.val»,
2 // а также вызываться опциональная функция обратного вызова: 
3 pin.read([callback fn]) 
4 
5 // отправляем значение на контакт:
6 pin.write(val)
7 Пример:
8 // при каждом изменении значения пишем его в консоль:
9 p.read(function(val){console.log(val);});

Специальные методы для записи данных

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

Методы для работы со светодиодами

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

 1 // инициализирует контакт для работы со светодиодом:
 2 led = board.pin(num, 'LED')
 3 
 4 // базовые функции чтения/записи, 
 5 // работающие на любом другом контакте:
 6 led.write()
 7 led.read()
 8 
 9 // запись значений «HIGH» и «LOW»:
10 led.on()
11 led.off()
12 
13 // запускает мигание; 
14 // в параметре «duration» задается, как долго светодиод
15 // будет оставаться включенным/выключенным (в миллисекундах):
16 led.blink(duration)
17 
18 // останавливает мигание:
19 led.noBlink()
20 
21 // увеличивает или уменьшает яркость светодиода;
22 // в параметре «start» задается начальный уровень яркости,
23 // а в параметре «stop» – конечный уровень яркости;
24 // яркость – это ШИМ в диапазоне от «0» до «255»;
25 // время задается в миллисекундах;
26 // значение по умолчанию в параметре «total time» - 3000,
27 // а в параметре «interval» – 200: 
28 led.fade([start, stop, [, total time, interval]])

Методы для работы с RGB-светодиодами

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

1 // инициализируем контакт 
2 // при помощи ассоциативного массива 
3 // с настройками для RGB-светодиода:
4 rgb = board.pin({ r: int, g: int, b: int, common: 'anode' || 'cathode' }, 'RGBLED');
5 
6 // при помощи этих методов осуществляется 
7 // запись/считывание данных о цветах RGB-светодиода:
8 rgb.write() 
9 rgb.read()

Метод write() принимает либо объект p5.Color, либо массив из трех чисел в диапазоне между «0» и «255», с помощью которых задаются цвета RGB-светодиода.

К примеру, вот три разных варианта, задающих для RGB-светодиода один и тот же цвет:

1 var c = color(255, 204, 0);
2 rgb.write(c);
3 
4 colorMode(hsla);
5 var h = color(48, 100, 50);
6 rgb.write(h);
7 
8 var a = [255, 204, 0];
9 rgb.write(a);

Методы on() и off() переключают состояние контакта между значениями «HIGH» и «LOW». При выключении RGB-светодиода его цветовое значение сохраняется.

 1 // включает RGB-светодиод, 
 2 // заставляя его загореться прежним или белым цветом:
 3 rgb.on()
 4 
 5 // задает для контакта значение «LOW», но сохраняет прежний цвет:
 6 rgb.off()
 7 
 8 // запускает мигание,
 9 // в параметре «duration» задается, 
10 // как долго RGB-светодиод будет находиться в положении вкл/выкл: 
11 rgb.blink(duration)
12 
13 // останавливает мигание (довольно забавным способом):
14 rgb.noBlink()
15 
16 // задает яркость трех компонентов RGB-светодиода;
17 // начальный уровень яркости задается в параметре «start», 
18 // а конечный уровень яркости – в параметре «stop»;
19 // яркость – это ШИМ в диапазоне от «0» до «255»;
20 // время задается в миллисекундах;
21 // значения по умолчанию в «total time» – 3000, в «interval» - 200;
22 // каждый контакт RGB-светодиода задается отдельно:
23 rgb.fade([start, stop, [, total time, interval]], [start, stop, [, total time, interval]], [start, stop, [, total time, interval]])

Методы для работы с мотором

 1 // инициализирует контакт для работы с мотором:
 2 motor = board.pin(num, 'MOTOR')
 3 
 4 // эти два метода задают
 5 // самую высокую и самую низкую скорости мотора:
 6 motor.start()
 7 motor.stop()
 8 
 9 // задает скорость для мотора;
10 // она задается в ШИМ в диапазоне между «0» и «255»:
11 motor.write(int)

Методы для работы с сервоприводом

 1 // инициализирует контакт для работы с сервоприводом:
 2 servo = board.pin(num, 'SERVO')
 3 
 4 // задает диапазон перемещения сервопривода в градусах;
 5 // по умолчанию стоит диапазон в промежутке между «0» и «180»:
 6 servo.range([int, int])
 7 
 8 // задает позицию, на которую нужно переместиться (в градусах):
 9 servo.write(int)
10 
11 // перемещают сервопривод вперед и назад по заданному диапазону;
12 // а также останавливают сервопривод:
13 servo.sweep()
14 servo.noSweep()

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

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

1 // инициализирует контакт
2 // для работы с пьезодинамиком в качестве источника звука:
3 t = board.pin(num, 'TONE') || board.pin(num, 'PIEZO')
4 
5 // отправка пьезодинамику одного значения:
6 t.write()

Информацию о звуках можно отправлять в виде ноты или частоты.

1 // отправляет пьезодинамику ноту или частоту;
2 // кроме того, в параметре «duration» задается 
3 // продолжительность проигрывания звука (в миллисекундах):
4 t.tone(note || freq, duration)
5 t.noTone()

К примеру, две этих строчки проиграют в течение полсекунды один и тот же звук:

1 t.tone('c#2', 500)
2 t.tone(69, 500)

Специальные методы для считывания данных

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

Методы для работы со кнопкой

Все три «кнопочных» метода являются спецверсиями метода read() – они будут вызываться, когда кнопка будет нажата, отпущена или зажата.

 1 // инициализирует контакт для работы с кнопкой:
 2 button = board.pin(num, 'BUTTON')
 3 
 4 // оба этих метода вызывают функцию обратного вызова,
 5 // но pressed() – если кнопка была нажата, 
 6 // а released() – если она была отпущена: 
 7 button.pressed(cb)
 8 button.released(cb)
 9 
10 // вызывает функцию обратного вызова, если кнопка была зажата;
11 // в параметре «int» задается, сколько времени (в мс) должно пройти,
12 // чтобы определить, что кнопка была зажата:
13 button.held(cb, int)

Методы для работы с регулируемым резистором

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

 1 // инициализирует контакт для работы с регулируемым резистором:
 2 vr = board.pin(num, 'VRES')
 3 
 4 // задает диапазон значений для методов ниже;
 5 // по умолчанию стоит диапазон между «0» и «1023»:
 6 vr.range([int, int]) 
 7 
 8 // работает как стандартная функция чтения, 
 9 // то есть с каждым изменением значения задает «vr.val»
10 // и запускает заданную функцию обратного вызова:
11 vr.read([cb])
12 
13 // задает пороговое значение:
14 vr.threshold(int)
15 
16 // если пороговое значение задано,
17 // эта функция позволяет узнать, находится ли значение
18 // выше заданного порога («true» или «false»):
19 vr.overThreshold

Методы для работы с температурными датчиками

Изначально эти методы были предназначены для датчиков, определяющих температуру при помощи считывания меняющегося напряжения. При инициализации контакта в параметрах нужно указать номер инициализируемого контакта и уровень считываемого напряжения: 3.3 или 5 вольт.

 1 // инициализация контакта с указанием номера контакта и напряжения: 
 2 temp = board.pin({pin: num, voltsIn: 5})
 3 
 4 // этот метод всегда возвращает необработанные данные - 
 5 // на тот случай, если вы работаете не с температурным датчиком; 
 6 // кроме того, этот метод можно вызвать в таком виде:
 7 // temp.read( function(val) { console.log(temp.f(val)) } );
 8 temp.read() 
 9 
10 // возвращает температуру в заданной единице измерения:
11 temp.C
12 temp.F
13 temp.K

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

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

 1 // инициализирует контакт
 2 // для работы с пьзодинамиком в качестве датчика уровня шума:
 3 k = board.pin(num, 'KNOCK') || board.pin(num, 'PIEZO')
 4 
 5 // стандартный метод для чтения:
 6 k.read()
 7 
 8 // задает пороговое значение:
 9 k.threshold()
10 
11 // если было задано пороговое значение,
12 // этот метод определяет, превышено ли оно;
13 // возвращает булево значение («true» или «false»):
14 k.overThreshold()

Другие специальные методы

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

Вдобавок к методам выше, созданным на базе Firmata, в p5.bots также есть универсальная библиотека-обертка node-serialport.

 1 // настраивает доступ к последовательному порту:
 2 serial = p5.serial()
 3 
 4 // возвращает список портов, доступных на вашем ПК
 5 // (последовательный порт подключать необязательно): 
 6 serial.list()
 7 
 8 // вы можете подключиться сразу, без поиска доступных портов;
 9 // опции для объекта «config» перечислены тут: https://github.com/voodootikigod/node-serialport#serialport-path-options-openimmediately-callback
10 
11 serial.connect(path [, { config obj } ]) 
12 
13 // стандартные методы для чтения и записи:
14 serial.read()
15 serial.write()

Поскольку метод serial.read() работает в стиле Node.js – то есть принимает функцию обратного вызова, а не возвращает функцию – мы можем добавить еще два метода для чтения:

1 // как в API Processing:
2 serial.readEvent([callback function])
3 
4 // возвращает считанное значение:
5 serial.readData()

Создание ваших собственных методов

Если вы знакомы с Node.js, то можете написать собственные серверные функции, которые будут прослушивать вызовы со стороны клиента. Для этого:

  • Создаем серверный файл, где каждая функция, которую вы хотите использовать, является свойством объекта «exports». У каждой функции есть доступ к сокету и объекту платы Firmata
1 exports.mine = function mine(board, socket) {
2   socket.on('event', function(data){ .. });
3   socket.emit('another', { name: 'data-object' });
4 }
  • Начиная, сообщаем серверу об этом файле при помощи одного из следующих способов:
1 -p, --ufilepath <p>  путь к файлу, содержащему серверные функции-детекторы, заданные пользователем
2 -n, --ufilename <n>  путь к файлу (включая название файла), содержащему серверные функции-детекторы, заданные пользователем

По умолчанию путь ведет к текущей директории, а именем файла является «user.js».

См.также

Внешние ссылки