- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток! Сегодня я поделюсь опытом разработки программы для контроллера ROBO TX от немецкой фирмы Fischertechnik. Возможно, на данный момент он не является топовой моделью, однако базовые принципы, которые я собираюсь описать далее, могут быть полезны юным разработчикам, которые столкнутся с контроллерами этого производителя.
Данный контроллер в основном предназначен для конструирования простых роботов с целью обучения. В комплекте идет графическая среда программирования, которая помогает заложить в него простые алгоритмы. Также ребята из русского представительства Fischertechnik подсказали, что имеется динамическая библиотека c API от создателей, которая предоставляет полный контроль и позволяет решать требуемые задачи более гибко уже путем разработки собственного софта, что как раз и произошло в моем случае.
Раньше, когда учился, я работал в ЦТПО «Интеллектуальные роботы» на базе института МГУПИ. Центр занимался подготовкой абитуриентов и школьников старших классов по специальностям робототехники. И Андрей Назарович Будняк, который возглавлял его в то время, предложил создать для этого контроллера программу, которая позволит управлять роботом в режиме реального времени. Также был интересен вариант управления этим контроллером через Bluetooth, чтобы получить своего рода пульт управления, как у радио-машинки.
Для решения задачи потребовалось изучить документацию, которая шла с библиотекой. К счастью, она достаточно информативная.
Выяснилось, что у контроллера два режима:
Нас интересует второй.
Он делится на несколько этапов:
Как оказалось, в случае с соединением через Bluetooth этот механизм тот же самый и на программном уровне не отличается вовсе. Единственная задача заранее поднять COM-порт через Bluetooth.
При разработке я использовал ООП подход. Для данного рода и масштаба задачи он не слишком необходим и в некоторых местах, я бы даже сказал, избыточен. Однако позволяет упорядоченно разложить структуру программы в виде компонентов для более простого понимания стороннему человеку. К тому же эта статья ориентирована на начинающих программистов, а им полезно привыкать именно к такому ключу.
Весь исходный код с комментариями выложен на Гитхабе [1] в виде проекта на QT. Здесь опишу ключевые моменты по нему.
У контроллера 8 контактов для подключения 4 моторов (M1-M4). Наша задача при нажатии/отжимании клавиши подавать сигнал в контроллер, который включит/отключит определенный мотор.
Нам понадобится список клавиш, в котором мы сохраним код клавиши и соответствующий номер мотора. Но это не все. Контакты у ROBO TX способны выдавать последовательность импульсов с широтно-импульсной модуляцией (ШИМ) для регулировки скорости вращения моторов. Диапазон регулировки от 1 до 512. Это означает, что чем меньше цифра, тем реже подается напряжение, которое всегда имеет одинаковое значение (12В). Еще есть направление вращения. И вдобавок контроллеры способны объединяться в группы с помощью шлейфов до 9 за раз (1 мастер и 8 дополнительных).
Резюмируем и для быстрого понимания одновременно смотрим на финальный интерфейс формы ввода параметров клавиши:
Имея список, мы сможешь при нажатии клавиши с определенным кодом найти ее, определить, какие параметры передаем контроллеру, и отослать их. Вот и все в целом.
Для хранения состояния кнопки в памяти я использовал следующую структуру:
struct Button {
QString name;
int code;
int controller;
int motor;
bool direction;
int speed;
};
Метод из динамической библиотеки ftMscLib.dll, который передает параметры на конкретный мотор называется setOutPwmValues.
Принимает 4 параметра:
Весь функционал программы разбил на следующие компоненты, реализованные отдельными классами:
Возвращаясь к этапам, которые были перечислены в начале.
Connector::Connector() { //устанавливаем флаги в начальные значения
found = false;
connected = false;
started = false;
}
//поиск доступных портов
bool Connector::searchCom()
{
ports.clear();
char *portName = new char[256];
for (int i=0;i<libLoader.getAvailableComPorts(0);i++) {
libLoader.enumComPorts(i,portName,256);
ports.push_back(QString::fromLocal8Bit(portName));
}
return found = ports.size()>0 || debug;
}
//подключение по определенному порту
bool Connector::openCom(char* comPortName) {
DWORD errCode = FTLIB_ERR_SUCCESS;
fthdl = libLoader.ftxOpenComDevice(comPortName, 38400, &errCode);
if (errCode==FTLIB_ERR_SUCCESS || debug) connected = true;
return connected;
}
//запуск протокола общения с контроллером (Transfer Area) [необходимо уже иметь подключение через порт]
bool Connector::startTA() {
if (libLoader.ftxStartTransferArea(fthdl)==FTLIB_ERR_SUCCESS || debug) {
started = true;
}
return started;
}
void Controller::exec(int buttonKey, bool pressed) //установить на контроллере состояние мотора в зависимости от конфигурации клавиши
{
if (connector.getStarted()) { //если Трансфер Арея запущена
for (int i=0;i<getButtons().size();i++) { //перебираем список клавиш
if (buttonKey==getButtons()[i].code) { //если текущая нажатая или отпущенная клавиша имеется в списке
libLoader.setOutPwmValues( //то посылаем конфигурацию мотора на контроллер, соответствующую этой клавиши и ее статусу нажатия (нажата или отпущена)
connector.fthdl,
getButtons()[i].controller,
getButtons()[i].motor * 2 + (getButtons()[i].direction ? 1 : 0),
getMemorySpeed(getButtons()[i], pressed)
);
}
}
}
}
Стоит сказать пару слов о методе getMemorySpeed. Это своего рода буфер зажатых клавиш. Добавлен был для того, чтобы не забывать очередность зажатых клавиш относящихся к одному и тому же мотору, но передающих разную скорость. Возвращает скорость последней зажатой клавиши для текущего мотора, если такая есть. В противном случае останавливает мотор, возвращая 0.
//остановка протокола общения с контроллером (Transfer Area) [необходимо уже иметь подключение через порт]
bool Connector::stopTA() {
if (libLoader.ftxStopTransferArea(fthdl)==FTLIB_ERR_SUCCESS || debug) {
started = false;
}
return !started;
}
//отключение открытого порта
bool Connector::closeCom() {
if (libLoader.ftxCloseDevice(fthdl)==FTLIB_ERR_SUCCESS || debug) {
started = false;
connected = false;
}
return !connected;
}
Всю ключевую работу, в принципе, за нас делает библиотека ftMscLib.dll. Нам лишь важно это обернуть в удобную оболочку и приспособить для наших потребностей.
Данная разработка оказалась полезной на форуме роботов в 2012 году в соревновании «Трудная дорога». С помощью неё осуществлялся контроль роботом в реальном времени.
Все исходники, релиз и сама библиотека выложены здесь [1]. При желании можете вносить свои изменения и доработки. Спасибо всем за внимание и удачного дня!
→ Немецкий Сайт Fischertechnik [2]
→ Русский Сайт Fischertechnik [2]
→ Сайт русского комьюнити Fischertechnik [3]
→ Архив с библиотекой, документацией к ней и примерами с немецкого сайта Fischertechnik [4]
Отдельное спасибо Андрею Назаровичу Будняку за помощь при составлении статьи.
Автор: Quardex
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/qt-2/247555
Ссылки в тексте:
[1] выложен на Гитхабе: https://github.com/Quardex/Blue-Button
[2] Немецкий Сайт Fischertechnik: http://www.fischertechnik.de
[3] Сайт русского комьюнити Fischertechnik: http://pacpac.ru/
[4] Архив с библиотекой, документацией к ней и примерами с немецкого сайта Fischertechnik: http://www.fischertechnik.de/en/ResourceImage.aspx?raid=4979
[5] Источник: https://habrahabr.ru/post/323168/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.