Самодельная система smell-o-vision
Пост состоит из 2 частей. Общая система управления для 5D кинотеатра и исполнительная часть smell-o-vision.
Для управления внешними устройствами используется программа MultiFunPlayer. Пока про нее не узнал планировал использовать писк в правом канале аудиодорожки. Для воспроизведения используется MultiFunPlayer версии 1.31.3 и MPC-BE версии 1.7.3. В настройках MPC-BE нужно включить дистанционное управление.
Для аудио/видеофайла должен быть составлен файл funscript. Аудио/видеофайл воспроизводится MPC-BE. MultiFunPlayer синхронизируется с MPC-BE и подхватывает funscript с темже именем файла и лежащий в тойже папке. MultiFunPlayer в нужный момент времени отправляет команды в COM порт.
Пример funscript.
{
"version": "1.0",
"inverted": false,
"range": 90,
"actions": [
{ "at": 0, "pos": 0 },
{ "at": 1000, "pos": 10 },
{ "at": 2000, "pos": 20 },
{ "at": 3000, "pos": 30 },
{ "at": 4000, "pos": 40 },
{ "at": 5000, "pos": 50 },
{ "at": 6000, "pos": 0 },
{ "at": 7000, "pos": 0 },
]
}
После "at": указывается таймкод в миллисекундах. После "pos": указывается значение от 0 до 100 которое будет отправлено внешнему устройству. Первая и последняя строка могут быть не выполнены. Если устройств несколько то для управления каждым используется свой файл funscript и к названию файла дописывается канал (еще не пробовал использовать). По умолчанию используется канал L0. Чтобы MultiFunPlayer не давал лишние команды нужно переключить интерполяцию в Step и отключить Auto-home.
MultiFunPlayer отправляет в COM порт команды на языке T-code. Я использую настройки COM порта типичные для устройств на Arduino: скорость 9600, формат данных 8N1.
Пример строки T-code:
L01000I100
L0 канал (L группа каналов, 0 номер канала в группе), 1000 значение(от 0000 до 9999), I100 время выполнения(не используется).
"pos": 0 соответствует L00000
"pos": 10 соответствует L01000
"pos": 20 соответствует L02000
"pos": 90 соответствует L09000
"pos": 100 соответствует L09999
Для упрощения прошивки Arduino я жду по UART букву L, R, V или A (группа каналов) и читаю следующие за ними 2 цифры (номер канала и 1 разряд значения). Так на каждый канал можно получить 10 дискретных значений.
"pos": 0 соответствует L00
"pos": 10 соответствует L01
"pos": 20 соответствует L02
"pos": 90 соответствует L09
Во время инициализации MultiFunPlayer и Arduino возможны ложные команды поэтому нужно предусмотреть выключатель блокирующий работу исполнительных устройств.
Исполнительная часть smell-o-vision.
Прошивка написана в ArduinoIDE 1.8.19 (последняя версия не требующая интернет для установки и работы). 3D модели делались в OpenSCAD
Состоит из 5 вентиляторов направленных в сторону зрителя. Используются осевые вентиляторы 80X25 12V. Провода + вентиляторов соединены вместе. Перед вентиляторами установлены картриджи.
Держатель картриджа
Код OpenSCAD
$fn=100;
difference()
{
union()
{
translate([-45,-45,0])
cube([90,90,4]);
}
union()
{
union()
{
translate([-71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([-71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
}
cylinder(d=78,h=4);
}
}
difference()
{
cylinder(d=87,h=20);
cylinder(d=83,h=20);
}
Средний соединитель вентиляторов
Код OpenSCAD
$fn=100;
difference()
{
union()
{
translate([-45,-75,0])
cube([110,150,4]);
}
union()
{
union()
{
translate([-71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([-71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
cylinder(d=78,h=4);
}
translate([0,-100,0])
union()
{
translate([-71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([-71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
cylinder(d=78,h=4);
}
translate([0,100,0])
union()
{
translate([-71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([-71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
cylinder(d=78,h=4);
}
translate([55,-57,0])
cylinder(d=4.5,h=4);
translate([55,57,0])
cylinder(d=4.5,h=4);
}
}
Крайние соединители вентиляторов
Код OpenSCAD
$fn=100;
difference()
{
union()
{
translate([-45,-25,0])
cube([90,50,4]);
}
union()
{
translate([0,-50,0])
union()
{
translate([-71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([-71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
cylinder(d=78,h=4);
}
translate([0,50,0])
union()
{
translate([-71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,-71.5/2,0])
cylinder(d=5.5,h=4);
translate([-71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
translate([71.5/2,71.5/2,0])
cylinder(d=5.5,h=4);
cylinder(d=78,h=4);
}
}
}
Картриджи сделаны из фильтров респиратора Исток. От фильтра оставлен только корпус и пластмассовые решетки. Внутри лежит ватный диск пропитанный ароматизатором. Картриджи нужно хранить в герметичных контейнерах. Экспериментально выяснено что в корпусе должно быть много свободного места и свободный проход воздуха.
Прошивка Arduino. Для управления вентиляторами использован релейный модуль с инверсными входами. HIGH выключение вентилятора, LOW включение вентилятора.
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT); //fan1
pinMode(12, OUTPUT); //fan2
pinMode(11, OUTPUT); //fan3
pinMode(10, OUTPUT); //fan4
pinMode(9, OUTPUT); //fan5
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
}
byte key=0;
byte group=0;
byte channel=4;
void loop()
{
if (Serial.available())
{
byte in = Serial.read();
if(in=='L')
{
key=1;
group=1;
}
if(key==1)
{
if(in=='0')
{
key=2;
channel=0;
}
}
else if(key==2)
{
key=3;
if(group==1&channel==0)
{
//smell-o-vision code
if(in=='0')
{
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
}
if(in=='1')
{
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
digitalWrite(13, LOW);
}
if(in=='2')
{
digitalWrite(13, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
digitalWrite(12, LOW);
}
if(in=='3')
{
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, HIGH);
digitalWrite(11, LOW);
}
if(in=='4')
{
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
}
if(in=='5')
{
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
digitalWrite(10, HIGH);
digitalWrite(9, LOW);
}
//smell-o-vision code end
}
}
}
}
Соответствие команд и вентиляторов
"pos": 0 выключает все вентиляторы
"pos": 10 включает вентилятор 1
"pos": 20 включает вентилятор 2
"pos": 30 включает вентилятор 3
"pos": 40 включает вентилятор 4
"pos": 50 включает вентилятор 5
Между включение вентилятора и тем как воздух дойдет до лица есть задержка. Решить эту проблему можно включая вентилятор заранее или расположив более компактный вариант исполнительного устройства ближе к лицу (работа над этим уже идет). Планирую сделать и другие устройства работающие синхронно с видео (имитатор климата, трясущееся кресло ...)
Если захотели повторить и код из поста не работает попробуйте его не скопировать а перепечатать.





























