Я у мамы не инженер

intro

Я уже сбился со счёта часов, которые я потратил на то, чтобы сделать «небольшую коробочку» и вдруг я поймал себя на мысли, что я очень зауважал инженеров — людей, который умеют и могут проектировать и создавать новые вещи. В голове сразу нахлынули воспоминания об устройствах, который я разбирал в детстве (да и не только). Эти забавные ситуации, когда при откручивании последнего болтика, как чёрт из табакерки, вылетало несколько мелких пружинок и деталек, которые было совершенно невозможно упаковать обратно.

Однажды я решил сделать небольшое устройство («Security Access Tuner» из игры Alien: Isolation) — контроллер, экран, пара элементов управления, да упаковать это всё в небольшой корпус, который планировалось напечатать на 3d принтере. Тогда я ещё и подумать не мог, сколько же времени потребуется, чтобы все эти мелочи собрались в одно целое…

Меня всегда привлекала идея создания чего-то нового — что-то такого, чего не так часто получается делать в повседневной суете. Не знаю, что именно послужило толчком к созданию именно этого устройства, но в один из дней я так и подумал: «А почему бы не сделать security access tuner из игры Alien: Isolation».

В игре есть некое устройство для «взлома электронных замков». Это устройство вводит в игру механику мини игр. Тут уж выбирайте мемасик себе по вкусу, но это что-то между «Мы добавили игр в твою игру, чтобы ты мог играть в игры, играя в игру» и «We need to go deeper!». Не стану утомлять вас подробностями игрового процесса, т.к. каждый желающий может узнать о том, что это за «зверь» в деталях, написав название в любимом поисковике. Просто условимся, что есть некоторое карманное устройство с играми, которое я решил реализовать.

В игре устройство выглядит вот так (я стремился достаточно точно воспроизвести внешний вид устройства, однако это не было главной задачей, поэтому финальный результат немного отличается от оригинала):

AccessTuner


Скриншот из игры, устройство находится в руках персонажа.

Итак, нужно сделать небольшое устройство с играми и этих самых «мини игр» — две. В первой (та, что на картинке сверху) нужно за отведённое время выбрать символы в том порядке, в котором они отображены на экране. Игра не сложная, если привыкнуть, но поначалу заставляет задуматься. Вторая игра на реакцию и нужно просто вовремя нажимать на кнопку (не стану заострять не ней внимание, т.к. ничего особенного в ней нет). Помимо игр есть ещё несколько экранов состояние, переходов между играми и просто «Please wait…».

По удачному стечению обстоятельств, у меня без дела лежала плата от Texas Instruments — Tiva C (аналог Arduino) и экран для неё же. И вот в один из дней, вдохновение напало на человека с наличием свободного времени и для этой парочки (платы и экрана) нашлось применение…

Разработка


Я сразу решил для себя, что «вишенкой на торте» в этой задумке будет не программная часть, а именно инженерная. Я хотел сделать и собрать устройство так, чтобы всё было компактно, функционально, логично и удобно (спойлер: всё оказалось не так просто).

Программирование — это то, чем я зарабатываю на хлеб и я понимал, что серьёзных «вызовов» программная часть предоставить не сможет. Поэтому, для того, чтобы воплотить идею в жизнь, я начал с того, что мне ближе всего — с программной части.

Обработка событий от кнопок и поворотного энкодера (rotary encoder) совершенно банальны и я не вижу смысла что либо рассказывать об этом. Хоть сколько интересной частью программной реализации был вывод графики на экран. Точнее даже не сам вывод, а скорее совокупность действий, которые были необходимы, чтобы на экране появилось то, чего я хотел. В основном, «проблемными» частями были:

  1. Память устройства ограничена и много картинок (спрайтов) в память устройства сложить не получится.
  2. Экран работает с цветами в формате 565 (два байта на цвет), т.е. для всей графики, нужно делать конвертацию в конечный формат, но ввиду ограничения памяти, в памяти устройства не получится хранить все необходимые изображения в таком формате.
  3. Экран обновляется с ошеломительной частотой ~1 кадр в секунду, если необходимо перерисовывать весь экран.


Первые две проблемы решались относительно просто, ведь графика, которую нужно выводить на экран очень примитивна (так это есть в игре и я решил не уходить далеко от исходного материала). Именно поэтому я сразу решил использовать двухцветные изображения (спрайты), что означало, что в один байт ложатся 8 пикселей и цвета можно просто подменять при выводе.

