Недавно мы использовали контроллер Xbox One для отправки команд на Arduino. Поскольку несколько человек спрашивали, как это делается, я решил написать об этом.

Код, который использовался в этом конкретном проекте, можно найти здесь для тех, кто просто хотел сразу перейти к исходному коду.

Это была довольно простая установка. На высоком уровне контроллер взаимодействует с ноутбуком (или любым другим компьютером) через Bluetooth, и ноутбук интерпретирует это в команды для отправки через последовательный порт на Arduino.

Подключить контроллер

Итак, во-первых, нам нужно подключить контроллер к компьютеру. Это довольно просто в Windows или OSX, поэтому я не буду вдаваться в подробности, просто подключите его через Bluetooth, как если бы вы использовали мышь или клавиатуру.

Для тех, кто работает в Ubuntu или других дистрибутивах Linux, сначала подключите его через Bluetooth, и вы можете заметить, что индикатор на вашем контроллере все еще мигает, и если вы следите за настройками Bluetooth, контроллер продолжает подключаться и отключаться. Чтобы решить эту проблему, сначала установите sysfsutils, если у вас его еще нет.

  • Установить sysfsutils
  • Добавьте эту строку /module/bluetooth/parameters/disable_ertm=1 в /etc/sysfs.conf (не забудьте сделать это как администратор, например, используйте sudo)
  • Перезагрузите компьютер

Теперь, когда вы снова подключите контроллер, он должен дать вам постоянный свет.

Серийный номер Ардуино

Нам нужно настроить Serial на Arduino. Существует множество руководств о том, как это работает, поэтому, пожалуйста, обратитесь к ним. Для целей этого упражнения мы будем использовать приведенный ниже код. Этот код получит значение для каждого цвета и запишет это значение в светодиоды.

Как вы можете видеть, в строке 27 мы ожидаем символ 0xFF, прежде чем мы даже подумаем об остальных элементах, которые отправляются через последовательный порт. Затем мы читаем следующие 3 байта после этого значения и устанавливаем их как значения светодиода. Поэтому, когда мы настраиваем наш серийный код на ноутбуке, нам нужно убедиться, что мы отправляем одни и те же элементы.

Чтение ввода контроллера

Как только контроллер подключен, нам нужно будет прочитать эти входы, чтобы мы могли использовать его для наших приложений. Для этого воспользуемся замечательной библиотекой геймпад. Вы можете следовать документации для получения входных данных, эта библиотека упрощает работу с входными данными контроллера.

Отправка серийного вывода

Для отправки серийного вывода нам понадобятся два пакета serialport и struct.

Используя struct, мы определяем структуру данных, которую будем отправлять. Как упоминалось выше, мы будем отправлять начальный байт 0xFF, а затем наши данные, которые в данном случае являются целыми числами со знаком. Итак, мы определяем его следующим образом:

const data = Struct()
    .word8Sle('start')
    .word8Sle('blue')
    .word8Sle('red')
    .word8Sle('green');
data.allocate();
const proxy = data.fields;
// Define default values
proxy.start = 0xFF;
proxy.blue = 0;
proxy.red = 0;
proxy.green = 0;

Как только мы определим структуру данных, мы можем открыть последовательный порт и отправить данные, которые мы хотим отправить.

const port = new SerialPort(
    '/dev/ttyACM0',
    { baudRate: 9600 }
);
const buffer = data.buffer();
port.write(buffer, function (err) {
    if (err) return console.log('Error on write: ', err.message);
    console.log('Data sent successfully');
});
  • /dev/ttyACM0необходимо заменить на используемый вами последовательный путь
  • Установите скорость передачи такой же, как и в коде Arduino

Вот и все, объединив их, вы можете использовать значения, которые вы получаете от контроллера, и передавать их в Arduino, используя последовательный порт.

Примечания

Следует отметить одну вещь: рекомендуется отправлять последовательные данные только через определенный интервал. Это позволяет приложению быть более предсказуемым, а также, в зависимости от того, что делает ваш Arduino, вам может потребоваться убедиться, что в каждом цикле достаточно времени для выполнения необходимых задач перед получением следующей партии последовательных данных. Вот пример того, что вы можете сделать.

function callbackFromJoystick(button, value) {
    if (button === 'blue') {
        proxy.blue = value;
    } else if (button === 'red') {
        proxy.red = value;
    } else if (button === 'green') {
        proxy.green = value;
    }
}
setInterval(function() {
    const buffer = data.buffer();
    port.write(buffer, ... );
}, 50);