Virtual Color Mixer: управление цветом через аналоговые датчики
Урок о том, как передавать несколько значений с Arduino на компьютер и управлять цветом фона в Processing или Max/MSP.
В этом уроке разберём, как отправлять сразу несколько значений с Arduino на компьютер по последовательному порту. Показания трёх аналоговых датчиков задают красную, зелёную и синюю составляющие цвета фона — в скетче Processing или в патче Max/MSP. Получается настоящий виртуальный смеситель цветов, управляемый руками.
Необходимое железо
- 3 аналоговых датчика (потенциометр, фоторезистор, датчик силы FSR и т. п.)
- 3 резистора 10 кОм
- соединительные провода
- макетная плата
Необходимое программное обеспечение
- Processing или
Схема подключения
Подключите аналоговые датчики к аналоговым входам A0, A1 и A2.
В схеме используются три делителя напряжения voltage divider: два резистора включаются последовательно, и напряжение распределяется между ними пропорционально их сопротивлениям. Датчик силы (FSR) меняет своё сопротивление под нагрузкой, а резистор 10 кОм задаёт опорное плечо делителя — именно поэтому analogRead() возвращает разные значения при разном давлении на датчик.

Схема подключения трёх датчиков силы (FSR) к аналоговым входам Arduino UNO через макетную плату
Принципиальная схема