На основе этих самых спрайтов была реализована вся графика (в том числе и текст), если не считать пару исключений:

  • Логотип вымышленной компании производителя (Seegson), который использует палитру из 16-и цветов (т.е. 2 пикселя в одном байте). Мне захотелось чуть больше красоты при включении устройства и я добавил его уже в самом конце разработки, т.к. оставалось ещё немного памяти.
  • Были реализованы функции для рисования графических примитивов (например, прямоугольников, а в интерфейсе, который я пытался повторить, их много).


Проблему частоты обновления экрана, программно было решить не так уж и просто. Особенно для мест, где нужно обновлять данные на экране достаточно часто.

К счастью, проблема была не в самом экране, а в медленной шине данных (SPI шина), поэтому нужно было просто поберечь штаны и не шагать так широко — рисовать только то, что реально необходимо, т.е. «чем меньше, тем лучше».

Прорисовка интерфейса была разбита на три части, чтобы решить проблему частоты обновления:

  • Начальная прорисовка (тут рисуется всё то, что остаётся неизменным — фон и статичные элементы интерфейса). Этот этап занимает почти секунду, но происходит только при смене экранов и эта секунда не так и заметна.
  • Анимации, которые не зависят от действий пользователя (состояние таймера обратного отсчёта, помехи и прочее). Обычно это небольшие изменения — не более 15% экрана, что даже в таком случае позволяет обновить экран не реже 6 раз в секунду (на деле частота обновления значительно выше и задержки незаменты). Исключением был лишь экран с помехами — о нём я расскажу чуть ниже.
  • Анимации, которые зависят от действий пользователя (положение ползунков или рамка вокруг выбранного символа). Эти события происходят не так часто, т.к. при всём желании, пользователь не сможет нажимать на кнопки быстрее, чем состояние способен перерисовывать экран.


Говоря простыми словами, чтобы избежать перерисовок всего экрана, происходила перерисовка лишь того, что необходимо. Так например, если пользователь выбирает следующий символ на экране, то предыдущее «выделение» (рамку) необходимо стереть (закрасить цветом фона) и нарисовать рамку на новом месте.

Ещё одним примером такой оптимизации (где нужно рисовать много, но на деле рисуется мало), является экран с помехами (белым шумом) — это место, где пользователю нужно найти «нужную частоту», чтобы попасть в мини игру. Помехи занимают большую часть экрана и перерисовывать все чёрно-белые точки было бы слишком долго (да и глупо). Поэтому прорисовка белого шума работает следующим образом:

Экран делится на две части (левая и правая сторона). Рисование начинается сверху.

  1. Случайным образом выбирается часть экрана (левая или правая сторона).
  2. В рамках этой части рисуется полоска случайных чёрно-белых точек. Этот экран имеет две базовые операции для работы с ним (если не считать операции инициализации) — операция записи в буфер экрана и операция перемещения указателя в рамках этого самого экранного буфера. Причём, по непонятной мне причине, операция перемещения указателя работает ощутимо медленнее, чем операция записи. Таким образом, для этого экрана, последовательная запись в буфер экрана позволяет закрасить весь экран примерно за 0.75 секунд, а выполняя закрашивание каждого пикселя отдельно, потребуется почти за вдвое большее время (1.4 секунд). Именно из-за этой особенности рисуются полоски чёрно-белых точек, а не просто случайные пиксели.
  3. Переходим к следующей вертикальной полоске на экране и повторяем действия описанные в 1 пункте.


Когда все вертикальные строки нарисованы, то прорисовка продолжается заново сверху. В результате наложения одних чёрно-белых точек на другие, совершенно не заметно то, что экран по сути «закрашивается полосками» вот так (первые 20 случайных прорисовок):

Рисование шума


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

В интерфейсе был нужен ещё один довольно любопытный элемент — индикатор выбранной радио частоты. Для того, чтобы было проще представить, можем считать, что у нас в руках аналог радиоприёмника. Есть колёсико настройки, которое можно крутить по кругу, чтобы найти (выбрать) нужную частоту. На экране рисуется индикатор этой самой частоты, который может обойти полный круг по экрану и вернуться обратно в начальное положение. Индикатор в интерфейсе представляет собой треугольник (на деле это не совсем так, но для простоты отображения, условимся, что это треугольник), который вращается вокруг одной из вершин, расположенной в центре экрана:

Индикатор - треугольник


Серым цветом на картинке отмечены границы экрана.

