Печатаем картинки с помощью Arduino

от автора


Очень давно хотелось сделать какой-нибудь проект на Ardoino, да такой, чтобы всё в нём двигалось и работало. И, спустя пару месяцев проектирования, программирования и сборки получился вот такой мини-принтер, с помощью которого можно печатать разнообразные картинки и текст на самых обычных стикерах. Если после просмотра видео Вы загорелись необъятным желанием сделать нечто подобное — прошу под кат.

Что нам понадобится

  • Arduino Uno. Для этого проекта я использовал оригинальную итальянскую плату Arduino Uno. Не произойдет совершенно ничего страшного, если в этом проекте использовать её китайский аналог, который будет стоить в несколько раз дешевле.
  • Сервоприводы sg-90 — 3 штуки. Это самые дешёвые и маленькие сервоприводы из ныне существующих.
  • Любой стержень. Я использовал для этого алюминиевый пруток 5 мм, который можно купить в любом строительном магазине
  • Клей. В этом проекте я использовал 3 вида клея: столярный для фанеры, супер-клей для соединения шестерней с осями, также мне понадобился термический клей для крепления сервоприводов. Можно так сильно не запариваться и собрать все на какой-нибудь универсальный клей «Момент».
  • Наждачная бумага. Даже при очень точном изготовлении деталей им потребуется подгонка, поэтому без шлифовки — никуда.
  • Станок для лазерной резки(опционально). Если за Вас все детали сделает машина — это хорошо, но вполне реально сделать этот проект дома на коленке, используя обычный ручной лобзик. Первую версию принтера я делал именно так.
  • Фломастер. Можно использовать несколько фломастеров для печати цветных картинок
  • Пружинка и оси с маленьким диаметром. Для этого идеально подойдет «щелкающая» ручка, из которой можно достать пружинку и использовать её стержень в качестве оси
  • Фанера 4 мм. Можно найти в строительном или хобби-магазине. Возможно, подойдут и другие варианты, например, оргстекло.
  • Чертежи. Ссылки на них я оставлю здесь:
    1. Чертежи для лазерной резки;
    2. Чертежи для выпиливания вручную.

Собственно реализация

Изготовление деталей

Этот этап зависит от вашего желания и ваших возможностей. Можете вырезать на станке или выпиливать все детали вручную. Главное, что здесь надо отметить — это то, что качество и работоспособность этого проекта напрямую будет зависеть от вашей аккуратности. Также надо учитывать такой момент: некоторые детали, которые Вы увидите на фотографиях могут немного отличаться от тех, что будут на чертежах.

Для тех, кто планирует всё делать вручную

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

Самое сложное здесь — это пазо-шиповое соединение деталей и изготовление шестеренок.

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

Чтобы этот текст не казался таким сухим, разбавлю его этапами изготовления шестеренки:

Собираем боковые стенки

Пока всё просто: берете детали и склеиваете их. Следите за перпендикулярностью и за тем, чтобы на деталях не оставалось лишнего клея.

Приклеиваем ножки к основанию

Эти ножки представляют только эстетическую ценность. Если вы хотите сэкономить немного времени, то этот этап можно пропустить

Собираем корпус воедино

Текст на передней и задней табличках можете изменить на свой вкус.

Делаем площадку для бумаги

Этот этап требует особой аккуратности и тщательности выполнения работы. Особую сложность представляют «Г»-образные рельсы, на которых и будет держаться вся эта площадка.

Вам нужно аккуратно приклеить тонкие полоски точно по рискам, указанным в чертеже. Для лучшего эффекта я использовал такие необычные «прищепки», но можно спокойно обойтись и без них. Главное — убрать лишний клей и следить за тем, чтобы полоски никуда не съехали. Дальше на них сверху приклеиваем полоски пошире — технология здесь такая же.

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

С приклеиванием зубчатых реек проблем быть не должно. Следите за тем, чтобы они приклеились перпендикулярно.

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

Если всё было сделано правильно, то Ваш принтер должен выглядеть примерно вот так:

Протяжный механизм

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

После того, как клей высохнет, попробуйте аккуратно прокрутить стержень — площадка должна двигаться.

Устанавливаем первый сервопривод

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

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

А теперь можно проверить, всё ли у нас работает. Для этого подключите серво к Вашему Arduino через pin9 и загрузите скетч из Образцов: Servo > Sweep. Его код я, на всякий случай, привожу ниже.

Servo sweep

