Этой статьёй мы продолжаем цикл материалов о языке программирования Processing и сегодня мы рассмотрим как связь (родство) самих систем программирования Processing и Arduino, так и связь между программами и приложениями, работающими в этих системах. В частности, мы рассмотрим управление работой программ по последовательному интерфейсу (Serial).
Processing и Arduino
Processing и Arduino являются родственными системами с похожей идеологией и реализацией. Можно сказать, что Ардуино «выросла» из Процессинга. Ардуино использует похожий (хотя и несколько урезанный по сравнению с Processing) синтаксис, только ориентированный на работу с микроконтроллерами. Официально язык программирования Ардуино называется Wiring.
Поскольку это родственные и очень похожие системы (у них даже интерфейс среды разработки практически один и тот же), то освоив одну из них, вы с лёгкостью сможете работать и в другой. И это здорово потому, что очень снижает порог входа и освоение программирования как микроконтроллеров, так и полноценных компьютеров, работающих под различными операционными системами.
Связь между Processing и Arduino
Зачем может понадобиться связь между Processing и Arduino? Применений подобной связи множество: это и управление микроконтроллерами с компьютера, программирование микроконтроллеров, передача данных из микроконтроллеров на компьютер, визуализация данных и параметров работы как микроконтроллеров, так и компьютеров и т. д. и т. п. — применений этой технологии не счесть.
Вообще, связать микроконтроллер под управлением Wiring и компьютерную программу под управлением Processing можно множеством способов, среди них:
- по Serial
- при помощи специализированного протокола Firmata
- по Ethernet сети
- различными беспроводными способами
- и т. д.
В этой статье мы рассмотрим и подробно разберём самый простой «нативный» способ связи между скетчем на Processing и Arduino микроконтроллером. А в процессе изучения реализации такой связи вы сможете потренироваться в освоении программирования как контроллеров Ардуино, так программирования на Processing.
Управление «Processing to Arduino»
Сначала мы рассмотрим вариант управления Ардуино-контроллером из скетча на Processing. Этот вариант может понадобиться вам для управления (по последовательному интерфейсу) контроллером с вашего компьютера.
Поскольку взаимодействие происходит между двумя системами, то мы приведём здесь два скетча, которые должны будут работать одновременно — один на контроллере, другой — на компьютере. В качестве Ардуино контроллера мы будем использовать Arduino Nano.
Примечание: здесь предполагается, что вы достаточно опытный пользователь и умеете создавать скетчи и загружать их в Ардуино микроконтроллер.
Первый скетч для Ардуино контроллера:
/* Serial Processing to Arduino */ #define LED_PIN 13 void setup() { Serial.begin(115200); pinMode(LED_PIN, OUTPUT); } void loop() { if (Serial.available() > 0) { int i = Serial.read(); if (i == 'H') {digitalWrite(LED_PIN, HIGH);} else if (i == 'L') {digitalWrite(LED_PIN, LOW);} } }
Здесь мы определяем пин к которому присоединён светодиод (на плате Arduino Nano).
#define LED_PIN 13
Затем запускаем работу Serial интерфейса на скорости 115200.
Serial.begin(115200);
И переключаем пин светодиода на «выход».
pinMode(LED_PIN, OUTPUT);
Далее следует цикл loop().
void loop() { if (Serial.available() > 0) { int i = Serial.read(); if (i == 'H') {digitalWrite(LED_PIN, HIGH);} else if (i == 'L') {digitalWrite(LED_PIN, LOW);} } }
В котором мы «ловим» приходящие данные по Serial интерфейсу (от нашего компьютера и скетча на Processing) и присваиваем их переменной i.
if (Serial.available() > 0) { int i = Serial.read();
А далее просто включаем или выключаем светодиод в зависимости от приходящих байтов (символов).
if (i == 'H') {digitalWrite(LED_PIN, HIGH);} else if (i == 'L') {digitalWrite(LED_PIN, LOW);}
Теперь рассмотрим «ответный» скетч на Processing:
/* Serial Processing to Arduino */ import processing.serial.*; int boxX; int boxY; int boxSize = 20; Serial port; void setup() { port = new Serial(this, "COM41", 115200); size(200, 200); boxX = width / 2; boxY = height / 2; rectMode(RADIUS); } void draw() { background(0); if (mouseX > boxX - boxSize && mouseX < boxX + boxSize && mouseY > boxY - boxSize && mouseY < boxY + boxSize) { fill(220, 0, 0); port.write('H'); } else { fill(127); port.write('L'); } rect(boxX, boxY, boxSize, boxSize); }
Здесь мы вначале подключаем соответствующую библиотеку.
import processing.serial.*;
Затем определяем параметры графического элемента.
int boxX; int boxY; int boxSize = 20;
Определяем объект.
Serial port;
И затем создаём его. Обратите внимание: вместо "COM41" вы должны указать номер COM порта, к которому у вас подключён микроконтроллер Arduino.
port = new Serial(this, "COM41", 115200);
Далее задаём размер графического окна на котором будем выводить графику, в данном случае это окно размером 200 на 200 пикселей.
size(200, 200);
Определяем центр графического окна.
boxX = width / 2; boxY = height / 2;
И переключаем режим рисования прямоугольников в состояние, когда первые два значения определяют центр прямоугольника, а вторые — половинные значения по горизонтали и вертикали и откладываемые от центральной точки.
rectMode(RADIUS);
Затем в циклической функции draw() рисуем серый или красный квадрат в зависимости от положения указателя мыши и посылаем соответствующие управляющие символы в Serial порт (на контроллер Ардуино).
void draw() { background(0); if (mouseX > boxX - boxSize && mouseX < boxX + boxSize && mouseY > boxY - boxSize && mouseY < boxY + boxSize) { fill(220, 0, 0); port.write('H'); } else { fill(127); port.write('L'); } rect(boxX, boxY, boxSize, boxSize); }
Подробнее: очищаем графическое окно.
background(0);
Определяем положение указателя мыши (над квадратом или нет).
if (mouseX > boxX - boxSize && mouseX < boxX + boxSize && mouseY > boxY - boxSize && mouseY < boxY + boxSize) {
Определяем цвет и посылаем управляющие символы.
fill(220, 0, 0); port.write('H'); } else { fill(127); port.write('L'); }
Рисуем квадрат.
rect(boxX, boxY, boxSize, boxSize);
В результате когда указатель мыши находится не над квадратом, квадрат выводится серым цветом, на контроллер отправляется символ «L» и на контроллере не горит светодиод.
Как только курсор мыши появляется над квадратом, квадрат становится красным, на контроллер посылается символ «H» и на нём загорается встроенный светодиод.
Таким образом при помощи движения мыши мы можем управлять включением и выключением светодиода на контроллере Ардуино. Понятно, что это только пример управления контроллером с компьютера при помощи скетча на Processing — по этому принципу вы можете создать любые другие варианты управления контроллеров в соответствии с вашими задачами и содержанием вашего проекта.
Управление «Arduino to Processing»
Теперь рассмотрим противоположный вариант — управление (или передачу данных) компьютером (скетчем на Processing) с Ардуино контроллера. Это тоже очень востребованный паттерн работы системы, которому можно найти множество практических применений.
Итак, скетч для Ардуино контроллера, реализующий свою часть работы системы:
/* Serial Arduino to Processing */ #define ANALOG_PIN A0 void setup() { Serial.begin(115200); } void loop() { int i = analogRead(ANALOG_PIN); i = map(i, 0, 1023, 0, 255); Serial.println(i); delay(1000); Serial.println(0); delay(1000); }
Здесь мы определяем аналоговый пин, с которого будем получать данные.
#define ANALOG_PIN A0
В цикле получаем данные и преобразуем их.
int i = analogRead(ANALOG_PIN); i = map(i, 0, 1023, 0, 255);
Отправляем их на компьютер и делаем задержку в 1 секунду.
Serial.println(i); delay(1000);
Далее посылаем нулевое значение и снова делаем задержку.
Serial.println(0); delay(1000);
В общем, наш скетч делает одну простую вещь — раз в секунду посылает либо данные с аналогового порта A0, либо нулевое значение в Serial.
Теперь «ответный» скетч на Processing:
/* Serial Arduino to Processing */ import processing.serial.*; Serial port; float bright = 0; void setup() { size(300, 300); port = new Serial(this, "COM41", 115200); port.bufferUntil('\n'); } void draw(){ background(bright); } void serialEvent(Serial port) { bright = float(port.readStringUntil('\n')); }
Здесь: создаём переменную для хранения значения яркости и присваиваем ей нулевое значение:
float bright = 0;
Проводим стандартные операции, описанные выше.
size(300, 300); port = new Serial(this, "COM41", 115200);
Очищаем буфер последовательного порта.
port.bufferUntil('\n');
И далее в цикле устанавливаем яркость фона графического окна.
void draw(){ background(bright); }
Всю работу по получению данных от микроконтроллера Ардуино выполняет функция serialEvent(), которая автоматически вызывается всякий раз, когда появляются новые данные в порту.
void serialEvent(Serial port) { bright = float(port.readStringUntil('\n')); }
Таким образом, наш контроллер на Ардуино передаёт управляющие байты (взятые им из аналогового порта), а скетч на Processing использует эти значения для установки яркости фона графического окна (серый):
А затем предаёт нулевой байт и скетч на Processing соответствующим образом меняет цвет фона графического окна (чёрный):
Это тоже только пример управления (передачи данных) компьютером с контроллера и используя этот принцип, вы можете создать любые другие варианты работы системы в соответствии с вашими задачами.
Заключение
В этой статье мы рассмотрели варианты управления «Processing to Arduino» и «Arduino to Processing» и используя их или их сочетание вы сможете добавить новый и очень интересный функционал в ваши проекты.
Ссылки по теме
Система программирования Processing
Processing и Ардуино. Работа по Serial
Сетевые возможности Processing
Работа Processing в браузере и на сайте
Веб-сервер на Processing. Часть 1 — Код сервера
Веб-сервер на Processing. Часть 2 — Файлы и код на HTML и CSS