Однаждый мне рассказали о самодельном девайсе под названием Yayagram (по какой-то причине описанном создателем в Твиттере, а вот тут по-русски). Я на него посмотрел и решил сделать свой, с преферансом и поэтессами аркадными кнопками и старым термопринтером.
Так родился БабаГрам, чёрный ящик, открывающий моей бабушке общение в Телеграме.
Что такое Бабаграм
![](https://habrastorage.org/getpro/habr/upload_files/72f/d5e/e69/72fd5ee69a27d35349fd0a5391d80e42.jpg)
Мне хотелось сделать что-то похожее на Yayagram - устройство, которое бы печатало входящие сообщения на встроенном принтере, и позволяло бы бабушке отправлять мне и другим контактам сообщения. При этом бабушка не умеет набирать на клавиатуре телефона, и очень неуверенно читает с экрана.
Yayagram использовал провода и джеки для выбора, кому отправится сообщение. Я же решил использовать аркадные кнопки - мне кажется, это более естественный выбор. Они удобны и производятся для аркадных машин, на которых играют довольно азартно, а значит, выдерживают большие нагрузки.
Итого, нам нужно устройство с принтером, микрофоном, кнопками, выходом в интернет и управляющей этим всем логикой.
Оглавление
Начнём с "железной" части - термопринтера и периферии, контроллеров, питания. Дальше немного про производство корпуса. И, наконец, про код.
Термопринтер
Когда-то давно мне отдали старую кассу. Кажется, это была Ока 102к, но это не так важно. Выпаяв из неё всё, что может пригодиться, я стал обладателем древнего термопринтера. Вот такого.
![](https://habrastorage.org/getpro/habr/upload_files/b90/546/14b/b9054614bda7423d2e788ff118ba1e0f.jpg)
Документации по этому термопринтеру я не нашёл, зато нашёл обозначение собственно термопечатающей головки (Т1001Б) и, после продолжительного гугления, даташит на неё. Считаю себя квалифицированным интернет-детективом после такого и выкладываю даташит на гугл драйв. Где я его нашёл, уже не помню.
Дальше надо было разобраться в плате, которая управляла этим термопринтером. Не утомляя вас деталями, скажу лишь, что логика там примитивная: головка - это сдвиговый регистр на 128 бит, где каждый бит - это один резистор в термоголовке. Нужно отправить 128 бит последовательно, а потом коротко подать сигнал "огонь", который включает нагрев выбранных резисторов. Важно не перегреть, а то сгорят. И больше 32 включать за раз нельзя, поэтому более заполненные строки будут печататься медленнее.
Выжигать линию на бумаге - это ещё полдела. Надо уметь двигать ленту. Для этого в принтере есть шаговый двигатель. От него идёт 6 проводов, 2 из которых одного цвета и, после долгого тыканья мультиметром, определены как один провод в двух лицах (для увеличения сечения). Есть стандартный шаговый двигатель с 5 проводами с вот таким вот расположением пинов:
![](https://habrastorage.org/getpro/habr/upload_files/4b5/548/ffc/4b5548ffc620bb35b2963dca1fb98068.png)
Управлять таким двигателем довольно легко - знай себе по очереди дёргай фазы (а красная всегда или на GND или на VCC). Определив экспериментально последовательность фаз, которая приводит к движению ленты вверх, я пошёл дальше.
Начался долгий процесс обнюхивания с термоголовкой. Я подбирал тайминги тактового сигнала, время включения геены огненной нагрева резисторов и порядок битов в регистре. В силу существования big-endian/little-endian я посмотрел на все возможные комбинации перевёрнутых отпечатков, включая отзеркаленный и четырежды-внутри-отзеркаленный (когда каждый байт в неправильном порядке). Я даже смог добиться оттенков серого. В какой-то мере.
![Так вот как печатают фотороботы! Или фотороботов? Так вот как печатают фотороботы! Или фотороботов?](https://habrastorage.org/getpro/habr/upload_files/db0/75e/909/db075e909f7454cfdb8e17e9320e1f03.jpg)
Но вот беда: напечатанное было существенно сжато по вертикали. Что это? Прямоугольные пиксели? Или я слишком мало шагов двигателя делаю? А не посмотреть ли мне на двигатель? Знаете, что я увидел? Два двигателя на одном валу. У каждого по 3 провода, один из которых, по видимому, центральный между фазами. Эти центральные провода были соединены в один на плате. Поэтому тыканье мультиметром показало их замкнутыми, но на самом деле они в моторе (моторах!) не замкнуты. Один двигатель вращает ленту вперёд, другой назад.
Так что, когда я делал 4 шага фаз, двигатели включались поочерёдно, и двигатель "вперёд" двигал ленту по-честному (и даже чуть дальше), а двигатель "назад" мешал. Выкинув 2 фазы из 4х, я всё починил.
Ни разу не слышал об однонаправленных шаговых двигателях, а они, оказывается, есть?
Периферия
Кроме термопринтера, который у меня уже был, мне были нужны кнопки и микрофон. Я купил их на амазоне. Про микрофон особо нечего рассказывать - самый дешёвый USB-микрофон, по стечению обстоятельств точно такой же, как в Yayagram'е. При распаковке бабаграма бабушкой он был вырван из корпуса и порвал провод внутри, потому что бабушка решила, что это ручка. Пришлось оперативно чинить - впервые в жизни паял в новогоднюю ночь.
Ещё я добавил пищалку из набора ардуино, но это мелочи.
А вот кнопки интереснее. Ну так, чуть-чуть. Они со светодиодами с интегрированными резисторами, и на 3.3v светятся тускло. Светодиоды можно заменять, и в одной кнопке я поменял стоковый белый светодиод на красный. Нет, не в кнопке запись, а в кнопке SOS.
Кнопки прекрасно монтируются на корпусе - у них есть "юбка". И очень легко разбираются. Контакты там под клеммы, но мне было лениво обжимать 24 клеммы, поэтому я просто припаял провода. В комментариях справедливо отметили, что это не очень хорошая идея из-за возможного перегрева пластмассы. Я внимательно следил за деформациями, но всё равно - не могу рекомендовать такой подход.
![В следующий раз сделаю аккуратно В следующий раз сделаю аккуратно](https://habrastorage.org/getpro/habr/upload_files/7e5/3cb/457/7e53cb45789f88e30b6e6813a2966ec3.jpg)
Одна кнопка мне нужна была маленькая, поэтому я нарисовал и напечатал корпус для микропереключателя. Не буду публиковать модели - получилось не очень. По факту, она одноразовая и немножко залипает.
Контроллеры
Проблема всплыла, где не ждали. Я хотел собрать устройство на Raspberry Pi, а он 3.3 вольтовый. Но вся логика управления термопринтером 5-вольтовая, и кнопки на 3.3v светятся плохо.
В общем, я решил, что девайс я собираю сложный, а поэтому можно использовать два управляющих устройства, одно для 5v логики, другое для интернета и, в целом, для более сложных операций.
Я использовал Raspberry Pi Model 3B, но любой Pi (или аналог) должен сработать, если у него есть WiFi. Ну или можно сделать Babagram-over-Ethernet.
![](https://habrastorage.org/getpro/habr/upload_files/894/b87/021/894b87021a16f0dd18b28ff9d1d36704.jpg)
Для 5v логики я выбрал (по причине наличия дома) Attiny88. Я вообще очень люблю atmel'ы этой серии. Их сложно убить и очень просто программировать, если есть какая-нибудь ардуинка дома. И возможостей много за копейки. Единственный минус - у них очень мало памяти, как оперативной (512 байт) так и флеш (8Кб у 8x моделей). Но здесь тини будет очень прямолинейным исполнителем. Самое большое, что ей придётся хранить - одну строчку печати, 128 бит, 16 байт. Справится.
Для связи тини и Pi я использовал шину I2C: она требует мало проводов - SDA, SCL и земля. А ещё пины Pi не толерантны к 5 вольтам, поэтому любой протокол, который использует высокий уровень от ведомого устройства, потребует делителя напряжения. Лень подсказала мне, что I2C - мой выбор.
Пришлось, правда, подправить код I2C клиента в attiny - стоковый включает pull-up резистор, который выдаст 5v, а мне этого не надо. Высокий уровень будет задавать мастер, который у нас Pi. Все известные мне atmel'ы понимают 3.3v как логическую единицу. Attiny88 это гарантирует при питании от 5v (для него VIH >= 0.6VCC, то есть, 3v).
![](https://habrastorage.org/getpro/habr/upload_files/6df/e33/72d/6dfe3372da1e647461c29077f715c0c5.png)
Неожиданно узнал, что гребёнка Raspberry Pi имеет количество пинов и шаг между ними в точности совпадающий со шлейфом IDE. Приятное открытие, которое позволило мне впервые в жизни сделать более-менее разборный девайс на шлейфах. Я уже давно выпаял IDE разъёмы с нескольких старых материнок, поэтому просто вырезал очень простую плату для разводки этого разъёма. И ещё одну для атмела, чтобы связать его с платой термопринтера (тоже шлейфом).
А вот так выглядят питание, Pi и плата термопринтера на стенке корпуса:
![Pi со шлейфом, с питанием и платой термопринтера Pi со шлейфом, с питанием и платой термопринтера](https://habrastorage.org/getpro/habr/upload_files/390/082/931/390082931544ec617bf55f636194720f.jpg)
Питание
Для термопринтера было нужно 12 вольт, и у меня был блок питания 220 -> 12v (слева-сверху на фото выше).
Для 5v я сначала использовал копеечный асинхронный DC-DC преобразователь с алиэкспресса, но потом словил эпичные глюки из-за шумного питания (несмотря на развязывающие конденсаторы), и выкинул нафиг этот преобразователь. Вместо него использовал завалявшийся USB-C блок питания.
![](https://habrastorage.org/getpro/habr/upload_files/61a/942/2c8/61a9422c8a9f0ede498c4939ae4f4e30.jpg)
Для привыкшего к старому USB-A меня было открытием, что USB-C адаптеры требуют нетривиальной настройки, чтобы отдать даже стандартные 5 вольт. Нет, я понимаю, что сразу выдавать в линию 12v не стоит. Но 5 вольт можно бы... Ладно, там надо просто резистор добавить между линиями CC и GND. На 5.1кОм, которые есть только в серии E24 и далее, но ближайший "обычный" номинал в 4.7кОм у меня работает нормально. В итоге получается такая вот колбаса:
![Куда же без термоклея? Куда же без термоклея?](https://habrastorage.org/getpro/habr/upload_files/6e9/0dd/785/6e90dd785015e501144a2c54446fce83.jpg)
Корпус
С электроникой понятно, осталось разобраться с тем, как сделать коробку. Yayagram, судя по всему, использовал заводскую, но это не наш метод.
Я закупился 4мм фанерой и вырезал корпус на лазерном ЧПУ-станке (диодном!). Оказывается, если резать фанеру, которая для этого не предназначена, появляются забавные артефакты - некоторые волокна фанеры прорезаются плохо, и остаётся много непрорезанных точек. А в некоторых местах она горит внутри.
Лазер у меня на 40 китайских ватт. При питании от 12v он потребляет ~1.7A - такая вот китайская арифметика, но я отвлёкся. Худо-бедно фанеру он режет. Специальную "лазерную" фанеру он режет вообще отлично.
![CNC с лазером CNC с лазером](https://habrastorage.org/getpro/habr/upload_files/181/75a/0a0/18175a0a009e6850a85057d7b1ac5a9e.jpg)
Внезапно обнаружилось, что станок не совсем декартов. То есть, оси у него не перпендикулярны. Раньше я только платы вырезал, там перпендикулярность была не так важна. А тут я вырезал два прямоугольника на пределе размера стола и сложил их, провернув. И узрел расхождение в ~1.5мм. Пришлось подтюнить станок молотком, чтобы он стал перпендикулярнее.
Для сборки корпуса я напечатал на принтере уголки, часть обычных мебельных, а часть "трёхсторонних" - см. здесь. Очень удобно собирать по месту - часа два с шуруповёртом, и корпус примерно собрался. Правда, часть дырок оказались лишними, пришлось их залить эпоксидкой, и после покраски они стали глянцевыми.
После покраски встал вопрос, как наносить текст на корпус. Эмбоссированные пластиковые полоски как в Yayagram'е я сразу отверг - хотелось честных изображений на поверхности. Я попробовал гравировать фрезой поверх краски, предположив, что я срежу краску и оставлю более-менее яркую фанеру, но вышла фигня.
Фигня
![На фото красивее, чем в реальности, из-за вспышки. Контраст вживую ещё меньше. На фото красивее, чем в реальности, из-за вспышки. Контраст вживую ещё меньше.](https://habrastorage.org/getpro/habr/upload_files/e65/e7d/f28/e65e7df286ec5c41cbbedc4f1e47e9fa.jpg)
Поэтому я перешёл к более тяжёлой артиллерии. Одну эмблему (для кнопки протяжки бумаги) я нарисовал более простым способом: вырезал лазером трафарет на клейкой этикетке, наклеил на дерево и закрасил акрилом из аэрографа. Это возможно, потому что эмблема без изолированных участков чёрного. Иначе говоря, область чёрного связная.
Фото покраски по трафарету
![](https://habrastorage.org/getpro/habr/upload_files/24f/5f1/63d/24f5f163d0a2782c3452951956cb3a76.jpg)
![](https://habrastorage.org/getpro/habr/upload_files/271/20c/c43/27120cc43feb1246d1487fd3056b5f83.jpg)
![](https://habrastorage.org/getpro/habr/upload_files/091/27c/11a/09127c11a1274aac5003045b01ec565c.jpg)
Для обычного текста такой режим не подходит. Либо придётся использовать трафаретный (стенсильный?) шрифт, который делает все буквы правильным образом связными, либо придумывать другой метод. Мне не хотелось ограничивать себя в том, что я могу нарисовать, поэтому я выбрал второй вариант.
Для рисования произвольного (одноцветного) изображения я заклеивал всю поверхность малярным скотчем, затем лазером гравировал участки, где должна быть краска (белые в конечном итоге). Это испаряло малярный скотч и чуть-чуть дерева, и я красил аэрографом по такой маске.
Фото более сложного процесса
![](https://habrastorage.org/getpro/habr/upload_files/354/f10/2de/354f102dea9feb98364fe67c24bda74f.jpg)
![](https://habrastorage.org/getpro/habr/upload_files/81b/b7c/a66/81bb7ca660f31f4d2cb23e32fe4cdff0.jpg)
![](https://habrastorage.org/getpro/habr/upload_files/037/5d2/6d6/0375d26d632ba0fd85b3c0c6186df24f.jpg)
![Шрифт как на усилителях VEF Шрифт как на усилителях VEF](https://habrastorage.org/getpro/habr/upload_files/7df/60d/f52/7df60df520119e33b89460418659e4f3.jpg)
На самом деле, не так уж сложно это оказалось делать. И качество на удивление неплохое. Единственно что плохо - контрастность ниже, потому что краска не очень хорошо ложится на шероховатую после лазера поверхность. Хотя казалось бы.
Фото собранного и покрашенного бабаграма:
![Это изображение было в превью, всё верно. Это изображение было в превью, всё верно.](https://habrastorage.org/getpro/habr/upload_files/1be/672/f71/1be672f7168833a57b81f4b3399bf197.jpg)
Код
Код для аттини я написал как для ардуино и залил через ISP, которой была Arduino Uno.
Код для малины базируется на python-telegram-bot и работает как телеграм-бот. Там очень много чего сделано криво, в частности, многопоточность реализована плохо. Может быть, я допилю этот код до более красивого.
Запускать код как system service нельзя - это должна быть user service, иначе pyaudio не может использовать микрофон. Не знаю, почему, вероятно, из-за какой-то аутентификации в pulseaudio.
Я не базировался на коде Yayagram, потому что местами он ещё хуже. В частности, запись звука там производится запуском бинарника arecord, с последующим его убийством при отпускании кнопки записи.
![](https://habrastorage.org/getpro/habr/upload_files/7ea/238/ea7/7ea238ea778d6a2dedd23793dd8e146a.jpg)
Для печати текста на термопринтере нужен шрифт. Его нужно выбрать, и это было тяжело. Я пробовал векторные шрифты (потому что растровые были нечитаемыми), и выглядели они в разной степени криво. Как я понял потом, растровые не работали из-за описанного выше неправильного управления шаговым мотором. Но пока я этого не понял, я перепробовал десятки шрифтов и потратил кучу бумаги.
Наконец, починив управление мотором, я смог печатать один к одному и заменил шрифты на растровые. Какое же это было счастье!
Когда всё уже работало, я понял, что мне не всегда удобно слушать аудиосообщения, и я хочу читать текст. Для этого есть много разных сервисов, но я выбрал Google. Продравшись сквозь дебри версий компилятора Rust'а и glibc, я таки установил google-cloud-speech, и всё заработало. Если хотите мой совет, ставьте unstable версию raspbian'a - там версии пакетов более подходящие. Обновить свой Pi я уже не могу, потому что, оказывается, при обновлении отваливается WiFi.
Весь код лежит здесь: https://github.com/gurux13/babagram
Заключение
Бабушке очень понравился Бабаграм. Она его использует, и это очень удобно - мы посылаем сообщение, оно печатается на кассовой ленте, и, когда она видит вылезший чек, она отвечает нам аудиосообщением, которое тут же распознаётся в текст.
![](https://habrastorage.org/getpro/habr/upload_files/bed/a5a/073/beda5a073060fb22456091e5e17a7656.jpg)
Спасибо, что дочитали до конца. Ну или долистали :) Надеюсь, было интересно.