#include <Servo.h>  #define MIN_ANGLE 0 #define MAX_ANGLE 180  Servo servo;  void setup() {    servo.attach(9); }    void loop() {    for(int i=MIN_ANGLE; i<=MAX_ANGLE; ++i) {     servo.write(i);      delay(15);   }    for(int i=MAX_ANGLE; i>=MIN_ANGLE; --i) {                                     servo.write(i);     delay(15);   }  }  

Если всё заработало — замечательно. Если нет — попробуйте поменять положение привода или значения MIN_ANGLE и MAX_ANGLE в коде.

Устанавливаем второй сервопривод

Здесь всё делается аналогично с первым мотором. Единственное отличие — понадобится небольшая ось длиной ~12 мм, чтобы закрепить две шестерни.

Ставим печатающую каретку

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

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

Последний сервопривод

На этом этапе собираем рычажок для фломастера. Нужно суметь просверлить сбоку отверстие для шурупа, которым мы будем поджимать винт. Постарайтесь, чтобы в состоянии, когда фломастер опущен, серво имел положение 90 градусов, тогда Вам не придется делать лишних исправлений в коде.

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

Первый запуск и отладка

Для начала мы подключаем серво к нашему Arduino Uno, не обязательно на данном этапе помещать его внутрь принтера, так будет неудобно работать. Первый мотор подключаем к pin2, второй — к pin4, третий — к pin6. Далее загружаем вот этот скетч (весь код я постарался подробно и понятно закомментировать, сильно в его подрробности вдаваться не буду):

Разверни меня

#include <Servo.h>  /* *  MiniPrinter *  Designed in May 2015 *  By Alexandrow Yegor */  //Структура мотора, хранящая диапазон допустимых углов и экземпляр класса Servo struct Motor {   int min_angle, max_angle;   Servo servo; };  #define IMG_W 64 //Ширина изображения #define IMG_H 64 //Высота изображения int STEP = 2;    //Градус поворота серво на 1 пиксель #define IDLING_MS 4 // Время, тербующееся на поворот в 1 градус #define WRITING_MS 8  struct Motor motor_x, motor_y, motor_p; byte img[IMG_W/8]; //Изображение передается построчно                    //Один пиксель = один бит  struct Motor newMotor(int pin, int a1, int a2) { //Инициализация мотора   struct Motor m;    m.servo.attach(pin);   m.min_angle = a1;   m.max_angle = a2;    return m; }   void gotoStart() {    motor_p.servo.write(motor_p.max_angle); //Поднятие фломастера    delay(15);        //Перемещение в точку (0; 0)    motor_x.servo.write(motor_x.min_angle);    motor_y.servo.write(motor_y.min_angle);     delay(IDLING_MS * STEP * IMG_W + 150); }  void finish() { //Закрыть принтер     motor_p.servo.write(motor_p.max_angle);      delay(15);     motor_x.servo.write(motor_x.min_angle);     motor_y.servo.write(motor_y.max_angle);     delay(IDLING_MS * STEP * IMG_W + 150); }  void setup() { //Инициализация   Serial.begin(9600);   motor_y = newMotor(2, 50, 180);   motor_x = newMotor(4, 30, 160);   motor_p = newMotor(6, 90, 99);   gotoStart(); }  //Проверяет, есть ли в строке черные пиксели, которые еще не были напечатаны boolean nextWayIsEmpty(int i) {   for(; i<IMG_W; ++i) {     if(!(img[i/8] & (1 << 7-(i%8)))) continue;     else return false;   }      return true; }  void printImg() {   gotoStart();   int x = 0;   for(int y=0; y<IMG_H; ++y) {       for(int i=0; i<IMG_W/8; ++i) img[i] = Serial.read();       Serial.write(61);//Эта команда означает, что принтер принял строку с ПК и готов принимать новую              for(int i=0; i<STEP; ++i) { //Каждый пиксель на бумаге имеет длину и ширину, равную STEP           motor_x.servo.write(motor_x.min_angle); //Переход на новую строку           motor_y.servo.write(motor_y.min_angle + y*STEP + i);            delay(IDLING_MS * STEP * x + 30);                      for(x=0; x<IMG_W; ++x) {                          if(nextWayIsEmpty(x)) {               motor_p.servo.write(motor_p.max_angle); delay(IDLING_MS * (motor_p.max_angle-motor_p.min_angle));               break;             }                          //Определяет положение фломастера(нажат/поднят), исходя из цвеа пикселя             motor_p.servo.write((img[x/8] & (1 << 7-(x%8))) ? motor_p.min_angle : motor_p.max_angle);             delay(IDLING_MS * (motor_p.max_angle-motor_p.min_angle));                          //Продвижение печатающей каретки по оси X             motor_x.servo.write(motor_x.min_angle + x*STEP);             delay(((img[x/8] & (1 << 7-(x%8))) ? WRITING_MS : IDLING_MS) * STEP);          }                  //Поднять фломастер         motor_p.servo.write(motor_p.max_angle); delay(IDLING_MS * (motor_p.max_angle-motor_p.min_angle));       }          //Поднять фломастер     motor_p.servo.write(motor_p.max_angle); delay(IDLING_MS * (motor_p.max_angle-motor_p.min_angle));   }        gotoStart();   Serial.flush(); }  //Проверка входящего сообщения //ПК может отправлять на принтер команды, состоящие из двух байтов //Некоторые команды требуют дополнительных параметров  void checkMessage() {     if(Serial.available()) {       delay(10);       byte msg[] = {Serial.read(), Serial.read()};              if(msg[0] == 'P' && msg[1] == 'R') printImg(); //Печать       if(msg[0] == 'S' && msg[1] == 'T') gotoStart(); //Перейти в точку (0; 0)       if(msg[0] == 'C' && msg[1] == 'L') finish(); //"Закрыть принтер"       if(msg[0] == 'S' && msg[1] == 'Z') STEP = Serial.read(); //Определить размер пикселя на бумаге       if(msg[0] == 'P' && msg[1] == 'T') { // Определить высоту поднятия фломастера (PT+1 - на градус выше, PT-2 на 2 градуса ниже)         if(Serial.read() == '+') {           byte b = Serial.read();           motor_p.min_angle += b-'0';           motor_p.max_angle += b-'0';         } else {           byte b = Serial.read();           motor_p.min_angle -= b-'0';           motor_p.max_angle -= b-'0';         }       }       } }  void loop() {   checkMessage(); }  

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