На деле же этот самый треугольник в интерфейсе должен рисоваться не полностью. На экране должна отрисовываться лишь фрагмент, расположенный в той части экрана, которая находится дальше от центра (у краёв экрана). На примере я показал её оранжевым:

Индикатор


Серый полупрозрачный прямоугольник в центре оставлен для наглядности, но в прорисовке не участвует.

Задача сама по себе не сложная, просто её решение «в лоб» с перерисовкой всего экрана снова недопустима. Поэтому рисовались только отдельные фрагменты индикатора (две скошенные границы и прямоугольник, что соединяет их), а предыдущее состояние индикатора «стиралось» (красный цвет на картинке) перед прорисовкой:

Индикатор - прорисовка

Т.е. для этого самого индикатора была добавлена функция рисования прямоугольника, который разделён по диагонали и закрашен двумя цветами (один цвет с одной стороны относительно диагонали и другой цвет со второй стороны). Индикатор представлял собой два таких элемента (отмечены цифрой 1 на картинке) и прямоугольники соединяющие их (отмечены цифрой 2):

image

Ширину (или высоту) этого элемента определяет смещение относительно центра экрана. Так, когда индикатор находится в самом центре экрана, рисуется только прямоугольник (2), а при смещении индикатора ближе к краю экрана ширина элементов (1) увеличивается. Когда индикатор находится у краёв экрана, то при прорисовке добавляется ещё один прямоугольник:

image

Пожалуй на этом и заканчиваются все «интересности» программной части и я могу перейти к тому, что же заставило меня так сильно зауважать инженеров…

Не инженер


Несмотря на то, что в университетском дипломе у меня написано, что я «инженер компьютерных наук», на деле я осознал, что я «всё что угодно компьютерных наук», но не инженер. Я понимаю, что у слова «инженер» довольно широкое определение и в наше время вообще очень часто получается, что тот, кто не менеджер, тот инженер.

Говоря «инженер», я имею ввиду людей, которые умеют и могут планировать, проектировать, конструировать и разрабатывать. И в моём понимании, я не совсем инженер. В этом вопросе я любитель — мне нравится придумывать и реализовывать что-то, но нельзя сказать, что у меня это всегда получается. Инженерные задачи (речь идёт о корпусе устройства и основных его компонентах), которые я оценил, как вполне себе простые, заняли такое количество часов, которое я и предположить не мог. Я не знаю точного времени, но решил считать, что люди не придумали чисел, которыми можно было бы описать столь огромные величины.

В детстве, отец часто повторял мне поговорку «Семь раз отмерь, один раз отрежь». Тогда я до конца не понимал зачем он это говорил так часто, но именно в процессе создания этого устройства я понял, как же важно отмерить семь раз перед тем, как принять решение в пользу одного или другого варианта. Если бы я слушал папу, то не пришлось бы делать так много проб и ошибок.

Итак, у устройства, с левой стороны должно быть колёсико прокрутки, которое можно вращать вверх (или вперёд), чтобы выбрать следующий символ на экране или вращать вниз (назад), чтобы выбрать предыдущий символ. Я решил, что полноценное колесо прокрутки я делать не буду, т.к. для поворотного энкодера (rotary encoder) или чего-то похожего потребовалось бы куда больше места в корпусе, да и для перехода «вперёд» / «назад», более логичным решением показались именно кнопки.

Я решил спроектировать рычаг в виде полукруга, который можно будет сдвигать вверх или вниз. Этот самый рычаг должен был нажимать на кнопку «вверх» или кнопку «вниз» и находиться на какой-то оси, чтобы избежать «лишних телодвижений»:

Идея рычага

Идея казалась мне до безумия простой, но вместе с ней появилась масса вопросов (на которые люди, занимающиеся проектированием устройств, скорее всего бы имели готовые ответы) на которые у меня не было ответов. А вопросы были следующие:

  • На чём и как крепить кнопки? На картинке сверху ведь они просто «болтаются в воздухе» и в конечном устройстве так быть не может.
  • Нужно ли думать о механизме для возврата рычага на центр? Нужны ли пружины или хватит упругости кнопок?.
  • Как вставить рычаг в корпус так, чтобы отверстие в корпусе было максимально незаметным? Будет ли рычаг одной деталью или несколькими?
  • Как будет крепиться ось? Будет ли ось частью корпуса или отдельной деталью?
  • Как убедиться, что то, что «работает на бумаге», будет работать после печати на 3d принтере?