Принципиальная схема: датчики силы и резисторы 10 кОм (чувствительные резисторы) подключены к входам A0–A2 Arduino UNO
Как это работает
Arduino считывает три аналоговых значения (от 0 до 1023) и отправляет их в одной строке через Serial, разделяя запятыми. Принимающая сторона — Processing или Max/MSP — парсит эту строку и применяет числа как компоненты RGB-цвета.
Ключевой момент: данные передаются в формате ASCII-encoded decimal numbers, то есть каждая цифра числа кодируется отдельным ASCII-символом. Например, значение 234 занимает три байта: '2' (50), '3' (51), '4' (52). Строка завершается символами возврата каретки (\r) и перевода строки (\n), что позволяет принимающей программе понять, где заканчивается одна порция данных.
Код Arduino
/*
Этот пример считывает три аналоговых датчика (проще всего использовать потенциометры) и
передаёт их значения по последовательному порту. Программы Processing и Max/MSP, приведённые
ниже, принимают эти три значения и используют их для изменения цвета фона экрана.
Схема:
- потенциометры подключены к аналоговым входам 0, 1 и 2
создан 2 декабря 2006 г.
автор David A. Mellis
изменён 30 августа 2011 г.
авторы Tom Igoe и Scott Fitzgerald
Код примера находится в открытом доступе (public domain).
https://www.arduino.cc/en/Tutorial/VirtualColorMixer
*/
const int redPin = A0; // датчик управления красным цветом
const int greenPin = A1; // датчик управления зелёным цветом
const int bluePin = A2; // датчик управления синим цветом
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print(analogRead(redPin));
Serial.print(",");
Serial.print(analogRead(greenPin));
Serial.print(",");
Serial.println(analogRead(bluePin));
}
/* Код Processing для этого примера
// Код примера находится в открытом доступе (public domain).
import processing.serial.*;
float redValue = 0; // значение красного
float greenValue = 0; // значение зелёного
float blueValue = 0; // значение синего
Serial myPort;
void setup() {
size(200, 200);
// Вывести список всех доступных последовательных портов
// в Processing 2.1 и выше используйте Serial.printArray()
println(Serial.list());
// На моём Mac первый порт в списке всегда соответствует Arduino,
// поэтому открываю Serial.list()[0].
// Откройте тот порт, который используете вы.
myPort = new Serial(this, Serial.list()[0], 9600);
// не генерировать serialEvent(), пока не получен символ новой строки:
myPort.bufferUntil('\n');
}
void draw() {
// установить цвет фона по значениям цветовых компонент:
background(redValue, greenValue, blueValue);
}
void serialEvent(Serial myPort) {
// получить строку ASCII:
String inString = myPort.readStringUntil('\n');
if (inString != null) {
// убрать пробельные символы по краям:
inString = trim(inString);
// разбить строку по запятым и преобразовать полученные подстроки
// в массив чисел с плавающей точкой:
float[] colors = float(split(inString, ","));
// если массив содержит не менее трёх элементов, данные получены полностью.
// Записать числа в переменные цвета:
if (colors.length >= 3) {
// привести к диапазону 0–255:
redValue = map(colors[0], 0, 1023, 0, 255);
greenValue = map(colors[1], 0, 1023, 0, 255);
blueValue = map(colors[2], 0, 1023, 0, 255);
}
}
}
*/
/* Патч Max/MSP для этого примера
----------begin_max5_patcher----------
1512.3oc4Z00aaaCE8YmeED9ktB35xOjrj1aAsXX4g8xZQeYoXfVh1gqRjdT
TsIsn+2K+PJUovVVJ1VMdCAvxThV7bO7b48dIyWtXxzkxaYkSA+J3u.Sl7kK
lLwcK6MlT2dxzB5so4zRW2lJXeRt7elNy+HM6Vs61uDDzbOYkNmo02sg4euS
4BSede8S2P0o2vEq+aEKU66PPP7b3LPHDauPvyCmAvv4v6+M7L2XXF2WfCaF
lURgVPKbCxzKUbZdySDUEbgABN.ia08R9mccGYGn66qGutNir27qWbg8iY+7
HDRx.Hjf+OPHCQgPdpQHoxhBlwB+QF4cbkthlCRk4REnfeKScs3ZwaugWBbj
.PS+.qDPAkZkgPlY5oPS4By2A5aTLFv9pounjsgpnZVF3x27pqtBrRpJnZaa
C3WxTkfUJYA.BzR.BhIy.ehquw7dSoJCsrlATLckR.nhLPNWvVwL+Vp1LHL.
SjMG.tRaG7OxT5R2c8Hx9B8.wLCxVaGI6qnpj45Ug84kL+6YIM8CqUxJyycF
7bqsBRULGvwfWyRMyovElat7NvqoejaLm4f+fkmyKuVTHy3q3ldhB.WtQY6Z
x0BSOeSpTqA+FW+Yy3SyybH3sFy8p0RVCmaMpTyX6HdDZ2JsPbfSogbBMueH
JLd6RMBdfRMzPjZvimuWIK2XgFA.ZmtfKoh0Sm88qc6OF4bDQ3P6kEtF6xej
.OkjD4H5OllyS+.3FlhY0so4xRlWqyrXErQpt+2rsnXgQNZHZgmMVzEofW7T
S4zORQtgIdDbRHrObRzSMNofUVZVcbKbhQZrSOo934TqRHIN2ncr7BF8TKR1
tHDqL.PejLRRPKMR.pKFAkbtDa+UOvsYsIFH0DYsTCjqZ66T1CmGeDILLpSm
myk0SdkOKh5LUr4GbWwRYdW7fm.BvDmzHnSdH3biGpSbxxDNJoGDAD1ChH7L
I0DaloOTBLvkO7zPs5HJnKNoGAXbol5eytUhfyiSfnjE1uAq+Fp0a+wygGwR
q3ZI8.psJpkpJnyPzwmXBj7Sh.+bNvVZxlcKAm0OYHIxcIjzEKdRChgO5UMf
LkMPNN0MfiS7Ev6TYQct.F5IWcCZ4504rGsiVswGWWSYyma01QcZgmL+f+sf
oU18Hn6o6dXkMkFF14TL9rIAWE+6wvGV.p.TPqz3HK5L+VxYxl4UmBKEjr.B
6zinuKI3C+D2Y7azIM6N7QL6t+jQyZxymK1ToAKqVsxjlGyjz2c1kTK3180h
kJEYkacWpv6lyp2VJTjWK47wHA6fyBOWxH9pUf6jUtZkLpNKW.9EeUBH3ymY
XSQlaqGrkQMGzp20adYSmIOGjIABo1xZyAWJtCX9tg6+HMuhMCPyx76ao+Us
UxmzUE79H8d2ZB1m1ztbnOa1mGeAq0awyK8a9UqBUc6pZolpzurTK232e5gp
aInVw8QIIcpaiNSJfY4Z+92Cs+Mc+mgg2cEsvGlLY6V+1kMuioxnB5VM+fsY
9vSu4WI1PMBGXye6KXvNuzmZTh7U9h5j6vvASdngPdgOFxycNL6ia1axUMmT
JIzebXcQCn3SKMf+4QCMmOZung+6xBCPLfwO8ngcEI52YJ1y7mx3CN9xKUYU
bg7Y1yXjlKW6SrZnguQdsSfOSSDItqv2jwJFjavc1vO7OigyBr2+gDYorRk1
HXZpVFfu2FxXkZtfp4RQqNkX5y2sya3YYL2iavWAOaizH+pw.Ibg8f1I9h3Z
2B79sNeOHvBOtfEalWsvyu0KMf015.AaROvZ7vv5AhnndfHLbTgjcCK1KlHv
gOk5B26OqrXjcJ005.QqCHn8fVTxnxfj93SfQiJlv8YV0VT9fVUwOOhSV3uD
eeqCUClbBPa.j3vWDoMZssNTzRNEnE6gYPXazZaMF921syaLWyAeBXvCESA8
ASi6Zyw8.RQi65J8ZsNx3ho93OhGWENtWpowepae4YhCFeLErOLENtXJrOSc
iadi39rf4hwc8xdhHz3gn3dBI7iDRlFe8huAfIZhq
-----------end_max5_patcher-----------
*/
Практические замечания
- Выбор датчиков. Потенциометр — самый предсказуемый вариант: диапазон хорошо растянут, нет дребезга. Фоторезистор и FSR зависят от условий окружения, поэтому результирующий цвет будет «живым» и непредсказуемым — что само по себе интересно.
- Стабильность показаний. Если значения скачут, добавьте простое скользящее среднее или используйте
constrain()иmap()для нормировки. - Скорость обмена. В скетче используется
9600бод. Убедитесь, что в Processing или Max/MSP выставлена та же скорость — иначе вместо цифр получите мусор. - Порт COM. В Processing нужно указать правильный номер порта. Запустите
Serial.list()в Processing, чтобы увидеть доступные порты, и выберите тот, к которому подключена Arduino.
Код Processing
Скопируйте скетч Processing из примера выше. По мере изменения положения датчиков фон окна будет плавно менять цвет:

