Собираем на Arduino автоматическое поворотное устройство дисплея компьютера
Узнайте, как создать устройство, которое определяет, когда компьютерный монитор физически повернут, и автоматически сообщает компьютеру повернуть дисплей соответствующим образом.
В настоящее время большое количество цифрового контента является узким и высоким (портретная ориентация), но большинство компьютерных мониторов являются широкими и низкими (ландшафтная ориентация). Это означает, что много места на мониторе теряется впустую. Сравните два скриншота ниже. В ландшафтном представлении видны только полтора поста, а в портретном – 3.
По этой причине при просмотре социальных сетей может быть полезен поворот монитора на 90°, однако переключение настроек дисплея назад и вперед может быть слишком утомительно. Особенно это актуально, если у вас несколько мониторов или компьютер, на котором не работают стандартные сочетания горячих клавиш. Сегодня я собираюсь показать, как создать устройство, которое будет автоматически говорить компьютеру, повернуть дисплей, когда монитор физически повернут.
Принцип действия
Устройство будет собрано на Arduino и установлено на задней панели монитора. Для определения направления мы будем использовать акселерометр. В стационарном режиме акселерометр интерпретирует гравитацию как ускорение вверх, равное 9,8 м/с2. Акселерометр будет взаимодействовать с Arduino через интерфейс I2C. Arduino будет постоянно следить (опрашивать), в каком направлении акселерометр думает, что он ускоряется. При изменении Arduino через USB отправит сигнал на компьютер. Скрипт на python, запущенный на компьютере, прочитает это изменение и сообщит компьютеру о необходимости повернуть дисплей в соответствующем направлении.
В данной статье объясняется, как реализовать это на Windows и Linux. Вероятно это можно сделать и на Mac. Однако, поскольку у меня нет Mac, я не могу попробовать. Единственное отличие – это системная команда, вызываемая скриптом Python.
Комплектующие
Вам понадобятся:
- Arduino – мы использовали Uno, но вы можете любой тип Arduino, какой захотите;
- плата расширения Arduino для прототипирования – подойдет любая;
- акселерометр MMA7455;
- разъемы;
- кнопка;
- резистор 100 кОм;
- несколько проводов;
- припой и паяльник.
Конечно, вам также понадобится монитор, который может вращаться. Если у вас есть не вращающийся монитор, проверьте, имеются ли на нем монтажные отверстия VESA (4 или 8 отверстий в квадрате(ах) на задней панели).
Сборка
Берите паяльник, и начнем!
Если у вас есть опыт в электронике, то некоторые названия контактов на акселерометре должны быть вам знакомы. VCC и GND будут подключены к шинам питания Arduino. CS означает «выбор микросхемы». Поскольку у нас в этом проекте только одно ведомое устройство на шине I2C, мы физически подключим этот вывод к шине 5V. SDA и SCL – это линии связи на шине I2C. Если вы используете не Arduino Uno, то выводы для SDA и SCL могут отличаться.
Вывод акселерометра | Вывод Arduino Uno |
---|---|
VCC | 5V |
GND | GND |
CS | 5V |
SDA | 4 |
SCL | 5 |
Код Arduino
Если у вас нет опыта работы с платами Arduino, ознакомьтесь с нашей вводной статьей об Arduino для начинающих.
Подключите Arduino с помощью USB кабеля к компьютеру.
Как упоминалось ранее, мы можем использовать акселерометр для определения направления, измеряя, какое направление считывает ускорение 9,8 м/с2. Поскольку монитор всегда будет либо в вертикальном, либо в горизонтальном положении, это будет легко (если бы нам было нужно учитывать диагональные ориентации, было бы сложнее).
При программировании хорошей практикой считается разделение кода по различным аспектам на разные файлы. Для определения ориентации мы написали библиотеку на базе официальной библиотеки MMA7455. Это позволяет нам абстрагироваться от деталей того, как это делается, и поэтому наш основной файл может оставаться простым, в нем будет проверяться ориентация вызовом только одной функции и при изменениях отправляться сообщение на компьютер.
Скачайте и распакуйте следующий архив:
Откройте monitor.ino в Arduino IDE. Скомпилируйте и запустите код (все 3 файла для Arduino должны быть в одном каталоге). Откройте монитор последовательного порта Инструменты (Tools) > Монитор порта (Serial Monitor) или с помощью Ctrl + Shift + M.
Вы должны будете увидеть что-то похожее:
Freescale MMA7455 accelerometer
May 2012
The MMA7455 is okay
STATUS : 0
WHOAMI : 55
Assuming the device is Y_POS
Теперь возьмите Arduino так, чтобы она находилась параллельно вертикальной плоскости. Повращайте её (тоже в вертикальной плоскости). Каждый раз при повороте на 90° вы должны видеть что-то похожее:
Rotate Monitor
change detected
Rotate Monitor
change detected
Rotate Monitor
change detected
Rotate Monitor
Установите устройство на заднюю панель монетора и подключите его к компьютеру с помощью USB кабеля. Для установки вы можете использовать любой способ. Я использовал пластиковые стойки и двухсторонний скотч.
Нам нужно откалибровать акселерометр, чтобы он знал, в каком направлении он указывает при включении. Эта инициализация будет выполняться при каждом включении Arduino. При использовании на мониторе это может быть всякий раз, когда вы включаете компьютер (зависит от того, остается ли питание на USB портах, когда компьютер выключен). Поэтому, когда вы включаете компьютер, это устройство ожидает, что ваш монитор будет находиться в том положении, которое вы определили как положение по умолчанию. Если это не так, Arduino сообщит компьютеру, что дисплей повернут неправильно, или она будет дезориентирована и не будет говорить компьютеру о вращении вовсе.
Вот почему мы добавили кнопку. Когда кнопка нажата, Arduino повторно запускает процедуру настройки и сообщает компьютеру, чтобы он повернул дисплей в положение START_ORIENTATION
.
Когда вы устанавливаете устройство на заднюю панель монитора, обратите внимание на то, какое направление является верхом, когда ваш монитор находится в положении по умолчанию (в том, при котором, вероятно, он будет находиться при включении компьютера).
В monitor.ino есть строка кода, которую нужно соответствующим образом изменить. Если стрелка y на акселерометре указывает вверх, то оставьте в строке Y_POS
. Если стрелка указывает вниз, измените строку на Y_NEG
. Аналогично и с осью x, используйте X_POS
и X_NEG
.
#define START_ORIENTATION Y_POS
Если вы хотите понять, как работает код, то продолжайте чтение. Если вам необходим просто работающий продукт, то можно перейти к разделу «Код со стороны компьютера».
Пояснения к коду
Понимание деталей интерфейса I2C для этого проекта необязательно. Но если вы хотите узнать о нем больше, то посмотрите нашу статью «Шина I2C. Основные понятия».
Посмотрим на MMA7455.h.
typedef enum {Y_POS, Y_NEG, X_POS, X_NEG, Z_POS, Z_NEG, NOT_SURE} orientation;
Перечисление enum
в C представляет собой тип данных, как int
или char
. Оно используется для переменных, которые точно могут быть одним из значений из короткого списка нечисловых переменных. В данном случае мы используем enum
для сохранения ориентации устройства в переменной.
Посмотрите на акселерометр. Вы увидите на нем стрелки x и y. Когда стрелка x указывает на верх, то мы должны указать X_POS
. Когда стрелка x указывает вниз, мы должны указать X_NEG
. Ось z указывает на плату. Когда плата лежит на столе в горизонтальном положение, это состояние обозначается Z_POS
.
При установке на заднюю панель монитора устройство должно всегда по x-оси или по y-оси быть направлено вверх или вниз. В monitor.ino мы создали макрос под названием VALID_ORIENTATION
для проверки, соответствует заданная ориентация одному из 4 возможных вариантов. Как вы можете видеть, можем проверить значение перечисления, как и значения любого другого типа данных.
#define VALID_ORIENTATION(o) ((o==Y_POS) || (o==Y_NEG) || (o==X_POS) || (o==X_NEG))
В функции setup()
в основном диагностика. В ней три важных строки:
Serial.begin(9600);
Строка выше инициализирует связь по последовательному порту, через который мы будем взаимодействовать с компьютером.
Wire.begin();
Инициализирует связь по шине I2C, через которую мы будем взаимодействовать с акселерометром. Она инициализирует настройки только на стороне Arduino. Акселерометр мы инициализируем с помощью следующей строки:
error = MMA7455_init(START_ORIENTATION);
Когда вы нажимаете кнопку, ее контакты не замыкаются идеально. Они «дребезжат», и сигнал выглядит так, как если бы пользователь в течение нескольких миллисекунд нажал кнопку несколько раз. Мы ждем 100 мс, чтобы убедиться, что наш код не интерпретирует этот дребезг как последовательность нажатий. Существует два подхода борьбы с дребезгом контактов. Мы можем реализовать либо аппаратное, либо программное подавление дребезга контактов. Аппаратный метод включает в себя добавление в схему фильтра нижних частот, либо активного, либо пассивного. Поскольку это связано с покупкой и пайкой дополнительных компонентов, вместо него я выбрал программное подавление дребезга.
Используемый нами акселерометр имеет некоторые функции прерываний, но в нашем случае они неприменимы. Вот почему мы прибегли к опросу (прерывания предпочтительны с точки зрения производительности). Как правило, при работе с кнопками рекомендуется использовать прерывания. Однако, поскольку мы уже опрашиваем акселерометр, то можем заодно опросить и кнопку.
Каждый раз в цикле мы проверяем, нажата ли кнопка в данный момент. Если это так, и она была не нажата в предыдущий раз, то мы знаем, что поьзователь нажал ее только что, и поэтому мы запускаем функцию setup()
снова и отправляем START_ORIENTATION
на компьютер. Затем, прежде чем продолжить, мы ждем 100 мс. Эта задержка нужна, чтобы перед продолжением работы Arduino дождалась, чтобы контакты установили конечное состояние. По общему признанию, это довольно небрежный и ленивый подход к программному подавлению дребезга контактов, потому что Arduino ничего не делает во время задержки. Более сложный подход будет включать в себя таймеры, чтобы, пока Arduino ждет установления состояния контактов, мог выполняться другой код. В этом конкретном случае единственное, что мы упускаем, используя задержку вместо таймера, – это изменение показаний акселерометра. Поскольку, когда пользователь нажимает кнопку, этого происходить не должно, то этот неаккуратный метод можно считать приемлемым. Единственное преимущество метода задержки – это простота. Аппаратное подавление дребезга контактов требует дополнительных компонентов, а написание кода для прерываний и задержек может оказаться сложным.
}else if(!digitalRead(BUTTON_PIN) // кнопка была нажата
&& previous_button_state) // и это первый раз, когда она нажата
{
// послать, даже если ориентация на была изменена
setup(); // перекалибровать
sendOrientation(START_ORIENTATION);
delay(100); //программное подавление дребезга контактов
previous_button_state = 0;
}
Код со стороны компьютера
Arduino отправит информацию на компьютер, используя тот же последовательный интерфейс, который мы используем для ее программирования и отладки. Чтобы избежать конфликтов, убедитесь, что монитор последовательного порта в Arduino IDE закрыт, когда запущен скрипт. Если он открыт, некоторые сообщения от Arduino будут захвачены монитором последовательного порта, и скрипт их не увидит или увидит только их часть.
На стороне компьютера мы будем использовать код на Python. Он будет слушать то, что Arduino пишет в последовательный интерфейс, и выполнять системный вызов для поворота дисплея.
Пользователи Linux могут пропустить следующий подраздел и перейти к подразделу «Linux».
Windows
Скачайте отсюда Python 3. На запрос о добавление python в path
во время установки, ответьте да.
Найдите файл windows-script.py в архиве, который вы скачали ранее.
Откройте Arduino IDE. Кликните Инструменты (Tools) > Монитор порта (Serial Monitor). Посмотрите, какие перечислены порты, например, COM3.
Если номер порта, который вы видите, не COM3, то откройте в текстовом редакторе windows-script.py. Найдите следующую строку и измените порт на тот, что вы видели:
possibleDevices = ["COM3"]
Найдите следующие строки. Вам необходимо изменить эти числа на те, что соответствуют вашей сборке. Числа – это повороты по часовой стрелке в градусах для каждого возможного положения монитора.
translation = {"Y_POS":"90",
"X_POS":"180",
"X_NEG":"0",
"Y_NEG":"270"}
Теперь нам необходимо установить модуль pySerial, который используется для чтения USB порта. Откройте командную строку. На Windows 8 и позднее найдите cmd. На Windows 7 и ранее найдите утилиту поиска в меню пуска и введите cmd.
В появившемся терминале введите следующее:
python -m pip install pyserial
Установка модуле python может быть сложной. Пока не установите модуль, дальше можно не продолжать.
Прежде чем запускать скрипт, нам необходимо сделать еще одну вещь. Найдите утилиту display в каталоге Windows в zip-архиве, который в скачали ранее (она была взята с этого сайта).
Если у вас несколько мониторов, то сделайте следующее (если у вас только один монитор, то пропустите этот параграф). Откройте командную строку там, где сохранили display.exe (откройте проводник в этом месте, затем выполните Shift + правый клик на фоне проводника, и выберите "Открыть окно команд"). Введите в консоли display.exe /listdevices
. Вы должны будете увидеть индекс каждого вашего монитора. Обратите внимание на индекс монитора, который хотите вращать.
Python скрипт откроет соединение с USB портом. Когда он обнаружит сообщение от Arduino, он пошлет соответствующую команду утилите display.exe, которая и повернет дисплей. Найдите следующую строку и укажите каталог, в котором находится display.exe:
command = "C:/.../display.exe /rotate:" + translation[direction]
Пользователям с несколькими мониторами необходимо добавить еще /device x
(где x – индекс вашего монитора). Получится что-то похожее:
command = "C:/.../display.exe /device 2 /rotate:" + translation[direction]
В командной строке перейдите к каталогу, в котором сохранили display.exe и windows-script.py. Это можно сделать с помощью команды cd
. Например, если они сохранены в Documents/rotate, используйте:
cd Documents/rotate
Теперь наберите dir
, чтобы увидеть список файлов в каталоге. Дважды проверьте, что в нем есть оба файла. Теперь давайте запустим python-скрипт.
python windows-script.py
Попробуйте повращать устройство. Дисплей должен поворачиваться в соответствующем направлении.
Теперь нам необходимо, чтобы Windows запускала эту программу в фоновом режиме при включении компьютера. По умолчанию программы из автозапуска запускаются видимыми. Но мы не хотим постоянно видеть окно командной строки. Поэтому мы создадим batch файл, который будет запускать python скрипт в фоновом режиме, а затем выполнение этого batch файла будет завершаться.
Сначала откройте каталог автозагрузки. Расположение этой папки зависит от используемой версии Windows. Нажмите клавишу Windows, а затем R. Должно появиться окно запуска. Наберите shell:startup
и нажмите Enter. Теперь вы должны увидеть каталог автозагрузки. Создайте там новый текстовый файл monitor.bat и вставьте в него следующий код. Измените путь так, чтобы он указывал на python скрипт.
@echo off
START pythonw C:\...\windows-script.py
Мы используем pythonw вместо python, потому что это обязательно для скрытия окна командной строки python скрипта.
Теперь перезагрузите компьютер и проверьте, что всё работает. Если всё хорошо, то можно перейти к концу статьи.
Linux
Скачайте Python 3 отсюда. Вы можете также сделать это с помощью менеджера пакетов. На вопрос, хотите ли вы добавить python в path, во время установки ответьте да.
Установите модуль pySerial.
python3 -m pip install pyserial
Установка модуле python может быть сложной. Пока не установите модуль, дальше можно не продолжать.
Откройте Arduino IDE. Кликните Инструменты (Tools) > Монитор порта (Serial Monitor). Посмотрите, какие перечислены порты, например, /dev/ttyACM1
.
Найдите файл linux-script.py в архиве, который вы скачали ранее. Откройте linux-script.py в текстовом редакторе. Найдите следующую строку и, если необходимо, измените ее, чтобы добавить ваш порт.
possibleDevices = ["/dev/ttyACM0", "/dev/ttyACM1", "/dev/ttyACM2"]
Команда, которую нам необходимо выполнить, зависит от вашей конкретной комплектации. Откройте терминал (Ctrl + Alt + T) и введите xrandr
. Вы должны увидеть дисплей (или несколько), например, как eDP1 или HDMI1. Обратите внимание на это имя. Поэкспериментируйте со следующими командами, чтобы увидеть, будет ли вращаться дисплей.
Для одного монитора с именем HDMI1:
xrandr --output HDMI1 --rotate left &
Чтобы вернуть дисплей назад:
xrandr --output HDMI1 --rotate left &
Для двух мониторов, eDP1 (невращающийся, справа) и HDMI1 (слева) попробуйте:
xrandr --output HDMI1 --rotate left --primary --output eDP1 --auto --right-of HDMI1 &
Чтобы вернуть назад:
xrandr --output HDMI1 --rotate normal --primary --output eDP1 --auto --right-of HDMI1 &
Обратите внимание, какая команда работает с вашей комплектацией. Измените строку command = "xrandr --output ...
в вашем скрипте соответствующим образом, где normal
или left
заменены на " + translation[direction] + "
(включая двойные кавычки).
Теперь запустите скрипт с помощью:
python3 script.py
Попробуйте повращать устройство. Экран должен вращаться в соответствующих направлениях.
Если экран вращается, но вращение не правильное, измените следующую строку в python скрипте нужным образом:
translation = {"Y_POS":"normal",
"X_POS":"right",
"X_NEG":"left",
"Y_NEG":"inverted"}
Всё, что осталось, это, чтобы скрипт при загрузке запускался автоматически. Подробности зависят от вашего дистрибутива. Попробуйте поискать автозагрузку в стартовом меню. В противном случае, вы можете добавить для этого задание cron.
Всё готово!
Теперь присаживайтесь и наслаждайтесь более эффективным использованием места на вашем мониторе.