И я уверен, что есть куча готовых решений, а у китайцев скорее всего можно заказать что-то вроде «Модуль рычага кнопки мода инженерное запах женщины» в красивой коробочке. Я знаю и о готовых инструментов (редакторов) для создания подобных решений, но ради спортивного интереса, я решил «изобретать колесо», придумывать всё сам и обойтись только базовыми инструментами, которые «были под рукой».

Я придумывал прототипы разных вариантов этого рычага и проверял их в деле. Проверял прочность разных размеров оси, соединений и стенок, проверял возможность создания рычага из нескольких частей (чтобы упростить размещение рычага в корпусе). Думал над тем, как это всё ляжет в корпус.

Каждый раз, собирая очередной прототип, я вспоминал про все эти включатели / кнопочки и рычажки, которые окружают нас в повседневной жизни. Меня не покидало ощущение того, что я «котёнок на ламинате» — пока вокруг, в каждом чайнике, всё так элегантно и удобно, а все мои прототипы были какими-то корявыми и «недодуманными». Каждый мой прототип собирался «еле-еле» (если собирался вообще), т.е. казалось всё было бы отлично собралось, если бы размеры были чуть побольше, но приходилось придумывать решение в рамках того места, которое было доступно в корпусе. Это и был тот момент, который я упоминал в самом начале:

В голове сразу нахлынули воспоминания об устройствах, который я разбирал в детстве (да и не только). Эти забавные ситуации, когда при откручивании последнего болтика, как чёрт из табакерки, вылетало несколько метких пружинок и деталек, которые было совершенно невозможно упаковать обратно.


Были моменты, когда мне начинало казаться, что эту задачу просто невозможно решить. Т.е. я понимал, что это возможно, просто мне казалось, что я не смогу придумать ничего дельного. В такие моменты я пытался посмеяться над ситуацией, отвлечься и вернуться к задаче позже, с новыми силами. В конце концов я пришёл к следующим ответам на свои вопросы (ответы не претендуют на какую-то глобальную истину, но сработали для меня):

  • В корпусе будет отдельное место под кнопки, кнопки снизу будет удерживать дополнительная деталь.
  • Рычаг в центр будет возвращаться за счёт упругости кнопок (благо ход у рычага очень маленький и его смещение относительно центра не особо и заметно). К тому же у рычага очень маленький вес, что позволяет не беспокоиться о том, что под весом рычага кнопка будет нажата.
  • Рычаг будет одной деталью (т.е. не будет собираться из нескольких частей) и вставляться он будет сверху. Отверстие будет такого размера, чтобы свободно проходила одна из «ног» рычага, после этого рычаг будет сдвигаться, чтобы «просунуть вторую ногу».
    Вставляем рычаг
  • Ось будет частью той самой дополнительной детали, которая будет удерживать кнопки.
  • Прототипы позволили убедиться в том, что работать будет и в жизни, т.к. я на на деле проверял свои предположения по мере их поступления.


Блок рычага собирался следующим образом (оранжевый — рычаг, полупрозрачная стенка и серая деталь — части большого корпуса, а зелёная — дополнительная деталь для фиксации кнопок и осью рычага):

Сборка блока рычага

Отверстие под рычаг на деле получилось вот таким и на конечном устройстве не бросается в глаза:

Отверстие под рычаг

Я догадываюсь, что это далеко не самое элегантное инженерное решение в мире, но в данном решении, для мне всё было «вымерено» до миллиметра. Будь ширина детали чуть меньше и не хватило бы прочности — появлялся бы люфт (да и я серьёзно сомневаюсь, что работать в ещё меньшем масштабе было бы удобно). Если оставить чуть больше места «для манёвров» или сделать стенки детали чуть толще и на своё законное место не влезет экран.

Я понимаю, что читая всё это, может показаться, что этот самый рычаг — это очень незначительная часть устройства, но на деле, почти половину времени, что я потратил на весь этот проект, я потратил именно на этот рычаг.

Прототипы


Когда я рассказываю кому-либо похожие истории, люди не воспринимают меня всерьёз. Основным ответом на моё заявление о моей «пониженной инженерности» было: «Ну что ты рассказываешь сказки? — Ведь всё ведь работает, да и смотрится не хуже фабричного производства!».

