Пожалуй, одной из наиболее популярных задач для
Arduino является сопряжение с "большим братом" - иными словами, обмен данными с компьютером (и вовсе не обязательно с тем, на котором создается скетч).
Самый простой способ - использовать библиотеку
Serial, которая доступна по умолчанию. При помощи операторов
Serial.print() можно передать произвольные данные через USART МК ATmega в реальный или виртуальный COM-порт (текущие модели Arduino/Freeduino используют USB-to-TTL мост на чипе FT232RL). Естественно, можно не только получать, но и отправлять, организовав таким образом полноценный интерактив.
Написание собственного протокола обмена, пусть даже не очень сложного - весьма скучное занятие. В поисках того, как реализовать его просто и непринужденно, вы обязательно наткнетесь на
Processing: он примечателен тем, что именно от его IDE была унаследована ArduinoIDE.
Что же такое
Processing?
Если кратко - еще один язык программирования, порожденный от
Java и позволяющий быстро создавать программы построения изображений и анимации, а также делать все это интерактивным. При этом Arduino как раз и может стать тем самым элементом, который эту интерактивность обеспечивает.
Скачав, распаковав и запустив
последнюю версию PDE (Processing Development Evironment), вы найдете сходство с ArduinoIDE настоль очевидным, что руки сами начнут автоматически набирать "setup":
Здесь программы тоже называются скетчами. Однократно выполняемая часть оформляется в
setup, повторяемая циклически - в
draw (аналог
loop). Меню
Sketch | Run вызывает компиляцию скетча в полноценное Java-приложение и его запуск в отдельном окне, куда оно старательно отображает свою картинку. После окончательной отладки можно нажать Export (соответствует пиктограмме Upload для ArduinoIDE) - и тогда создается html-код страницы с java-апплетом, готовый к размещению в www.
Для быстрого ознакомления с различиями Processing и Wiring создана
вот эта страничка. По большому счету, все сводится к отличиям C++ от Java, которые обычно подробно описываются в любом учебнике по Java.
Вернемся к Arduino, точнее к его библиотеке
Firmata. Она берет на себя "черную работу" по поддержке механизма обмена между скетчем и программой на "большом брате". Разработчику остается только продумать логику работы этого небольшого АПК, определить поведение нужных callback-функций и вставить вызовы библиотеки в
setup и
loop. Если вы уже пробовали реализовывать интерактив средствами
Serial - попробуйте как-нибудь с
Firmata - должно получиться проще, лучше и быстрее.
Именно с помощью Firmata можно "прикрутить" Arduino к Processing-у, для этого:
- скачайте библиотеку для Processing-а и распакуйте ее в папку libraries/arduino в каталоге для скетчей Processing (создайте каталоги при необходимости) - но имейте ввиду, что в версии 1.1 она уже включена в состав дистрибутива, так что скорее всего можно обойтись без этого шага;
- запустите ArduinoIDE, откройте скетч из Examples | Firmata | StandardFirmata, откомпилируйте и загрузите его в свою Arduino-совместимую плату (и не отключайте её после этого);
- запустите Processing, откройте пример из папки libraries/arduino/examples/arduio_output через File | Open;
- запустите скетч на выполнение.
Если в ответ на попытку компиляции Processing ругается на невозможность найти cc.arduino.*, сходите в меню Sketch | Add file..., добавьте файл libraries/arduino/library/Arduino.jar и повторите попытку компиляции.
Результатом работы скетча является вот такое нехитрое окно состояния цифровых выходов:
Каждый кубик обозначает один цифровой выход от 13 до 0. Щелкая по нему, мы переключаем состояние межу HIGH и LOW. Как минимум, к выходу 13 подключен светодиод L, так что изменение его состояния можно наблюдать вполне визуально.
Вот как это выглядит внутри скетча Processing:
import processing.serial.*;
import cc.arduino.*;
Arduino arduino;
color off = color(4, 79, 111);
color on = color(84, 145, 158);
int[] values = { Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW,
Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW,
Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW };
void setup() {
size(470, 200);
println(Arduino.list());
arduino = new Arduino(this, Arduino.list()[0], 57600);
for (int i = 0; i <= 13; i++)
arduino.pinMode(i, Arduino.OUTPUT);
}
void draw() {
background(off);
stroke(on);
for (int i = 0; i <= 13; i++) {
if (values[i] == Arduino.HIGH)
fill(on);
else
fill(off);
rect(420 - i * 30, 30, 20, 20);
}
}
void mousePressed()
{
int pin = (450 - mouseX) / 30;
if (values[pin] == Arduino.LOW) {
arduino.digitalWrite(pin, Arduino.HIGH);
values[pin] = Arduino.HIGH;
} else {
arduino.digitalWrite(pin, Arduino.LOW);
values[pin] = Arduino.LOW;
}
}
Сначала в функции setup() происходит создание объекта Arduino, через вызов его конструктора:
arduino = new Arduino(this, Arduino.list()[0], 57600);
Первым аргументом в списке идет
this - так уж принято. Далее указывается порт, к которому подключен Arduino, например
/dev/ttyUSB0 для Linux. Для его получения существует функция
Arduino.list() - статическая (можно использовать без привязки к экземпляру объекта), возвращающая список плат. Подключение будет выполнено к первой из этого списка (элемент с номером 0). Последним идет скорость порта, для этой версии Firmata она фиксирована и составляет 57600.
После создания объекта можно вызывать привычные операторы Wiring, не забывая предварять их именем объекта arduino (например - перевод всех цифровых пинов в режим вывода):
for (int i = 0; i <= 13; i++)
arduino.pinMode(i, Arduino.OUTPUT);
Циклически вызываемый метод
draw() занимается перерисовкой кубиков по текущим значениям выходов, хранимых в промежуточном массиве
values (инициализирован в начале значениями константы
Arduino.LOW).
И, наконец, обработчик событий от мыши
mousePressed() - вычисляет по координатам клика нужный кубик, инвертирует соответствующую ему ячейку массива
values и вызывает
digitalWrite, чтобы актуализировать состояние выхода нашего Arduino.
Попробуем наваять скетч самостоятельно, например - пусть при помощи потенциометра будет регулироваться насыщенность красным. Схема подключения переменного сопротивления до безобразия тривиальна:
А вот скетч Processing:
import processing.serial.*;
import cc.arduino.*;
Arduino arduino;
void setup() {
size(200, 200);
arduino = new Arduino(this, Arduino.list()[0], 57600);
}
void draw() {
background(255 * arduino.analogRead(0) / 1024,0,0);
}
Всю отрисовку выполняет функция
background(value1, value2, value3) - где valueN соответствуют составляющим красного, зеленого и синего. Зная, что analogRead вернет число от 0 до 1023, нехитрой операцией масштабируем этот диапазон в 0..255.
Как видите - запредельно просто, почти как с ArduinoIDE. Наиболее выдающиеся скетчи Processing можно посмотреть на
openprocessing.org. Все они, конечно же, доступны под лицензией CC-SA.
В статье использованы материалы из Playground:
http://www.arduino.cc/playground/Interfacing/Processing