В наше время никого уже не удивишь печатью картиночек на листе бумаги. Существует огромный выбор принтеров (в том числе и карманных). Многие из моих знакомых покупают или собирают 3D-принтеры. Я же хочу рассказать, как я снова изобретал велосипед. Итак, снова шаг назад — это история про 2D печать. Рассказ про то, как я делал мобильный принтер для телефона на основе термального принтера (принтер, который печатает на термобумаге — не нужны чернила, только специальная бумага и электричество), модуля bluetooth и ещё нескольких мелочей.
Хочу сразу предупредить, что в электронике и электротехнике я ничего не понимаю, что я принципиально не использовал готовых решений и библиотек. Поэтому это рассказ про рукожопство и велосипеды, про проблемы с которыми я столкнулся. Продолжайте чтение на свой страх и риск.
Супертехнологическое устройство
Я думаю, что мне не нужно напоминать, что мы живём в век мобильных технологий. Я помню, как лет 20 назад я думал, что вот ещё немного и мир будет полон роботов, летающих автомобилей и ещё много-много чего удивительного. С учётом того, что я считал, что ещё немного и у всех будут свои роботы, символично и то, что роботов у нас толком нет (защитников робопылесосов прошу простить мне прошлую фразу), но есть кое-что другое… Я бы скорее всего не поверил, если бы мне тогда сказали, что у почти у каждого человека на земле в кармане будет супертехнологическое устройство, с помощью которого, люди будут, сидя в туалете, запускать симуляцию физических взаимодействий процесса вброса птиц в свиней. А если бы мне сказали, что это устройство будут называть телефоном, я бы и вовсе рассмеялся в лицо рассказчику.
Немного истории
На носу был 95-ый год (может и раньше, но я уже в прошлом абзаце написал про «20 лет назад», а «20» это красивое и круглое число, поэтому я останусь при нём) и у одного из знакомых со двора был Gameboy (DMG-001). Не думаю, что стоит рассказывать, насколько он был крут по меркам того времени и какая очередь выстраивалась, чтобы посмотреть и подержать в руках это чудо техники. В начале 2000-ых данное устройство снова напомнило о себе, т.к. к нему появилась дополнительная периферия, а именно камера и принтер. Реальной необходимости в такой камере или принтере (уж тем более такого качества) не было, но сама идея мобильного устройства, с которого можно было распечатать небольшую картиночку казалось шагом в будущее.
Назад к теме
Итак, прошло 20 лет и я подумал, что можно было бы сделать похожее устройство, только для супертехнологического устройства — телефона.
Идея была довольно проста и основывалась на следующих вещах:
- Термальный принтер (A2 Micro Panel Thermal Printer).
- Модуль bluetooth (JY-MCU BT_BOARD V1.06).
- Контроллер (Stellaris Launchpad LM4F120XL. Чтобы избежать вопросов «а почему?», сразу отвечу, что просто у меня была под рукой именно эта плата).
- Экран (LCD 84x48 Nokia 5110) и несколько led диодов для индикации состояния.
- Аккумулятор и регулятор (Turnigy UBEC 5A).
- Приложение под Android для управления принтером (читать, как «печати»).
- Разряд по рукожопству и слабые знания основ электротехники.
Именно из-за 7-ого пункта я должен попросить прощения у всех, кого расстроит моя реализация. Уж простите, но изготовления печатных плат, отладки устройства с использованием осциллографа и прочих плюшек адекватной разработки устройств в этом повествовании вы не найдёте. Необходимых инструментов у меня тоже нет, т.к. в повседневной жизни я не работаю в этой сфере, да и разряд по рукожопству терять не хочется. Я постарался немного улучшить свои знания предметной области, но так или иначе, понимаю, что могу ошибиться и в терминологии. Мне самому бывает больно смотреть на код людей далёких от программирования, поэтому, чтобы не отнимать более времени у любителей прекрасного в области электротехники, выкладываю фото того, как всё было собрано:
Чтож, для всех, кто продолжил чтение после прошлой фотографии, доступна ачивка «Пережил ад перфекциониста электротехника»…
![](https://habrastorage.org/files/a03/975/d70/a03975d703b047d1b7fe851d1a8e9074.png)
Итак, как я уже говорил, идея была проста: есть картинка на телефоне (тут уж не важно, что является источником картинки, просто примем, что картинка есть), необходимо её уменьшить, совершить манипуляции с яркостью и контрастом (если есть необходимость), затем дитеринг (dither), чтобы получить чёрно-белое изображение, затем отправка по bluetooth на принтер и непосредственно печать.
Поскольку я занимаюсь разработкой программного обеспечения, то с программной частью не было проблем или заморочек. Был реализован простенький протокол обмена данными между принтером и управляющим устройством (поскольку принтер принимает команды по bluetooth, то нет смысла ограничиваться только телефоном):
- Используется бинарный протокол для обмана данными.
- Данные передаются в виде пакетов, каждый из который начинается с заголовка (что за пакет, сколько данных).
- На каждый пакет-запрос есть два ответа (“запрос получен” и “выполнение запроса завершено”). Можно было бы обойтись и одним ответом, но в таком режиме можно было лучше контролировать состояние принтера — нет необходимости реализовывать очередь команд на стороне контроллера, т.к. контроллер сам сообщает, что готов к выполнению нового запроса.
Помимо служебных команд типа «а жив ли принтер?», было реализовано лишь несколько команд, которые напрямую связаны с печатью (печать изображения и подача бумаги — feed).
Поскольку принтер способен печатать только монохромные изображения, то в качестве формата изображения был выбран упрощённый аналог Bitmap с 1bpp (1 бит на пиксель). Принтер способен печатать 384 точек на линию, что означает, что для печати одной полной линии необходимо 48 байт (не считая заголовка).
Проблемы со связью
Не стану заострять внимание на том, что контроллер отказался получать данные от модуля bluetooth из-за слишком низкого напряжения на ноге TX модуля, т.к. уж больно много времени я потратил на отладку этой детали. На это я убил примерно два дня, т.к. сначала проверил всё что только мог и только потом пошёл читать интернет, откуда и узнал, что это особенность выбранного модуля и что уровень придётся подтянуть до необходимых 3.3V самому или же придётся насиловать модуль и выпаивать из него диод (что я решил не делать).
После того, как я смог получать пакеты на стороне контроллера появилась другая проблема: данные приходили частично. До сих пор не могу точно сказать в чём именно была проблема, но тут толи лимит буфера модуля bluetooth, толи его скорость передачи / обработки данных. Проблема была такова: шлём пакет (например, килобайт данных), на стороне контроллера получаем 990-1023 байта с потерями в случайном диапазоне (случайная область данных, случайное количество). Потери данных случались примерно в 50% случаев и составляли всегда небольшой процент от исходных данных (не более 50 байт, даже при пересылки нескольких килобайт). Проблема повторялась на всех скоростях обмена данными (не то, чтобы я проверял все, но проверил как среднее значение, так и границы — 1200 и 115200 бод), но исчезала при добавлении задержки между отправкой данных. Чтобы не встраивать синтетических задержек, я решил, что просто дополню протокол обмена данными:
- Была добавлена контрольная сумма пакета.
- Данные в рамках пакета передавались фрагментами, после передачи фрагмента данных, ожидался ответ от контроллера, который пересылал порядковый номер полученного фрагмента.
- Был добавлен служебный пакет для установки размера фрагмента (обычно используется размер 128 байт, но возможность менять размер фрагмента я оставил).
Итак, первое, что было необходимо, чтобы определить начало пакета — это подпись (определённая последовательность байтов):
inline bool _receiveSignature( )
{
unsigned char character;
unsigned int offset = 0;
while( offset != SIGNATURE_SIZE )
{
if( _readByte( &character ) )
{
if( character != SIGNATURE[offset] )
{
if( character == SIGNATURE[0] )
offset = 1;
else
offset = 0;
}
else
offset++;
}
else
return false;
}
return true;
}
Идея с подписью не нова. В случае, если одна из сторон, по каким либо причинам прервала приём пакета на середине передачи, то оставшиеся данные пакета не должны быть интерпретированы, как следующий пакет. Таким образом, приём начинается с того, что из буфера удаляются (игнорируются) все байты, до подписи — начала заголовка пакета. Таким образом, обеспечивается то, что случайный мусор в буфере (остатки прошлого пакета) не будут считаться заголовком нового пакета.
Код получения данных фрагментами (область данных, после получения и проверки заголовка):
unsigned char *buffer = m_buffer;
unsigned int size = m_header.size;
_sendCallback( 0 ); // resets fragment id
while( size > 0 )
{
unsigned int fragmentSize = _min( size, m_fragmentSize );
if( read( buffer, fragmentSize ) )
{
size -= fragmentSize;
buffer += fragmentSize;
_sendCallback( );
}
else
{
_sendCallback( 0 ); // sends wrong fragment id
_setError( READ_ERROR );
return false;
}
// тут был код для вызова callback (экран и прочее)
}
unsigned int checksum = _getChecksum( m_buffer, m_header.size );
if( m_header.checksum != checksum )
{
send( COMMAND_ERROR );
_setError( INVALID_CHECKSUM );
return false;
}
Поскольку существует вероятность того, что при передачи данных будут потери, необходимо проверять и порядковый номер пакета. Например, запрос на печать отправлен, а ответ не получен. В таком случае, запрос будет отправлен повторно, но выполнять его не нужно, т.к. достаточно просто ответить статусом предыдущего выполнения запроса. Каждая из сторон считает пакеты и если порядковый номер пакета неверен, значит следует начать коммуникацию “с чистого листа” (сбросить счётчики).
Помимо самого принтера
Помимо самого принтера, контроллера и модуля связи (bluetooth), было добавлено несколько элементов для индикации состояния. Были добавлены 3 светодиода:
- Индикатор включения.
- Индикатор наличия связи с телефоном (горит, если в течении последних 5 секунд была передача данных).
- Индикатор печати (горит, когда происходит печать).
Помимо простых индикаторов, был добавлен монохромный экран для вывода прогресса, состояния и прочих мелочей.
Общая схема выглядит так:
![](https://habrastorage.org/files/a87/246/16d/a8724616df4d49b4a1ddaaffc0df37fd.png)
Внешний вид
Для корпуса я решил использовать 4мм фанеру, резку фанеры я доверил станку с лазером. От меня требовались только векторный чертёж и деньги за работу. Чертёж вышел вот такой:
![](https://habrastorage.org/files/d00/cf2/69d/d00cf269d0164116805e0dbcc888205c.png)
Красным отмечены области, которые было необходимо выжигать, а не резать. Результатом доволен. Из минусов данной коробки могу назвать лишь то, что она склеена и разбору не подлежит. Благо порт для новых прошивок контроллера и порт для зарядки аккумулятора я вывел, поэтому необходимости разбирать коробку нет:
![](https://habrastorage.org/files/d3e/a9a/81d/d3ea9a81d2b8425d972c845b3d040702.jpg)
Следует уточнить, что коробка получилась с третьего раза. Сначала коробка просто не сошлась — я поторопился, не проверил размеры и одна грань не подошла. Потом я переделал чертёж, но сделал довольно глупый выбор в том, как крепить стекло, защищающее экран:
![](https://habrastorage.org/files/bcd/e20/8fd/bcde208fd67046b1a4fd2fee08a225fa.jpg)
В результате, стекло было спрятано в корпус и не торчало снаружи (не стану тут снова вставлять картинку из начала статьи).
Приложение
На стороне телефона я сделал довольно примитивный интерфейс:
Выбор картинки для печати (с камеры или из файловой системы):
![](https://habrastorage.org/files/f71/0fc/976/f710fc976f854215bbe257733231e9d4.png)
Настройки изображения — яркость и контрастность:
![](https://habrastorage.org/files/33e/a7b/c1a/33ea7bc1a7e043bbb0172e51970384a2.png)
Несколько элементов управления (подключение к принтеру, печать, подача бумаги, поворот изображения):
![](https://habrastorage.org/files/6b6/e51/630/6b6e51630f0b494da8d88c40249e6aee.png)
Результаты
Качество печати довольно приличное (для термального принтера):
Как и многие принтеры, этот не исключение и немного “полосатит”:
![](https://habrastorage.org/files/b5d/dd4/478/b5ddd447878a440da49dcebdbf160cf9.jpg)
В целом, то, что я хотел бы сказать этой историей — это то, что не стоит бояться делать вещи своими руками, не стоит бояться и велосипедов. В наше время, разработка своих устройств стала намного проще. Контроллеры не так ограничены в ресурсах, неприхотливы в работе и прощают некоторые ошибки (которые бы не допустил человек, понимающий в электротехнике). Делайте вещи своими руками, изобретайте свои велосипеды. Спасибо всем, кто дочитал до конца.