Итак, я уже говорил, что использовал лишь инструменты, которые были под рукой. Для 3d моделирования я использовал online редактор, который не стану называть вслух (чтобы пост не сочли за рекламный). Этот самый редактор не слишком хорошо подходит для моделирования сложных объектов, но меня он полностью устраивал, т.к. с ним я был знаком и мог начать работать сразу. Если мне нужно было бы описать его функционал, то я бы сказал, что это такой MS Paint из мира 3d моделирования — только базовые операции, только хардкор. В этом редакторе нет возможности напрямую работать с вершинами или нормалями — только со всем объектом целиком.

Вот так в этом редакторе выглядит модель, которую я использовал для печати:

Модель для печати

Но дьявол кроется в деталях, поэтому, давайте взглянем на все те «шрамы», которые оставил человек с «неинженерной костью» на несложном корпусе устройства:

Модель вблизи


На изображении показано место расположения того самого рычага о котором я говорил чуть выше.

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

Конечно, на конечном устройстве это никак не сказалось, т.к. это смещения / несоответствия в масштабе меньше 0.1 мм и точность 3d печати не так высока, чтобы это было заметно.

Вот ещё одно место, где в корпусе делался «паз» под экран:

Паз под экран


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

Экран должен заходить в это углубление и оставаться там. Этот элемент нужен для того, чтобы экран не болтался в корпусе. В идеале, тут должно было быть отверстие (паз) в форме точно вымеренного параллелепипеда, но видно, что что-то пошло не так и форма углубления менялась несколько раз. В общем, нужно было слушать папу и семь раз отмерить перед тем, как рисовать паз и не пришлось бы его несколько раз переделывать. И я знаю, что можно было бы всё это привести в порядок, но средствами того самого редактора — это боль.

Ну и наконец, крышка корпуса… Крышка крепится к корпусу четырьмя болтами M3. Для этого в корпусе я предусмотрел место под гайки:

Место под гайки


На изображении вид снизу корпуса, прямоугольное отверстие — место под гайку.

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

И тут во мне проснулся художник


Настал день X, когда все подготовительные работы подошли к концу и пришло время распечатать детали, собрать всё вместе и покрасить.
image
Самый первый этап — печать корпуса и отрывание поддержек (supports).

Как видно по фото (а я надеюсь, что видно), качество печати недостаточно высоко, чтобы было можно просто покрасить корпус, поэтому следующим шагом было так любимое мной «доработать напильником до нужной формы»:
image
По мере шлифования корпуса, я отмечал «проблемные места» крестиками.

Когда модель приняла нормальный вид, можно было переходить к покраске в два этапа. Первый шаг покраски — грунтовка. Этот шаг можно и пропустить, но грунтом можно окончательно выровнять геометрию (убрать небольшие царапины) и цвет.
image
Остались непрокрашенные участки в углублениях, но они закрасятся позже.

Забавным моментом был и подбор цвета. Похоже, что я отношусь к тем людям, которые различают 7 с половиной цветов, поэтому цвет может существенно отличаться от того, что был в игре. Да и глядя на скриншоты из интернета я вообще потерял веру в свою способность воспринимать цвет. Казалось, что на каждом скриншоте я видел новый цвет (оттенки серого / синего). Я старался подобрать что-то похожее, да и просто искал такой цвет, в который я бы стал красить подобное устройство, если бы я производил что-то подобное.
image
Тут появилось и защитное стёклышко для экрана — оргстекло со сточенными краями.

Помимо самого корпуса, было необходимо распечатать россыпь мелких декоративных деталей, которые должны были дополнить конечный вид устройства:
image
Экран заработал пару царапин, пока валялся вместе с остальными деталями, поэтому был «упакован» в полиэтилен до лучших времён.

Некоторые детали нужно было склеить между собой и покрасить, чем я и занялся:
image

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

image

image

image

image

Сразу скажу, что символы внизу совершенно случайны и ничего не значат. Любителей теории заговора я попрошу расслабиться.

Ну и пара картинок «в работе»:
image

image

image

image

Ну и работает это всё примерно вот так:

image

Послесловие


В целом, как и обычно, то, что я хотел бы сказать этой историей — это то, что не стоит бояться делать что-то своими руками, не стоит бояться придумывать что-то новое (читать, как «костыли и велосипеды»). И даже если у вас «неинженерная кость», вы сможете узнать много нового и просто забавно провести время.

Иногда я задаю вопросы к любителями радиоэлектроники и они смеются с того, насколько мало я понимаю в электронике. Иногда я помогаю кому-то с написанием кода и улыбаюсь, когда вижу исходный код людей далёких от программирования. Возможно, читая всё это, где-то улыбнулся один инженер.

Спасибо всем, кто дочитал до конца.

© Habrahabr.ru