Здравствуйте, дорогие читатели!
Пришла мне тут одна идейка, а не собрать ли пульт управления космическим кораблем. На USB. С нативной поддержкой драйверов. Custom HID. Чтобы воткнул и всё работает, без всяких танцев и бубнов. В итоге, получился некий монструозный «геймпад» для космических симуляторов. В общем, судите сами.
Поначалу, я мало представлял, что будет в итоге. Хотелось два основных джойстика, как на Союзе-МС, немного переключателей, кнопок и несколько дисплеев.
Прикинув рабочую поверхность моего стола, выбрал размеры пульта по ширине и глубине 500*300 мм. А пошарив по строительным складам и магазинам в поисках стройматериалов, выбрал высоту 125мм. В итоге приобрел лист 4 мм фанеры, рейки 20*12 мм и доску 120*20 мм.
В каде был быстренько набросан эскизик пульта. И делал в дереве я его очень долго. Месяца три. по выходным. И не потому, что так вальяжно работал пилой, а от нехватки времени. Панель шпаклевал, шкурил и красил эмалевой краской, похожей по цвету на настоящие панели космических кораблей или самолетов.
Но пока оставим малярные работы в стороне и я расскажу про электронную начинку.
Радиодетали закупались на али. В качестве джойстиков, нашел вот такие. Вообще, ситуация с такими джойстиками — полный швах. Промышленные решение слишком дорогие, а дешевые, идут в качестве игрушек и поэтому плохи. Эти вполне качественные, но как по долговечности будет, не в курсе.
Остальная мелочь проблем не вызвала. Контроллер выбрал STM32. В качестве АЦП для джойстиков 16-битные ADS1118. Также был куплен блок питания на 12 В. Собственно такое напряжение объясняется тем, что мне в руки попал указатель уровня топлива от «шахи», который я тоже хотел сюда же пристроить.
На фото блок питания, стабилизаторы на 5 и 3.3 В, STM32, MCP23017, ADS1118
Контроллер 100-выводный STM32F407VET6, к нему подключается:
2 селектора на 4 положения
1 переменный резистор
2 переключателя осей
4 основных оси
2 вспомогательных оси
2 регулирующих оси
4 клавишных переключателя по 2 кнопки каждый
20 кнопок со светодиодами
4 основных выключателя со светодиодами
2 кнопки-грибка со светодиодами
2 кнопки таймеров
3 выключателей со светодиодами
13 переключателей
2 ADS1118 (АЦП)
4 MAX7219 (8-знаковые LED-дисплеи)
2 TM1637 (дисплей-часы)
1 PCF8574 (расширитель I/O, воткнут в знакосинтезирующий дисплей)
Получилась такая структурка
Чего-то многовато будет для сотни ног МК, решил я, и добавил сюда же расширители входов-выходов: четыре штуки MCP23017, на 16 входов или выходов каждый. Забегая вперед, скажу, что задержка опроса входов у расширителя получилась около 0.13 мс на одну микросхему, при скорости шины I2C 400кГц. То есть это с запасом перекрывает минимальное время опроса USB в 1 мс.
Чтобы не гонять шину I2C бесполезными запросами, у MCP23017 есть выхода-прерывания, которые устанавливаются при изменении состояния входов. Их я тоже применил в своем проекте. Как оказалось далее, из-за дребезга контактов эти прерывания оказались бесполезными.
АЦП ADS1118 несколько не успевает за скоростью USB, заявленная производительность у него составляет максимально 820 отсчетов в секунду, что равно 1.2 мс, при этом, он имеет несколько входов, которые внутри через мультиплексор уже подключены к АЦП. Я использовал 2 входа на одну микросхему, поэтому время обновления значений составляет 2.4 мс. Плоховато, но что поделаешь? К сожалению на али других 16-битных быстрых АЦП нет.
Внутри выглядит так, но после монтажа проводов гораздо хуже
Программа CPU написана в стиле программы ПЛК. Никаких блокирующих запросов. Ядро периферию не ждет, не успела и хрен с ним, на следующем цикле опросит. Никаких RTOS в проекте тоже нет, попробовал, уперся в минимальное время ожидания задачи 1 мс — получается медленно, если нам надо отправлять данные по USB с частотой 1 мс. В итоге понял, что буду использовать ОС без osDelay(), а тогда зачем RTOS? Просто, как в ПЛК, располагать инструкции программы один за другим внутри бесконечного цикла вполне достаточно.
Использовал, конечно же CubeMX и библиотеки HAL. Кстати, на HAL недавно перешел и удивился удобности. Не знаю, почему до сих пор не очень популярен, там главное разобраться поначалу, а потом пойдет очень просто. Такое чувство, что программируешь ардуину.
Девайс у нас будет USB custom HID. HID есть mouse, keyboard, gamepad, joystick, какие-то еще. А есть custom. Всё это не требует драйверов от операционной системы. Точнее, они уже написаны разработчиком. Кастомный девайс хорош тем, что мы сами комбинируем возможности всех вышеназванных устройств по своему усмотрению.
Вообще, USB штука очень сложная, имеет мануал почти в тысячу страниц и с наскока её не взять. Кто не хочет читать тяжелые мануалы, есть великолепная статья USB in a NutShell, погуглите. Также у неё есть перевод. Всё же попытаюсь некоторые моменты объяснить «на пальцах».
USB — пакетированная передача данных с кучей уровней и абстракций. Девайс у нас — никаких данных запрашивать не может, всю передачу инициализирует хост. Хост пишет и запрашивает данные в так называемые конечные точки, физически это некоторые буферы в памяти МК. Чтобы хост понимал по каким конечным точкам можно писать, а какие конечные точки читать и какие данные он может интерпретировать как кнопки и оси нашего устройства и, вообще, что это тут у нас за устройство, в начале коннекта он запрашивает дескрипторы девайса. Этих дескриптеров много и составлять их сложно и можно как угодно, и ошибиться тоже, где угодно. Физически они представляют собой массив байт.
На самом деле, CubeMX сгенерирует код инициализации Custom HID лучше нас.
Прошу обратить внимание на последней картинке под цифрой 3. Это размер дескриптора в байтах, который и определяет какие оси и кнопки есть на нашем девайсе. Генерируется этот дескриптор в программе HID Descriptor Tool. Там есть несколько примеров для самостоятельного изучения. Вообще, вот мой дескриптор. Там пока отсутствуют данные для дисплеев, для простоты понимания, но присутствуют все кнопки и оси джойстиков. Его нужно поместит в файл usbd_custom_hid_if.c. По-умолчанию, куб этот дескриптор делает пустым.
HID Descriptor (размер 104 байта)
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x02, // USAGE_PAGE (Simulation Controls)
0x09, 0xbb, // USAGE (Throttle)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x32, // USAGE (Z)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x33, // USAGE (Rx)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x34, // USAGE (Ry)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x35, // USAGE (Rz)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x36, // USAGE (Slider)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x39, // USAGE (Hat switch)
0x15, 0x01, // LOGICAL_MINIMUM (1)
0x25, 0x08, // LOGICAL_MAXIMUM (8)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270)
0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x40, // USAGE_MAXIMUM (Button 64)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x40, // REPORT_COUNT (64)
0x55, 0x00, // UNIT_EXPONENT (0)
0x65, 0x00, // UNIT (None)
0x81, 0x02, // INPUT (Data,Var,Abs)
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
По сути, его можно составлять как угодно, сначала задаются параметры USAGE PAGE и необходимый USAGE, например ось USAGE (Throttle), а затем после слова INPUT (Data,Var,Abs) система будет считать, что у нас есть ось «Газ». Размерность переменной оси и их кол-во задается параметрами LOGICAL_MAXIMUM, MINIMUM, REPORT_SIZE, REPORT_COUNT, которые должны стоять перед INPUT.
Более подробно про эти параметры, а также, что такое (Data,Var,Abs), можно прочесть в Device Class Definition for Human Interface Devices (HID) v1.11.
Ниже приведен пример инициализации оси Throttle из моего дескриптора. В данном примере Throttle имеет диапазон значений 0-65535, что соответствует одной переменной uint16_t.
0x05, 0x02, // USAGE_PAGE (Simulation Controls)
0x09, 0xbb, // USAGE (Throttle)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
А да, еще, допустим, можно не писать LOGICAL_MAXIMUM, MINIMUM, REPORT_SIZE, REPORT_COUNT каждый раз, хост будет определять это значение по предыдущему параметру. Это иллюстрируют оси, которые идут один за другим, без указания размера и кол-ва:
0x09, 0x32, // USAGE (Z)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x33, // USAGE (Rx)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x34, // USAGE (Ry)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x35, // USAGE (Rz)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x36, // USAGE (Slider)
Всему этому дескриптору, который выше под спойлером, соответствует следующая структура. Она, по сути, уже не обязательна, просто так удобнее вести запись на основе указателей.
#pragma pack(push, 1)
typedef struct _myReportStruct
{
uint16_t Throttle;
uint16_t X;
uint16_t Y;
uint16_t Z;
uint16_t Rx;
uint16_t Ry;
uint16_t Rz;
uint16_t Slider;
uint8_t Hat; // 0 - none, 1 - up, 2 - up-right, 3 - right, 4 - down-right...
uint32_t Buttons1; // 32 buttons of 1 bit each
uint32_t Buttons2; // 32 buttons of 1 bit each
}myReportStruct;
#pragma pack(pop)
volatile myReportStruct Desk;
Эту структуру можно посылать хосту функцией
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, (uint8_t *) &Desk, sizeof(Desk));
Первый параметр — хендл USB, он у нас уже создан кубом. Возможно, понадобится подключить include-ом необходимый файл, где впервые инициализируется этот хендл и прописать extern USBD_HandleTypeDef hUsbDeviceFS;, чтобы с ним можно было работать. Второй параметр — указатель на нашу структуру и третий — размер структуры в байтах.
После заливки и прошивки контроллера можно заметить, что чего-то USB медленно шевелится. Данные с нашей панели обновляются не быстро. Чтобы было быстро, в файлах usbd_customhid.h нужно поменять #define CUSTOM_HID_EPIN_SIZE на максимальное значение 0x40, #define CUSTOM_HID_EPOUT_SIZE тоже поставить 0x40. В файле usbd_customhid.c найти комментарии в дескрипторе эндпойнтов "/* bInterval: Polling Interval (20 ms) */" и поменять байт дескриптора на 0x01 для каждого эндпойнта, всего два раза. Что будет соответствовать 1 мс обмена данными.
Должно получиться нечто подобное. Стандартное устройство без установки каких-либо драйверов
В общем-то, с функцией управления немного разобрались. Её сделать довольно легко и все кнопки и оси уже работают. Осталось сделать работу дисплеев. Делал я её делал, полгода примерно, и уже полгода панель пылится в долгом ящике. Нет времени. Поэтому решил выложить статью именно в таком виде, а то она рискует вообще не выйти.
С дисплеями всё тоже самое, что и с осями. Под них нужно дополнить наш дескриптор HID девайса, только указать что это дисплеи и вместо принятия данных Input, хост будет посылать данные Output.
Дескриптор HID девайса значительно разросся. Здесь я уже применил параметры Report ID, чтобы не забивать буфер приема/передачи и эндпойнты полными данными и различать, что за телеграмма нам пришла. Report ID представляет собой байт uint8_t со значением, который идет вначале телеграммы. Значением мы сами задаем в дескрипторе HID девайса.
CUSTOM_HID_ReportDesc_FS
//AXIS
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)28
0x05, 0x02, // USAGE_PAGE (Simulation Controls)
0x09, 0xbb, // USAGE (Throttle)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x85, 0x01, // REPORT_ID (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x32, // USAGE (Z)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x33, // USAGE (Rx)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x34, // USAGE (Ry)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x35, // USAGE (Rz)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x36, // USAGE (Slider)
0x81, 0x02, // INPUT (Data,Var,Abs)
//HAT
0x09, 0x39, // USAGE (Hat switch)
0x15, 0x01, // LOGICAL_MINIMUM (1)
0x25, 0x08, // LOGICAL_MAXIMUM (8)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270)
0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
//Buttons
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x40, // USAGE_MAXIMUM (Button 64)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x40, // REPORT_COUNT (64)
0x55, 0x00, // UNIT_EXPONENT (0)
0x65, 0x00, // UNIT (None)
0x81, 0x02, // INPUT (Data,Var,Abs)
//LEDs
0x85, 0x02, // REPORT_ID (2)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x09, 0x4B, // USAGE (Generic Indicator)
0x95, 0x40, // REPORT_COUNT (16)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
//LCD Displays
0x05, 0x14, // USAGE_PAGE (Alphnumeric Display)
0x09, 0x01, // USAGE (Alphanumeric Display)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x32, // USAGE (Cursor Position Report)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x04, // REPORT_ID (4)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x25, 0x13, // LOGICAL_MAXIMUM (19)
0x09, 0x34, // USAGE (Column)
0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf)
0x25, 0x03, // LOGICAL_MAXIMUM (3)
0x09, 0x33, // USAGE (Row)
0x91, 0x22, // OUTPUT (Data,Var,Abs,NPrf)
0xc0, // END_COLLECTION
0x09, 0x2b, // USAGE (Character Report)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x05, // REPORT_ID (5)
0x95, 0x14, // REPORT_COUNT (20)
0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255)
0x09, 0x2c, // USAGE (Display Data)
0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf)
0xc0, // END_COLLECTION
0x09, 0x24, // USAGE (Display Control Report)
0x85, 0x06, // REPORT_ID (6)
0x95, 0x01, // REPORT_COUNT (1)
0x91, 0x22, // OUTPUT (Data,Var,Abs,NPrf)
0xc0, // END_COLLECTION
//LED Displays
0x05, 0x14, // USAGE_PAGE (Alphnumeric Display)
0x09, 0x01, // USAGE (Alphanumeric Display)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x2b, // USAGE (Character Report)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x07, // REPORT_ID (7)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x28, // REPORT_COUNT (40)
0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255)
0x09, 0x2c, // USAGE (Display Data)
0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf)
0xc0, // END_COLLECTION
//Other DATA
0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x08, // REPORT_ID (8)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x0A, // REPORT_COUNT (10)
0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol)
Обработка Output происходит в функции static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state), которая, по-умолчанию, находится в usbd_custom_hid_if.c.
static int8_t CUSTOM_HID_OutEvent_FS()
static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
uint8_t dataReceiveArray[USBD_CUSTOMHID_OUTREPORT_BUF_SIZE];
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
for (uint8_t i = 0; i < USBD_CUSTOMHID_OUTREPORT_BUF_SIZE; i++)
{
dataReceiveArray[i] = hhid->Report_buf[i];
}
if (dataReceiveArray[0] == 2) //report ID 2 leds
{
// если Report id == 2, то делаем что-то на основе данных в dataReceiveArray[1 + N], например, зажигаем LED
}
if (dataReceiveArray[0] == 4) //report ID 4 cursor position
{
// если Report id == 4, то делаем что-то, например устанавливаем курсор на LCD
}
if (dataReceiveArray[0] == 5) //report ID 5 display data
{
// если Report id == 5, то делаем что-то, например выводим данные с USB на LCD
}
// и так далее, смотря сколько ID у нас в дескрипторе
return (USBD_OK);
/* USER CODE END 6 */
}
Осталось только написать программу на ПК, которая отправляет нужные репорты, чтобы рулить дисплеями. Впрочем, для проверки кода МК подойдет великолепная программа от ST: USB HID Demonstrator. Она позволяет слать репорты с ПК с каким угодно содержимым.
Тест LED дисплеев
На этом этапе я пока закончил. И не известно, начну ли снова.
Играется в симуляторы интереснее, чем с клавиатурой. Но не настолько, чтобы прямо был вау-эффект. Клавиатура, она тоже похожа на пульт управления. Но управлять осями-джойстиками, как минимум, необычно. Чувствуешь себя космонавтом. Правда, для полного погружения необходим скафандр.
Надеюсь, вам было интересно. Опечатки, неточности и бред присутствует. Желающие поковыряться в коде могут посмотреть здесь.
С уважением.
Anton23
Спасибо, интересно. Но не хватает видео с игрой на этом ПУ.
TyVik
Очень крутая идея! Даёшь симуляцию стыковки или посадки на Луну.
8street Автор
Постараюсь сделать на выходных.
8street Автор
chapter_one
Очень здорово! Монитор может поставить повыше?
norguhtar
А для какого сима это все запиливалось?
8street Автор
Подойдет для любого сима, к которому можно подключить джойстик или геймпад. Я чаще всего играю в KSP.
MuKPo6
Попробуйте «Reentry — An Orbital Simulator»
chapter_one
Ну тогда сразу Orbiter. Куда уж хардкорнее?
chapter_one
Автор, остановись! Это начинается все невинно: там дощечка, тут фанерка, топливомер от «шахи», а через пару лет ты покупаешь гараж, потому что в квартиру это уже не помещается.
www.creativesimulations.com/Cockpit%20Shell.htm
LynXzp
0xd34df00d
Блин, круто! Надо такой кокпит для F/A-18 сделать.
200sx_Pilot
www.avsim.su/forum/topic/113299-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8%D0%BC%D0%B8%D1%82%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%B2-%D1%81%D1%82%D1%80%D0%B5%D0%BB%D0%BE%D1%87%D0%BD%D1%8B%D1%85-%D0%BF%D1%80%D0%B8%D0%B1%D0%BE%D1%80%D0%BE%D0%B2-%D0%BD%D0%B0-%D0%B1%D0%B0%D0%B7%D0%B5-%D0%BF%D1%80%D0%B8%D0%B1%D0%BE%D1%80%D0%BD%D1%8B%D1%85-%D1%88%D0%B0%D0%B3%D0%BE%D0%B2%D1%8B%D1%85-%D0%B4%D0%B2%D0%B8%D0%B3%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%B9
Создание имитаторов стрелочных приборов на базе приборных шаговых двигателей
chapter_one
0xd34df00d
Офигенно. Это под какой сим? С DCS заведётся? (Edit: увидел домен. Заведётся, конечно)
Я не представляю, например, как сделать отображение чего надо на MFCD и, тем более, например, на UFC или панели двигателя и топлива.
chapter_one
Я когда начал задумываться о постройке своего «гнезда симмера» и пошел гуглить информацию просто офигел, насколько обширный рынок этого дела существует в США (в первую очередь) и в Европе. Куча контор, которые выпускают панельки, приборы, экраны, органы управления, и прочее для нужд замороченных симмеров, даже готовые киты есть из которых можно собрать полную кабину 737, только каркас нужно самому сделать. Крайне недешевое удовольствие, но качество изготовления попадается просто потрясающее, а сборка и подключение не представляет никаких сложностей. Пока остановился на сайтековских панельках для Цессны, вот таких saitek.pro/flight-simulation/pro-flight-panels которые просто собраны под мониторами в самопальный корпус. Не то, конечно, но уже интереснее.
rstepanov
Это вы еще спецификацию Bluetooth не смотрели, там около 5 тысяч страниц :)
super-guest
8street Автор
Joystick Potentiometer JH-D202X-R2/R4
SomaTayron
а мягкий/жесткий упор есть на джойстиках, или фиксатор по крену, типа союзовского РУО?
Кстати, на Федерации уже одна ручка самолетного типа. Управление самой ручкой и «джойстиком» на ней под большим пальцем
RigelNM
Откуда информация? Если занимаетесь разработкой можете еще чем-то интересным поделиться с общественностью?
chapter_one
Да это, вообще-то, не секрет никакой tass.ru/kosmos/4130417
Zenitchik
Охренеть. Т.е. дублирования управления не будет. Надеюсь, этот гроб в таком виде никогда не полетит.
chapter_one
С одной стороны меня это тоже удивляет. С другой стороны, вроде бы сейчас все так свои проекты делают. Ручное управление там нужно в крайне редких случаях, ломаться в этой ручке особенно нечему. Возможно, все не так уж страшно, как может показаться дилетанту.
SomaTayron
Дублирование вообще то будет, хотя и не совсем классическое. А переход на одну ручку — чтоб в случае чего БИ мог той же ручкой управлять, но своей левой рукой.
PS там не гроб, достаточно просторно. На этом снимке экраны уже в опущенном состоянии — когда поднимают, места намного больше
Zenitchik
Но ручка-то одна. Она не дублирована. Что они будут делать в случае её отказа? Только чинить в полёте.
Следовательно — это гроб. Не во вместимости дело.
SomaTayron
«ручка» съемная, и запасная примерно в 1,5 метрах хранится. Так что если отказа не будет прямо в 2-5 метрах от стыковочного, проблем никаких. Кстати, на Союзе тоже один действующий комплект РУО-РУД, так что это решение как минимум не хуже
Zenitchik
Понял, был не прав.
А если будет — перейдут на автомат. И то и другое сразу — не откажет.
SomaTayron
В рамках разрешенного в принципе мог бы, мы в тренажере Федерации в пятницу только для руководства презентационные снимки делали в новых прототипах летных скафандров )))
Но тут пара троллей карму просаживает постоянно, из-за больших пауз приходится редко заходить
RigelNM
Ясно, успехов в вашей работе. Вообще сами как оцениваете настроение в команде, федерации быть?
SomaTayron
Быть конечно, хотя кое-какие рекомендации по изменениям мы уже дали. А по срокам еще не ясно, от ЦПК заказов даже предварительно не было, только разработчик и мы пока пробуем его. ЦПК больше на Союзовские пока смотрит (замену Океану-5), хочет комбинированный тренажер, не только приводнения (на муромской платформе), но и этап сведения до контакта. Может после этого начнет интересоваться по Федерации.
RigelNM
Спасибо! Получил информации больше чем за 2 года слежения за всеми новостями…
8street Автор
SomaTayron
По союзовским в общих чертах описать не проблема — левый отвечает за движение (плоское перемещение, РУД), правый за ориентацию, «вращение (РУО).
Левый имеет свободный ход — до „мягкого упора“, а если сильнее двигать, то и „жесткий упор“. Оси ручек расположены горизонтально (руки на подставку упираются предплечьем), слева от оси ручки чуть внизу — тумблер движения „вперед-назад“, назад тяга в 2 раза сильнее.
Правая ручка тоже с мягким и жестким упором, но может еще и вращаться вокруг оси (для крена корабля). Ориентацию можно зафиксировать сквозным механическим „штифтом“ в ручке РУО (там их 2, на крен отдельный штифт, этот кажется белый, второй красный). Штифт подпружинен, возвращается отщелкиванием при нажатии с другой стороны.
В принципе не секрет и уровней мягкого и жесткого, сейчас это 0,87 и 2,7.
А по Федерации говорить пока нельзя, по шее дадут )))
dmitryredkin
Чёрт, как это непохоже на обычный игровой джойстик! Сразу вспоминается:
vvzvlad
Традиционно пирожки пишутся без знаков препинания и больших букв.
Polaris99
Было интересно, но некоторые моменты удивили.
8street Автор
1. Тут, вообще, можно долго дискутировать. Хотелось точности, так как уже на новых геймпадах Xbox стоят 16-битные оси.
Но я с вами не согласен, что из 12 бит можно получить 16. Случайный шум и интерполяция там будет.
2. Расширители не медленные. Они быстрее, чем время между отсылкой данных по USB, почти в 10 раз. Можно было и с матрицей заморочиться. Много возни, чтобы упаковать большее в меньшее, но зачем? Все профессиональные игровые девайсы могут обрабатывать одновременное нажатие всех кнопок.
3. Честно сказать, я гуглил, как сделать не 1кГц, а 10, но решения не нашел. Таймеры и прерывания можно и без RTOS сделать. На самом деле, без RTOS работает очень быстро. У меня встроен счетчик в бесконечном цикле и, когда он насчитывает 10000 циклов, мигает светодиод. Мигает примерно раз в 0,5 сек. Т.е. скорость даже избыточная. Потому что никаких блокирующих функций нет при работе с периферией.
Zolg
ZEvS_Poisk
Из статьи:
Плохо? Мне думается что было бы достаточно 20 мс… Дергать джойстиками с такой частотой никто не сможет :)
8street Автор
Мне в соседней статье люди утверждали, что чувствуют 10-20мс, поэтому и написал, что плохо. Я сам 2мс задержки не чувствую.
chapter_one
2 мс — никто не почувствует, это за пределами возможностей человека, а вот 20 — совсем другое дело. Концерт, исполнитель играет на миди-клавиатуре через комп. Общая задержка от нажатия клавиши до появления звука примерно 20 мс., жалуется, что не попадает в долю. И действительно, я тоже слышу, что он немного мажет мимо ритм-секции. Смена драйвера, уменьшение буферов, и задержка становится на уровне 8-10 мс. Музыкант перестает чувствовать дискомфорт, я тоже перестаю слышать косяки.
Вообще тренированный человек (будь то музыкант, или геймер, или любой другой профи, который в рилтайме ждет ответа системы на свой ввод, пилот современного истребителя как пример) начинает напрягаться при задержках больше 10 мс. Некоторые уникумы чувствуют лаг в 8 мс, но таких немного. В любом случае, 20 мс — это очень много.
Попробуйте поиграть на любом музыкальном инструменте через компьютер под фанеру, задержав свой сигнал на 20 мс. Хрена с два в долю попадете.
engine9
Здорово! Спасибо за технические детали.
Barafu_Albino_Cheetah
Раз речь о пультах, подскажите кто-нибудь пожалуйста, как оптимальнее всего подключить к малинке 218 кнопок? Нажимаемых в любом сочетании.
Zolg
Взять пару хороших usb-клавиатур ?
psycho-coder
У меня вопрос, наверно больше риторический: почему при использовании светодиодных цифровых индикторов повсеместно игнорируют светофильтры для них? Ведь с ними лучше читаемость и выглядить эстетичней.
rPman
Столько сил потеряли на вырезание панели из фанеры, когда как любое рекламное агентство вырежет лазером или фрезой вам по вашим эскизам что угодно, по цене 60-100р за метр реза.
По теме поста, неужели все эти кнопочки можно будет прописать в управление симулятором?
chapter_one
А почему нет? Если посчитать все кнопки и переключатели, которые есть штатно на моем HOTAS Warthog, то их примерно столько же наберется. И все равно для DCS мало, еще остаются на клаве шорткаты
max1muz
Зашел в комменты, чтобы написать то же самое. Рез 4мм фанеры даже дешевле сделают — 40 — 50р за метр. Аж больно было когда прочитал, что автор три недели ковырялся с панелью.
Zenitchik
Почему? Панель — это интересно. Я скорее поверю, что он так ни во что с её помощью и не играл, потому что не бывает игры, настолько же интересной, как разработка подобной хреновины )))
max1muz
Разработка, сборка и настройка это интересно, но человек явно страдал вручную выгрызая все эти отверстия)
Zenitchik
Это он прибедняется. Там всех сверлильно-пилильных работ часа на четыре. Растянуться на три недели это могло в случае дефицита свободного времени: если было по 20 минут и то не каждый день (что вполне вероятно, вон, Паскаль свою машину 10 лет конструировал).
Автор, кстати и пишет «от нехватки времени».
chapter_one
А может наслаждался? Ну нравится человеку по 20-30 минут в день спокойно ручками попилить фанерку после напряженного дня на работе, вполне могу понять. А делать где-то на стороне, это же надо чертеж готовить, искать исполнителей (куча времени уйдет только на то, чтоб сравнить предложения и выбрать подходящее), заказ оформлять, ехать забирать потом (курьерская доставка будет дороже, чем вся фанерка с работой вместе), да и кайфа никакого.