Если Вы столкнулись с проблемами посерьёзнее, рекомендую перечитать внимательно весь туториал еще раз, и проверить, все ли Вы сделали правильно. А еще будет неплохо в таком случае проверить каждый моторчик еще раз с помощью первого листинга(Servo sweep).

Далее мы подключаем наш принтер к компьютеру и запускаем вот эту программу (нужна установленная java).

Сначала мы выбираем тот последовательный порт, к которому подключен принтер и нажимаем кнопку «OK», после чего принтер должен слегка подёрнуть площадкой для бумаги. Затем нажимаем кнопку «Log». У нас открылось окно терминала. Далее вводим команду CL — принтер должен задвинуть площадку внутрь. Если ввести ST, то принтер вернется в исходное положение. Также можно отправлять несколько команд подряд, например: CLSTCL. Главное не использовать пробелов и других символов между командами.

Если с эти справились, идём дальше — устанавливаем рычажок с фломастером. Для начала закрепим фломастер на рычаге. расстояние от его кончика до нижней грани рычага должно составлять около 25 мм. После чего нужно вкрутить шуруп так, чтобы фломастер закрепился и никуда не делся. Теперь просто надеваем этот рычаг на ось сервопривода — расстояние от кончика фломастера до бумаги должно составлять около 7 мм. Более точно высоту можно отрегулировать с помощью команд PT+1 и PT-1. Они регулируют угол подъема фломастера, вместо 1 может быть любое число от 0 до 9.

А теперь настал самый ответственный момент — печать первого рисунка. Маленькие картинки разрешения 64×64 подходят лучше всего. Я рекомендую использовать вот этого Марио:


Скачать

Сначала нужно открыть изображение:

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

Это всё. Потом Вы просто нажимаете кнопку «Print» и любуетесь тем, как работает ваше творение. Единственная возможная проблема на этом этапе — нажатия фломастера. Он будет либо давить слишком сильно, либо не давить совсем. Помимо управления высотой фломастера через терминал, можно попробовать подстроить высоту вручную.

Также вы можете на свой страх и риск поменять значения глобальных переменных в скетче: поиграть со скоростью и размерами печати.

Как только вы будете довольны качеством получаемой картинки, можете смело помещать Arduino в корпус принтера, прикрутив её винтами — на этом Ваш проект можно считать завершенным, можете хвастаться им перед всеми друзьями!

Заключение

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

ссылка на оригинал статьи http://geektimes.ru/post/262098/