Код Max/MSP
Патч выглядит следующим образом. Скопируйте его текст из примера выше и вставьте в новое окно Max:

Патч Max/MSP принимает строку с тремя числами (от 0 до 1023), разделёнными запятыми, преобразует их в целые числа и устанавливает цвет фона. Нажмите на элемент управления портом, чтобы открыть последовательный порт и запустить патч.
Типичные ошибки
- Ничего не происходит в Processing. Проверьте номер порта в коде Processing — он должен совпадать с тем, который использует Arduino IDE.
- Цвет «застрял» на одном значении. Убедитесь, что делитель напряжения собран правильно: один конец датчика на
5V, другой — через резистор 10 кОм наGND, а средняя точка — на аналоговый вход. - Значения не меняются при нажатии на FSR. Возможно, резистор и датчик перепутаны местами в делителе — поменяйте их местами и проверьте снова.
- Цвет мигает или дёргается. Добавьте небольшую задержку (
delay(10)) в конецloop(), чтобы не перегружать последовательный буфер.
Как проверить результат
Откройте Serial Monitor в Arduino IDE и убедитесь, что в каждой строке приходят три числа, разделённые запятыми, например: 512,0,1023. Если строки выглядят корректно — Arduino работает правильно, и можно переходить к запуску Processing или Max/MSP.
Дополнительные материалы
Больше базовых уроков можно найти в разделе built-in examples.
Также изучите language reference — подробный справочник по языку программирования Arduino.
Последнее обновление: 11.08.2015, SM